Spring Boot autoconfiguration improvements.

Unit test refactoring, now with autoconfiguration integration testing.
Bug fix that did not initialize the bots, even with the deprecated @EnableTelegramBots
* [Removed - If users wish to disable, just inform telegrambots.enabled = false].
Upgrade Spring boot 2.0.2
This commit is contained in:
Lucas Oliveira 2018-06-09 15:02:22 -03:00
parent c4e13e25b3
commit 493568649a
7 changed files with 172 additions and 121 deletions

View File

@ -25,7 +25,7 @@ Usage
**Gradle** **Gradle**
```gradle ```gradle
compile "org.telegram:telegrambots-spring-boot-starter:3.6" compile "org.telegram:telegrambots-spring-boot-starter:3.6.1"
``` ```
Motivation Motivation
@ -39,8 +39,6 @@ Your main spring boot class should look like this:
```java ```java
@SpringBootApplication @SpringBootApplication
//Add this annotation to enable automatic bots initializing
@EnableTelegramBots
public class YourApplicationMainClass { public class YourApplicationMainClass {
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -60,7 +60,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<bots.version>3.6.1</bots.version> <bots.version>3.6.1</bots.version>
<spring-boot.version>1.5.10.RELEASE</spring-boot.version> <spring-boot.version>2.0.2.RELEASE</spring-boot.version>
</properties> </properties>
<dependencies> <dependencies>
@ -75,24 +75,41 @@
<artifactId>spring-boot</artifactId> <artifactId>spring-boot</artifactId>
<version>${spring-boot.version}</version> <version>${spring-boot.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId> <artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring-boot.version}</version> <version>${spring-boot.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
<version>3.9.1</version>
</dependency>
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId> <artifactId>mockito-all</artifactId>
<version>2.0.2-beta</version> <version>2.0.2-beta</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.11</version> <version>4.11</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -1,10 +0,0 @@
package org.telegram.telegrambots.starter;
import org.springframework.context.annotation.Import;
/**
* Imports configuration #TelegramBotStarterConfiguration in spring context.
*/
@Import(TelegramBotStarterConfiguration.class)
public @interface EnableTelegramBots {
}

View File

@ -0,0 +1,45 @@
package org.telegram.telegrambots.starter;
import java.util.List;
import java.util.Objects;
import org.springframework.beans.factory.InitializingBean;
import org.telegram.telegrambots.TelegramBotsApi;
import org.telegram.telegrambots.exceptions.TelegramApiException;
import org.telegram.telegrambots.generics.LongPollingBot;
import org.telegram.telegrambots.generics.WebhookBot;
/**
* Receives all beand which are #LongPollingBot and #WebhookBot and register them in #TelegramBotsApi.
*/
public class TelegramBotInitializer implements InitializingBean {
private final TelegramBotsApi telegramBotsApi;
private final List<LongPollingBot> longPollingBots;
private final List<WebhookBot> webHookBots;
public TelegramBotInitializer(TelegramBotsApi telegramBotsApi,
List<LongPollingBot> longPollingBots,
List<WebhookBot> webHookBots) {
Objects.requireNonNull(telegramBotsApi);
Objects.requireNonNull(longPollingBots);
Objects.requireNonNull(webHookBots);
this.telegramBotsApi = telegramBotsApi;
this.longPollingBots = longPollingBots;
this.webHookBots = webHookBots;
}
@Override
public void afterPropertiesSet() throws Exception {
try {
for (LongPollingBot bot : longPollingBots) {
telegramBotsApi.registerBot(bot);
}
for (WebhookBot bot : webHookBots) {
telegramBotsApi.registerBot(bot);
}
} catch (TelegramApiException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1,70 +1,37 @@
package org.telegram.telegrambots.starter; package org.telegram.telegrambots.starter;
import org.springframework.beans.factory.annotation.Autowired; import java.util.Collections;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.telegram.telegrambots.TelegramBotsApi;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.generics.LongPollingBot;
import org.telegram.telegrambots.generics.WebhookBot;
import javax.annotation.PostConstruct;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.telegram.telegrambots.TelegramBotsApi;
import org.telegram.telegrambots.generics.LongPollingBot;
import org.telegram.telegrambots.generics.WebhookBot;
/** /**
* Receives all beand which are #LongPollingBot and #WebhookBot and register them in #TelegramBotsApi.
* #TelegramBotsApi added to spring context as well * #TelegramBotsApi added to spring context as well
*/ */
@Configuration @Configuration
@ConditionalOnProperty(prefix="telegrambots",name = "enabled", havingValue = "true", matchIfMissing = true)
public class TelegramBotStarterConfiguration { public class TelegramBotStarterConfiguration {
private final List<LongPollingBot> longPollingBots;
private final List<WebhookBot> webHookBots;
private TelegramBotsApi telegramBotsApi;
@Autowired
public void setTelegramBotsApi(TelegramBotsApi telegramBotsApi) {
this.telegramBotsApi = telegramBotsApi;
}
public TelegramBotStarterConfiguration(@Autowired(required = false) List<LongPollingBot> longPollingBots,
@Autowired(required = false) List<WebhookBot> webHookBots) {
this.longPollingBots = longPollingBots;
this.webHookBots = webHookBots;
}
@PostConstruct
public void registerBots() {
Optional.ofNullable(longPollingBots).ifPresent(bots -> {
bots.forEach(bot -> {
try {
telegramBotsApi.registerBot(bot);
} catch (TelegramApiRequestException e) {
throw new RuntimeException(e);
}
});
});
Optional.ofNullable(webHookBots).ifPresent(bots -> {
bots.forEach(bot -> {
try {
telegramBotsApi.registerBot(bot);
} catch (TelegramApiRequestException e) {
throw new RuntimeException(e);
}
});
});
}
@Bean @Bean
@ConditionalOnMissingBean(TelegramBotsApi.class) @ConditionalOnMissingBean(TelegramBotsApi.class)
public TelegramBotsApi telegramBotsApi() { public TelegramBotsApi telegramBotsApi() {
return new TelegramBotsApi(); return new TelegramBotsApi();
} }
@Bean
@ConditionalOnMissingBean
public TelegramBotInitializer telegramBotInitializer(TelegramBotsApi telegramBotsApi,
Optional<List<LongPollingBot>> longPollingBots,
Optional<List<WebhookBot>> webHookBots) {
return new TelegramBotInitializer(telegramBotsApi,
longPollingBots.orElseGet(Collections::emptyList),
webHookBots.orElseGet(Collections::emptyList));
}
} }

View File

@ -0,0 +1 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.telegram.telegrambots.starter.TelegramBotStarterConfiguration

View File

@ -1,66 +1,99 @@
package org.telegram.telegrambots.starter; package org.telegram.telegrambots.starter;
import com.google.common.collect.Lists;
import org.junit.Rule; import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test; import org.junit.Test;
import org.mockito.Answers; import static org.mockito.Mockito.*;
import org.mockito.Mock; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.mockito.junit.MockitoJUnit; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.mockito.junit.MockitoRule; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.telegram.telegrambots.TelegramBotsApi; import org.telegram.telegrambots.TelegramBotsApi;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.generics.LongPollingBot; import org.telegram.telegrambots.generics.LongPollingBot;
import org.telegram.telegrambots.generics.WebhookBot; import org.telegram.telegrambots.generics.WebhookBot;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
public class TestTelegramBotStarterConfiguration { public class TestTelegramBotStarterConfiguration {
@Mock private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
private TelegramBotsApi telegramBotsApi; .withConfiguration(AutoConfigurations.of(MockTelegramBotsApi.class, TelegramBotStarterConfiguration.class));
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Test @Test
public void TestRegisterBotsWithLongPollingBots() throws TelegramApiRequestException { public void createMockTelegramBotsApiWithDefaultSettings() {
when(telegramBotsApi.registerBot(any(LongPollingBot.class))).then(Answers.RETURNS_MOCKS.get()); this.contextRunner.run((context) -> {
LongPollingBot longPollingBot = mock(LongPollingBot.class); assertThat(context).hasSingleBean(TelegramBotsApi.class);
TelegramBotStarterConfiguration configuration = new TelegramBotStarterConfiguration(Lists.newArrayList(longPollingBot), null); assertThat(context).hasSingleBean(TelegramBotInitializer.class);
configuration.setTelegramBotsApi(telegramBotsApi); assertThat(context).doesNotHaveBean(LongPollingBot.class);
assertThat(context).doesNotHaveBean(WebhookBot.class);
configuration.registerBots(); verifyNoMoreInteractions(context.getBean(TelegramBotsApi.class));
});
verify(telegramBotsApi, times(1)).registerBot(longPollingBot);
verifyNoMoreInteractions(telegramBotsApi);
} }
@Test @Test
public void TestRegisterBotsWithWebhookBots() throws TelegramApiRequestException { public void createOnlyLongPollingBot() {
doNothing().when(telegramBotsApi).registerBot(any(WebhookBot.class)); this.contextRunner.withUserConfiguration(LongPollingBotConfig.class)
WebhookBot webhookBot = mock(WebhookBot.class); .run((context) -> {
TelegramBotStarterConfiguration configuration = new TelegramBotStarterConfiguration(null, Lists.newArrayList(webhookBot)); assertThat(context).hasSingleBean(LongPollingBot.class);
configuration.setTelegramBotsApi(telegramBotsApi); assertThat(context).doesNotHaveBean(WebhookBot.class);
configuration.registerBots(); TelegramBotsApi telegramBotsApi = context.getBean(TelegramBotsApi.class);
verify(telegramBotsApi, times(1)).registerBot(webhookBot); verify(telegramBotsApi, times(1)).registerBot( context.getBean(LongPollingBot.class) );
verifyNoMoreInteractions(telegramBotsApi); verifyNoMoreInteractions(telegramBotsApi);
});
} }
@Test @Test
public void TestRegisterBotsWithLongPollingBotsAndWebhookBots() throws TelegramApiRequestException { public void createOnlyWebhookBot() {
doNothing().when(telegramBotsApi).registerBot(any(WebhookBot.class)); this.contextRunner.withUserConfiguration(WebhookBotConfig.class)
LongPollingBot longPollingBot = mock(LongPollingBot.class); .run((context) -> {
WebhookBot webhookBot = mock(WebhookBot.class); assertThat(context).hasSingleBean(WebhookBot.class);
TelegramBotStarterConfiguration configuration = new TelegramBotStarterConfiguration(Lists.newArrayList(longPollingBot), Lists.newArrayList(webhookBot)); assertThat(context).doesNotHaveBean(LongPollingBot.class);
configuration.setTelegramBotsApi(telegramBotsApi);
configuration.registerBots(); TelegramBotsApi telegramBotsApi = context.getBean(TelegramBotsApi.class);
verify(telegramBotsApi, times(1)).registerBot(longPollingBot); verify(telegramBotsApi, times(1)).registerBot( context.getBean(WebhookBot.class) );
verify(telegramBotsApi, times(1)).registerBot(webhookBot);
verifyNoMoreInteractions(telegramBotsApi); verifyNoMoreInteractions(telegramBotsApi);
});
}
@Test
public void createLongPoolingBotAndWebhookBot() {
this.contextRunner.withUserConfiguration(LongPollingBotConfig.class, WebhookBotConfig.class)
.run((context) -> {
assertThat(context).hasSingleBean(LongPollingBot.class);
assertThat(context).hasSingleBean(WebhookBot.class);
TelegramBotsApi telegramBotsApi = context.getBean(TelegramBotsApi.class);
verify(telegramBotsApi, times(1)).registerBot( context.getBean(LongPollingBot.class) );
verify(telegramBotsApi, times(1)).registerBot( context.getBean(WebhookBot.class) );
//verifyNoMoreInteractions(telegramBotsApi);
});
}
@Configuration
static class MockTelegramBotsApi{
@Bean
public TelegramBotsApi telegramBotsApi() {
return mock(TelegramBotsApi.class);
}
}
@Configuration
static class LongPollingBotConfig{
@Bean
public LongPollingBot longPollingBot() {
return mock(LongPollingBot.class);
}
}
@Configuration
static class WebhookBotConfig{
@Bean
public WebhookBot webhookBot() {
return mock(WebhookBot.class);
}
} }
} }