chore: add pre-commit checks

pull/1/head
Davide Polonio 2023-03-27 13:19:58 +02:00
parent 11e3321220
commit 5beaf44407
36 changed files with 286 additions and 224 deletions

View File

@ -3,6 +3,11 @@ type: docker
name: default name: default
steps: steps:
- name: Static checks
image: eclipse-temurin:17-jdk
commands:
- apt-get update -qq && apt-get install python3 pip && pip install pre-commit
- pre-commit run --all-files
- name: UT & IT Tests - name: UT & IT Tests
image: quay.io/testcontainers/dind-drone-plugin image: quay.io/testcontainers/dind-drone-plugin
environment: environment:
@ -41,4 +46,4 @@ services:
volumes: volumes:
- name: dockersock - name: dockersock
temp: {} temp: {}

2
.markdownlint.yaml Normal file
View File

@ -0,0 +1,2 @@
MD013:
line_length: 120

31
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,31 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
exclude: "mvnw"
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: check-toml
- id: mixed-line-ending
- repo: https://github.com/gruntwork-io/pre-commit
rev: v0.1.17
hooks:
- id: shellcheck
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
rev: v2.4.0
hooks:
- id: pretty-format-java
args: [--autofix]
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.32.2
hooks:
- id: markdownlint
- id: markdownlint-fix
- repo: https://github.com/jorisroovers/gitlint
rev: v0.17.0
hooks:
- id: gitlint

View File

@ -14,4 +14,4 @@
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>
</configuration> </configuration>
</component> </component>

View File

@ -29,4 +29,4 @@
</extension> </extension>
<method v="2" /> <method v="2" />
</configuration> </configuration>
</component> </component>

View File

@ -19,4 +19,4 @@
</deployment> </deployment>
<method v="2" /> <method v="2" />
</configuration> </configuration>
</component> </component>

View File

@ -15,4 +15,4 @@ FROM gcr.io/distroless/java17:${DEBUG_BUILD}nonroot
COPY --from=builder /build/target/mezzotre.jar /opt/mezzotre.jar COPY --from=builder /build/target/mezzotre.jar /opt/mezzotre.jar
ENTRYPOINT ["java", "-jar", "/opt/mezzotre.jar"] ENTRYPOINT ["java", "-jar", "/opt/mezzotre.jar"]

View File

@ -5,7 +5,7 @@
Mezzotre is a DnD content management system. Currently, it is still in the first development stages and everything is Mezzotre is a DnD content management system. Currently, it is still in the first development stages and everything is
still evolving, goals included. still evolving, goals included.
The whole system is based on Java17+ for the language, incoming Webhooks from Telegram, Jooby backend to handle the The whole system is based on Java17+ for the language, incoming Webhooks from Telegram, Jooby backend to handle the
requests, PostgresSQL to store data and long-term chat context information. requests, PostgresSQL to store data and long-term chat context information.
## Shipping and running ## Shipping and running
@ -14,14 +14,17 @@ Keep in mind that Mezzotre is meant to be run behind a reverse proxy handling al
In the root of the project you can find a `docker-compose.yml` file that can be a useful starting point to generate your In the root of the project you can find a `docker-compose.yml` file that can be a useful starting point to generate your
configuration. Finally, you can use the same docker-compose definition as a developer to have a live version running. configuration. Finally, you can use the same docker-compose definition as a developer to have a live version running.
Simply run: Simply run:
```shell ```shell
DEBUG_OPTS=debug- docker-compose up -d --build && docker-compose logs -f DEBUG_OPTS=debug- docker-compose up -d --build && docker-compose logs -f
``` ```
to run a debug instance. Omit the `DEBUG_OPTS` env variable for a "production" style environment. Note that this
to run a debug instance. Omit the `DEBUG_OPTS` env variable for a "production" style environment. Note that this
configuration requires an `.env` file (that is not committed for obvious reasons) containing the database password and a configuration requires an `.env` file (that is not committed for obvious reasons) containing the database password and a
valid Telegram Bot token. valid Telegram Bot token.
To configure Webhook configuration for your bot, open up a terminal and type: To configure Webhook configuration for your bot, open up a terminal and type:
```shell ```shell
curl -F "url=https://example.com/api/tg" https://api.telegram.org/bot<YOUR BOT TOKEN>/setWebhook curl -F "url=https://example.com/api/tg" https://api.telegram.org/bot<YOUR BOT TOKEN>/setWebhook
``` ```
@ -29,11 +32,12 @@ curl -F "url=https://example.com/api/tg" https://api.telegram.org/bot<YOUR BOT T
## Building ## Building
Build is achieved through Maven. To build a `jar` run: Build is achieved through Maven. To build a `jar` run:
```shell ```shell
mvn package -DskipTests=true -Dmaven.test.skip=true -Dmaven.site.skip=true -Dmaven.javadoc.skip=true mvn package -DskipTests=true -Dmaven.test.skip=true -Dmaven.site.skip=true -Dmaven.javadoc.skip=true
``` ```
In the `target/` folder wou will find an uber-jar and optionally the possibility to run it via a script and to setup In the `target/` folder wou will find an uber-jar and optionally the possibility to run it via a script and to setup
auto-startup via systemd or openrc units. auto-startup via systemd or openrc units.
## Developing ## Developing
@ -44,11 +48,11 @@ You can simply run tests with `mvn test`. This will run `UT` and `IT` tests toge
### Manual testing ### Manual testing
For a manual approach, just open a terminal and type `mvn jooby:run`. Assuming you have a database locally available For a manual approach, just open a terminal and type `mvn jooby:run`. Assuming you have a database locally available
(check out [application.conf](conf/application.conf)) and a valid Telegram token set (maybe as enviroment variable) you (check out [application.conf](conf/application.conf)) and a valid Telegram token set (maybe as enviroment variable) you
can develop and see live changes of your Mezzotre on the fly. Finally, by using Postman, you can simulate incoming can develop and see live changes of your Mezzotre on the fly. Finally, by using Postman, you can simulate incoming
Telegram events. Telegram events.
## License ## License
This software is under AGPL3+. You can find all details in the [LICENSE](LICENSE) file. This software is under AGPL3+. You can find all details in the [LICENSE](LICENSE) file.

