Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unification of all test-framework-related options #791

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.quarkus.test.services.containers;

import static io.quarkus.test.bootstrap.BaseService.SERVICE_STARTUP_TIMEOUT;
import static io.quarkus.test.bootstrap.BaseService.SERVICE_STARTUP_TIMEOUT_DEFAULT;
import static io.quarkus.test.utils.PropertiesUtils.RESOURCE_PREFIX;
import static io.quarkus.test.utils.PropertiesUtils.RESOURCE_WITH_DESTINATION_PREFIX;
Expand All @@ -25,6 +24,7 @@
import io.quarkus.test.bootstrap.ManagedResource;
import io.quarkus.test.bootstrap.Protocol;
import io.quarkus.test.bootstrap.ServiceContext;
import io.quarkus.test.configuration.Configuration;
import io.quarkus.test.logging.Log;
import io.quarkus.test.logging.LoggingHandler;
import io.quarkus.test.logging.TestContainersLoggingHandler;
Expand Down Expand Up @@ -63,7 +63,7 @@ public void start() {
}

innerContainer.withStartupTimeout(context.getOwner().getConfiguration()
.getAsDuration(SERVICE_STARTUP_TIMEOUT, SERVICE_STARTUP_TIMEOUT_DEFAULT));
.getAsDuration(Configuration.Property.SERVICE_STARTUP_TIMEOUT, SERVICE_STARTUP_TIMEOUT_DEFAULT));
innerContainer.withEnv(resolveProperties());

loggingHandler = new TestContainersLoggingHandler(context.getOwner(), innerContainer);
Expand All @@ -75,7 +75,7 @@ public void start() {
}

private boolean isDockerImageDeletedOnStop() {
return context.getOwner().getConfiguration().isTrue(DELETE_IMAGE_ON_STOP_PROPERTY);
return context.getOwner().getConfiguration().isTrue(Configuration.Property.DELETE_IMAGE_ON_STOP_PROPERTY);
}

protected abstract GenericContainer<?> initContainer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;

import io.quarkus.test.configuration.Configuration;
import io.quarkus.test.logging.Log;
import io.quarkus.test.utils.DockerUtils;

