Skip to content

Commit

Permalink
Merge pull request #5 from aguibert/ci-timeouts
Browse files Browse the repository at this point in the history
Latest drop of improvements
  • Loading branch information
aguibert authored Aug 8, 2019
2 parents 057adb3 + 8dd5eff commit ef01f00
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,67 @@
*/
package org.eclipse.microprofile.system.test;

import org.eclipse.microprofile.system.test.testcontainers.TestcontainersConfiguration;
import java.util.HashSet;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;

public interface ApplicationEnvironment {

public static String ENV_CLASS = "MP_TEST_ENV_CLASS";
/**
* The default priority returned by an implementation of {@link ApplicationEnvironment.isAvailable()}
* In general, built-in ApplicationEnvironment implementations have a priority less than the default
* and user-defined priorities will have a greater than default priority.
*/
public static final int DEFAULT_PRIORITY = 0;

@SuppressWarnings("unchecked")
public static Class<? extends ApplicationEnvironment> getEnvClass() throws ClassNotFoundException {
public static final String ENV_CLASS = "MP_TEST_ENV_CLASS";

public static ApplicationEnvironment load() throws ClassNotFoundException {
// First check explicilty configured environment via system property or env var
String strategy = System.getProperty(ENV_CLASS);
if (strategy == null)
if (strategy == null || strategy.isEmpty())
strategy = System.getenv(ENV_CLASS);
if (strategy == null) {
return TestcontainersConfiguration.class;
} else {
if (strategy != null && !strategy.isEmpty()) {
Class<?> found = Class.forName(strategy);
if (!ApplicationEnvironment.class.isAssignableFrom(found)) {
throw new IllegalStateException("ApplicationEnvironment class " + strategy +
" was found, but it does not implement the required interface " + ApplicationEnvironment.class);
} else {
return (Class<? extends ApplicationEnvironment>) found;
try {
return (ApplicationEnvironment) found.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new IllegalStateException("Unable to initialize " + found, e);
}
}
}

// If nothing explicitly defined in sysprops or env, check ServiceLoader
Set<ApplicationEnvironment> envs = new HashSet<>();
ServiceLoader.load(ApplicationEnvironment.class).forEach(envs::add);
Optional<ApplicationEnvironment> selectedEnv = envs.stream()
.filter(env -> env.isAvailable())
.sorted((c1, c2) -> c1.getClass().getCanonicalName().compareTo(c2.getClass().getCanonicalName()))
.sorted((c1, c2) -> Integer.compare(c2.getPriority(), c1.getPriority()))
.findFirst();
return selectedEnv.orElseThrow(() -> new IllegalStateException("No available " + ApplicationEnvironment.class + " was discovered."));
}

/**
* @return true if the ApplicationEnvironment is currently available
* false otherwise
*/
public default boolean isAvailable() {
return true;
}

/**
* @return The priority of the ApplicationEnvironment. The ApplicationEnvironment
* with the highest prioirty that is also available. A higher number corresponds
* to a higher priority.
*/
public default int getPriority() {
return DEFAULT_PRIORITY;
}

public void applyConfiguration(Class<?> testClass);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,18 @@
public class ManuallyStartedConfiguration implements ApplicationEnvironment {

public static final String RUNTIME_URL_PROPERTY = "MP_TEST_RUNTIME_URL";
public static final String MANUAL_ENALBED = "MP_TEST_MANUAL_ENV";

public static boolean isAvailable() {
return System.getProperty(RUNTIME_URL_PROPERTY) != null ||
System.getenv(RUNTIME_URL_PROPERTY) != null;
@Override
public boolean isAvailable() {
boolean manualEnabled = Boolean.valueOf(System.getProperty(MANUAL_ENALBED, System.getenv(MANUAL_ENALBED)));
String url = System.getProperty(RUNTIME_URL_PROPERTY, System.getenv(RUNTIME_URL_PROPERTY));
return manualEnabled && url != null && !url.isEmpty();
}

@Override
public int getPriority() {
return ApplicationEnvironment.DEFAULT_PRIORITY - 30;
}

public static String getRuntimeURL() {
Expand All @@ -41,10 +49,6 @@ public static String getRuntimeURL() {
return url;
}

public ManuallyStartedConfiguration() {
ManuallyStartedConfiguration.getRuntimeURL();
}

@Override
public void applyConfiguration(Class<?> testClass) {
// no-op
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,8 @@ public class MicroProfileTestExtension implements BeforeAllCallback {
@Override
public void beforeAll(ExtensionContext context) throws Exception {
Class<?> testClass = context.getRequiredTestClass();
// For now this is hard-coded to using Testcontainers for container management.
// In the future, this could be configurable to something besides Testcontainers
Class<?> envClass = ApplicationEnvironment.getEnvClass();
LOGGER.info("Using ApplicationEnvironment class: " + envClass.getCanonicalName());
ApplicationEnvironment config = (ApplicationEnvironment) envClass.newInstance();
ApplicationEnvironment config = ApplicationEnvironment.load();
LOGGER.info("Using ApplicationEnvironment class: " + config.getClass().getCanonicalName());
config.applyConfiguration(testClass);
config.start();
injectRestClients(testClass, config);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.Set;
import java.util.stream.Collectors;

import org.eclipse.microprofile.system.test.ApplicationEnvironment;
import org.eclipse.microprofile.system.test.ManuallyStartedConfiguration;
import org.junit.jupiter.api.extension.ExtensionConfigurationException;
import org.slf4j.Logger;
Expand All @@ -37,6 +38,18 @@ public class HollowTestcontainersConfiguration extends TestcontainersConfigurati

private static final Logger LOG = LoggerFactory.getLogger(HollowTestcontainersConfiguration.class);

@Override
public boolean isAvailable() {
String url = System.getProperty(ManuallyStartedConfiguration.RUNTIME_URL_PROPERTY,
System.getenv(ManuallyStartedConfiguration.RUNTIME_URL_PROPERTY));
return url != null && !url.isEmpty();
}

@Override
public int getPriority() {
return ApplicationEnvironment.DEFAULT_PRIORITY - 10;
}

@Override
public void applyConfiguration(Class<?> testClass) {
super.applyConfiguration(testClass);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ public class TestcontainersConfiguration implements ApplicationEnvironment {
final Set<GenericContainer<?>> unsharedContainers = new HashSet<>();
final Set<GenericContainer<?>> sharedContainers = new HashSet<>();

@Override
public int getPriority() {
return ApplicationEnvironment.DEFAULT_PRIORITY - 20;
}

@Override
public boolean isAvailable() {
return true;
}

@Override
public void applyConfiguration(Class<?> testClass) {
this.testClass = testClass;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
org.eclipse.microprofile.system.test.ManuallyStartedConfiguration
org.eclipse.microprofile.system.test.testcontainers.TestcontainersConfiguration
org.eclipse.microprofile.system.test.testcontainers.HollowTestcontainersConfiguration
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,6 @@ public int getDefaultHttpsPort() {
return 9443;
}

@Override
public int getDefaultAppStartTimeout() {
return 30;
}

@Override
public void setConfigProperties(Map<String, String> properties) {
String MP_TEST_CONFIG_FILE = System.getProperty("MP_TEST_CONFIG_FILE", System.getenv("MP_TEST_CONFIG_FILE"));
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,22 @@

public class AppContainerConfig implements SharedContainerConfiguration {

@Container
public static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>()
.withNetworkAliases("testpostgres")
.withDatabaseName("testdb");

@Container
public static MicroProfileApplication<?> app = new MicroProfileApplication<>()
.withEnv("POSTGRES_HOSTNAME", "testpostgres")
.withEnv("POSTGRES_HOSTNAME", "testpostgres")
.withEnv("POSTGRES_PORT", "5432")
.withAppContextRoot("/myservice");

@Container
public static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>()
.withNetworkAliases("testpostgres")
.withDatabaseName("testdb");

//.dependsOn(postgres); intermittent bugs, see: https://github.com/testcontainers/testcontainers-java/issues/1722

@Override
public void startContainers() {
//TODO: Reset to default if we move away from the Parallel streams API for loading
postgres.start();
app.start();
postgres.start();
app.start();
}

}
11 changes: 5 additions & 6 deletions sample-apps/maven-app/.dockerignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#*
#!build/libs/basic-liberty.war
#!src/main/liberty/config

*~
[a-b-c]
build/
target/
!target/*.war
src/
!src/main/liberty/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.testcontainers.containers.microprofile;

import java.nio.file.Path;
import java.util.Optional;

import com.github.dockerjava.api.command.BuildImageCmd;

public class ImageFromDockerfile extends org.testcontainers.images.builder.ImageFromDockerfile {

private Optional<Path> baseDir = Optional.empty();

public ImageFromDockerfile() {
super();
}

public ImageFromDockerfile(String dockerImageName) {
super(dockerImageName);
}

public ImageFromDockerfile(String dockerImageName, boolean deleteOnExit) {
super(dockerImageName, deleteOnExit);
}

@Override
protected void configure(BuildImageCmd buildImageCmd) {
baseDir.ifPresent(p -> buildImageCmd.withBaseDirectory(p.toFile()));
super.configure(buildImageCmd);
}

public ImageFromDockerfile withBaseDirectory(Path baseDir) {
this.baseDir = Optional.of(baseDir);
return this;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
package org.testcontainers.containers.microprofile;

import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.ArrayList;
Expand All @@ -29,14 +31,15 @@
import java.util.ServiceLoader;
import java.util.concurrent.Future;

import org.junit.jupiter.api.extension.ExtensionConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.microprofile.spi.ServerAdapter;
import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.utility.Base58;

import com.github.dockerjava.api.command.InspectImageResponse;
import com.github.dockerjava.api.model.ExposedPort;
Expand All @@ -54,10 +57,27 @@ public class MicroProfileApplication<SELF extends MicroProfileApplication<SELF>>
private int lateBind_port;
private boolean lateBind_started = false;

private static Path autoDiscoverDockerfile() {
Path root = Paths.get(".", "Dockerfile");
if (Files.exists(root))
return root;
Path srcMain = Paths.get(".", "src", "main", "docker", "Dockerfile");
if (Files.exists(srcMain))
return srcMain;
throw new ExtensionConfigurationException("Unable to locate any Dockerfile in " +
root.toAbsolutePath() + " or " + srcMain.toAbsolutePath());
}

public MicroProfileApplication() {
super(new ImageFromDockerfile()
.withDockerfilePath("Dockerfile") // TODO use withDockerfile(File) here because it honors .dockerignore
.withFileFromPath(".", Paths.get(".")));
this(autoDiscoverDockerfile());
}

public MicroProfileApplication(Path dockerfilePath) {
super(new ImageFromDockerfile("testcontainers/mpapp-" + Base58.randomString(10).toLowerCase())
.withBaseDirectory(Paths.get("."))
.withDockerfile(dockerfilePath));
if (!Files.exists(dockerfilePath))
throw new ExtensionConfigurationException("Dockerfile did not exist at: " + dockerfilePath);
commonInit();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,13 @@ public interface ServerAdapter {
/**
* @return The default amount of time (in seconds) to wait for a runtime to start before
* assuming that application start has failed and aborting the start process.
*
* Implementation note:
* It is reccomended to increase the default app start timeout when running in
* remote CI environments such as TravisCI by checking for the CI=true env var.
*/
public default int getDefaultAppStartTimeout() {
return 30;
return "true".equalsIgnoreCase(System.getenv("CI")) ? 90 : 30;
}

/**
Expand Down

0 comments on commit ef01f00

Please sign in to comment.