From 4481ed8eb1007d3790b94680d48cb3a2f5a34e1c Mon Sep 17 00:00:00 2001 From: David Kornel Date: Thu, 3 Oct 2024 10:38:31 +0200 Subject: [PATCH] Ability to store all created resoruces as yaml files for easy reprodcing issues (#188) ## Description Store yaml files created by RM to easy reproduce test/issues ## Type of Change Please delete options that are not relevant. * New feature (non-breaking change which adds functionality) ## Checklist - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit/integration tests pass locally with my changes Signed-off-by: David Kornel --- .../listeners/ResourceManagerExtension.java | 3 +- .../resources/KubeResourceManager.java | 55 +++++++++++++++++++ .../test/integration/AbstractIT.java | 3 + 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/listeners/ResourceManagerExtension.java b/test-frame-common/src/main/java/io/skodjob/testframe/listeners/ResourceManagerExtension.java index 3dd0d8c..309e5c1 100644 --- a/test-frame-common/src/main/java/io/skodjob/testframe/listeners/ResourceManagerExtension.java +++ b/test-frame-common/src/main/java/io/skodjob/testframe/listeners/ResourceManagerExtension.java @@ -18,12 +18,11 @@ public class ResourceManagerExtension implements BeforeAllCallback, BeforeEachCallback, AfterAllCallback, AfterEachCallback { private ResourceManagerExtension() { - // Private constructor to prevent instantiation + KubeResourceManager.getInstance(); } @Override public void beforeAll(ExtensionContext extensionContext) { - KubeResourceManager.getInstance(); KubeResourceManager.setTestContext(extensionContext); } diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/resources/KubeResourceManager.java b/test-frame-common/src/main/java/io/skodjob/testframe/resources/KubeResourceManager.java index 6701a4d..5f8975e 100644 --- a/test-frame-common/src/main/java/io/skodjob/testframe/resources/KubeResourceManager.java +++ b/test-frame-common/src/main/java/io/skodjob/testframe/resources/KubeResourceManager.java @@ -4,9 +4,13 @@ */ package io.skodjob.testframe.resources; +import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; @@ -24,6 +28,7 @@ import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.ReplicaSet; import io.fabric8.kubernetes.api.model.apps.StatefulSet; +import io.fabric8.kubernetes.client.utils.Serialization; import io.skodjob.testframe.utils.LoggerUtils; import io.skodjob.testframe.TestFrameConstants; import io.skodjob.testframe.TestFrameEnv; @@ -57,6 +62,8 @@ public class KubeResourceManager { private static final ThreadLocal TEST_CONTEXT = new ThreadLocal<>(); private static final Map>> STORED_RESOURCES = new LinkedHashMap<>(); + private static String storeYamlPath = null; + private KubeResourceManager() { // Private constructor to prevent instantiation } @@ -143,6 +150,24 @@ public final void addDeleteCallback(Consumer callback) { this.deleteCallbacks.add(callback); } + /** + * Set path for storing yaml resources + * + * @param path root path for storing + */ + public static void setStoreYamlPath(String path) { + storeYamlPath = path; + } + + /** + * Returns root path of stored yaml resources + * + * @return path + */ + public static String getStoreYamlPath() { + return storeYamlPath; + } + /** * Reads Kubernetes resources from a file at the specified path. * @@ -309,6 +334,9 @@ private void createOrUpdateResource(boolean async, for (T resource : resources) { ResourceType type = findResourceType(resource); pushToStack(resource); + if (storeYamlPath != null) { + writeResourceAsYaml(resource); + } if (type == null) { // Generic create for any resource @@ -538,4 +566,31 @@ private boolean isResourceWithReadiness(T resource) { || resource instanceof Node || resource instanceof StatefulSet; } + + private void writeResourceAsYaml(HasMetadata resource) { + File logDir = Paths.get(storeYamlPath) + .resolve("test-files").resolve(getTestContext().getRequiredTestClass().getName()).toFile(); + if (getTestContext().getTestMethod().isPresent()) { + logDir = logDir.toPath().resolve(getTestContext().getRequiredTestMethod().getName()).toFile(); + } + + if (!logDir.exists()) { + if (!logDir.mkdirs()) { + throw new RuntimeException( + String.format("Failed to create root log directories on path: %s", logDir.getAbsolutePath()) + ); + } + } + + String r = Serialization.asYaml(resource); + try { + Files.writeString(logDir.toPath().resolve( + resource.getKind() + "-" + + (resource.getMetadata().getNamespace() == null ? "" : + (resource.getMetadata().getNamespace() + "-")) + + resource.getMetadata().getName() + ".yaml"), r, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException(e); + } + } } diff --git a/test-frame-test-examples/src/test/java/io/skodjob/testframe/test/integration/AbstractIT.java b/test-frame-test-examples/src/test/java/io/skodjob/testframe/test/integration/AbstractIT.java index 710077b..0daf465 100644 --- a/test-frame-test-examples/src/test/java/io/skodjob/testframe/test/integration/AbstractIT.java +++ b/test-frame-test-examples/src/test/java/io/skodjob/testframe/test/integration/AbstractIT.java @@ -36,6 +36,9 @@ public abstract class AbstractIT { new DeploymentType() ); + // Allow storing yaml files + KubeResourceManager.setStoreYamlPath(LOG_DIR.toString()); + // Register callback which are called with every create resource method for every resource KubeResourceManager.getInstance().addCreateCallback(r -> { isCreateHandlerCalled.set(true);