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

[WIP] Integrate integration tests with Gradle test API #931

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import org.gradle.internal.os.OperatingSystem
import java.util.regex.*

plugins {
id 'com.gradle.build-scan' version '1.8'
id 'com.gradle.build-scan' version '2.4.2'
}

buildScan {
Expand Down
33 changes: 5 additions & 28 deletions buildSrc/src/main/groovy/eclipsebuild/TestBundlePlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,13 @@

package eclipsebuild

import org.gradle.api.Task
import eclipsebuild.testing.EclipseTestTask

import javax.inject.Inject

import eclipsebuild.testing.EclipseTestExecuter
import eclipsebuild.testing.EclipseTestExtension
import eclipsebuild.testing.EclipseTestTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.internal.file.FileResolver
import org.gradle.api.tasks.testing.Test
import org.gradle.internal.operations.BuildOperationExecutor

/**
* Gradle plug-in to build Eclipse test bundles and launch tests.
Expand Down Expand Up @@ -54,30 +48,18 @@ import org.gradle.internal.operations.BuildOperationExecutor
*/
class TestBundlePlugin implements Plugin<Project> {

// name of the root node in the DSL
static String DSL_EXTENSION_NAME = "eclipseTest"

// task names
static final TASK_NAME_ECLIPSE_TEST = 'eclipseTest'

static final TASK_NAME_CROSS_VERSION_ECLIPSE_TEST = 'crossVersionEclipseTest'

public final FileResolver fileResolver

@Inject
public TestBundlePlugin(FileResolver fileResolver) {
this.fileResolver = fileResolver
}

@Override
public void apply(Project project) {
configureProject(project)
validateDslBeforeBuildStarts(project)
addTaskCreateEclipseTest(project)
}

static void configureProject(Project project) {
project.extensions.create(DSL_EXTENSION_NAME, EclipseTestExtension)
project.getPlugins().apply(eclipsebuild.BundlePlugin)

// append the sources of each first-level dependency and its transitive dependencies of
Expand All @@ -96,13 +78,6 @@ class TestBundlePlugin implements Plugin<Project> {
dep.children.each { childDep -> addSourcesRecursively(project, childDep) }
}

static void validateDslBeforeBuildStarts(Project project) {
project.gradle.taskGraph.whenReady {
// the eclipse application must be defined
assert project.eclipseTest.applicationName != null
}
}

static void addTaskCreateEclipseTest(Project project) {
Config config = Config.on(project)

Expand All @@ -120,7 +95,6 @@ class TestBundlePlugin implements Plugin<Project> {
description = taskDescription

// configure the test runner to execute all classes from the project
testExecuter = new EclipseTestExecuter(project, config, services.get(BuildOperationExecutor.class))
testClassesDirs = project.sourceSets.main.output.classesDirs
classpath = project.sourceSets.main.output + project.sourceSets.test.output
reports.html.destination = new File("${project.reporting.baseDir}/eclipseTest")
Expand All @@ -146,6 +120,9 @@ class TestBundlePlugin implements Plugin<Project> {
}
}

maxParallelForks = 1
forkEvery = 0

doFirst { beforeEclipseTest(project, config, testDistributionDir, additionalPluginsDir) }
}

Expand Down

This file was deleted.

152 changes: 152 additions & 0 deletions buildSrc/src/main/groovy/eclipsebuild/testing/EclipseTestAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Copyright (c) 2015 the original author or authors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Donát Csikós (Gradle Inc.) - initial API and implementation and initial documentation
*/

package eclipsebuild.testing;

import org.eclipse.jdt.internal.junit.model.ITestRunListener2;
import org.gradle.api.internal.tasks.testing.DefaultTestClassDescriptor;
import org.gradle.api.internal.tasks.testing.DefaultTestDescriptor;
import org.gradle.api.internal.tasks.testing.DefaultTestMethodDescriptor;
import org.gradle.api.internal.tasks.testing.DefaultTestOutputEvent;
import org.gradle.api.internal.tasks.testing.DefaultTestSuiteDescriptor;
import org.gradle.api.internal.tasks.testing.TestCompleteEvent;
import org.gradle.api.internal.tasks.testing.TestDescriptorInternal;
import org.gradle.api.internal.tasks.testing.TestResultProcessor;
import org.gradle.api.internal.tasks.testing.TestStartEvent;
import org.gradle.api.internal.tasks.testing.results.AttachParentTestResultProcessor;
import org.gradle.api.tasks.testing.TestOutputEvent;
import org.gradle.api.tasks.testing.TestResult;
import org.gradle.api.tasks.testing.TestResult.ResultType;
import org.gradle.internal.id.IdGenerator;
import org.gradle.internal.time.Clock;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class EclipseTestAdapter implements ITestRunListener2 {

private final TestResultProcessor resultProcessor;
private final Clock clock;
private final IdGenerator<?> idGenerator;
private final Object lock = new Object();
private final Map<String, TestDescriptorInternal> executing = new HashMap<String, TestDescriptorInternal>();


public EclipseTestAdapter(TestResultProcessor resultProcessor, Clock clock, IdGenerator<?> idGenerator) {
this.resultProcessor = resultProcessor;
this.clock = clock;
this.idGenerator = idGenerator;
}

@Override
public synchronized void testStarted(String testId, String testName) {
TestDescriptorInternal descriptor = nullSafeDescriptor(idGenerator.generateId(), testName);
synchronized (lock) {
TestDescriptorInternal oldTest = executing.put(testId, descriptor);
assert oldTest == null : String.format("Unexpected start event for %s", testName);
}
resultProcessor.started(descriptor, startEvent());
}

@Override
public synchronized void testEnded(String testId, String testName) {
long endTime = clock.getCurrentTime();
TestDescriptorInternal testInternal;
ResultType resultType = ResultType.SUCCESS;
synchronized (lock) {
testInternal = executing.remove(testId);
if (testInternal == null && executing.size() == 1) {
// Assume that test has renamed itself (this can actually happen)
testInternal = executing.values().iterator().next();
executing.clear();
}
assert testInternal != null : String.format("Unexpected end event for %s", testName);
resultType = null;
}
resultProcessor.completed(testInternal.getId(), new TestCompleteEvent(endTime, resultType));
}

@Override
public synchronized void testFailed(int status, String testId, String testName, String trace, String expected, String actual) {
TestDescriptorInternal descriptor = nullSafeDescriptor(idGenerator.generateId(), testName);
TestDescriptorInternal testInternal;
synchronized (lock) {
testInternal = executing.get(testId);
}
boolean needEndEvent = false;
if (testInternal == null) {
// This can happen when, for example, a @BeforeClass or @AfterClass method fails
needEndEvent = true;
testInternal = descriptor;
resultProcessor.started(testInternal, startEvent());
}
String message = testName + " failed";
if (expected != null || actual != null) {
message += " (expected=" + expected + ", actual=" + actual + ")";
}
resultProcessor.failure(testInternal.getId(), new EclipseTestFailure(message, trace));
if (needEndEvent) {
resultProcessor.completed(testInternal.getId(), new TestCompleteEvent(clock.getCurrentTime()));
}
}

@Override
public synchronized void testRunStarted(int testCount) {
}

@Override
public synchronized void testRunEnded(long elapsedTime) {
}

@Override
public synchronized void testRunStopped(long elapsedTime) {
}

@Override
public synchronized void testRunTerminated() {
}

@Override
public synchronized void testReran(String testId, String testClass, String testName, int status, String trace, String expected, String actual) {
}

@Override
public synchronized void testTreeEntry(String description) {
}

private TestDescriptorInternal nullSafeDescriptor(Object id, String testName) {
String methodName = methodName(testName);
if (methodName != null) {
return new DefaultTestDescriptor(id, className(testName), methodName);
} else {
return new DefaultTestDescriptor(id, className(testName), "classMethod");
}
}

private static String className(String testName) {
return testName.substring(testName.lastIndexOf('(') + 1, testName.length() - 1);
}

private static String methodName(String testName) {
return testName.substring(0, testName.lastIndexOf('('));
}

private TestStartEvent startEvent() {
return new TestStartEvent(clock.getCurrentTime());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package eclipsebuild.testing;

import org.gradle.api.internal.tasks.testing.detection.TestClassVisitor;

class EclipseTestClassDetector extends TestClassVisitor {

EclipseTestClassDetector(final EclipseTestFrameworkDetector detector) {
super(detector);
}

@Override
protected boolean ignoreNonStaticInnerClass() {
return true;
}
}
Loading