diff --git a/Mage.Common/pom.xml b/Mage.Common/pom.xml
index f6b346f88c..a84170a4a9 100644
--- a/Mage.Common/pom.xml
+++ b/Mage.Common/pom.xml
@@ -56,6 +56,21 @@
gson
2.8.6
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+ org.apache.commons
+ commons-lang3
+ test
+
@@ -82,7 +97,10 @@
UTF-8
-
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
mage-common
diff --git a/Mage.Common/src/main/java/mage/utils/FluentBuilder.java b/Mage.Common/src/main/java/mage/utils/FluentBuilder.java
new file mode 100644
index 0000000000..3e4ab75b91
--- /dev/null
+++ b/Mage.Common/src/main/java/mage/utils/FluentBuilder.java
@@ -0,0 +1,36 @@
+package mage.utils;
+
+import java.util.ArrayList;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public abstract class FluentBuilder> {
+
+ final ArrayList> buildSequence;
+ private final Supplier newReference;
+
+ protected FluentBuilder(Supplier newReference) {
+ this.buildSequence = new ArrayList<>();
+ this.newReference = newReference;
+ }
+
+ private RealBuilder copy() {
+ final RealBuilder realBuilder = newReference.get();
+ realBuilder.buildSequence.addAll(buildSequence);
+ return realBuilder;
+ }
+
+ protected abstract ToBuild makeValue();
+
+ public RealBuilder with(Consumer consumer) {
+ final RealBuilder nextBuilder = this.copy();
+ nextBuilder.buildSequence.add(consumer);
+ return nextBuilder;
+ }
+
+ public ToBuild build() {
+ final RealBuilder instance = this.copy();
+ instance.buildSequence.forEach(c -> c.accept(instance));
+ return instance.makeValue();
+ }
+}
\ No newline at end of file
diff --git a/Mage.Common/src/test/java/mage/remote/ConnectionTest.java b/Mage.Common/src/test/java/mage/remote/ConnectionTest.java
new file mode 100644
index 0000000000..1e49ed9c37
--- /dev/null
+++ b/Mage.Common/src/test/java/mage/remote/ConnectionTest.java
@@ -0,0 +1,123 @@
+package mage.remote;
+
+import mage.utils.FluentBuilder;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.RandomUtils;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import java.net.URI;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ConnectionTest {
+
+ static class ConnectionBuilder extends FluentBuilder {
+
+ public int port;
+ public String host;
+ public String parameter;
+
+ private ConnectionBuilder() {
+ super(ConnectionBuilder::new);
+ }
+
+ @Override
+ protected Connection makeValue() {
+ final Connection result = new Connection(parameter);
+ result.setHost(host);
+ result.setPort(port);
+ return result;
+ }
+ }
+
+ private ConnectionBuilder baseBuilder() {
+ return new ConnectionBuilder();
+ }
+
+ class TestsTemplate {
+ final ConnectionBuilder testeeBuilder;
+
+ TestsTemplate(ConnectionBuilder testeeBuilder) {
+ this.testeeBuilder = testeeBuilder;
+ }
+
+ @Test
+ @DisplayName("produce the expected scheme")
+ void scheme() throws Exception {
+ final URI testee = make(testeeBuilder);
+ assertThat(testee.getScheme()).isEqualTo("bisocket");
+ }
+
+ URI make(ConnectionBuilder builder) {
+ try {
+ return new URI(builder.build().getURI());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ @DisplayName("generate the expected port")
+ void port() {
+ final int expected = RandomUtils.nextInt(1000, 65000);
+ final int port = make(testeeBuilder.with(c -> c.port = expected)).getPort();
+
+ assertThat(port).isEqualTo(expected);
+ }
+
+ @Test
+ @DisplayName("generate the expected serialisation parameter")
+ void serialisation() {
+ final String query = make(testeeBuilder).getQuery();
+
+ assertThat(query).contains("serializationtype=jboss");
+ }
+
+ @Test
+ @DisplayName("generate the expected threadpool parameter")
+ void threadpool() {
+ final String parameter = RandomStringUtils.randomAlphanumeric(12);
+ final String query = make(testeeBuilder.with(c -> c.parameter = parameter)).getQuery();
+
+ assertThat(query).contains("onewayThreadPool=mage.remote.CustomThreadPool" + parameter);
+ }
+
+ }
+
+ @Nested
+ @DisplayName("getUri when host is localhost should")
+ class LocalhostTest extends TestsTemplate {
+
+ LocalhostTest() {
+ super(baseBuilder().with(c -> c.host = "localhost"));
+ }
+
+ @Test
+ @DisplayName("generate an ipv4 as host")
+ void ipv4Gen() {
+ final String host = make(testeeBuilder).getHost();
+
+ assertThat(host).matches("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+");
+ }
+ }
+
+ private final String randomHost = RandomStringUtils.randomAlphabetic(15);
+
+ @Nested
+ @DisplayName("getUri when host is not localhost should")
+ class StandardHostTest extends TestsTemplate {
+ StandardHostTest() {
+ super(baseBuilder().with(c -> c.host = randomHost));
+ }
+
+ @Test
+ @DisplayName("generate the selected host as host")
+ void hostGen() {
+ final String host = make(testeeBuilder).getHost();
+
+ assertThat(host).isEqualTo(randomHost);
+ }
+ }
+}
diff --git a/Mage.Common/src/test/java/mage/utils/FluentBuilderTest.java b/Mage.Common/src/test/java/mage/utils/FluentBuilderTest.java
new file mode 100644
index 0000000000..180f82ef20
--- /dev/null
+++ b/Mage.Common/src/test/java/mage/utils/FluentBuilderTest.java
@@ -0,0 +1,116 @@
+package mage.utils;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
+
+public class FluentBuilderTest {
+
+
+ private ABuilder baseBuilder() {
+ return new ABuilder();
+ }
+
+ @Test
+ @DisplayName("build with default parameters")
+ void testDefault() {
+ final A actual = baseBuilder().build();
+
+ verifyAB(actual, null, 0);
+ }
+
+ private void verifyAB(A actual, String a, int b) {
+ assertThat(actual.getA()).isEqualTo(a);
+ assertThat(actual.getB()).isEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("chain with clause and add new parameters")
+ void testBaseChain() {
+ final A actual = baseBuilder().with(a -> a.a = "hello").build();
+
+ verifyAB(actual, "hello", 0);
+ }
+
+ @Test
+ @DisplayName("chain multiple with clauses and add new parameters")
+ void testMultiChain() {
+ final A actual = baseBuilder().with(a -> a.a = "world").with(a -> a.b = 6).build();
+
+ verifyAB(actual, "world", 6);
+ }
+
+ @Test
+ @DisplayName("chain multiple with clauses and override latest writes")
+ void testMultiChainOverride() {
+ final A actual = baseBuilder().with(a -> a.a = "world").with(a -> a.b = 4).with(a -> a.a = "foobar").build();
+
+ verifyAB(actual, "foobar", 4);
+ }
+
+ @Test
+ @DisplayName("not mutate the state of previous builder in the chain")
+ void testImmutability() {
+ final ABuilder builder1 = baseBuilder().with(a -> a.a = "world");
+ final ABuilder builder2 = builder1.with(a -> {
+ a.a = "hello";
+ a.b = 42;
+ });
+
+ verifyAB(builder1.build(), "world", 0);
+ verifyAB(builder2.build(), "hello", 42);
+ }
+
+ @Test
+ @DisplayName("produce different objects")
+ void differentObjects() {
+ final ABuilder builder = baseBuilder().with(a -> {
+ a.a = "hello";
+ a.b = 42;
+ });
+ final A a1 = builder.build();
+ final A a2 = builder.build();
+
+ assertThat(a1).isNotSameAs(a2);
+ verifyAB(a1, "hello", 42);
+ verifyAB(a2, "hello", 42);
+ }
+
+ static class A {
+ public final String a;
+ private int b;
+
+ public A(String a) {
+ this.a = a;
+ }
+
+ public String getA() {
+ return a;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+ }
+
+ static class ABuilder extends FluentBuilder {
+ public String a;
+ public int b;
+
+ private ABuilder() {
+ super(ABuilder::new);
+ }
+
+ @Override
+ protected A makeValue() {
+ final A result = new A(a);
+ result.setB(b);
+ return result;
+ }
+ }
+}
diff --git a/Mage.Server/config/config_error.xml b/Mage.Server/config/config_error.xml
new file mode 100644
index 0000000000..cf0b854367
--- /dev/null
+++ b/Mage.Server/config/config_error.xml
@@ -0,0 +1,173 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml
index 826e3c5533..2136236c01 100644
--- a/Mage.Server/pom.xml
+++ b/Mage.Server/pom.xml
@@ -285,6 +285,18 @@
sqlite-jdbc
3.32.3.2
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
@@ -358,6 +370,10 @@
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
mage-server
diff --git a/Mage.Server/src/main/java/mage/server/util/ConfigFactory.java b/Mage.Server/src/main/java/mage/server/util/ConfigFactory.java
new file mode 100644
index 0000000000..793419d06e
--- /dev/null
+++ b/Mage.Server/src/main/java/mage/server/util/ConfigFactory.java
@@ -0,0 +1,20 @@
+package mage.server.util;
+
+import mage.server.util.config.Config;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Unmarshaller;
+import java.io.File;
+
+public class ConfigFactory {
+
+ public static Config loadFromFile(final String filePath) {
+ try {
+ final JAXBContext jaxbContext = JAXBContext.newInstance("mage.server.util.config");
+ final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ return (Config) unmarshaller.unmarshal(new File(filePath));
+ } catch (Exception e) {
+ throw new ConfigurationException(e);
+ }
+ }
+}
diff --git a/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java b/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java
index ac65aae03b..e66e8f9276 100644
--- a/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java
+++ b/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java
@@ -14,7 +14,7 @@ import org.apache.log4j.Logger;
/**
* @author BetaSteward_at_googlemail.com
*/
-public enum ConfigSettings {
+public enum ConfigSettings implements ConfigSettingsContract {
instance;
private final Logger logger = Logger.getLogger(ConfigSettings.class);
diff --git a/Mage.Server/src/main/java/mage/server/util/ConfigSettingsContract.java b/Mage.Server/src/main/java/mage/server/util/ConfigSettingsContract.java
new file mode 100644
index 0000000000..a8ded69912
--- /dev/null
+++ b/Mage.Server/src/main/java/mage/server/util/ConfigSettingsContract.java
@@ -0,0 +1,72 @@
+package mage.server.util;
+
+import mage.server.util.config.GamePlugin;
+import mage.server.util.config.Plugin;
+
+import java.util.List;
+
+public interface ConfigSettingsContract {
+ String getServerAddress();
+
+ String getServerName();
+
+ int getPort();
+
+ int getSecondaryBindPort();
+
+ int getLeasePeriod();
+
+ int getSocketWriteTimeout();
+
+ int getMaxPoolSize();
+
+ int getNumAcceptThreads();
+
+ int getBacklogSize();
+
+ int getMaxGameThreads();
+
+ int getMaxSecondsIdle();
+
+ int getMinUserNameLength();
+
+ int getMaxUserNameLength();
+
+ String getInvalidUserNamePattern();
+
+ int getMinPasswordLength();
+
+ int getMaxPasswordLength();
+
+ String getMaxAiOpponents();
+
+ Boolean isSaveGameActivated();
+
+ Boolean isAuthenticationActivated();
+
+ String getGoogleAccount();
+
+ String getMailgunApiKey();
+
+ String getMailgunDomain();
+
+ String getMailSmtpHost();
+
+ String getMailSmtpPort();
+
+ String getMailUser();
+
+ String getMailPassword();
+
+ String getMailFromAddress();
+
+ List getPlayerTypes();
+
+ List getGameTypes();
+
+ List getTournamentTypes();
+
+ List getDraftCubes();
+
+ List getDeckTypes();
+}
diff --git a/Mage.Server/src/main/java/mage/server/util/ConfigWrapper.java b/Mage.Server/src/main/java/mage/server/util/ConfigWrapper.java
new file mode 100644
index 0000000000..1a461a73aa
--- /dev/null
+++ b/Mage.Server/src/main/java/mage/server/util/ConfigWrapper.java
@@ -0,0 +1,145 @@
+package mage.server.util;
+
+import mage.server.util.config.Config;
+import mage.server.util.config.GamePlugin;
+import mage.server.util.config.Plugin;
+
+import java.util.List;
+
+public class ConfigWrapper implements ConfigSettingsContract {
+
+ private final Config config;
+
+ public ConfigWrapper(final Config config) {
+ this.config = config;
+ }
+
+ public String getServerAddress() {
+ return config.getServer().getServerAddress();
+ }
+
+ public String getServerName() {
+ return config.getServer().getServerName();
+ }
+
+ public int getPort() {
+ return config.getServer().getPort().intValue();
+ }
+
+ public int getSecondaryBindPort() {
+ return config.getServer().getSecondaryBindPort().intValue();
+ }
+
+ public int getLeasePeriod() {
+ return config.getServer().getLeasePeriod().intValue();
+ }
+
+ public int getSocketWriteTimeout() {
+ return config.getServer().getSocketWriteTimeout().intValue();
+ }
+
+ public int getMaxPoolSize() {
+ return config.getServer().getMaxPoolSize().intValue();
+ }
+
+ public int getNumAcceptThreads() {
+ return config.getServer().getNumAcceptThreads().intValue();
+ }
+
+ public int getBacklogSize() {
+ return config.getServer().getBacklogSize().intValue();
+ }
+
+ public int getMaxGameThreads() {
+ return config.getServer().getMaxGameThreads().intValue();
+ }
+
+ public int getMaxSecondsIdle() {
+ return config.getServer().getMaxSecondsIdle().intValue();
+ }
+
+ public int getMinUserNameLength() {
+ return config.getServer().getMinUserNameLength().intValue();
+ }
+
+ public int getMaxUserNameLength() {
+ return config.getServer().getMaxUserNameLength().intValue();
+ }
+
+ public String getInvalidUserNamePattern() {
+ return config.getServer().getInvalidUserNamePattern();
+ }
+
+ public int getMinPasswordLength() {
+ return config.getServer().getMinPasswordLength().intValue();
+ }
+
+ public int getMaxPasswordLength() {
+ return config.getServer().getMaxPasswordLength().intValue();
+ }
+
+ public String getMaxAiOpponents() {
+ return config.getServer().getMaxAiOpponents();
+ }
+
+ public Boolean isSaveGameActivated() {
+ return config.getServer().isSaveGameActivated();
+ }
+
+ public Boolean isAuthenticationActivated() {
+ return config.getServer().isAuthenticationActivated();
+ }
+
+ public String getGoogleAccount() {
+ return config.getServer().getGoogleAccount();
+ }
+
+ public String getMailgunApiKey() {
+ return config.getServer().getMailgunApiKey();
+ }
+
+ public String getMailgunDomain() {
+ return config.getServer().getMailgunDomain();
+ }
+
+ public String getMailSmtpHost() {
+ return config.getServer().getMailSmtpHost();
+ }
+
+ public String getMailSmtpPort() {
+ return config.getServer().getMailSmtpPort();
+ }
+
+ public String getMailUser() {
+ return config.getServer().getMailUser();
+ }
+
+ public String getMailPassword() {
+ return config.getServer().getMailPassword();
+ }
+
+ public String getMailFromAddress() {
+ return config.getServer().getMailFromAddress();
+ }
+
+ public List getPlayerTypes() {
+ return config.getPlayerTypes().getPlayerType();
+ }
+
+ public List getGameTypes() {
+ return config.getGameTypes().getGameType();
+ }
+
+ public List getTournamentTypes() {
+ return config.getTournamentTypes().getTournamentType();
+ }
+
+ public List getDraftCubes() {
+ return config.getDraftCubes().getDraftCube();
+ }
+
+ public List getDeckTypes() {
+ return config.getDeckTypes().getDeckType();
+ }
+
+}
diff --git a/Mage.Server/src/main/java/mage/server/util/ConfigurationException.java b/Mage.Server/src/main/java/mage/server/util/ConfigurationException.java
new file mode 100644
index 0000000000..e1c1e5d0f0
--- /dev/null
+++ b/Mage.Server/src/main/java/mage/server/util/ConfigurationException.java
@@ -0,0 +1,7 @@
+package mage.server.util;
+
+public class ConfigurationException extends RuntimeException {
+ public ConfigurationException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/Mage.Server/src/test/java/mage/server/util/ConfigFactoryTest.java b/Mage.Server/src/test/java/mage/server/util/ConfigFactoryTest.java
new file mode 100644
index 0000000000..aab38e713a
--- /dev/null
+++ b/Mage.Server/src/test/java/mage/server/util/ConfigFactoryTest.java
@@ -0,0 +1,34 @@
+package mage.server.util;
+
+import mage.server.util.config.Config;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+
+public class ConfigFactoryTest {
+
+ @Test
+ @DisplayName("should unmarshal configuration from file")
+ void loadConfig() {
+ final Config config = ConfigFactory.loadFromFile("config/config.xml");
+
+ assertThat(config.getServer().getServerName()).isEqualTo("mage-server");
+ assertThat(config.getServer().getPort()).isEqualTo(17171);
+ }
+
+ @Test
+ @DisplayName("should fail if config is malformed")
+ void failOnMalformed() {
+ assertThatExceptionOfType(ConfigurationException.class)
+ .isThrownBy(() -> ConfigFactory.loadFromFile("config/config_error.xml"));
+ }
+
+ @Test
+ @DisplayName("should fail if file does not exist")
+ void failOnNotFound() {
+ assertThatExceptionOfType(ConfigurationException.class)
+ .isThrownBy(() -> ConfigFactory.loadFromFile("does not exist"));
+ }
+}
diff --git a/Mage.Server/src/test/java/mage/server/util/ConfigWrapperTest.java b/Mage.Server/src/test/java/mage/server/util/ConfigWrapperTest.java
new file mode 100644
index 0000000000..c8a80c34c4
--- /dev/null
+++ b/Mage.Server/src/test/java/mage/server/util/ConfigWrapperTest.java
@@ -0,0 +1,294 @@
+package mage.server.util;
+
+import mage.server.util.config.*;
+import mage.utils.FluentBuilder;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.RandomUtils;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.DynamicTest;
+import org.junit.jupiter.api.TestFactory;
+
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ConfigWrapperTest {
+
+ static class ConfigBuilder extends FluentBuilder {
+
+ public String serverAddress;
+ public String serverName;
+ public int port;
+ public int secondaryBindPort;
+ public int leasePeriod;
+ public int socketWriteTimeout;
+ public int maxPoolSize;
+ public int numAcceptThreads;
+ public int backlogSize;
+ public int maxGameThreads;
+ public int maxSecondsIdle;
+ public int minUsernameLength;
+ public int maxUsernameLength;
+ public String invalidUsernamePattern;
+ public int minPasswordLength;
+ public int maxPasswordLength;
+ public String maxAiOpponents;
+ public boolean saveGameActivated;
+ public boolean authenticationActivated;
+ public String googleAccount;
+ public String mailgunApiKey;
+ public String mailgunDomain;
+ public String mailSmtpHost;
+ public String mailSmtpPort;
+ public String mailUser;
+ public String mailPassword;
+ public String mailFromAddress;
+ public List playerTypes = Collections.emptyList();
+ public List gameTypes = Collections.emptyList();
+ public List tournamentTypes = Collections.emptyList();
+ public List draftCubes = Collections.emptyList();
+ public List deckTypes = Collections.emptyList();
+
+ private ConfigBuilder() {
+ super(ConfigBuilder::new);
+ }
+
+ @Override
+ protected Config makeValue() {
+ final Config result = new Config();
+ result.setServer(makeServer());
+ result.setPlayerTypes(makePlayerTypes());
+ result.setGameTypes(makeGameTypes());
+ result.setTournamentTypes(makeTournamentTypes());
+ result.setDraftCubes(makeDraftCubes());
+ result.setDeckTypes(makeDeckTypes());
+ return result;
+ }
+
+ private Server makeServer() {
+ final Server server = new Server();
+ server.setServerAddress(serverAddress);
+ server.setServerName(serverName);
+ server.setPort(BigInteger.valueOf(port));
+ server.setSecondaryBindPort(bi(secondaryBindPort));
+ server.setLeasePeriod(bi(leasePeriod));
+ server.setSocketWriteTimeout(bi(socketWriteTimeout));
+ server.setMaxPoolSize(bi(maxPoolSize));
+ server.setNumAcceptThreads(bi(numAcceptThreads));
+ server.setBacklogSize(bi(backlogSize));
+ server.setMaxGameThreads(bi(maxGameThreads));
+ server.setMaxSecondsIdle(bi(maxSecondsIdle));
+ server.setMinUserNameLength(bi(minUsernameLength));
+ server.setMaxUserNameLength(bi(maxUsernameLength));
+ server.setInvalidUserNamePattern(invalidUsernamePattern);
+ server.setMinPasswordLength(bi(minPasswordLength));
+ server.setMaxPasswordLength(bi(maxPasswordLength));
+ server.setMaxAiOpponents(maxAiOpponents);
+ server.setSaveGameActivated(saveGameActivated);
+ server.setAuthenticationActivated(authenticationActivated);
+ server.setGoogleAccount(googleAccount);
+ server.setMailgunApiKey(mailgunApiKey);
+ server.setMailgunDomain(mailgunDomain);
+ server.setMailSmtpHost(mailSmtpHost);
+ server.setMailSmtpPort(mailSmtpPort);
+ server.setMailUser(mailUser);
+ server.setMailPassword(mailPassword);
+ server.setMailFromAddress(mailFromAddress);
+ return server;
+ }
+
+ private PlayerTypes makePlayerTypes() {
+ final PlayerTypes playerTypes = new PlayerTypes();
+ this.playerTypes.forEach(p -> playerTypes.getPlayerType().add(p));
+ return playerTypes;
+ }
+
+ private GameTypes makeGameTypes() {
+ final GameTypes gameTypes = new GameTypes();
+ this.gameTypes.forEach(g -> gameTypes.getGameType().add(g));
+ return gameTypes;
+ }
+
+ private TournamentTypes makeTournamentTypes() {
+ final TournamentTypes tournamentTypes = new TournamentTypes();
+ this.tournamentTypes.forEach(t -> tournamentTypes.getTournamentType().add(t));
+ return tournamentTypes;
+ }
+
+ private DraftCubes makeDraftCubes() {
+ final DraftCubes draftCubes = new DraftCubes();
+ this.draftCubes.forEach(d -> draftCubes.getDraftCube().add(d));
+ return draftCubes;
+ }
+
+ private DeckTypes makeDeckTypes() {
+ final DeckTypes deckTypes = new DeckTypes();
+ this.deckTypes.forEach(d -> deckTypes.getDeckType().add(d));
+ return deckTypes;
+ }
+
+ private BigInteger bi(int value) {
+ return BigInteger.valueOf(value);
+ }
+ }
+
+ private ConfigBuilder baseConfigBuilder() {
+ return new ConfigBuilder();
+ }
+
+ private final String expectedString = RandomStringUtils.randomAlphanumeric(15);
+ private final int expectedPositiveInt = RandomUtils.nextInt(0, Integer.MAX_VALUE);
+
+
+ @TestFactory
+ @DisplayName("should return from server")
+ Stream assignmentFromServer() {
+ return Stream.of(
+ testString("server address", c -> c.serverAddress = expectedString, ConfigWrapper::getServerAddress),
+ testString("server name", c -> c.serverName = expectedString, ConfigWrapper::getServerName),
+ testInt("port", c -> c.port = expectedPositiveInt, ConfigWrapper::getPort),
+ testInt("secondary bind port", c -> c.secondaryBindPort = expectedPositiveInt, ConfigWrapper::getSecondaryBindPort),
+ testInt("lease period", c -> c.leasePeriod = expectedPositiveInt, ConfigWrapper::getLeasePeriod),
+ testInt("socket write timeout", c -> c.socketWriteTimeout = expectedPositiveInt, ConfigWrapper::getSocketWriteTimeout),
+ testInt("max pool size", c -> c.maxPoolSize = expectedPositiveInt, ConfigWrapper::getMaxPoolSize),
+ testInt("number of accept threads", c -> c.numAcceptThreads = expectedPositiveInt, ConfigWrapper::getNumAcceptThreads),
+ testInt("backlog size", c -> c.backlogSize = expectedPositiveInt, ConfigWrapper::getBacklogSize),
+ testInt("max game threads", c -> c.maxGameThreads = expectedPositiveInt, ConfigWrapper::getMaxGameThreads),
+ testInt("max seconds idle", c -> c.maxSecondsIdle = expectedPositiveInt, ConfigWrapper::getMaxSecondsIdle),
+ testInt("min username length", c -> c.minUsernameLength = expectedPositiveInt, ConfigWrapper::getMinUserNameLength),
+ testInt("max username length", c -> c.maxUsernameLength = expectedPositiveInt, ConfigWrapper::getMaxUserNameLength),
+ testString("invalid username pattern", c -> c.invalidUsernamePattern = expectedString, ConfigWrapper::getInvalidUserNamePattern),
+ testInt("min password length", c -> c.minPasswordLength = expectedPositiveInt, ConfigWrapper::getMinPasswordLength),
+ testInt("max password length", c -> c.maxPasswordLength = expectedPositiveInt, ConfigWrapper::getMaxPasswordLength),
+ testString("max AI opponents", c -> c.maxAiOpponents = expectedString, ConfigWrapper::getMaxAiOpponents),
+ testTrue("save game activated", c -> c.saveGameActivated = true, ConfigWrapper::isSaveGameActivated),
+ testTrue("authentication activated", c -> c.authenticationActivated = true, ConfigWrapper::isAuthenticationActivated),
+ testString("google account", c -> c.googleAccount = expectedString, ConfigWrapper::getGoogleAccount),
+ testString("mailgun api key", c -> c.mailgunApiKey = expectedString, ConfigWrapper::getMailgunApiKey),
+ testString("mailgun domain", c -> c.mailgunDomain = expectedString, ConfigWrapper::getMailgunDomain),
+ testString("mail smtp host", c -> c.mailSmtpHost = expectedString, ConfigWrapper::getMailSmtpHost),
+ testString("mail smtp port", c -> c.mailSmtpPort = expectedString, ConfigWrapper::getMailSmtpPort),
+ testString("mail from address", c -> c.mailFromAddress = expectedString, ConfigWrapper::getMailFromAddress),
+ testString("mail user", c -> c.mailUser = expectedString, ConfigWrapper::getMailUser),
+ testString("mail password", c -> c.mailPassword = expectedString, ConfigWrapper::getMailPassword)
+ );
+ }
+
+ private DynamicTest testString(String description, Consumer builderSetter, Function valueExtractor) {
+ return testTemplate(description, builderSetter, valueExtractor, expectedString);
+ }
+
+ private DynamicTest testTemplate(String description, Consumer builderSetter, Function valueExtractor, Object expectedValue) {
+ return DynamicTest.dynamicTest(description, () -> assertThat(valueExtractor.apply(makeTestee(baseConfigBuilder().with(builderSetter)))).isEqualTo(expectedValue));
+ }
+
+ private ConfigWrapper makeTestee(ConfigBuilder builder) {
+ return new ConfigWrapper(builder.build());
+ }
+
+ private DynamicTest testInt(String description, Consumer builderSetter, Function valueExtractor) {
+ return testTemplate(description, builderSetter, valueExtractor, expectedPositiveInt);
+ }
+
+ private DynamicTest testTrue(String description, Consumer builderSetter, Function valueExtractor) {
+ return testTemplate(description, builderSetter, valueExtractor, true);
+ }
+
+
+ private final Comparator pluginComparator = (p1, p2) -> {
+ if (Objects.equals(p1.getName(), p2.getName()) &&
+ Objects.equals(p1.getJar(), p2.getJar()) &&
+ Objects.equals(p1.getClassName(), p2.getClassName())) {
+ return 0;
+ } else {
+ return -1;
+ }
+ };
+
+ private final Comparator gamePluginComparator = (p1, p2) -> {
+ if (Objects.equals(p1.getName(), p2.getName()) &&
+ Objects.equals(p1.getJar(), p2.getJar()) &&
+ Objects.equals(p1.getClassName(), p2.getClassName()) &&
+ Objects.equals(p1.getTypeName(), p2.getTypeName())) {
+ return 0;
+ } else {
+ return -1;
+ }
+ };
+
+ private final List randomPlugins = IntStream.range(0, RandomUtils.nextInt(1, 10))
+ .mapToObj(i -> makePlugin(
+ RandomStringUtils.randomAlphanumeric(15),
+ RandomStringUtils.randomAlphanumeric(16),
+ RandomStringUtils.randomAlphanumeric(17))
+ ).collect(Collectors.toList());
+ private final List randomGamePlugins = IntStream.range(0, RandomUtils.nextInt(1, 10))
+ .mapToObj(i -> makeGamePlugin(
+ RandomStringUtils.randomAlphanumeric(15),
+ RandomStringUtils.randomAlphanumeric(16),
+ RandomStringUtils.randomAlphanumeric(17),
+ RandomStringUtils.randomAlphanumeric(18))
+ ).collect(Collectors.toList());
+
+ private Plugin makePlugin(String name, String jar, String className) {
+ final Plugin plugin = new Plugin();
+ plugin.setName(name);
+ plugin.setJar(jar);
+ plugin.setClassName(className);
+ return plugin;
+ }
+
+ private GamePlugin makeGamePlugin(String name, String jar, String className, String typeName) {
+ final GamePlugin plugin = new GamePlugin();
+ plugin.setName(name);
+ plugin.setJar(jar);
+ plugin.setClassName(className);
+ plugin.setTypeName(typeName);
+ return plugin;
+ }
+
+ @TestFactory
+ @DisplayName("should extract")
+ Stream pluginsExtraction() {
+ return Stream.of(
+ pluginTest("playerTypes from playerTypes", c -> c.playerTypes = randomPlugins, ConfigWrapper::getPlayerTypes),
+ gamePluginTest("gameTypes from gameTypes", c -> c.gameTypes = randomGamePlugins, ConfigWrapper::getGameTypes),
+ gamePluginTest("tournamentTypes from tournamentTypes", c -> c.tournamentTypes = randomGamePlugins, ConfigWrapper::getTournamentTypes),
+ pluginTest("draftCubes from draftCubes", c -> c.draftCubes = randomPlugins, ConfigWrapper::getDraftCubes),
+ pluginTest("deckTypes from deckTypes", c -> c.deckTypes = randomPlugins, ConfigWrapper::getDeckTypes)
+ );
+ }
+
+ private DynamicTest pluginTest(String description,
+ Consumer builderSetter,
+ Function> listExtractor) {
+ return testTemplateForLists(description, builderSetter, listExtractor, randomPlugins, pluginComparator);
+ }
+
+ private DynamicTest gamePluginTest(String description,
+ Consumer builderSetter,
+ Function> listExtractor) {
+ return testTemplateForLists(description, builderSetter, listExtractor, randomGamePlugins, gamePluginComparator);
+ }
+
+ private DynamicTest testTemplateForLists(String description,
+ Consumer builderSetter,
+ Function> listExtractor,
+ List expectedValue,
+ Comparator comparator) {
+ return DynamicTest.dynamicTest(description, () ->
+ assertThat(listExtractor.apply(makeTestee(baseConfigBuilder().with(builderSetter))))
+ .usingElementComparator(comparator)
+ .containsExactlyElementsOf(expectedValue)
+ );
+ }
+}
diff --git a/pom.xml b/pom.xml
index 61c118cd57..1032f1a955 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,6 +52,18 @@
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.22.2
+
+ -Dfile.encoding=UTF-8
+
+
+
+
Mage
@@ -113,6 +125,21 @@
guava
29.0-jre
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.7.0
+
+
+ org.assertj
+ assertj-core
+ 3.18.0
+
+
+ org.apache.commons
+ commons-lang3
+ 3.11
+