View File

@ -8,4 +8,4 @@ telegram.key = akey
application.lang = en en-US it it-IT application.lang = en en-US it it-IT
server.port = 9191 server.port = 9191
server.gzip = true server.gzip = true

View File

@ -27,4 +27,4 @@
"default": 0 "default": 0
} }
} }
} }

View File

@ -38,4 +38,4 @@ max_java_memory: 512
# Try to create a symbolic link to java executable in <app_home>/run with # Try to create a symbolic link to java executable in <app_home>/run with
# the name of "<app_name>-java" so that commands like "ps" will make it # the name of "<app_name>-java" so that commands like "ps" will make it
# easier to find your app # easier to find your app
symlink_java: true symlink_java: true

View File

@ -1,7 +1,9 @@
package com.github.polpetta.mezzotre; package com.github.polpetta.mezzotre;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides;import io.jooby.Jooby;import org.slf4j.Logger; import com.google.inject.Provides;
import io.jooby.Jooby;
import org.slf4j.Logger;
public class InjectionModule extends AbstractModule { public class InjectionModule extends AbstractModule {
private final Jooby jooby; private final Jooby jooby;

View File

@ -1,5 +1,7 @@
package com.github.polpetta.mezzotre.i18n; package com.github.polpetta.mezzotre.i18n;
import java.util.Locale;
import javax.inject.Inject;
import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.resource.loader.JarResourceLoader; import org.apache.velocity.runtime.resource.loader.JarResourceLoader;
import org.apache.velocity.tools.Scope; import org.apache.velocity.tools.Scope;
@ -8,8 +10,6 @@ import org.apache.velocity.tools.ToolManager;
import org.apache.velocity.tools.config.FactoryConfiguration; import org.apache.velocity.tools.config.FactoryConfiguration;
import org.apache.velocity.tools.config.ToolConfiguration; import org.apache.velocity.tools.config.ToolConfiguration;
import org.apache.velocity.tools.config.ToolboxConfiguration; import org.apache.velocity.tools.config.ToolboxConfiguration;
import javax.inject.Inject;
import java.util.Locale;
public class LocalizedMessageFactory { public class LocalizedMessageFactory {
@ -22,8 +22,7 @@ public class LocalizedMessageFactory {
public ToolManager create(Locale locale) { public ToolManager create(Locale locale) {
// properties.setProperty("file.resource.loader.class", FileResourceLoader.class.getName());. // properties.setProperty("file.resource.loader.class", FileResourceLoader.class.getName());.
final ToolManager toolManager = new ToolManager(); final ToolManager toolManager = new ToolManager();
toolManager.setVelocityEngine(velocityEngine); toolManager.setVelocityEngine(velocityEngine);

View File

@ -1,8 +1,8 @@
package com.github.polpetta.mezzotre.i18n; package com.github.polpetta.mezzotre.i18n;
import java.util.Locale;
import org.apache.velocity.tools.config.DefaultKey; import org.apache.velocity.tools.config.DefaultKey;
import org.apache.velocity.tools.generic.ResourceTool; import org.apache.velocity.tools.generic.ResourceTool;
import java.util.Locale;
@DefaultKey("i18n") @DefaultKey("i18n")
public class LocalizedTool extends ResourceTool { public class LocalizedTool extends ResourceTool {

View File

@ -1,38 +1,46 @@
package com.github.polpetta.mezzotre.orm.di; package com.github.polpetta.mezzotre.orm.di;
import com.google.inject.AbstractModule;import com.google.inject.Provides;import com.google.inject.Singleton;import com.zaxxer.hikari.HikariConfig;import io.jooby.Extension;import io.jooby.ebean.EbeanModule;import io.jooby.flyway.FlywayModule;import io.jooby.hikari.HikariModule;import javax.inject.Named; import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.zaxxer.hikari.HikariConfig;
import io.jooby.Extension;
import io.jooby.ebean.EbeanModule;
import io.jooby.flyway.FlywayModule;
import io.jooby.hikari.HikariModule;
import javax.inject.Named;
public class Db extends AbstractModule { public class Db extends AbstractModule {
/** /**
* Returns null. This allows to fetch the configuration from file rather than fetch from other * Returns null. This allows to fetch the configuration from file rather than fetch from other
* environment * environment
* *
* @return a {@link HikariConfig} configuration if possible * @return a {@link HikariConfig} configuration if possible
*/ */
@Provides @Provides
@Singleton @Singleton
public HikariConfig getHikariConfig() { public HikariConfig getHikariConfig() {
return null; return null;
} }
@Provides @Provides
@Singleton @Singleton
@Named("hikariPoolExtension") @Named("hikariPoolExtension")
public Extension getHikariExtension() { public Extension getHikariExtension() {
return new HikariModule(); return new HikariModule();
} }
@Provides @Provides
@Singleton @Singleton
@Named("flyWayMigrationExtension") @Named("flyWayMigrationExtension")
public Extension getFlyWayMigrationExtension() { public Extension getFlyWayMigrationExtension() {
return new FlywayModule(); return new FlywayModule();
} }
@Provides @Provides
@Singleton @Singleton
@Named("ebeanExtension") @Named("ebeanExtension")
public Extension getEbeanExtension() { public Extension getEbeanExtension() {
return new EbeanModule(); return new EbeanModule();
} }
} }

View File

@ -3,11 +3,12 @@ package com.github.polpetta.mezzotre.orm.model;
import io.ebean.Model; import io.ebean.Model;
import io.ebean.annotation.WhenCreated; import io.ebean.annotation.WhenCreated;
import io.ebean.annotation.WhenModified; import io.ebean.annotation.WhenModified;
import javax.persistence.MappedSuperclass;
import java.time.Instant; import java.time.Instant;
import javax.persistence.MappedSuperclass;
/** /**
* Father class to all the database objects. It allows to add when an object has been created and modifies * Father class to all the database objects. It allows to add when an object has been created and
* modifies
* *
* @author Davide Polonio * @author Davide Polonio
* @since 1.0-SNAPSHOT * @since 1.0-SNAPSHOT

View File

@ -1,6 +1,6 @@
package com.github.polpetta.mezzotre.route; package com.github.polpetta.mezzotre.route;
public final class Constants { public final class Constants {
public final static String V1 = "v1"; public static final String V1 = "v1";
public final static String API = "api"; public static final String API = "api";
} }

View File

@ -21,7 +21,10 @@ public class Route extends AbstractModule {
.orElseThrow( .orElseThrow(
() -> () ->
new IllegalStateException( new IllegalStateException(
"Telegram token is required to make the application work. Please set 'telegram.key = \"value\"' in your application.conf file or as the application argument. Alternatively, you can set 'TELEGRAM_KEY' as an environment variable.")); "Telegram token is required to make the application work. Please set"
+ " 'telegram.key = \"value\"' in your application.conf file or as the"
+ " application argument. Alternatively, you can set 'TELEGRAM_KEY' as"
+ " an environment variable."));
return new TelegramBot(telegramKey); return new TelegramBot(telegramKey);
} }
} }

View File

@ -3,7 +3,6 @@ package com.github.polpetta.mezzotre.telegram.command;
import com.github.polpetta.mezzotre.orm.model.TgChat; import com.github.polpetta.mezzotre.orm.model.TgChat;
import com.pengrad.telegrambot.model.Update; import com.pengrad.telegrambot.model.Update;
import com.pengrad.telegrambot.request.BaseRequest; import com.pengrad.telegrambot.request.BaseRequest;
import com.pengrad.telegrambot.request.SendMessage;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -27,10 +26,10 @@ public interface Executor {
/** /**
* Process the current update * Process the current update
* *
* @param chat the chat the {@link Executor} is currently replying to * @param chat the chat the {@link Executor} is currently replying to
* @param update the update to process * @param update the update to process
* @return a {@link CompletableFuture} with the result of the computation * @return a {@link CompletableFuture} with the result of the computation
*/ */
// FIXME cannot be void - we don't want pesky side effects! // FIXME cannot be void - we don't want pesky side effects!
CompletableFuture<Optional<BaseRequest<?,?>>> process(TgChat chat, Update update); CompletableFuture<Optional<BaseRequest<?, ?>>> process(TgChat chat, Update update);
} }

View File

@ -86,13 +86,13 @@ public class Start implements Executor {
.get(); .get();
log.trace("Start command - message to send back: " + message); log.trace("Start command - message to send back: " + message);
final ChatContext chatContext = chat.getChatContext(); final ChatContext chatContext = chat.getChatContext();
chatContext.setLastMessageSentId(update.message().messageId()); chatContext.setLastMessageSentId(update.message().messageId());
chatContext.setStage(getTriggerKeyword()); chatContext.setStage(getTriggerKeyword());
chatContext.setStep(0); chatContext.setStep(0);
chatContext.setPreviousMessageUnixTimestampInSeconds(update.message().date()); chatContext.setPreviousMessageUnixTimestampInSeconds(update.message().date());
chat.setChatContext(chatContext); chat.setChatContext(chatContext);
chat.save(); chat.save();
return Optional.of(new SendMessage(chat.getId(), message).parseMode(ParseMode.Markdown)); return Optional.of(new SendMessage(chat.getId(), message).parseMode(ParseMode.Markdown));
}, },

View File

@ -1,28 +1,31 @@
package com.github.polpetta.mezzotre.telegram.command.di; package com.github.polpetta.mezzotre.telegram.command.di;
import com.github.polpetta.mezzotre.telegram.command.Executor;import com.github.polpetta.mezzotre.telegram.command.Start;import com.google.common.io.Resources;import com.google.inject.AbstractModule;import com.google.inject.Provides;import org.apache.velocity.app.VelocityEngine; import com.github.polpetta.mezzotre.telegram.command.Executor;
import com.github.polpetta.mezzotre.telegram.command.Start;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import java.util.Set;
import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants; import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import javax.inject.Named;
import javax.inject.Singleton;import java.util.Set;
public class Command extends AbstractModule { public class Command extends AbstractModule {
@Provides @Provides
@Singleton @Singleton
@Named("commands") @Named("commands")
public Set<Executor> getCommandExecutors( public Set<Executor> getCommandExecutors(Start start) {
Start start return Set.of(start);
) { }
return Set.of(start);
}
@Provides @Provides
public VelocityEngine getVelocityEngine() { public VelocityEngine getVelocityEngine() {
final VelocityEngine velocityEngine = new VelocityEngine(); final VelocityEngine velocityEngine = new VelocityEngine();
velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
velocityEngine.setProperty( velocityEngine.setProperty(
"classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); "classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
velocityEngine.init(); velocityEngine.init();
return velocityEngine; return velocityEngine;
} }
} }

View File

@ -2,11 +2,11 @@ package com.github.polpetta.mezzotre.util.di;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool;
import javax.inject.Named;
import javax.inject.Singleton;
public class ThreadPool extends AbstractModule { public class ThreadPool extends AbstractModule {
@Provides @Provides

View File

@ -21,4 +21,3 @@ create table registered_user (
-- foreign keys and indices -- foreign keys and indices
alter table registered_user add constraint fk_registered_user_telegram_id foreign key (telegram_id) references telegram_chat (id) on delete cascade on update restrict; alter table registered_user add constraint fk_registered_user_telegram_id foreign key (telegram_id) references telegram_chat (id) on delete cascade on update restrict;

View File

@ -1,3 +1,3 @@
start.hello=Hello start.hello=Hello
start.thisIs=This is start.thisIs=This is
start.description=a simple bot focused on DnD content management! Please start by choosing a language down below. start.description=a simple bot focused on DnD content management! Please start by choosing a language down below.

View File

@ -1,3 +1,3 @@
start.hello=Hello start.hello=Hello
start.thisIs=This is start.thisIs=This is
start.description=a simple bot focused on DnD content management! Please start by choosing a language down below. start.description=a simple bot focused on DnD content management! Please start by choosing a language down below.

View File

@ -1,3 +1,3 @@
start.hello=Ciao start.hello=Ciao
start.thisIs=Questo è start.thisIs=Questo è
start.description=un semplice bot che ci concenta sulla gestione di contenuto per DnD! Per favore comincia selezionando la lingua qui sotto start.description=un semplice bot che ci concenta sulla gestione di contenuto per DnD! Per favore comincia selezionando la lingua qui sotto

View File

@ -1,3 +1,3 @@
start.hello=Ciao start.hello=Ciao
start.thisIs=Questo è start.thisIs=Questo è
start.description=un semplice bot che ci concenta sulla gestione di contenuto per DnD! Per favore comincia selezionando la lingua qui sotto start.description=un semplice bot che ci concenta sulla gestione di contenuto per DnD! Per favore comincia selezionando la lingua qui sotto

View File

@ -1,4 +1,4 @@
## https://velocity.apache.org/tools/2.0/apidocs/org/apache/velocity/tools/generic/ResourceTool.html ## https://velocity.apache.org/tools/2.0/apidocs/org/apache/velocity/tools/generic/ResourceTool.html
**$i18n.start.hello $firstName! 👋** **$i18n.start.hello $firstName! 👋**
$i18n.start.thisIs _${programName}_, $i18n.start.description 👇 $i18n.start.thisIs _${programName}_, $i18n.start.description 👇

View File

@ -3,21 +3,14 @@ package com.github.polpetta.mezzotre;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import com.github.polpetta.mezzotre.helper.IntegrationAppFactory; import com.github.polpetta.mezzotre.helper.IntegrationAppFactory;
import com.github.polpetta.mezzotre.helper.Loader;
import com.github.polpetta.mezzotre.helper.TestConfig;
import io.ebean.Database;
import io.jooby.JoobyTest; import io.jooby.JoobyTest;
import io.jooby.StatusCode; import io.jooby.StatusCode;
import java.io.IOException; import java.io.IOException;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@Tag("slow") @Tag("slow")
@Tag("database") @Tag("database")

View File

@ -1,7 +1,6 @@
package com.github.polpetta.mezzotre.helper; package com.github.polpetta.mezzotre.helper;
import com.github.polpetta.mezzotre.App; import com.github.polpetta.mezzotre.App;
import com.github.polpetta.mezzotre.InjectionModule;
import com.github.polpetta.mezzotre.route.di.Route; import com.github.polpetta.mezzotre.route.di.Route;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;

View File

@ -1,43 +1,52 @@
package com.github.polpetta.mezzotre.helper; package com.github.polpetta.mezzotre.helper;
import com.github.polpetta.mezzotre.App;import com.google.common.io.Resources;import com.zaxxer.hikari.HikariConfig;import com.zaxxer.hikari.HikariDataSource;import io.ebean.Database;import io.ebean.DatabaseFactory;import io.ebean.config.DatabaseConfig;import org.apache.commons.lang3.tuple.Pair;import org.testcontainers.containers.PostgreSQLContainer;import java.io.IOException;import java.io.InputStream;import java.net.URL;import java.util.Properties;public class Loader { import com.google.common.io.Resources;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import io.ebean.Database;
import io.ebean.DatabaseFactory;
import io.ebean.config.DatabaseConfig;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
import org.apache.commons.lang3.tuple.Pair;
import org.testcontainers.containers.PostgreSQLContainer;
public static Pair<Properties, Properties> loadDefaultEbeanConfigWithPostgresSettings( public class Loader {
PostgreSQLContainer<?> container) throws IOException {
public static Pair<Properties, Properties> loadDefaultEbeanConfigWithPostgresSettings(
PostgreSQLContainer<?> container) throws IOException {
final URL ebeanRes = Resources.getResource("database-test.properties"); final URL ebeanRes = Resources.getResource("database-test.properties");
final URL hikariRes = Resources.getResource("hikari.properties"); final URL hikariRes = Resources.getResource("hikari.properties");
final Properties ebeanConnectionProperties = new Properties(); final Properties ebeanConnectionProperties = new Properties();
final Properties hikariConnectionProperties = new Properties(); final Properties hikariConnectionProperties = new Properties();
try (InputStream ebeanInputStream = ebeanRes.openStream(); try (InputStream ebeanInputStream = ebeanRes.openStream();
InputStream hikariInputStream = hikariRes.openStream()) { InputStream hikariInputStream = hikariRes.openStream()) {
hikariConnectionProperties.load(hikariInputStream); hikariConnectionProperties.load(hikariInputStream);
hikariConnectionProperties.put("username", container.getUsername()); hikariConnectionProperties.put("username", container.getUsername());
hikariConnectionProperties.put("password", container.getPassword()); hikariConnectionProperties.put("password", container.getPassword());
hikariConnectionProperties.put("jdbcUrl", container.getJdbcUrl()); hikariConnectionProperties.put("jdbcUrl", container.getJdbcUrl());
ebeanConnectionProperties.load(ebeanInputStream); ebeanConnectionProperties.load(ebeanInputStream);
ebeanConnectionProperties.put("datasource_db_username", container.getUsername()); ebeanConnectionProperties.put("datasource_db_username", container.getUsername());
ebeanConnectionProperties.put("datasource_db_password", container.getPassword()); ebeanConnectionProperties.put("datasource_db_password", container.getPassword());
ebeanConnectionProperties.put("datasource_db_databaseUrl", container.getJdbcUrl()); ebeanConnectionProperties.put("datasource_db_databaseUrl", container.getJdbcUrl());
ebeanConnectionProperties.put("datasource_db_databaseDriver", "org.postgresql.Driver"); ebeanConnectionProperties.put("datasource_db_databaseDriver", "org.postgresql.Driver");
}
return Pair.of(ebeanConnectionProperties, hikariConnectionProperties);
} }
return Pair.of(ebeanConnectionProperties, hikariConnectionProperties);
}
public static Database connectToDatabase( public static Database connectToDatabase(Properties ebean, Properties hikari) {
Properties ebean, final HikariDataSource hikariDataSource = new HikariDataSource(new HikariConfig(hikari));
Properties hikari final DatabaseConfig databaseConfig = new DatabaseConfig();
) { databaseConfig.loadFromProperties(ebean);
final HikariDataSource hikariDataSource = databaseConfig.setDataSource(hikariDataSource);
new HikariDataSource(new HikariConfig(hikari));
final DatabaseConfig databaseConfig = new DatabaseConfig();
databaseConfig.loadFromProperties(ebean);
databaseConfig.setDataSource(hikariDataSource);
return DatabaseFactory.create(databaseConfig); return DatabaseFactory.create(databaseConfig);
} }
public static Database connectToDatabase(Pair<Properties, Properties> connectionProperties) { public static Database connectToDatabase(Pair<Properties, Properties> connectionProperties) {
return connectToDatabase(connectionProperties.getLeft(), connectionProperties.getRight()); return connectToDatabase(connectionProperties.getLeft(), connectionProperties.getRight());
} }
} }

View File

@ -52,7 +52,8 @@ public class UserIntegrationTest {
final Timestamp timestampFromUnixEpoch = Clock.getTimestampFromUnixEpoch(1L); final Timestamp timestampFromUnixEpoch = Clock.getTimestampFromUnixEpoch(1L);
final String insertQuery = final String insertQuery =
"insert into registered_user (id, is_active, telegram_id, email_address, entry_created, entry_modified) values (?, ?, null, ?, ?, ?)"; "insert into registered_user (id, is_active, telegram_id, email_address, entry_created,"
+ " entry_modified) values (?, ?, null, ?, ?, ?)";
final int affectedRows = final int affectedRows =
database database
.sqlUpdate(insertQuery) .sqlUpdate(insertQuery)

View File

@ -78,30 +78,30 @@ class TelegramIntegrationTest {
final Context fakeContext = mock(Context.class); final Context fakeContext = mock(Context.class);
final Update update = final Update update =
gson.fromJson( gson.fromJson(
""" "{\n"
{ + "\"update_id\":10000,\n"
"update_id":10000, + "\"message\":{\n"
"message":{ + " \"date\":1441645532,\n"
"date":1441645532, + " \"chat\":{\n"
"chat":{ + " \"last_name\":\"Test Lastname\",\n"
"last_name":"Test Lastname", + " \"id\":1111111,\n"
"id":1111111, + " \"type\": \"private\",\n"
"type": "private", + " \"first_name\":\"Test Firstname\",\n"
"first_name":"Test Firstname", + " \"username\":\"Testusername\"\n"
"username":"Testusername" + " },\n"
}, + " \"message_id\":1365,\n"
"message_id":1365, + " \"from\":{\n"
"from":{ + " \"last_name\":\"Test Lastname\",\n"
"last_name":"Test Lastname", + " \"id\":1111111,\n"
"id":1111111, + " \"first_name\":\"Test Firstname\",\n"
"first_name":"Test Firstname", + " \"username\":\"Testusername\"\n"
"username":"Testusername" + " },\n"
}, + " \"text\":\"/start\"\n"
"text":"/start" + "}\n"
} + "}\n",
}""",
Update.class); Update.class);
final CompletableFuture<String> integerCompletableFuture = telegram.incomingUpdate(fakeContext, update); final CompletableFuture<String> integerCompletableFuture =
telegram.incomingUpdate(fakeContext, update);
verify(fakeContext, times(1)).setResponseType(MediaType.JSON); verify(fakeContext, times(1)).setResponseType(MediaType.JSON);
final String gotReply = integerCompletableFuture.get(); final String gotReply = integerCompletableFuture.get();
assertDoesNotThrow(() -> gotReply); assertDoesNotThrow(() -> gotReply);

View File

@ -1,22 +1,24 @@
package com.github.polpetta.mezzotre.telegram.command; package com.github.polpetta.mezzotre.telegram.command;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.github.polpetta.mezzotre.orm.model.TgChat; import com.github.polpetta.mezzotre.orm.model.TgChat;
import com.github.polpetta.types.json.ChatContext; import com.github.polpetta.types.json.ChatContext;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.pengrad.telegrambot.model.Update; import com.pengrad.telegrambot.model.Update;
import com.pengrad.telegrambot.request.BaseRequest; import com.pengrad.telegrambot.request.BaseRequest;
import com.pengrad.telegrambot.request.SendMessage; import com.pengrad.telegrambot.request.SendMessage;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.BeforeAll;
import static org.mockito.ArgumentMatchers.any; import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.mock; import org.junit.jupiter.api.parallel.Execution;
import static org.mockito.Mockito.when; import org.junit.jupiter.api.parallel.ExecutionMode;
@Execution(ExecutionMode.CONCURRENT) @Execution(ExecutionMode.CONCURRENT)
class RouterTest { class RouterTest {

View File

@ -1,5 +1,7 @@
package com.github.polpetta.mezzotre.telegram.command; package com.github.polpetta.mezzotre.telegram.command;
import static org.junit.jupiter.api.Assertions.*;
import com.github.polpetta.mezzotre.helper.Loader; import com.github.polpetta.mezzotre.helper.Loader;
import com.github.polpetta.mezzotre.helper.TestConfig; import com.github.polpetta.mezzotre.helper.TestConfig;
import com.github.polpetta.mezzotre.i18n.LocalizedMessageFactory; import com.github.polpetta.mezzotre.i18n.LocalizedMessageFactory;
@ -11,6 +13,9 @@ import com.pengrad.telegrambot.model.Update;
import com.pengrad.telegrambot.request.BaseRequest; import com.pengrad.telegrambot.request.BaseRequest;
import com.pengrad.telegrambot.request.SendMessage; import com.pengrad.telegrambot.request.SendMessage;
import io.ebean.Database; import io.ebean.Database;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants; import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
@ -24,12 +29,6 @@ import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import static org.junit.jupiter.api.Assertions.*;
@Tag("slow") @Tag("slow")
@Tag("database") @Tag("database")
@Tag("velocity") @Tag("velocity")
@ -76,28 +75,27 @@ class StartIntegrationTest {
final Update update = final Update update =
gson.fromJson( gson.fromJson(
""" "{\n"
{ + "\"update_id\":10000,\n"
"update_id":10000, + "\"message\":{\n"
"message":{ + " \"date\":1441645532,\n"
"date":1441645532, + " \"chat\":{\n"
"chat":{ + " \"last_name\":\"Test Lastname\",\n"
"last_name":"Test Lastname", + " \"id\":1111111,\n"
"id":1111111, + " \"type\": \"private\",\n"
"type": "private", + " \"first_name\":\"Test Firstname\",\n"
"first_name":"Test Firstname", + " \"username\":\"Testusername\"\n"
"username":"Testusername" + " },\n"
}, + " \"message_id\":1365,\n"
"message_id":1365, + " \"from\":{\n"
"from":{ + " \"last_name\":\"Test Lastname\",\n"
"last_name":"Test Lastname", + " \"id\":1111111,\n"
"id":1111111, + " \"first_name\":\"Test Firstname\",\n"
"first_name":"Test Firstname", + " \"username\":\"Testusername\"\n"
"username":"Testusername" + " },\n"
}, + " \"text\":\"/start\"\n"
"text":"/start" + "}\n"
} + "}",
}""",
Update.class); Update.class);
final CompletableFuture<Optional<BaseRequest<?, ?>>> gotFuture = start.process(tgChat, update); final CompletableFuture<Optional<BaseRequest<?, ?>>> gotFuture = start.process(tgChat, update);
@ -108,7 +106,9 @@ class StartIntegrationTest {
assertInstanceOf(SendMessage.class, gotMessage); assertInstanceOf(SendMessage.class, gotMessage);
final String message = (String) gotMessage.getParameters().get("text"); final String message = (String) gotMessage.getParameters().get("text");
assertEquals( assertEquals(
"**Hello Test Firstname! \uD83D\uDC4B**\n\nThis is _Mezzotre_, a simple bot focused on DnD content management! Please start by choosing a language down below. \uD83D\uDC47", "**Hello Test Firstname! \uD83D\uDC4B**\n\n"
+ "This is _Mezzotre_, a simple bot focused on DnD content management! Please start by"
+ " choosing a language down below. \uD83D\uDC47",
message); message);
assertEquals(1111111L, (Long) gotMessage.getParameters().get("chat_id")); assertEquals(1111111L, (Long) gotMessage.getParameters().get("chat_id"));

View File

@ -1,5 +1,8 @@
package com.github.polpetta.mezzotre.telegram.command; package com.github.polpetta.mezzotre.telegram.command;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import com.github.polpetta.mezzotre.i18n.LocalizedMessageFactory; import com.github.polpetta.mezzotre.i18n.LocalizedMessageFactory;
import com.github.polpetta.mezzotre.orm.model.TgChat; import com.github.polpetta.mezzotre.orm.model.TgChat;
import com.github.polpetta.types.json.ChatContext; import com.github.polpetta.types.json.ChatContext;
@ -7,6 +10,10 @@ import com.google.gson.Gson;
import com.pengrad.telegrambot.model.Update; import com.pengrad.telegrambot.model.Update;
import com.pengrad.telegrambot.request.BaseRequest; import com.pengrad.telegrambot.request.BaseRequest;
import com.pengrad.telegrambot.request.SendMessage; import com.pengrad.telegrambot.request.SendMessage;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants; import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
@ -18,14 +25,6 @@ import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode; import org.junit.jupiter.api.parallel.ExecutionMode;
import org.slf4j.Logger; import org.slf4j.Logger;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
@Tag("velocity") @Tag("velocity")
@Execution(ExecutionMode.CONCURRENT) @Execution(ExecutionMode.CONCURRENT)
class StartTest { class StartTest {
@ -38,7 +37,9 @@ class StartTest {
@BeforeAll @BeforeAll
static void beforeAll() { static void beforeAll() {
gson = new Gson(); gson = new Gson();
}@BeforeEach }
@BeforeEach
void setUp() { void setUp() {
velocityEngine = new VelocityEngine(); velocityEngine = new VelocityEngine();
velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADERS, "classpath"); velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADERS, "classpath");
@ -61,28 +62,27 @@ class StartTest {
final Update update = final Update update =
gson.fromJson( gson.fromJson(
""" "{\n"
{ + "\"update_id\":10000,\n"
"update_id":10000, + "\"message\":{\n"
"message":{ + " \"date\":1441645532,\n"
"date":1441645532, + " \"chat\":{\n"
"chat":{ + " \"last_name\":\"Test Lastname\",\n"
"last_name":"Test Lastname", + " \"id\":1111111,\n"
"id":1111111, + " \"type\": \"private\",\n"
"type": "private", + " \"first_name\":\"Test Firstname\",\n"
"first_name":"Test Firstname", + " \"username\":\"Testusername\"\n"
"username":"Testusername" + " },\n"
}, + " \"message_id\":1365,\n"
"message_id":1365, + " \"from\":{\n"
"from":{ + " \"last_name\":\"Test Lastname\",\n"
"last_name":"Test Lastname", + " \"id\":1111111,\n"
"id":1111111, + " \"first_name\":\"Test Firstname\",\n"
"first_name":"Test Firstname", + " \"username\":\"Testusername\"\n"
"username":"Testusername" + " },\n"
}, + " \"text\":\"/start\"\n"
"text":"/start" + "}\n"
} + "}",
}""",
Update.class); Update.class);
final CompletableFuture<Optional<BaseRequest<?, ?>>> gotFuture = final CompletableFuture<Optional<BaseRequest<?, ?>>> gotFuture =
@ -94,7 +94,9 @@ class StartTest {
assertInstanceOf(SendMessage.class, gotMessage); assertInstanceOf(SendMessage.class, gotMessage);
final String message = (String) gotMessage.getParameters().get("text"); final String message = (String) gotMessage.getParameters().get("text");
assertEquals( assertEquals(
"**Hello Test Firstname! \uD83D\uDC4B**\n\nThis is _Mezzotre_, a simple bot focused on DnD content management! Please start by choosing a language down below. \uD83D\uDC47", "**Hello Test Firstname! \uD83D\uDC4B**\n\n"
+ "This is _Mezzotre_, a simple bot focused on DnD content management! Please start by"
+ " choosing a language down below. \uD83D\uDC47",
message); message);
assertEquals(1111111L, (Long) gotMessage.getParameters().get("chat_id")); assertEquals(1111111L, (Long) gotMessage.getParameters().get("chat_id"));
verify(fakeChat, times(1)).save(); verify(fakeChat, times(1)).save();