public class GenericDockerContainerManagedResource extends DockerContainerManagedResource {

private static final String PRIVILEGED_MODE = "container.privileged-mode";
private static final String REUSABLE_MODE = "container.reusable";
private final ContainerManagedResourceBuilder model;

protected GenericDockerContainerManagedResource(ContainerManagedResourceBuilder model) {
Expand Down Expand Up @@ -68,10 +67,10 @@ public void stop() {
}

protected boolean isReusable() {
return model.getContext().getOwner().getConfiguration().isTrue(REUSABLE_MODE);
return model.getContext().getOwner().getConfiguration().isTrue(Configuration.Property.REUSABLE_MODE);
}

private boolean isPrivileged() {
return model.getContext().getOwner().getConfiguration().isTrue(PRIVILEGED_MODE);
return model.getContext().getOwner().getConfiguration().isTrue(Configuration.Property.PRIVILEGED_MODE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,7 @@

public class BaseService<T extends Service> implements Service {

public static final String SERVICE_STARTUP_TIMEOUT = "startup.timeout";
public static final Duration SERVICE_STARTUP_TIMEOUT_DEFAULT = Duration.ofMinutes(5);
public static final String DELETE_FOLDER_ON_EXIT = "delete.folder.on.exit";

private static final String SERVICE_STARTUP_CHECK_POLL_INTERVAL = "startup.check-poll-interval";
private static final Duration SERVICE_STARTUP_CHECK_POLL_INTERVAL_DEFAULT = Duration.ofSeconds(2);

protected ServiceContext context;
Expand Down Expand Up @@ -244,7 +240,7 @@ public void stop() {
public void close() {
if (!context.getScenarioContext().isDebug()) {
stop();
if (getConfiguration().isTrue(DELETE_FOLDER_ON_EXIT)) {
if (getConfiguration().isTrue(Configuration.Property.DELETE_FOLDER_ON_EXIT)) {
try {
FileUtils.deletePath(getServiceFolder());
} catch (Exception ex) {
Expand Down Expand Up @@ -345,9 +341,10 @@ private boolean isRunningOrFailed() {
private void waitUntilServiceIsStarted() {
try {
Duration startupCheckInterval = getConfiguration()
.getAsDuration(SERVICE_STARTUP_CHECK_POLL_INTERVAL, SERVICE_STARTUP_CHECK_POLL_INTERVAL_DEFAULT);
.getAsDuration(Configuration.Property.SERVICE_STARTUP_CHECK_POLL_INTERVAL,
SERVICE_STARTUP_CHECK_POLL_INTERVAL_DEFAULT);
Duration startupTimeout = getConfiguration()
.getAsDuration(SERVICE_STARTUP_TIMEOUT, SERVICE_STARTUP_TIMEOUT_DEFAULT);
.getAsDuration(Configuration.Property.SERVICE_STARTUP_TIMEOUT, SERVICE_STARTUP_TIMEOUT_DEFAULT);
untilIsTrue(this::isRunningOrFailed, AwaitilitySettings
.using(startupCheckInterval, startupTimeout)
.doNotIgnoreExceptions()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,36 @@

import java.io.InputStream;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import jakarta.annotation.Nullable;

import org.apache.commons.lang3.StringUtils;

public final class Configuration {

private static final String GLOBAL_PROPERTIES = System.getProperty("ts.test.resources.file.location", "global.properties");
private static final String TEST_PROPERTIES = "test.properties";
private static final String PREFIX_TEMPLATE = "ts.%s.";
private static final String PREFIX = "ts.";
private static final String PREFIX_TEMPLATE = PREFIX + "%s.";
private static final String GLOBAL_SCOPE = "global";

private final Map<String, String> properties;
private final EnumMap<Property, String> properties;

private Configuration(Map<String, String> properties) {
private Configuration(EnumMap<Property, String> properties) {
this.properties = properties;
}

public List<String> getAsList(String property) {
public List<String> getAsList(Property property) {
String value = get(property);
if (StringUtils.isEmpty(value)) {
return Collections.emptyList();
Expand All @@ -35,7 +40,7 @@ public List<String> getAsList(String property) {
return Stream.of(value.split(",")).collect(Collectors.toList());
}

public Duration getAsDuration(String property, Duration defaultValue) {
public Duration getAsDuration(Property property, Duration defaultValue) {
String value = get(property);
if (StringUtils.isEmpty(value)) {
return defaultValue;
Expand All @@ -48,7 +53,7 @@ public Duration getAsDuration(String property, Duration defaultValue) {
return Duration.parse(value);
}

public Double getAsDouble(String property, double defaultValue) {
public Double getAsDouble(Property property, double defaultValue) {
String value = get(property);
if (StringUtils.isEmpty(value)) {
return defaultValue;
Expand All @@ -57,24 +62,24 @@ public Double getAsDouble(String property, double defaultValue) {
return Double.parseDouble(value);
}

public String get(String property) {
public String get(Property property) {
return properties.get(property);
}

public String getOrDefault(String property, String defaultValue) {
public String getOrDefault(Property property, String defaultValue) {
return properties.getOrDefault(property, defaultValue);
}

public boolean isTrue(String property) {
public boolean isTrue(Property property) {
return is(property, Boolean.TRUE.toString());
}

public boolean is(String property, String expected) {
public boolean is(Property property, String expected) {
return StringUtils.equalsIgnoreCase(properties.get(property), expected);
}

public static Configuration load() {
Map<String, String> properties = new HashMap<>();
EnumMap<Property, String> properties = new EnumMap<>(Property.class);
// Lowest priority: properties from global.properties and scope `global`
properties.putAll(loadPropertiesFrom(GLOBAL_PROPERTIES, GLOBAL_SCOPE));
// Then, properties from system properties and scope `global`
Expand All @@ -97,32 +102,110 @@ public static Configuration load(String... serviceNames) {
return configuration;
}

private static Map<String, String> loadPropertiesFromSystemProperties(String scope) {
private static EnumMap<Property, String> loadPropertiesFromSystemProperties(String scope) {
return loadPropertiesFrom(System.getProperties(), scope);
}

private static Map<String, String> loadPropertiesFrom(String propertiesFile, String scope) {
private static EnumMap<Property, String> loadPropertiesFrom(String propertiesFile, String scope) {
try (InputStream input = Configuration.class.getClassLoader().getResourceAsStream(propertiesFile)) {
Properties prop = new Properties();
prop.load(input);
return loadPropertiesFrom(prop, scope);
} catch (Exception ignored) {
// There is no properties file: this is not mandatory.
} catch (Exception exception) {
if (exception instanceof NullPointerException && exception.getMessage().equals("inStream parameter is null")) {
System.out.println("No properties file: " + propertiesFile);
} else {
throw new IllegalStateException(exception);
}
}

return Collections.emptyMap();
return new EnumMap<>(Property.class);
}

private static Map<String, String> loadPropertiesFrom(Properties prop, String scope) {
Map<String, String> properties = new HashMap<>();
private static EnumMap<Property, String> loadPropertiesFrom(Properties prop, String scope) {
EnumMap<Property, String> properties = new EnumMap<>(Property.class);

String prefix = String.format(PREFIX_TEMPLATE, scope);
for (Entry<Object, Object> entry : prop.entrySet()) {
String key = (String) entry.getKey();
if (StringUtils.startsWith(key, prefix)) {
properties.put(key.replace(prefix, StringUtils.EMPTY), (String) entry.getValue());
String property = key.replace(prefix, StringUtils.EMPTY);
Property parsed = Property.getByName(property)
.orElseThrow(() -> new NoSuchElementException("Unknown property: " + property + " from " + key));
properties.put(parsed, (String) entry.getValue());
}
}

return properties;
}

public enum Property {
RESOURCES_FILE_LOCATION("resources.file.location"),
SERVICE_STARTUP_TIMEOUT("startup.timeout"),
DELETE_FOLDER_ON_EXIT("delete.folder.on.exit"),
SERVICE_STARTUP_CHECK_POLL_INTERVAL("startup.check-poll-interval"),
TIMEOUT_FACTOR_PROPERTY("factor.timeout"),
KUBERNETES_DEPLOYMENT_SERVICE_PROPERTY("kubernetes.service"),
KUBERNETES_DEPLOYMENT_TEMPLATE_PROPERTY("kubernetes.template"),
KUBERNETES_USE_INTERNAL_SERVICE_AS_URL_PROPERTY("kubernetes.use-internal-service-as-url"),
OPENSHIFT_DEPLOYMENT_SERVICE_PROPERTY("openshift.service"),
OPENSHIFT_DEPLOYMENT_TEMPLATE_PROPERTY("openshift.template"),
OPENSHIFT_USE_INTERNAL_SERVICE_AS_URL_PROPERTY("openshift.use-internal-service-as-url"),

DELETE_IMAGE_ON_STOP_PROPERTY("container.delete.image.on.stop"),
IMAGE_STREAM_TIMEOUT("imagestream.install.timeout"),
OPERATOR_INSTALL_TIMEOUT("operator.install.timeout"),

CREATE_SERVICE_BY_DEFAULT("generated-service.enabled"),
PROPAGATE_PROPERTIES_STRATEGY("maven.propagate-properties-strategy"),
PROPAGATE_PROPERTIES_STRATEGY_ALL_EXCLUSIONS("maven.propagate-properties-strategy.all.exclude"),
PRIVILEGED_MODE("container.privileged-mode"),
REUSABLE_MODE("container.reusable"),
EXPECTED_OUTPUT("quarkus.expected.log"),
PORT_RANGE_MIN("port.range.min"),
PORT_RANGE_MAX("port.range.max"),
PORT_RESOLUTION_STRATEGY("port.resolution.strategy"),

METRICS_EXTENSION_ENABLED_PROPERTY("metrics.enabled"),
METRICS_PUSH_AFTER_EACH_TEST("metrics.push-after-each-test"),
METRICS_EXPORT_PROMETHEUS_PROPERTY("metrics.export.prometheus.endpoint"),
JAEGER_HTTP_ENDPOINT_SYSTEM_PROPERTY("tracing.jaeger.endpoint"),

LOG_ENABLE("log.enable"),
LOG_LEVEL_NAME("log.level"),
LOG_FORMAT("log.format"),
LOG_FILE_OUTPUT("log.file.output"),
LOG_NOCOLOR("log.nocolor");

private final String name;

Property(String name) {
this.name = name;
}

public String getName(@Nullable String scope) {
String scopePart = "";
if (scope != null) {
scopePart = scope + ".";
}
return PREFIX + scopePart + name;
}

public String getName() {
return name;
}

public static Optional<Property> getByName(String requested) {
return Arrays.stream(Property.values())
.filter(property -> property.name.equals(requested))
.findAny();
}

static Property byName(String requested) {
return getByName(requested).orElseThrow(() -> new NoSuchElementException("Unknown property: " + requested));
}

public static boolean isKnownProperty(String toCheck) {
return Arrays.stream(Property.values()).map(property -> property.name).anyMatch(name -> name.equals(toCheck));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public String get(ServiceContext service) {
}

// Or from test.properties
value = service.getOwner().getConfiguration().get(propertyKey);
value = Configuration.Property.getByName(propertyKey).map(GLOBAL::get).orElse("");
if (StringUtils.isNotBlank(value)) {
return value;
}
Expand All @@ -50,7 +50,7 @@ public String get(ServiceContext service) {

public String get() {
// Try first using the Configuration API
String value = GLOBAL.get(propertyKey);
String value = Configuration.Property.getByName(propertyKey).map(GLOBAL::get).orElse("");
if (StringUtils.isNotBlank(value)) {
return value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.quarkus.test.bootstrap.QuarkusScenarioBootstrap;
import io.quarkus.test.bootstrap.ScenarioContext;
import io.quarkus.test.bootstrap.Service;
import io.quarkus.test.configuration.Configuration;
import io.quarkus.test.configuration.PropertyLookup;

public final class Log {
Expand All @@ -32,7 +33,6 @@ public final class Log {
public static final PropertyLookup LOG_NOCOLOR = new PropertyLookup("log.nocolor", "false");

public static final String LOG_SUFFIX = ".log";
public static final String LOG_LEVEL_NAME = "log.level";

private static final Service NO_SERVICE = null;
private static final String COLOR_RESET = "\u001b[0m";
Expand Down Expand Up @@ -142,7 +142,7 @@ private static void log(Service service, Level level, String msg, Object... args
private static boolean isServiceLogLevelAllowed(Service service, Level level) {
boolean enabled = true;
if (Objects.nonNull(service) && Objects.nonNull(service.getConfiguration())) {
String serviceLogLevel = service.getConfiguration().getOrDefault(LOG_LEVEL_NAME, EMPTY);
String serviceLogLevel = service.getConfiguration().getOrDefault(Configuration.Property.LOG_LEVEL_NAME, EMPTY);
if (!serviceLogLevel.isEmpty()) {
enabled = Level.parse(serviceLogLevel).intValue() <= level.intValue();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.test.logging;

import io.quarkus.test.bootstrap.Service;
import io.quarkus.test.configuration.Configuration;

public abstract class ServiceLoggingHandler extends LoggingHandler {

Expand All @@ -17,7 +18,7 @@ protected void logInfo(String line) {

@Override
protected boolean isLogEnabled() {
return service.getConfiguration().isTrue("log.enable");
return service.getConfiguration().isTrue(Configuration.Property.LOG_ENABLE);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
import org.hamcrest.Matchers;

import io.quarkus.test.bootstrap.Service;
import io.quarkus.test.configuration.Configuration;
import io.quarkus.test.logging.Log;

/**
* Awaitility utils to make a long or repeatable operation.
*/
public final class AwaitilityUtils {

private static final String TIMEOUT_FACTOR_PROPERTY = "factor.timeout";
private static final int POLL_SECONDS = 1;
private static final int TIMEOUT_SECONDS = 30;

Expand Down Expand Up @@ -174,7 +174,8 @@ private static ConditionFactory awaits(AwaitilitySettings settings) {
private static long timeoutInSeconds(AwaitilitySettings settings) {
double timeoutFactor = 1.0;
if (settings.service != null) {
timeoutFactor = settings.service.getConfiguration().getAsDouble(TIMEOUT_FACTOR_PROPERTY, timeoutFactor);
timeoutFactor = settings.service.getConfiguration()
.getAsDouble(Configuration.Property.TIMEOUT_FACTOR_PROPERTY, timeoutFactor);
}

return Math.round(settings.timeout.toSeconds() * timeoutFactor);
Expand Down
Loading