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

Add ResourceManager for OLM handling #23

Merged
merged 3 commits into from
Dec 5, 2023
Merged
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
38 changes: 37 additions & 1 deletion src/main/java/io/odh/test/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;

/**
Expand All @@ -23,6 +24,28 @@ public class Environment {
private static final String PASSWORD_ENV = "KUBE_PASSWORD";
private static final String TOKEN_ENV = "KUBE_TOKEN";
private static final String URL_ENV = "KUBE_URL";
/**
* OLM env variables
*/
private static final String OLM_OPERATOR_NAME_ENV = "OLM_OPERATOR_NAME";
private static final String OLM_OPERATOR_NAMESPACE_ENV = "OLM_OPERATOR_NAMESPACE";
private static final String OLM_OPERATOR_DEPLOYMENT_NAME_ENV = "OLM_OPERATOR_DEPLOYMENT_NAME";
private static final String OLM_SOURCE_NAME_ENV = "OLM_SOURCE_NAME";
private static final String OLM_SOURCE_NAMESPACE_ENV = "OLM_SOURCE_NAMESPACE";
private static final String OLM_APP_BUNDLE_PREFIX_ENV = "OLM_APP_BUNDLE_PREFIX";
private static final String OLM_OPERATOR_VERSION_ENV = "OLM_OPERATOR_VERSION";
private static final String OLM_OPERATOR_CHANNEL_ENV = "OLM_OPERATOR_CHANNEL";

/**
* Defaults
*/
public static final String OLM_OPERATOR_NAME_DEFAULT = "opendatahub-operator";
public static final String OLM_OPERATOR_NAMESPACE_DEFAULT = "openshift-operators";
public static final String OLM_OPERATOR_DEPLOYMENT_NAME_DEFAULT = "opendatahub-operator-controller-manager";
public static final String OLM_SOURCE_NAME_DEFAULT = "community-operators";
public static final String OLM_APP_BUNDLE_PREFIX_DEFAULT = "opendatahub-operator";
public static final String OLM_OPERATOR_CHANNEL_DEFAULT = "fast";
public static final String OLM_OPERATOR_VERSION_DEFAULT = "2.4.0";

/**
* Set values
Expand All @@ -33,14 +56,27 @@ public class Environment {
public static final String KUBE_TOKEN = getOrDefault(TOKEN_ENV, null);
public static final String KUBE_URL = getOrDefault(URL_ENV, null);

// OLM env variables
public static final String OLM_OPERATOR_NAME = getOrDefault(OLM_OPERATOR_NAME_ENV, OLM_OPERATOR_NAME_DEFAULT);
public static final String OLM_OPERATOR_NAMESPACE = getOrDefault(OLM_OPERATOR_NAMESPACE_ENV, OLM_OPERATOR_NAMESPACE_DEFAULT);
public static final String OLM_OPERATOR_DEPLOYMENT_NAME = getOrDefault(OLM_OPERATOR_DEPLOYMENT_NAME_ENV, OLM_OPERATOR_DEPLOYMENT_NAME_DEFAULT);
public static final String OLM_SOURCE_NAME = getOrDefault(OLM_SOURCE_NAME_ENV, OLM_SOURCE_NAME_DEFAULT);
public static final String OLM_SOURCE_NAMESPACE = getOrDefault(OLM_SOURCE_NAMESPACE_ENV, "openshift-marketplace");
public static final String OLM_APP_BUNDLE_PREFIX = getOrDefault(OLM_APP_BUNDLE_PREFIX_ENV, OLM_APP_BUNDLE_PREFIX_DEFAULT);
public static final String OLM_OPERATOR_CHANNEL = getOrDefault(OLM_OPERATOR_CHANNEL_ENV, OLM_OPERATOR_CHANNEL_DEFAULT);
public static final String OLM_OPERATOR_VERSION = getOrDefault(OLM_OPERATOR_VERSION_ENV, OLM_OPERATOR_VERSION_DEFAULT);
private Environment() { }

static {
String debugFormat = "{}: {}";
LOGGER.info("Used environment variables:");
VALUES.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.forEach(entry -> LOGGER.info(debugFormat, entry.getKey(), entry.getValue()));
.forEach(entry -> {
if (!Objects.equals(entry.getValue(), "null")) {
LOGGER.info(debugFormat, entry.getKey(), entry.getValue());
}
});
}

public static void print() { }
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/io/odh/test/TestConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,19 @@
*/
package io.odh.test;

import java.time.Duration;

