Skip to content

Commit

Permalink
Add method for read resoruces from yaml files + fixes (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
kornys authored Dec 5, 2023
1 parent 2274ada commit 3978997
Show file tree
Hide file tree
Showing 13 changed files with 182 additions and 82 deletions.
13 changes: 13 additions & 0 deletions src/main/java/io/odh/test/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,19 @@ public class Environment {
private static final Logger LOGGER = LoggerFactory.getLogger(Environment.class);
private static final Map<String, String> VALUES = new HashMap<>();

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

private static final String USERNAME_ENV = "KUBE_USERNAME";
private static final String PASSWORD_ENV = "KUBE_PASSWORD";
private static final String TOKEN_ENV = "KUBE_TOKEN";
private static final String URL_ENV = "KUBE_URL";

/**
* Install bundle files
*/
private static final String INSTALL_FILE_ENV = "INSTALL_FILE";
private static final String INSTALL_FILE_RELEASED_ENV = "INSTALL_FILE_PREVIOUS";

/**
* OLM env variables
*/
Expand Down Expand Up @@ -56,6 +65,10 @@ public class Environment {
public static final String KUBE_TOKEN = getOrDefault(TOKEN_ENV, null);
public static final String KUBE_URL = getOrDefault(URL_ENV, null);

// Bundle
public static final String INSTALL_FILE_PATH = getOrDefault(INSTALL_FILE_ENV, TestConstants.LATEST_BUNDLE_DEPLOY_FILE);
public static final String INSTALL_FILE_PREVIOUS_PATH = getOrDefault(INSTALL_FILE_RELEASED_ENV, TestConstants.RELEASED_BUNDLE_DEPLOY_FILE);

// 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);
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/io/odh/test/TestConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public class TestConstants {
public static final String SUBSCRIPTION = "Subscription";
public static final String OPERATOR_GROUP = "OperatorGroup";

public static final String LATEST_BUNDLE_DEPLOY_FILE = "install-files/latest.yaml";
public static final String RELEASED_BUNDLE_DEPLOY_FILE = "install-files/released.yaml";

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();
Expand Down
75 changes: 72 additions & 3 deletions src/main/java/io/odh/test/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,25 @@
import io.odh.test.framework.WaitException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
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.
*/
Expand All @@ -37,9 +43,10 @@ private TestUtils() {
/**
* 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, () -> { });
}
Expand Down Expand Up @@ -105,4 +112,66 @@ public static long waitFor(String description, long pollIntervalMs, long timeout
}
}
}

private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool(new ThreadFactory() {
final ThreadFactory defaultThreadFactory = Executors.defaultThreadFactory();

@Override
public Thread newThread(Runnable r) {
Thread result = defaultThreadFactory.newThread(r);
result.setDaemon(true);
return result;
}
});

public static CompletableFuture<Void> asyncWaitFor(String description, long pollIntervalMs, long timeoutMs, BooleanSupplier ready) {
LOGGER.info("Waiting for {}", description);
long deadline = System.currentTimeMillis() + timeoutMs;
CompletableFuture<Void> future = new CompletableFuture<>();
Executor delayed = CompletableFuture.delayedExecutor(pollIntervalMs, TimeUnit.MILLISECONDS, EXECUTOR);
Runnable r = new Runnable() {
@Override
public void run() {
boolean result;
try {
result = ready.getAsBoolean();
} catch (Exception e) {
future.completeExceptionally(e);
return;
}
long timeLeft = deadline - System.currentTimeMillis();
if (!future.isDone()) {
if (!result) {
if (timeLeft >= 0) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("{} not ready, will try again ({}ms till timeout)", description, timeLeft);
}
delayed.execute(this);
} else {
future.completeExceptionally(new TimeoutException(String.format("Waiting for %s timeout %s exceeded", description, timeoutMs)));
}
} else {
future.complete(null);
}
}
}
};
r.run();
return future;
}

public static InputStream getFileFromResourceAsStream(String fileName) {

// The class loader that loaded the class
ClassLoader classLoader = TestUtils.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(fileName);

// the stream holding the file content
if (inputStream == null) {
throw new IllegalArgumentException("file not found! " + fileName);
} else {
return inputStream;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ private <T extends HasMetadata> void createResource(boolean waitReady, T... reso
if (type == null) {
if (resource instanceof Deployment) {
Deployment deployment = (Deployment) resource;
ResourceManager.getClient().getClient().apps().deployments().resource(deployment).create();
client.getClient().apps().deployments().resource(deployment).create();
if (waitReady) {
DeploymentUtils.waitForDeploymentReady(resource.getMetadata().getNamespace(), resource.getMetadata().getName());
}
Expand Down Expand Up @@ -111,7 +111,7 @@ public final <T extends HasMetadata> void deleteResource(T... resources) {
if (type == null) {
if (resource instanceof Deployment) {
Deployment deployment = (Deployment) resource;
ResourceManager.getClient().getClient().apps().deployments().resource(deployment).delete();
client.getClient().apps().deployments().resource(deployment).delete();
DeploymentUtils.waitForDeploymentDeletion(resource.getMetadata().getNamespace(), resource.getMetadata().getName());
} else {
LOGGER.error("Invalid resource {} {}/{}. Please implement it in ResourceManager",
Expand All @@ -130,7 +130,7 @@ public final <T extends HasMetadata> void deleteResource(T... resources) {
type.delete(resource);
assertTrue(waitResourceCondition(resource, ResourceCondition.deletion()),
String.format("Timed out deleting %s %s/%s", resource.getKind(), resource.getMetadata().getNamespace(), resource.getMetadata().getName()));
} catch (Exception e) {
} catch (Exception e) {
if (resource.getMetadata().getNamespace() == null) {
LOGGER.error("Failed to delete {} {}", resource.getKind(), resource.getMetadata().getName(), e);
} else {
Expand Down Expand Up @@ -167,7 +167,7 @@ public final <T extends HasMetadata> boolean waitResourceCondition(T resource, R
TestConstants.GLOBAL_POLL_INTERVAL, TestConstants.GLOBAL_TIMEOUT,
() -> {
T res = type.get(resource.getMetadata().getNamespace(), resource.getMetadata().getName());
resourceReady[0] = condition.getPredicate().test(res);
resourceReady[0] = condition.getPredicate().test(res);
if (!resourceReady[0]) {
type.delete(res);
}
Expand Down
43 changes: 43 additions & 0 deletions src/main/java/io/odh/test/install/BundleInstall.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,48 @@
*/
package io.odh.test.install;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.odh.test.Environment;
import io.odh.test.TestConstants;
import io.odh.test.TestUtils;
import io.odh.test.framework.manager.ResourceManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class BundleInstall {

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

List<HasMetadata> resources;

public BundleInstall(String installFilePath) throws IOException {
InputStream is;
if (installFilePath.equals(TestConstants.LATEST_BUNDLE_DEPLOY_FILE)
|| installFilePath.equals(TestConstants.RELEASED_BUNDLE_DEPLOY_FILE)) {
is = TestUtils.getFileFromResourceAsStream(installFilePath);
} else {
is = new FileInputStream(installFilePath);
}
resources = ResourceManager.getClient().readResourcesFromYaml(is);
}

public BundleInstall() throws IOException {
//use default latest
this(Environment.INSTALL_FILE_PATH);
}

public void printResources() {
resources.forEach(r -> {
LOGGER.info("Kind: {}, Name: {}", r.getKind(), r.getMetadata().getName());
});
}

public void installBundle() {
//TODO implement using RM
}
}
2 changes: 1 addition & 1 deletion src/main/java/io/odh/test/install/OlmInstall.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import java.util.Collections;

public class OlmInstall {
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceManager.class);
private static final Logger LOGGER = LoggerFactory.getLogger(OlmInstall.class);

private String namespace = Environment.OLM_OPERATOR_NAMESPACE;
private String channel = Environment.OLM_OPERATOR_CHANNEL;
Expand Down
29 changes: 23 additions & 6 deletions src/main/java/io/odh/test/platform/KubeClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public KubeClient inNamespace(String namespace) {
}

private Config getConfig() {
if (Environment.KUBE_PASSWORD != null
if (Environment.KUBE_USERNAME != null
&& Environment.KUBE_PASSWORD != null
&& Environment.KUBE_URL != null) {
return new ConfigBuilder()
Expand Down Expand Up @@ -117,13 +117,13 @@ public Namespace getNamespace(String namespace) {

public boolean namespaceExists(String namespace) {
return client.namespaces().list().getItems().stream().map(n -> n.getMetadata().getName())
.collect(Collectors.toList()).contains(namespace);
.toList().contains(namespace);
}

// =============================================
// ---------> Create multi-resoruces <---------
// =============================================
public void apply(String namespace, InputStream is, Function<HasMetadata, HasMetadata> modifier) throws IOException {
// ==================================================
// ---------> Create/read multi-resoruces <---------
// ==================================================
public void create(String namespace, InputStream is, Function<HasMetadata, HasMetadata> modifier) throws IOException {
try (is) {
client.load(is).get().forEach(i -> {
HasMetadata h = modifier.apply(i);
Expand All @@ -134,6 +134,23 @@ public void apply(String namespace, InputStream is, Function<HasMetadata, HasMet
}
}

public void create(InputStream is, Function<HasMetadata, HasMetadata> modifier) throws IOException {
try (is) {
client.load(is).get().forEach(i -> {
HasMetadata h = modifier.apply(i);
if (h != null) {
client.resource(h).create();
}
});
}
}

public List<HasMetadata> readResourcesFromYaml(InputStream is) throws IOException {
try (is) {
return client.load(is).items();
}
}

/**
* Gets namespace status
*/
Expand Down
55 changes: 0 additions & 55 deletions src/main/java/io/odh/test/platform/KubeUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,6 @@
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.BooleanSupplier;

public class KubeUtils {

Expand All @@ -29,53 +21,6 @@ public static org.kubeflow.v1.notebookstatus.Conditions getNotebookConditionByTy
return conditions.stream().filter(c -> c.getType().equals(type)).findFirst().orElseGet(null);
}

private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool(new ThreadFactory() {
final ThreadFactory defaultThreadFactory = Executors.defaultThreadFactory();

@Override
public Thread newThread(Runnable r) {
Thread result = defaultThreadFactory.newThread(r);
result.setDaemon(true);
return result;
}
});

public static CompletableFuture<Void> asyncWaitFor(String description, long pollIntervalMs, long timeoutMs, BooleanSupplier ready) {
LOGGER.info("Waiting for {}", description);
long deadline = System.currentTimeMillis() + timeoutMs;
CompletableFuture<Void> future = new CompletableFuture<>();
Executor delayed = CompletableFuture.delayedExecutor(pollIntervalMs, TimeUnit.MILLISECONDS, EXECUTOR);
Runnable r = new Runnable() {
@Override
public void run() {
boolean result;
try {
result = ready.getAsBoolean();
} catch (Exception e) {
future.completeExceptionally(e);
return;
}
long timeLeft = deadline - System.currentTimeMillis();
if (!future.isDone()) {
if (!result) {
if (timeLeft >= 0) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("{} not ready, will try again ({}ms till timeout)", description, timeLeft);
}
delayed.execute(this);
} else {
future.completeExceptionally(new TimeoutException(String.format("Waiting for %s timeout %s exceeded", description, timeoutMs)));
}
} else {
future.complete(null);
}
}
}
};
r.run();
return future;
}

private KubeUtils() {
}
}
3 changes: 0 additions & 3 deletions src/test/java/io/odh/test/e2e/Abstract.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

import io.odh.test.framework.manager.ResourceManager;
import io.odh.test.framework.TestExceptionCallbackListener;
import io.odh.test.platform.KubeClient;
import io.odh.test.TestConstants;
import io.odh.test.framework.TestSeparator;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.DisplayNameGeneration;
Expand All @@ -19,7 +17,6 @@
@ExtendWith(TestExceptionCallbackListener.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class Abstract implements TestSeparator {
protected KubeClient kubeClient = new KubeClient(TestConstants.ODH_NAMESPACE);

static {
ResourceManager.getInstance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.fabric8.kubernetes.client.dsl.Resource;
import io.odh.test.TestConstants;
import io.odh.test.e2e.Abstract;
import io.odh.test.framework.manager.ResourceManager;
import io.odh.test.platform.KubeUtils;
import io.opendatahub.datasciencecluster.v1.DataScienceCluster;
import io.opendatahub.datasciencecluster.v1.datascienceclusterspec.components.Codeflare;
Expand Down Expand Up @@ -39,8 +40,8 @@ public class DataScienceClusterIT extends Abstract {

@BeforeAll
void init() {
dataScienceProjectCli = kubeClient.dataScienceClusterClient();
dashboardConfigCli = kubeClient.dashboardConfigClient();
dataScienceProjectCli = ResourceManager.getClient().dataScienceClusterClient();
dashboardConfigCli = ResourceManager.getClient().dashboardConfigClient();
}

@Test
Expand Down
Loading

0 comments on commit 3978997

Please sign in to comment.