Skip to content
Open
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
15 changes: 15 additions & 0 deletions core/src/main/java/cz/xtf/core/openshift/OpenShift.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
Expand Down Expand Up @@ -1316,11 +1317,21 @@ public Path storePodLog(Pod pod, Path dirPath, String fileName) throws IOExcepti
return storeLog(log, dirPath, fileName);
}

public void storePodLog(Pod pod, PrintStream printStream) {
String log = getPodLog(pod);
storeLog(log, printStream);
}

public Path storeBuildLog(Build build, Path dirPath, String fileName) throws IOException {
String log = getBuildLog(build);
return storeLog(log, dirPath, fileName);
}

public void storeBuildLog(Build build, PrintStream printStream) {
String log = getBuildLog(build);
storeLog(log, printStream);
}

private Path storeLog(String log, Path dirPath, String fileName) throws IOException {
Path filePath = dirPath.resolve(fileName);

Expand All @@ -1331,6 +1342,10 @@ private Path storeLog(String log, Path dirPath, String fileName) throws IOExcept
return filePath;
}

private void storeLog(String log, PrintStream printStream) {
printStream.write(log.getBytes(), 0, log.length());
}

// Waiting

/**
Expand Down
1 change: 1 addition & 0 deletions junit5/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Extensions enable better test management.

#### @OpenShiftRecorder
Record OpenShift state when a test throws an exception or use `xtf.record.always` to record on success. Specify app names (which will be turned into regexes) to filter resources by name. When not specified, everything in test and build namespace will be recorded (regex - `.*`). Use `xtf.record.dir` to set the directory.
In case of test failure you can append pod logs and events into JUnit failure report by setting `xtf.record.append.logs.into.junit.report.on.failure` property.

#### @CleanBeforeAll/@CleanBeforeEach
Cleans namespace specified by `xtf.openshift.namespace` property. Either before all tests or each test execution.
Expand Down
6 changes: 6 additions & 0 deletions junit5/src/main/java/cz/xtf/junit5/config/JUnitConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class JUnitConfig {
private static final String RECORD_DIR = "xtf.record.dir";
private static final String RECORD_ALWAYS = "xtf.record.always";
private static final String RECORD_BEFORE = "xtf.record.before";
private static final String REPORT_LOGS_ON_FAILURE = "xtf.record.append.logs.into.junit.report.on.failure";

public static String recordDir() {
return XTFConfig.get(RECORD_DIR);
Expand Down Expand Up @@ -59,4 +60,9 @@ public static String jenkinsRerun() {
public static boolean prebuilderSynchronized() {
return Boolean.parseBoolean(XTFConfig.get(PREBUILDER_SYNCHRONIZED, "false"));
}

public static boolean appendLogsToReportOnFailure() {
return XTFConfig.get(REPORT_LOGS_ON_FAILURE) != null
&& (XTFConfig.get(REPORT_LOGS_ON_FAILURE).equals("") || XTFConfig.get(REPORT_LOGS_ON_FAILURE).equals("true"));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package cz.xtf.junit5.extensions;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.nio.charset.StandardCharsets;

import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
Expand Down Expand Up @@ -59,12 +63,25 @@ public void beforeEach(ExtensionContext context) {

@Override
public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable {
Throwable newThrowable = throwable;
final ByteArrayOutputStream messageStream = new ByteArrayOutputStream();
try {
openShiftRecorderService.recordState(context);

if (JUnitConfig.appendLogsToReportOnFailure()) {
try (PrintStream ps = new PrintStream(messageStream, true, StandardCharsets.UTF_8.name())) {
openShiftRecorderService.recordState(context, ps);
}
if (messageStream.size() != 0) {
Constructor<? extends Throwable> constructor = throwable.getClass().getConstructor(String.class,
Throwable.class);
newThrowable = constructor.newInstance(throwable.getMessage() + messageStream, throwable.getCause());
}
}
} catch (Throwable t) {
log.error("Throwable: ", t);
} finally {
throw throwable;
throw newThrowable;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package cz.xtf.junit5.extensions;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicBoolean;
Expand Down Expand Up @@ -133,7 +135,6 @@ public void initFilters(ExtensionContext context) {
* @param context The test execution context
*/
public void updateFilters(ExtensionContext context) {
ExtensionContext.Store classStore = getClassStore(context);
OpenShift master = OpenShifts.master();
OpenShift bm = BuildManagers.get().openShift();
if (!isFilterInitializationComplete(context)) {
Expand Down Expand Up @@ -215,6 +216,15 @@ public void recordState(ExtensionContext context) throws IOException {
!isMasterAndBuildNamespaceSame() ? getFilter(context, EVENT_FILTER_BUILDS) : null);
}

public void recordState(ExtensionContext context, PrintStream ps) throws IOException {
savePodLogs(context, getFilter(context, POD_FILTER_MASTER),
!isMasterAndBuildNamespaceSame() ? getFilter(context, POD_FILTER_BUILDS) : null, ps);
saveBuildLogs(context, getFilter(context, BUILD_FILTER_MASTER),
!isMasterAndBuildNamespaceSame() ? getFilter(context, BUILD_FILTER_MASTER) : null, ps);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please be aware of the same problem fixed in #521

saveEvents(context, getFilter(context, EVENT_FILTER_MASTER),
!isMasterAndBuildNamespaceSame() ? getFilter(context, EVENT_FILTER_BUILDS) : null, ps);
}

private boolean isFilterInitializationComplete(ExtensionContext context) {
ExtensionContext.Store classStore = getClassStore(context);
return classStore.get(FILTER_INITIALIZATION_DONE, AtomicBoolean.class).get();
Expand Down Expand Up @@ -256,6 +266,10 @@ private void initMethodFilter(ExtensionContext context, String key, OpenShift op
}

private ExtensionContext.Store getClassStore(ExtensionContext extensionContext) {
if (extensionContext.getTestMethod().isPresent()) {
return extensionContext.getParent().get()
.getStore(ExtensionContext.Namespace.create(extensionContext.getRequiredTestClass()));
}
return extensionContext.getStore(ExtensionContext.Namespace.create(extensionContext.getRequiredTestClass()));
}

Expand Down Expand Up @@ -447,6 +461,15 @@ protected void saveDCs(ExtensionContext context, ResourcesFilterBuilder<Deployme

protected void savePodLogs(ExtensionContext context, ResourcesFilterBuilder<Pod> masterFilter,
ResourcesFilterBuilder<Pod> buildsFilter) {
savePodLogs(context, masterFilter, buildsFilter, null);
}

protected void savePodLogs(ExtensionContext context, ResourcesFilterBuilder<Pod> masterFilter,
ResourcesFilterBuilder<Pod> buildsFilter, PrintStream ps) {
if (ps != null) {
ps.println("\nAvailable PodLogs:");
}

BiConsumer<OpenShift, ResourcesFilterBuilder<Pod>> podPrinter = (openShift, filter) -> openShift.getPods()
.stream()
.filter(filter.build())
Expand All @@ -460,10 +483,15 @@ protected void savePodLogs(ExtensionContext context, ResourcesFilterBuilder<Pod>
.count() == 0)
.forEach(pod -> {
try {
openShift.storePodLog(
pod,
Paths.get(attachmentsDir(), dirNameForTest(context)),
pod.getMetadata().getName() + ".log");
if (ps == null) {
openShift.storePodLog(
pod,
Paths.get(attachmentsDir(), dirNameForTest(context)),
pod.getMetadata().getName() + ".log");
} else {
ps.println("POD " + pod.getMetadata().getName() + ":");
openShift.storePodLog(pod, ps);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
Expand All @@ -477,10 +505,21 @@ protected void savePodLogs(ExtensionContext context, ResourcesFilterBuilder<Pod>

protected void saveEvents(ExtensionContext context, ResourcesFilterBuilder<Event> masterFilter,
ResourcesFilterBuilder<Event> buildsFilter) throws IOException {
saveEvents(context, masterFilter, buildsFilter, null);
}

protected void saveEvents(ExtensionContext context, ResourcesFilterBuilder<Event> masterFilter,
ResourcesFilterBuilder<Event> buildsFilter, PrintStream ps) throws IOException {
// master namespace
final Path eventsMasterLogPath = Paths.get(attachmentsDir(), dirNameForTest(context),
"events-" + OpenShifts.master().getNamespace() + ".log");
try (final ResourcesPrinterHelper<Event> printer = ResourcesPrinterHelper.forEvents(eventsMasterLogPath)) {
ResourcesPrinterHelper<Event> printHelper = ResourcesPrinterHelper.forEvents(eventsMasterLogPath);
if (ps != null) {
ps.println("\nAvailable Openshift events:");
printHelper = ResourcesPrinterHelper.forEvents(new OutputStreamWriter(ps));
}

try (final ResourcesPrinterHelper<Event> printer = printHelper) {
OpenShifts.master().getEvents()
.stream()
.filter(masterFilter.build())
Expand All @@ -490,7 +529,10 @@ protected void saveEvents(ExtensionContext context, ResourcesFilterBuilder<Event
if (!isMasterAndBuildNamespaceSame()) {
final Path eventsBMLogPath = Paths.get(attachmentsDir(), dirNameForTest(context),
"events-" + BuildManagers.get().openShift().getNamespace() + ".log");
try (final ResourcesPrinterHelper<Event> printer = ResourcesPrinterHelper.forEvents(eventsBMLogPath)) {
printHelper = ps == null ? ResourcesPrinterHelper.forEvents(eventsBMLogPath)
: ResourcesPrinterHelper.forEvents(new OutputStreamWriter(ps));

try (final ResourcesPrinterHelper<Event> printer = printHelper) {
BuildManagers.get().openShift().getEvents()
.stream()
.filter(buildsFilter.build())
Expand All @@ -501,17 +543,31 @@ protected void saveEvents(ExtensionContext context, ResourcesFilterBuilder<Event

protected void saveBuildLogs(ExtensionContext context, ResourcesFilterBuilder<Build> masterFilter,
ResourcesFilterBuilder<Build> buildsFilter) {
saveBuildLogs(context, masterFilter, buildsFilter, null);
}

protected void saveBuildLogs(ExtensionContext context, ResourcesFilterBuilder<Build> masterFilter,
ResourcesFilterBuilder<Build> buildsFilter, PrintStream ps) {
if (ps != null) {
ps.println("\nAvailable BuildLogs:");
}

BiConsumer<OpenShift, ResourcesFilterBuilder<Build>> buildPrinter = (openShift, filter) -> openShift.getBuilds()
.stream()
.filter(filter.build())
.forEach(build -> {
try {
openShift.storeBuildLog(
build,
Paths.get(attachmentsDir(), dirNameForTest(context)),
build.getMetadata().getName() + ".log");
} catch (IOException e) {
throw new RuntimeException(e);
if (ps == null) {
openShift.storeBuildLog(
build,
Paths.get(attachmentsDir(), dirNameForTest(context)),
build.getMetadata().getName() + ".log");
} else {
ps.println("BUILD " + build.getMetadata().getName() + ":");
openShift.storeBuildLog(build, ps);
}
} catch (Exception e) {
// ignoring KubernetesClientExceptions
}
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package cz.xtf.junit5.extensions.helpers;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashMap;
Expand All @@ -25,9 +25,10 @@
import io.fabric8.openshift.api.model.Route;

public class ResourcesPrinterHelper<X> implements AutoCloseable {
private final Path file;
private Path file = null;
private final Function<X, LinkedHashMap<String, String>> resourceToCols;
private final List<String[]> rows;
private OutputStreamWriter outputStream = null;
private int[] maxLengths;
private String[] headers = null;

Expand All @@ -37,10 +38,20 @@ private ResourcesPrinterHelper(Path file, Function<X, LinkedHashMap<String, Stri
rows = new ArrayList<>();
}

private ResourcesPrinterHelper(OutputStreamWriter outputStream, Function<X, LinkedHashMap<String, String>> resourceToCols) {
this.outputStream = outputStream;
this.resourceToCols = resourceToCols;
rows = new ArrayList<>();
}

public static ResourcesPrinterHelper<Event> forEvents(Path filePath) {
return new ResourcesPrinterHelper<>(filePath, ResourcesPrinterHelper::getEventCols);
}

public static ResourcesPrinterHelper<Event> forEvents(OutputStreamWriter outputStream) {
return new ResourcesPrinterHelper<>(outputStream, ResourcesPrinterHelper::getEventCols);
}

public static ResourcesPrinterHelper<Pod> forPods(Path filePath) {
return new ResourcesPrinterHelper<>(filePath, ResourcesPrinterHelper::getPodCols);
}
Expand Down Expand Up @@ -222,9 +233,14 @@ public void close() throws IOException {
}

public void flush() throws IOException {
file.getParent().toFile().mkdirs();
//mutually exclusive options file OR outputStream
OutputStreamWriter streamWriter = outputStream;
if (file != null) {
file.getParent().toFile().mkdirs();
streamWriter = new OutputStreamWriter(Files.newOutputStream(file.toFile().toPath()), StandardCharsets.UTF_8);
}

try (final Writer writer = new OutputStreamWriter(new FileOutputStream(file.toFile()), StandardCharsets.UTF_8)) {
try (final Writer writer = streamWriter) {
if (!rows.isEmpty()) {
StringBuilder formatBuilder = new StringBuilder();
for (int maxLength : maxLengths) {
Expand Down