public class TestConstants {
public static final String ODH_NAMESPACE = "opendatahub";
public static final String DEFAULT_NAMESPACE = "default";

public static final String SUBSCRIPTION = "Subscription";
public static final String OPERATOR_GROUP = "OperatorGroup";

public static final long GLOBAL_POLL_INTERVAL = Duration.ofSeconds(10).toMillis();
public static final long GLOBAL_POLL_INTERVAL_MEDIUM = Duration.ofSeconds(5).toMillis();
public static final long GLOBAL_POLL_INTERVAL_SHORT = Duration.ofSeconds(1).toMillis();
public static final long GLOBAL_TIMEOUT = Duration.ofMinutes(5).toMillis();

private TestConstants() {
}
Expand Down
108 changes: 108 additions & 0 deletions src/main/java/io/odh/test/TestUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright Skodjob authors.
* License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
*/
package io.odh.test;

import io.odh.test.framework.WaitException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.function.BooleanSupplier;

@SuppressWarnings({"checkstyle:ClassFanOutComplexity"})
public final class TestUtils {

private static final Logger LOGGER = LoggerFactory.getLogger(TestUtils.class);

public static final String USER_PATH = System.getProperty("user.dir");

/**
* Default timeout for asynchronous tests.
*/
public static final int DEFAULT_TIMEOUT_DURATION = 30;

/**
* Default timeout unit for asynchronous tests.
*/
public static final TimeUnit DEFAULT_TIMEOUT_UNIT = TimeUnit.SECONDS;

private TestUtils() {
// All static methods
}

/**
* Poll the given {@code ready} function every {@code pollIntervalMs} milliseconds until it returns true,
* or throw a WaitException if it doesn't return true within {@code timeoutMs} milliseconds.
* @return The remaining time left until timeout occurs
* (helpful if you have several calls which need to share a common timeout),
* */
public static long waitFor(String description, long pollIntervalMs, long timeoutMs, BooleanSupplier ready) {
return waitFor(description, pollIntervalMs, timeoutMs, ready, () -> { });
}

public static long waitFor(String description, long pollIntervalMs, long timeoutMs, BooleanSupplier ready, Runnable onTimeout) {
LOGGER.debug("Waiting for {}", description);
long deadline = System.currentTimeMillis() + timeoutMs;

String exceptionMessage = null;
String previousExceptionMessage = null;

// in case we are polling every 1s, we want to print exception after x tries, not on the first try
// for minutes poll interval will 2 be enough
int exceptionAppearanceCount = Duration.ofMillis(pollIntervalMs).toMinutes() > 0 ? 2 : Math.max((int) (timeoutMs / pollIntervalMs) / 4, 2);
int exceptionCount = 0;
int newExceptionAppearance = 0;

StringWriter stackTraceError = new StringWriter();

while (true) {
boolean result;
try {
result = ready.getAsBoolean();
} catch (Exception e) {
exceptionMessage = e.getMessage();

if (++exceptionCount == exceptionAppearanceCount && exceptionMessage != null && exceptionMessage.equals(previousExceptionMessage)) {
LOGGER.error("While waiting for {} exception occurred: {}", description, exceptionMessage);
// log the stacktrace
e.printStackTrace(new PrintWriter(stackTraceError));
} else if (exceptionMessage != null && !exceptionMessage.equals(previousExceptionMessage) && ++newExceptionAppearance == 2) {
previousExceptionMessage = exceptionMessage;
}

result = false;
}
long timeLeft = deadline - System.currentTimeMillis();
if (result) {
return timeLeft;
}
if (timeLeft <= 0) {
if (exceptionCount > 1) {
LOGGER.error("Exception waiting for {}, {}", description, exceptionMessage);

if (!stackTraceError.toString().isEmpty()) {
// printing handled stacktrace
LOGGER.error(stackTraceError.toString());
}
}
onTimeout.run();
WaitException waitException = new WaitException("Timeout after " + timeoutMs + " ms waiting for " + description);
waitException.printStackTrace();
throw waitException;
}
long sleepTime = Math.min(pollIntervalMs, timeLeft);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("{} not ready, will try again in {} ms ({}ms till timeout)", description, sleepTime, timeLeft);
}
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
return deadline - System.currentTimeMillis();
}
}
}
}
15 changes: 15 additions & 0 deletions src/main/java/io/odh/test/framework/WaitException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright Skodjob authors.
* License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
*/
package io.odh.test.framework;

public class WaitException extends RuntimeException {
public WaitException(String message) {
super(message);
}

public WaitException(Throwable cause) {
super(cause);
}
}
37 changes: 37 additions & 0 deletions src/main/java/io/odh/test/framework/manager/ResourceCondition.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright Skodjob authors.
* License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
*/

package io.odh.test.framework.manager;

import io.fabric8.kubernetes.api.model.HasMetadata;

import java.util.Objects;
import java.util.function.Predicate;

public class ResourceCondition<T extends HasMetadata> {
private final Predicate<T> predicate;
private final String conditionName;

public ResourceCondition(Predicate<T> predicate, String conditionName) {
this.predicate = predicate;
this.conditionName = conditionName;
}

public String getConditionName() {
return conditionName;
}

public Predicate<T> getPredicate() {
return predicate;
}

public static <T extends HasMetadata> ResourceCondition<T> readiness(ResourceType<T> type) {
return new ResourceCondition<>(type::waitForReadiness, "readiness");
}

public static <T extends HasMetadata> ResourceCondition<T> deletion() {
return new ResourceCondition<>(Objects::isNull, "deletion");
}
}
29 changes: 29 additions & 0 deletions src/main/java/io/odh/test/framework/manager/ResourceItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright Skodjob authors.
* License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
*/
package io.odh.test.framework.manager;

import io.fabric8.kubernetes.api.model.HasMetadata;

public final class ResourceItem<T extends HasMetadata> {

ThrowableRunner throwableRunner;
T resource;

public ResourceItem(ThrowableRunner throwableRunner, T resource) {
this.throwableRunner = throwableRunner;
this.resource = resource;
}

public ResourceItem(ThrowableRunner throwableRunner) {
this.throwableRunner = throwableRunner;
}

public ThrowableRunner getThrowableRunner() {
return throwableRunner;
}
public T getResource() {
return resource;
}
}
Loading
Loading