summaryrefslogtreecommitdiffstats
path: root/vespa-osgi-testrunner/src/main/java/com/yahoo/vespa/testrunner/JunitRunner.java
diff options
context:
space:
mode:
Diffstat (limited to 'vespa-osgi-testrunner/src/main/java/com/yahoo/vespa/testrunner/JunitRunner.java')
-rw-r--r--vespa-osgi-testrunner/src/main/java/com/yahoo/vespa/testrunner/JunitRunner.java124
1 files changed, 77 insertions, 47 deletions
diff --git a/vespa-osgi-testrunner/src/main/java/com/yahoo/vespa/testrunner/JunitRunner.java b/vespa-osgi-testrunner/src/main/java/com/yahoo/vespa/testrunner/JunitRunner.java
index 69134f86be0..3fc85365084 100644
--- a/vespa-osgi-testrunner/src/main/java/com/yahoo/vespa/testrunner/JunitRunner.java
+++ b/vespa-osgi-testrunner/src/main/java/com/yahoo/vespa/testrunner/JunitRunner.java
@@ -2,15 +2,12 @@
package com.yahoo.vespa.testrunner;
import ai.vespa.hosted.api.TestDescriptor;
+import ai.vespa.hosted.cd.internal.TestRuntimeProvider;
import com.google.inject.Inject;
import com.yahoo.component.AbstractComponent;
-import com.yahoo.exception.ExceptionUtils;
import com.yahoo.io.IOUtils;
import com.yahoo.jdisc.application.OsgiFramework;
-import com.yahoo.slime.Cursor;
-import com.yahoo.slime.Slime;
-import com.yahoo.slime.SlimeUtils;
-import com.yahoo.yolean.Exceptions;
+import com.yahoo.vespa.testrunner.legacy.LegacyTestRunner;
import org.junit.jupiter.engine.JupiterTestEngine;
import org.junit.platform.engine.discovery.DiscoverySelectors;
import org.junit.platform.launcher.Launcher;
@@ -20,16 +17,19 @@ import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
import org.junit.platform.launcher.core.LauncherFactory;
import org.junit.platform.launcher.listeners.LoggingListener;
import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
-import org.junit.platform.launcher.listeners.TestExecutionSummary;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -41,10 +41,12 @@ public class JunitRunner extends AbstractComponent {
private static final Logger logger = Logger.getLogger(JunitRunner.class.getName());
private final BundleContext bundleContext;
+ private final TestRuntimeProvider testRuntimeProvider;
+ private Future<TestReport> execution;
@Inject
- public JunitRunner(OsgiFramework osgiFramework) {
- // TODO mortent: Find a way to workaround this hack
+ public JunitRunner(OsgiFramework osgiFramework, TestRuntimeProvider testRuntimeProvider) {
+ this.testRuntimeProvider = testRuntimeProvider;
var tmp = osgiFramework.bundleContext();
try {
var field = tmp.getClass().getDeclaredField("wrapped");
@@ -55,27 +57,54 @@ public class JunitRunner extends AbstractComponent {
}
}
- public Bundle findTestBundle(String bundleNameSuffix) {
+ public void executeTests(TestDescriptor.TestCategory category, byte[] testConfig) {
+ if (execution != null) {
+ throw new RuntimeException("Test execution already in progress");
+ }
+ testRuntimeProvider.initialize(testConfig);
+ Optional<Bundle> testBundle = findTestBundle();
+ if (testBundle.isEmpty()) {
+ throw new RuntimeException("No test bundle available");
+ }
+
+ Optional<TestDescriptor> testDescriptor = loadTestDescriptor(testBundle.get());
+ if (testDescriptor.isEmpty()) {
+ throw new RuntimeException("Could not find test descriptor");
+ }
+ List<Class<?>> testClasses = loadClasses(testBundle.get(), testDescriptor.get(), category);
+
+ execution = CompletableFuture.supplyAsync(() -> launchJunit(testClasses));
+ }
+
+ public boolean isSupported() {
+ return findTestBundle().isPresent();
+ }
+
+ private Optional<Bundle> findTestBundle() {
return Stream.of(bundleContext.getBundles())
- .filter(bundle -> bundle.getSymbolicName().endsWith(bundleNameSuffix))
- .findAny()
- .orElseThrow(() -> new RuntimeException("No bundle on classpath with name ending on " + bundleNameSuffix));
+ .filter(this::isTestBundle)
+ .findAny();
}
- public TestDescriptor loadTestDescriptor(Bundle bundle) {
+ private boolean isTestBundle(Bundle bundle) {
+ var testBundleHeader = bundle.getHeaders().get("X-JDisc-Test-Bundle-Version");
+ return testBundleHeader != null && !testBundleHeader.isBlank();
+ }
+
+ private Optional<TestDescriptor> loadTestDescriptor(Bundle bundle) {
URL resource = bundle.getEntry(TestDescriptor.DEFAULT_FILENAME);
TestDescriptor testDescriptor;
try {
var jsonDescriptor = IOUtils.readAll(resource.openStream(), Charset.defaultCharset()).trim();
testDescriptor = TestDescriptor.fromJsonString(jsonDescriptor);
logger.info( "Test classes in bundle :" + testDescriptor.toString());
- return testDescriptor;
+ return Optional.of(testDescriptor);
} catch (IOException e) {
- throw new RuntimeException("Could not load " + TestDescriptor.DEFAULT_FILENAME + " [" + e.getMessage() + "]");
+ return Optional.empty();
}
}
- public List<Class<?>> loadClasses(Bundle bundle, TestDescriptor testDescriptor, TestDescriptor.TestCategory testCategory) {
+ private List<Class<?>> loadClasses(Bundle bundle, TestDescriptor testDescriptor, TestDescriptor.TestCategory testCategory) {
List<Class<?>> testClasses = testDescriptor.getConfiguredTests(testCategory).stream()
.map(className -> loadClass(bundle, className))
.collect(Collectors.toList());
@@ -94,7 +123,7 @@ public class JunitRunner extends AbstractComponent {
}
}
- public String executeTests(List<Class<?>> testClasses) {
+ private TestReport launchJunit(List<Class<?>> testClasses) {
LauncherDiscoveryRequest discoveryRequest = LauncherDiscoveryRequestBuilder.request()
.selectors(
testClasses.stream().map(DiscoverySelectors::selectClass).collect(Collectors.toList())
@@ -116,36 +145,8 @@ public class JunitRunner extends AbstractComponent {
// Execute request
launcher.execute(discoveryRequest);
-
var report = summaryListener.getSummary();
-
- return createJsonTestReport(report, logLines);
- }
-
- private String createJsonTestReport(TestExecutionSummary report, List<String> logLines) {
- var slime = new Slime();
- var root = slime.setObject();
- var summary = root.setObject("summary");
- summary.setLong("Total tests", report.getTestsFoundCount());
- summary.setLong("Test success", report.getTestsSucceededCount());
- summary.setLong("Test failed", report.getTestsFailedCount());
- summary.setLong("Test ignored", report.getTestsSkippedCount());
- summary.setLong("Test success", report.getTestsAbortedCount());
- summary.setLong("Test started", report.getTestsStartedCount());
- var failures = summary.setArray("failures");
- report.getFailures().forEach(failure -> serializeFailure(failure, failures.addObject()));
-
- var output = root.setArray("output");
- logLines.forEach(output::addString);
-
- return Exceptions.uncheck(() -> new String(SlimeUtils.toJsonBytes(slime), StandardCharsets.UTF_8));
- }
-
- private void serializeFailure(TestExecutionSummary.Failure failure, Cursor slime) {
- var testIdentifier = failure.getTestIdentifier();
- slime.setString("testName", testIdentifier.getUniqueId());
- slime.setString("testError",failure.getException().getMessage());
- slime.setString("exception", ExceptionUtils.getStackTraceAsString(failure.getException()));
+ return new TestReport(report, logLines);
}
private void log(List<String> logs, String message, Throwable t) {
@@ -162,4 +163,33 @@ public class JunitRunner extends AbstractComponent {
public void deconstruct() {
super.deconstruct();
}
+
+ public LegacyTestRunner.Status getStatus() {
+ if (execution == null) return LegacyTestRunner.Status.NOT_STARTED;
+ if (!execution.isDone()) return LegacyTestRunner.Status.RUNNING;
+ try {
+ TestReport report = execution.get();
+ if (report.isSuccess()) {
+ return LegacyTestRunner.Status.SUCCESS;
+ } else {
+ return LegacyTestRunner.Status.FAILURE;
+ }
+ } catch (InterruptedException|ExecutionException e) {
+ logger.log(Level.WARNING, "Error while getting test report", e);
+ return LegacyTestRunner.Status.ERROR;
+ }
+ }
+
+ public String getReportAsJson() {
+ if (execution.isDone()) {
+ try {
+ return execution.get().toJson();
+ } catch (Exception e) {
+ logger.log(Level.WARNING, "Error getting test report", e);
+ return "";
+ }
+ } else {
+ return "";
+ }
+ }
}