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 log collector triggered by test failure #40

Merged
merged 1 commit into from
Dec 13, 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
10 changes: 10 additions & 0 deletions src/main/java/io/odh/test/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
Expand All @@ -21,6 +25,8 @@ public class Environment {
private static final Logger LOGGER = LoggerFactory.getLogger(Environment.class);
private static final Map<String, String> VALUES = new HashMap<>();

public static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm");

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

private static final String USERNAME_ENV = "KUBE_USERNAME";
Expand All @@ -29,6 +35,8 @@ public class Environment {
private static final String URL_ENV = "KUBE_URL";
private static final String PRODUCT_ENV = "PRODUCT";

private static final String LOG_DIR_ENV = "LOG_DIR";

/**
* Install bundle files
*/
Expand Down Expand Up @@ -68,6 +76,8 @@ public class Environment {
public static final String OPERATOR_INSTALL_TYPE = getOrDefault(OPERATOR_INSTALL_TYPE_ENV, InstallTypes.BUNDLE.toString());
public static final String PRODUCT = getOrDefault(PRODUCT_ENV, PRODUCT_DEFAULT);

public static final Path LOG_DIR = getOrDefault(LOG_DIR_ENV, Paths::get, Paths.get(USER_PATH, "target", "logs")).resolve("test-run-" + DATE_FORMAT.format(LocalDateTime.now()));

private Environment() { }

static {
Expand Down
24 changes: 24 additions & 0 deletions src/main/java/io/odh/test/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.odh.test.framework.WaitException;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
Expand Down Expand Up @@ -189,4 +193,24 @@ public static <T> T configFromYaml(String yamlFile, Class<T> c) {
throw new RuntimeException(e);
}
}

public static Path getLogPath(String folderName, ExtensionContext context) {
String testMethod = context.getDisplayName();
String testClassName = context.getTestClass().map(Class::getName).orElse("NOCLASS");
return getLogPath(folderName, testClassName, testMethod);
}

public static Path getLogPath(String folderName, TestInfo info) {
String testMethod = info.getDisplayName();
String testClassName = info.getTestClass().map(Class::getName).orElse("NOCLASS");
return getLogPath(folderName, testClassName, testMethod);
}

public static Path getLogPath(String folderName, String testClassName, String testMethod) {
Path path = Environment.LOG_DIR.resolve(Paths.get(folderName, testClassName));
if (testMethod != null) {
path = path.resolve(testMethod.replace("(", "").replace(")", ""));
}
return path;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
package io.odh.test.framework.listeners;

import io.odh.test.framework.logs.LogCollector;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler;
import org.junit.jupiter.api.extension.TestExecutionExceptionHandler;
Expand All @@ -19,35 +20,30 @@ public class TestExceptionCallbackListener implements TestExecutionExceptionHand
@Override
public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable {
LOGGER.error("Test failed at {} : {}", "Test execution", throwable.getMessage(), throwable);
//TODO collect proper logs
throw throwable;
LogCollector.saveKubernetesState(context, throwable);
}

@Override
public void handleBeforeAllMethodExecutionException(ExtensionContext context, Throwable throwable) throws Throwable {
LOGGER.error("Test failed at {} : {}", "Test before all", throwable.getMessage(), throwable);
//TODO collect proper logs
throw throwable;
LogCollector.saveKubernetesState(context, throwable);
}

@Override
public void handleBeforeEachMethodExecutionException(ExtensionContext context, Throwable throwable) throws Throwable {
LOGGER.error("Test failed at {} : {}", "Test before each", throwable.getMessage(), throwable);
//TODO collect proper logs
throw throwable;
LogCollector.saveKubernetesState(context, throwable);
}

@Override
public void handleAfterEachMethodExecutionException(ExtensionContext context, Throwable throwable) throws Throwable {
LOGGER.error("Test failed at {} : {}", "Test after each", throwable.getMessage(), throwable);
//TODO collect proper logs
throw throwable;
LogCollector.saveKubernetesState(context, throwable);
}

@Override
public void handleAfterAllMethodExecutionException(ExtensionContext context, Throwable throwable) throws Throwable {
LOGGER.error("Test failed at {} : {}", "Test after all", throwable.getMessage(), throwable);
//TODO collect proper logs
throw throwable;
LogCollector.saveKubernetesState(context, throwable);
}
}
54 changes: 54 additions & 0 deletions src/main/java/io/odh/test/framework/logs/LogCollector.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* 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.logs;

import io.fabric8.kubernetes.api.model.PodStatus;
import io.odh.test.Environment;
import io.odh.test.TestUtils;
import io.odh.test.framework.manager.ResourceManager;
import io.odh.test.platform.cmdClient.KubeCmdClient;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;

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

/**
* Calls storing cluster info for connected cluster
*/
public static void saveKubernetesState(ExtensionContext extensionContext, Throwable throwable) throws Throwable {
LOGGER.warn("Printing all pods on cluster");
ResourceManager.getClient().getClient().pods().inAnyNamespace().list().getItems().forEach(p ->
LOGGER.info("Pod: {} in ns: {} with phase: {}",
p.getMetadata().getName(),
p.getMetadata().getNamespace(),
Optional.ofNullable(p.getStatus()).map(PodStatus::getPhase).orElse("null")));

Path logPath = TestUtils.getLogPath(Environment.LOG_DIR.resolve("failedTest").toString(), extensionContext);
Files.createDirectories(logPath);
LOGGER.info("Storing cluster info into {}", logPath);
try {
saveClusterState(logPath);
} catch (IOException ex) {
LOGGER.warn("Cannot save logs in {}", logPath);
}
throw throwable;
}

private static void saveClusterState(Path logpath) throws IOException {
KubeCmdClient cmdClient = ResourceManager.getKubeCmdClient();
Files.writeString(logpath.resolve("describe-cluster-nodes.log"), cmdClient.exec(false, false, "describe", "nodes").out());
Files.writeString(logpath.resolve("all-events.log"), cmdClient.exec(false, false, "get", "events", "--all-namespaces").out());
Files.writeString(logpath.resolve("pvs.log"), cmdClient.exec(false, false, "describe", "pv").out());
Files.writeString(logpath.resolve("dsc.yml"), cmdClient.exec(false, false, "get", "dsc", "-o", "yaml").out());
Files.writeString(logpath.resolve("dsci.yml"), cmdClient.exec(false, false, "get", "dsci", "-o", "yaml").out());
}
}