JUnit testing support Bug fixes and Enhancements - Step 1 (#4303)
Provide JUnit test real-time output in a `Tests` output view6.19.x
parent
85d3578900
commit
440f92d3bb
|
|
@ -10,6 +10,17 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.java.server.rest;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.eclipse.che.dto.server.DtoFactory;
|
||||
import org.eclipse.che.ide.ext.java.shared.dto.classpath.ClasspathEntryDto;
|
||||
import org.eclipse.jdt.core.IClasspathEntry;
|
||||
|
|
@ -19,35 +30,24 @@ import org.eclipse.jdt.core.JavaModelException;
|
|||
import org.eclipse.jdt.internal.core.JavaModel;
|
||||
import org.eclipse.jdt.internal.core.JavaModelManager;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
/**
|
||||
* Service for getting information about classpath.
|
||||
*
|
||||
* @author Valeriy Svydenko
|
||||
*/
|
||||
@Path("java/classpath/")
|
||||
public class ClasspathService {
|
||||
public class ClasspathService implements ClasspathServiceInterface {
|
||||
|
||||
private static final JavaModel model = JavaModelManager.getJavaModelManager().getJavaModel();
|
||||
|
||||
/**
|
||||
* Returns information about classpath.
|
||||
*
|
||||
* @param projectPath
|
||||
* path to the current project
|
||||
* @param projectPath path to the current project
|
||||
* @return list of classpath entries
|
||||
* @throws JavaModelException
|
||||
* when JavaModel has a failure
|
||||
* @throws JavaModelException when JavaModel has a failure
|
||||
*/
|
||||
@Override
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<ClasspathEntryDto> getClasspath(@QueryParam("projectpath") String projectPath) throws JavaModelException {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 Codenvy, S.A.
|
||||
* 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:
|
||||
* Codenvy, S.A. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.java.server.rest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.che.ide.ext.java.shared.dto.classpath.ClasspathEntryDto;
|
||||
import org.eclipse.jdt.core.JavaModelException;
|
||||
|
||||
import com.google.inject.ImplementedBy;
|
||||
|
||||
|
||||
/**
|
||||
* Interface for the service which gets information about classpath.
|
||||
*
|
||||
* @author Valeriy Svydenko
|
||||
*/
|
||||
@ImplementedBy(ClasspathService.class)
|
||||
public interface ClasspathServiceInterface {
|
||||
List<ClasspathEntryDto> getClasspath(String projectPath) throws JavaModelException;
|
||||
}
|
||||
|
|
@ -30,16 +30,85 @@
|
|||
<artifactId>guice-multibindings</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-core</artifactId>
|
||||
<groupId>org.eclipse.birt.runtime</groupId>
|
||||
<artifactId>org.eclipse.equinox.common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-commons-inject</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.lib</groupId>
|
||||
<artifactId>org-eclipse-jdt-core-repack</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>org.eclipse.jdt.core</artifactId>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-java-ext-lang-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-java-ext-lang-shared</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-testing-classpath-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>org.eclipse.core.resources</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<sourceDirectory>src/main/java</sourceDirectory>
|
||||
<testSourceDirectory>src/test/java</testSourceDirectory>
|
||||
<outputDirectory>target/classes</outputDirectory>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>src/test/resources</directory>
|
||||
</testResource>
|
||||
</testResources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/**/MavenTestClasspathProviderTest.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.surefire</groupId>
|
||||
<artifactId>surefire-junit47</artifactId>
|
||||
<version>${version.surefire.plugin}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -10,43 +10,50 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.testing.classpath.maven.server;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.che.api.core.util.CommandLine;
|
||||
import org.eclipse.che.api.core.util.LineConsumer;
|
||||
import org.eclipse.che.api.core.util.ProcessUtil;
|
||||
import org.eclipse.che.ide.ext.java.shared.dto.classpath.ClasspathEntryDto;
|
||||
import org.eclipse.che.plugin.java.server.rest.ClasspathServiceInterface;
|
||||
import org.eclipse.che.plugin.testing.classpath.server.TestClasspathProvider;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.IWorkspaceRoot;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
import org.eclipse.jdt.core.IClasspathEntry;
|
||||
import org.eclipse.jdt.core.JavaModelException;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* Maven implementation for the test classpath provider.
|
||||
*
|
||||
* @author Mirage Abeysekara
|
||||
* @author David Festal
|
||||
*/
|
||||
public class MavenTestClasspathProvider implements TestClasspathProvider {
|
||||
private ClasspathServiceInterface classpathService;
|
||||
|
||||
@Inject
|
||||
public MavenTestClasspathProvider(ClasspathServiceInterface classpathService) {
|
||||
this.classpathService = classpathService;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public ClassLoader getClassLoader(String projectPath, boolean updateClasspath) throws Exception {
|
||||
List<URL> classUrls;
|
||||
public ClassLoader getClassLoader(String projectAbsolutePath, String projectRelativePath, boolean updateClasspath) throws Exception {
|
||||
try {
|
||||
if (updateClasspath) {
|
||||
buildClasspath(projectPath);
|
||||
}
|
||||
classUrls = getProjectClasspath(projectPath);
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new Exception("Failed to build Maven classpath.", e);
|
||||
return new URLClassLoader(getProjectClasspath(projectAbsolutePath, projectRelativePath, getWorkspaceRoot()), null);
|
||||
} catch (JavaModelException e) {
|
||||
throw new Exception("Failed to build the classpath for testing project: " + projectRelativePath, e);
|
||||
}
|
||||
return new URLClassLoader(classUrls.toArray(new URL[classUrls.size()]), null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -57,35 +64,57 @@ public class MavenTestClasspathProvider implements TestClasspathProvider {
|
|||
return "maven";
|
||||
}
|
||||
|
||||
private boolean buildClasspath(String projectPath) throws IOException, InterruptedException {
|
||||
final CommandLine commandLineClassPath = new CommandLine("mvn", "clean", "dependency:build-classpath",
|
||||
"-Dmdep.outputFile=target/test.classpath.maven");
|
||||
Process processBuildClassPath = new ProcessBuilder().redirectErrorStream(true).directory(new File(projectPath))
|
||||
.command(commandLineClassPath.toShellCommand()).start();
|
||||
ProcessUtil.process(processBuildClassPath, LineConsumer.DEV_NULL, LineConsumer.DEV_NULL);
|
||||
processBuildClassPath.waitFor();
|
||||
final CommandLine commandLineTestCompile = new CommandLine("mvn", "test-compile");
|
||||
Process processTestCompile = new ProcessBuilder().redirectErrorStream(true).directory(new File(projectPath))
|
||||
.command(commandLineTestCompile.toShellCommand()).start();
|
||||
ProcessUtil.process(processTestCompile, LineConsumer.DEV_NULL, LineConsumer.DEV_NULL);
|
||||
return processTestCompile.waitFor() == 0;
|
||||
|
||||
private Stream<ClasspathEntryDto> toResolvedClassPath(Stream<ClasspathEntryDto> rawClasspath) {
|
||||
return rawClasspath.flatMap(dto -> {
|
||||
if (dto.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
|
||||
return toResolvedClassPath(dto.getExpandedEntries().stream());
|
||||
} else {
|
||||
return Stream.of(dto);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<URL> getProjectClasspath(String projectPath) throws IOException {
|
||||
List<URL> classUrls = new ArrayList<>();
|
||||
File cpFile = Paths.get(projectPath, "target", "test.classpath.maven").toFile();
|
||||
FileReader fileReader = new FileReader(cpFile);
|
||||
BufferedReader bufferedReader = new BufferedReader(fileReader);
|
||||
String line = bufferedReader.readLine();
|
||||
String[] paths = line.split(":");
|
||||
for (String path : paths) {
|
||||
classUrls.add(new File(path).toURI().toURL());
|
||||
}
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
classUrls.add(Paths.get(projectPath, "target", "classes").toUri().toURL());
|
||||
classUrls.add(Paths.get(projectPath, "target", "test-classes").toUri().toURL());
|
||||
return classUrls;
|
||||
private IWorkspaceRoot getWorkspaceRoot() {
|
||||
return ResourcesPlugin.getWorkspace().getRoot();
|
||||
}
|
||||
|
||||
public URL[] getProjectClasspath(String projectAbsolutePath, String projectRelativePath, IWorkspaceRoot root) throws JavaModelException {
|
||||
Stream<ClasspathEntryDto> rawClasspath = classpathService.getClasspath(projectRelativePath).stream();
|
||||
Stream<ClasspathEntryDto> resolvedClasspath = toResolvedClassPath(rawClasspath);
|
||||
return resolvedClasspath.map(dto -> {
|
||||
try {
|
||||
String dtoPath = dto.getPath();
|
||||
IResource res = root.findMember(new Path(dtoPath));
|
||||
File path;
|
||||
switch (dto.getEntryKind()) {
|
||||
case IClasspathEntry.CPE_LIBRARY:
|
||||
if (res == null) {
|
||||
path = new File(dtoPath);
|
||||
} else {
|
||||
path = res.getLocation().toFile();
|
||||
}
|
||||
break;
|
||||
case IClasspathEntry.CPE_SOURCE:
|
||||
IPath relativePathFromProjectRoot = new Path(dtoPath).removeFirstSegments(1);
|
||||
String relativePathFromProjectRootStr = relativePathFromProjectRoot.toString();
|
||||
switch (relativePathFromProjectRootStr) {
|
||||
case "src/main/java":
|
||||
path = Paths.get(projectAbsolutePath, "target", "classes").toFile();
|
||||
break;
|
||||
case "src/test/java":
|
||||
path = Paths.get(projectAbsolutePath, "target", "test-classes").toFile();
|
||||
break;
|
||||
default:
|
||||
path = Paths.get(projectAbsolutePath, "target", "classes").toFile();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
path = new File(dtoPath);
|
||||
}
|
||||
return path.toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
return null;
|
||||
}
|
||||
}).filter(url -> url != null).distinct().toArray(URL[]::new);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,154 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 RedHat, Inc
|
||||
* 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:
|
||||
* RedHat, Inc - initial test implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.testing.classpath.maven.server;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.che.dto.server.DtoFactory;
|
||||
import org.eclipse.che.ide.ext.java.shared.dto.classpath.ClasspathEntryDto;
|
||||
import org.eclipse.che.plugin.java.server.rest.ClasspathServiceInterface;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.IWorkspaceRoot;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
import org.eclipse.jdt.core.IClasspathEntry;
|
||||
import org.eclipse.jdt.core.JavaModelException;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
/**
|
||||
* Tests for the Maven implementation for the test classpath provider.
|
||||
*
|
||||
* @author David Festal
|
||||
*/
|
||||
public class MavenTestClasspathProviderTest {
|
||||
@Mock
|
||||
private ClasspathServiceInterface classpathService;
|
||||
@Mock
|
||||
private IWorkspaceRoot workspaceRoot;
|
||||
|
||||
private MavenTestClasspathProvider classpathProvider;
|
||||
|
||||
private static DtoFactory dtoFactory = DtoFactory.getInstance();
|
||||
|
||||
@Before
|
||||
public void initMocks() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
classpathProvider = new MavenTestClasspathProvider(classpathService);
|
||||
}
|
||||
|
||||
public static class ClasspathEntry {
|
||||
String fullPath;
|
||||
boolean external;
|
||||
int kind;
|
||||
List<ClasspathEntry> resolvedEntries;
|
||||
String fileSystemPath;
|
||||
|
||||
public ClasspathEntryDto dto() {
|
||||
return dtoFactory.createDto(ClasspathEntryDto.class)
|
||||
.withEntryKind(kind)
|
||||
.withPath(fullPath)
|
||||
.withExpandedEntries(resolvedEntries.stream().map(ClasspathEntry::dto).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
private ClasspathEntry externalLib(String fullPath) {
|
||||
ClasspathEntry cp = new ClasspathEntry();
|
||||
cp.external = true;
|
||||
cp.fullPath = fullPath;
|
||||
cp.fileSystemPath = fullPath;
|
||||
cp.kind = IClasspathEntry.CPE_LIBRARY;
|
||||
cp.resolvedEntries = Collections.emptyList();
|
||||
return cp;
|
||||
}
|
||||
|
||||
private ClasspathEntry internalLib(String fullPath, String fileSystemPath) {
|
||||
ClasspathEntry cp = new ClasspathEntry();
|
||||
cp.external = false;
|
||||
cp.fullPath = fullPath;
|
||||
cp.fileSystemPath = fileSystemPath;
|
||||
cp.kind = IClasspathEntry.CPE_LIBRARY;
|
||||
cp.resolvedEntries = Collections.emptyList();
|
||||
return cp;
|
||||
}
|
||||
|
||||
private ClasspathEntry source(String fullPath) {
|
||||
ClasspathEntry cp = new ClasspathEntry();
|
||||
cp.external = false;
|
||||
cp.fullPath = fullPath;
|
||||
cp.fileSystemPath = null;
|
||||
cp.kind = IClasspathEntry.CPE_SOURCE;
|
||||
cp.resolvedEntries = Collections.emptyList();
|
||||
return cp;
|
||||
}
|
||||
|
||||
private ClasspathEntry container(String containerPath, List<ClasspathEntry> resolvedEntries) {
|
||||
ClasspathEntry cp = new ClasspathEntry();
|
||||
cp.external = false;
|
||||
cp.fullPath = null;
|
||||
cp.fileSystemPath = null;
|
||||
cp.kind = IClasspathEntry.CPE_CONTAINER;
|
||||
cp.resolvedEntries = resolvedEntries;
|
||||
return cp;
|
||||
}
|
||||
|
||||
private void buildMocks(List<ClasspathEntry> entries) throws JavaModelException {
|
||||
when(classpathService.getClasspath(anyString()))
|
||||
.thenReturn(entries.stream().map(ClasspathEntry::dto).collect(Collectors.toList()));
|
||||
|
||||
for (ClasspathEntry entry : entries) {
|
||||
if (!entry.external && entry.kind == IClasspathEntry.CPE_LIBRARY) {
|
||||
IPath resourceLocation = new Path(entry.fileSystemPath);
|
||||
IResource result = mock(IResource.class);
|
||||
when(result.getLocation())
|
||||
.thenReturn(resourceLocation);
|
||||
|
||||
when(workspaceRoot.findMember(new Path(entry.fullPath)))
|
||||
.thenReturn(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypicalMavenProjectClasspath() throws JavaModelException, MalformedURLException {
|
||||
List<ClasspathEntry> entries =
|
||||
asList(
|
||||
externalLib("/home/user/.m2/repository/com/google/guava/guava/20.0/guava-20.0.jar"),
|
||||
internalLib("exampleProject/lib/internal.jar", "/some/fileSystemPath/internal.jar"),
|
||||
container("org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER",
|
||||
asList(externalLib("/home/user/.m2/repository/com/google/collections/google-collections/1.0/google-collections-1.0.jar"),
|
||||
externalLib("/home/user/.m2/repository/com/google/gwt/gwt-servlet/2.8.0/gwt-servlet-2.8.0.jar"))),
|
||||
source("exampleProject/src/main/java"),
|
||||
source("exampleProject/src/test/java"));
|
||||
buildMocks(entries);
|
||||
URL[] classpath = classpathProvider.getProjectClasspath("/projects/exampleProject", "exampleProject", workspaceRoot);
|
||||
assertArrayEquals(new URL[]{
|
||||
new URL("file:/home/user/.m2/repository/com/google/guava/guava/20.0/guava-20.0.jar"),
|
||||
new URL("file:/some/fileSystemPath/internal.jar"),
|
||||
new URL("file:/home/user/.m2/repository/com/google/collections/google-collections/1.0/google-collections-1.0.jar"),
|
||||
new URL("file:/home/user/.m2/repository/com/google/gwt/gwt-servlet/2.8.0/gwt-servlet-2.8.0.jar"),
|
||||
new URL("file:/projects/exampleProject/target/classes"),
|
||||
new URL("file:/projects/exampleProject/target/test-classes")
|
||||
}, classpath);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,8 +22,10 @@ public interface TestClasspathProvider {
|
|||
/**
|
||||
* Returns the project class loader for executing test cases.
|
||||
*
|
||||
* @param projectPath
|
||||
* absolute path for the project location.
|
||||
* @param projectAbsolutePath
|
||||
* absolute path for the project location on the disk.
|
||||
* @param projectRelativePath
|
||||
* path for the project relative to the workspace.
|
||||
* @param updateClasspath
|
||||
* calculate the classpath if true. otherwise return existing
|
||||
* class loader.
|
||||
|
|
@ -31,7 +33,7 @@ public interface TestClasspathProvider {
|
|||
* @throws Exception
|
||||
* when classloader creation failed.
|
||||
*/
|
||||
ClassLoader getClassLoader(String projectPath, boolean updateClasspath) throws Exception;
|
||||
ClassLoader getClassLoader(String projectAbsolutePath, String projectRelativePath, boolean updateClasspath) throws Exception;
|
||||
|
||||
/**
|
||||
* String representation of the project type.
|
||||
|
|
|
|||
|
|
@ -10,25 +10,14 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.testing.junit.ide.action;
|
||||
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE;
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PROGRESS;
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.che.api.promises.client.Operation;
|
||||
import org.eclipse.che.api.promises.client.OperationException;
|
||||
import org.eclipse.che.api.promises.client.Promise;
|
||||
import org.eclipse.che.api.promises.client.PromiseError;
|
||||
import org.eclipse.che.api.testing.shared.TestResult;
|
||||
import org.eclipse.che.ide.api.action.ActionEvent;
|
||||
import org.eclipse.che.ide.api.app.AppContext;
|
||||
import org.eclipse.che.ide.api.editor.EditorAgent;
|
||||
import org.eclipse.che.ide.api.filetypes.FileTypeRegistry;
|
||||
import org.eclipse.che.ide.api.notification.NotificationManager;
|
||||
import org.eclipse.che.ide.api.notification.StatusNotification;
|
||||
import org.eclipse.che.ide.api.resources.Project;
|
||||
import org.eclipse.che.ide.ext.java.client.action.JavaEditorAction;
|
||||
import org.eclipse.che.plugin.testing.ide.TestServiceClient;
|
||||
import org.eclipse.che.plugin.testing.ide.view.TestResultPresenter;
|
||||
|
|
@ -38,14 +27,16 @@ import org.eclipse.che.plugin.testing.junit.ide.JUnitTestResources;
|
|||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Mirage Abeysekara
|
||||
* @author David Festal
|
||||
*/
|
||||
public class RunAllTestAction extends JavaEditorAction {
|
||||
public class RunAllTestAction extends JavaEditorAction
|
||||
implements RunTestActionDelegate.Source {
|
||||
|
||||
private final NotificationManager notificationManager;
|
||||
private TestResultPresenter presenter;
|
||||
private final TestServiceClient service;
|
||||
private final NotificationManager notificationManager;
|
||||
private final TestResultPresenter presenter;
|
||||
private final TestServiceClient service;
|
||||
private final RunTestActionDelegate delegate;
|
||||
|
||||
@Inject
|
||||
public RunAllTestAction(JUnitTestResources resources,
|
||||
|
|
@ -56,43 +47,37 @@ public class RunAllTestAction extends JavaEditorAction {
|
|||
TestServiceClient service,
|
||||
JUnitTestLocalizationConstant localization) {
|
||||
super(localization.actionRunAllTitle(), localization.actionRunAllDescription(), resources.testAllIcon(),
|
||||
editorAgent, fileTypeRegistry);
|
||||
editorAgent, fileTypeRegistry);
|
||||
this.notificationManager = notificationManager;
|
||||
this.editorAgent = editorAgent;
|
||||
this.presenter = presenter;
|
||||
this.service = service;
|
||||
this.delegate = new RunTestActionDelegate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
final StatusNotification notification = new StatusNotification("Running Tests...", PROGRESS, FLOAT_MODE);
|
||||
notificationManager.notify(notification);
|
||||
final Project project = appContext.getRootProject();
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
parameters.put("updateClasspath", "true");
|
||||
Promise<TestResult> testResultPromise = service.getTestResult(project.getPath(), "junit", parameters);
|
||||
testResultPromise.then(new Operation<TestResult>() {
|
||||
@Override
|
||||
public void apply(TestResult result) throws OperationException {
|
||||
notification.setStatus(SUCCESS);
|
||||
if (result.isSuccess()) {
|
||||
notification.setTitle("Test runner executed successfully");
|
||||
notification.setContent("All tests are passed");
|
||||
} else {
|
||||
notification.setTitle("Test runner executed successfully with test failures.");
|
||||
notification.setContent(result.getFailureCount() + " test(s) failed.\n");
|
||||
}
|
||||
presenter.handleResponse(result);
|
||||
}
|
||||
}).catchError(new Operation<PromiseError>() {
|
||||
@Override
|
||||
public void apply(PromiseError exception) throws OperationException {
|
||||
final String errorMessage = (exception.getMessage() != null) ? exception.getMessage()
|
||||
: "Failed to run test cases";
|
||||
notification.setContent(errorMessage);
|
||||
notification.setStatus(FAIL);
|
||||
}
|
||||
});
|
||||
delegate.doRunTests(e, parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationManager getNotificationManager() {
|
||||
return notificationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppContext getAppContext() {
|
||||
return appContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestServiceClient getService() {
|
||||
return service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestResultPresenter getPresenter() {
|
||||
return presenter;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,10 +10,6 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.testing.junit.ide.action;
|
||||
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE;
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PROGRESS;
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS;
|
||||
import static org.eclipse.che.ide.workspace.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
|
@ -22,17 +18,10 @@ import java.util.Map;
|
|||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.che.api.promises.client.Operation;
|
||||
import org.eclipse.che.api.promises.client.OperationException;
|
||||
import org.eclipse.che.api.promises.client.Promise;
|
||||
import org.eclipse.che.api.promises.client.PromiseError;
|
||||
import org.eclipse.che.api.testing.shared.TestResult;
|
||||
import org.eclipse.che.ide.api.action.AbstractPerspectiveAction;
|
||||
import org.eclipse.che.ide.api.action.ActionEvent;
|
||||
import org.eclipse.che.ide.api.app.AppContext;
|
||||
import org.eclipse.che.ide.api.notification.NotificationManager;
|
||||
import org.eclipse.che.ide.api.notification.StatusNotification;
|
||||
import org.eclipse.che.ide.api.resources.Project;
|
||||
import org.eclipse.che.ide.api.resources.VirtualFile;
|
||||
import org.eclipse.che.ide.api.selection.Selection;
|
||||
import org.eclipse.che.ide.api.selection.SelectionAgent;
|
||||
|
|
@ -46,16 +35,18 @@ import org.eclipse.che.plugin.testing.junit.ide.JUnitTestResources;
|
|||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Mirage Abeysekara
|
||||
* @author David Festal
|
||||
*/
|
||||
public class RunClassContextTestAction extends AbstractPerspectiveAction {
|
||||
public class RunClassContextTestAction extends AbstractPerspectiveAction
|
||||
implements RunTestActionDelegate.Source {
|
||||
|
||||
private final NotificationManager notificationManager;
|
||||
private final TestResultPresenter presenter;
|
||||
private final TestServiceClient service;
|
||||
private final AppContext appContext;
|
||||
private final SelectionAgent selectionAgent;
|
||||
private final NotificationManager notificationManager;
|
||||
private final TestResultPresenter presenter;
|
||||
private final TestServiceClient service;
|
||||
private final AppContext appContext;
|
||||
private final SelectionAgent selectionAgent;
|
||||
private final RunTestActionDelegate delegate;
|
||||
|
||||
@Inject
|
||||
public RunClassContextTestAction(JUnitTestResources resources,
|
||||
|
|
@ -66,51 +57,26 @@ public class RunClassContextTestAction extends AbstractPerspectiveAction {
|
|||
SelectionAgent selectionAgent,
|
||||
JUnitTestLocalizationConstant localization) {
|
||||
super(Arrays.asList(PROJECT_PERSPECTIVE_ID), localization.actionRunClassContextTitle(),
|
||||
localization.actionRunClassContextDescription(), null, resources.testIcon());
|
||||
localization.actionRunClassContextDescription(), null, resources.testIcon());
|
||||
this.notificationManager = notificationManager;
|
||||
this.presenter = presenter;
|
||||
this.service = service;
|
||||
this.appContext = appContext;
|
||||
this.selectionAgent = selectionAgent;
|
||||
this.delegate = new RunTestActionDelegate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
final StatusNotification notification = new StatusNotification("Running Tests...", PROGRESS, FLOAT_MODE);
|
||||
notificationManager.notify(notification);
|
||||
final Selection<?> selection = selectionAgent.getSelection();
|
||||
final Selection< ? > selection = selectionAgent.getSelection();
|
||||
final Object possibleNode = selection.getHeadElement();
|
||||
if (possibleNode instanceof FileNode) {
|
||||
VirtualFile file = ((FileNode) possibleNode).getData();
|
||||
final Project project = appContext.getRootProject();
|
||||
VirtualFile file = ((FileNode)possibleNode).getData();
|
||||
String fqn = JavaUtil.resolveFQN(file);
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
parameters.put("fqn", fqn);
|
||||
parameters.put("runClass", "true");
|
||||
parameters.put("updateClasspath", "true");
|
||||
Promise<TestResult> testResultPromise = service.getTestResult(project.getPath(), "junit", parameters);
|
||||
testResultPromise.then(new Operation<TestResult>() {
|
||||
@Override
|
||||
public void apply(TestResult result) throws OperationException {
|
||||
notification.setStatus(SUCCESS);
|
||||
if (result.isSuccess()) {
|
||||
notification.setTitle("Test runner executed successfully");
|
||||
notification.setContent("All tests are passed");
|
||||
} else {
|
||||
notification.setTitle("Test runner executed successfully with test failures.");
|
||||
notification.setContent(result.getFailureCount() + " test(s) failed.\n");
|
||||
}
|
||||
presenter.handleResponse(result);
|
||||
}
|
||||
}).catchError(new Operation<PromiseError>() {
|
||||
@Override
|
||||
public void apply(PromiseError exception) throws OperationException {
|
||||
final String errorMessage = (exception.getMessage() != null) ? exception.getMessage()
|
||||
: "Failed to run test cases";
|
||||
notification.setContent(errorMessage);
|
||||
notification.setStatus(FAIL);
|
||||
}
|
||||
});
|
||||
delegate.doRunTests(e, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -121,7 +87,7 @@ public class RunClassContextTestAction extends AbstractPerspectiveAction {
|
|||
e.getPresentation().setEnabled(false);
|
||||
return;
|
||||
}
|
||||
final Selection<?> selection = selectionAgent.getSelection();
|
||||
final Selection< ? > selection = selectionAgent.getSelection();
|
||||
if (selection == null || selection.isEmpty()) {
|
||||
e.getPresentation().setEnabled(false);
|
||||
return;
|
||||
|
|
@ -132,7 +98,27 @@ public class RunClassContextTestAction extends AbstractPerspectiveAction {
|
|||
}
|
||||
final Object possibleNode = selection.getHeadElement();
|
||||
boolean enable = possibleNode instanceof FileNode
|
||||
&& "java".equals(((FileNode) possibleNode).getData().getExtension());
|
||||
&& "java".equals(((FileNode)possibleNode).getData().getExtension());
|
||||
e.getPresentation().setEnabled(enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationManager getNotificationManager() {
|
||||
return notificationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppContext getAppContext() {
|
||||
return appContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestServiceClient getService() {
|
||||
return service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestResultPresenter getPresenter() {
|
||||
return presenter;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,26 +10,15 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.testing.junit.ide.action;
|
||||
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE;
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PROGRESS;
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.che.api.promises.client.Operation;
|
||||
import org.eclipse.che.api.promises.client.OperationException;
|
||||
import org.eclipse.che.api.promises.client.Promise;
|
||||
import org.eclipse.che.api.promises.client.PromiseError;
|
||||
import org.eclipse.che.api.testing.shared.TestResult;
|
||||
import org.eclipse.che.ide.api.action.ActionEvent;
|
||||
import org.eclipse.che.ide.api.app.AppContext;
|
||||
import org.eclipse.che.ide.api.editor.EditorAgent;
|
||||
import org.eclipse.che.ide.api.editor.EditorPartPresenter;
|
||||
import org.eclipse.che.ide.api.filetypes.FileTypeRegistry;
|
||||
import org.eclipse.che.ide.api.notification.NotificationManager;
|
||||
import org.eclipse.che.ide.api.notification.StatusNotification;
|
||||
import org.eclipse.che.ide.api.resources.Project;
|
||||
import org.eclipse.che.ide.api.resources.VirtualFile;
|
||||
import org.eclipse.che.ide.ext.java.client.action.JavaEditorAction;
|
||||
import org.eclipse.che.ide.ext.java.client.util.JavaUtil;
|
||||
|
|
@ -41,15 +30,17 @@ import org.eclipse.che.plugin.testing.junit.ide.JUnitTestResources;
|
|||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Mirage Abeysekara
|
||||
* @author David Festal
|
||||
*/
|
||||
public class RunClassTestAction extends JavaEditorAction {
|
||||
public class RunClassTestAction extends JavaEditorAction
|
||||
implements RunTestActionDelegate.Source {
|
||||
|
||||
private final NotificationManager notificationManager;
|
||||
private final EditorAgent editorAgent;
|
||||
private final TestResultPresenter presenter;
|
||||
private final TestServiceClient service;
|
||||
private final NotificationManager notificationManager;
|
||||
private final EditorAgent editorAgent;
|
||||
private final TestResultPresenter presenter;
|
||||
private final TestServiceClient service;
|
||||
private final RunTestActionDelegate delegate;
|
||||
|
||||
@Inject
|
||||
public RunClassTestAction(JUnitTestResources resources,
|
||||
|
|
@ -60,18 +51,16 @@ public class RunClassTestAction extends JavaEditorAction {
|
|||
TestServiceClient service,
|
||||
JUnitTestLocalizationConstant localization) {
|
||||
super(localization.actionRunClassTitle(), localization.actionRunClassDescription(), resources.testIcon(),
|
||||
editorAgent, fileTypeRegistry);
|
||||
editorAgent, fileTypeRegistry);
|
||||
this.notificationManager = notificationManager;
|
||||
this.editorAgent = editorAgent;
|
||||
this.presenter = presenter;
|
||||
this.service = service;
|
||||
this.delegate = new RunTestActionDelegate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
final StatusNotification notification = new StatusNotification("Running Tests...", PROGRESS, FLOAT_MODE);
|
||||
notificationManager.notify(notification);
|
||||
final Project project = appContext.getRootProject();
|
||||
EditorPartPresenter editorPart = editorAgent.getActiveEditor();
|
||||
final VirtualFile file = editorPart.getEditorInput().getFile();
|
||||
String fqn = JavaUtil.resolveFQN(file);
|
||||
|
|
@ -79,29 +68,7 @@ public class RunClassTestAction extends JavaEditorAction {
|
|||
parameters.put("fqn", fqn);
|
||||
parameters.put("runClass", "true");
|
||||
parameters.put("updateClasspath", "true");
|
||||
Promise<TestResult> testResultPromise = service.getTestResult(project.getPath(), "junit", parameters);
|
||||
testResultPromise.then(new Operation<TestResult>() {
|
||||
@Override
|
||||
public void apply(TestResult result) throws OperationException {
|
||||
notification.setStatus(SUCCESS);
|
||||
if (result.isSuccess()) {
|
||||
notification.setTitle("Test runner executed successfully");
|
||||
notification.setContent("All tests are passed");
|
||||
} else {
|
||||
notification.setTitle("Test runner executed successfully with test failures.");
|
||||
notification.setContent(result.getFailureCount() + " test(s) failed.\n");
|
||||
}
|
||||
presenter.handleResponse(result);
|
||||
}
|
||||
}).catchError(new Operation<PromiseError>() {
|
||||
@Override
|
||||
public void apply(PromiseError exception) throws OperationException {
|
||||
final String errorMessage = (exception.getMessage() != null) ? exception.getMessage()
|
||||
: "Failed to run test cases";
|
||||
notification.setContent(errorMessage);
|
||||
notification.setStatus(FAIL);
|
||||
}
|
||||
});
|
||||
delegate.doRunTests(e, parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -109,4 +76,24 @@ public class RunClassTestAction extends JavaEditorAction {
|
|||
super.updateProjectAction(e);
|
||||
e.getPresentation().setVisible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationManager getNotificationManager() {
|
||||
return notificationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppContext getAppContext() {
|
||||
return appContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestServiceClient getService() {
|
||||
return service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestResultPresenter getPresenter() {
|
||||
return presenter;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2017 Codenvy, S.A.
|
||||
* 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:
|
||||
* Codenvy, S.A. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.testing.junit.ide.action;
|
||||
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE;
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PROGRESS;
|
||||
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.che.api.promises.client.Operation;
|
||||
import org.eclipse.che.api.promises.client.OperationException;
|
||||
import org.eclipse.che.api.promises.client.Promise;
|
||||
import org.eclipse.che.api.promises.client.PromiseError;
|
||||
import org.eclipse.che.api.testing.shared.TestResult;
|
||||
import org.eclipse.che.ide.api.action.ActionEvent;
|
||||
import org.eclipse.che.ide.api.app.AppContext;
|
||||
import org.eclipse.che.ide.api.notification.NotificationManager;
|
||||
import org.eclipse.che.ide.api.notification.StatusNotification;
|
||||
import org.eclipse.che.ide.api.resources.Project;
|
||||
import org.eclipse.che.plugin.testing.ide.TestServiceClient;
|
||||
import org.eclipse.che.plugin.testing.ide.view.TestResultPresenter;
|
||||
|
||||
/**
|
||||
* @author Mirage Abeysekara
|
||||
* @author David Festal
|
||||
*/
|
||||
public class RunTestActionDelegate {
|
||||
private final Source source;
|
||||
|
||||
public interface Source {
|
||||
NotificationManager getNotificationManager();
|
||||
|
||||
AppContext getAppContext();
|
||||
|
||||
TestServiceClient getService();
|
||||
|
||||
TestResultPresenter getPresenter();
|
||||
}
|
||||
|
||||
public RunTestActionDelegate(Source source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public void doRunTests(ActionEvent e, Map<String, String> parameters) {
|
||||
final StatusNotification notification = new StatusNotification("Running Tests...", PROGRESS, FLOAT_MODE);
|
||||
source.getNotificationManager().notify(notification);
|
||||
final Project project = source.getAppContext().getRootProject();
|
||||
parameters.put("updateClasspath", "true");
|
||||
Promise<TestResult> testResultPromise = source.getService().getTestResult(project.getPath(), "junit", parameters, notification);
|
||||
testResultPromise.then(new Operation<TestResult>() {
|
||||
@Override
|
||||
public void apply(TestResult result) throws OperationException {
|
||||
notification.setStatus(SUCCESS);
|
||||
if (result.isSuccess()) {
|
||||
notification.setTitle("Test runner executed successfully");
|
||||
notification.setContent("All tests are passed");
|
||||
} else {
|
||||
notification.setTitle("Test runner executed successfully with test failures.");
|
||||
notification.setContent(result.getFailureCount() + " test(s) failed.\n");
|
||||
}
|
||||
source.getPresenter().handleResponse(result);
|
||||
}
|
||||
}).catchError(new Operation<PromiseError>() {
|
||||
@Override
|
||||
public void apply(PromiseError exception) throws OperationException {
|
||||
final String errorMessage = (exception.getMessage() != null) ? exception.getMessage()
|
||||
: "Failed to run test cases";
|
||||
notification.setContent(errorMessage);
|
||||
notification.setStatus(FAIL);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -33,6 +33,10 @@
|
|||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-dto</artifactId>
|
||||
|
|
@ -57,5 +61,27 @@
|
|||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-testing-classpath-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/**/AbstractTestListener.java</exclude>
|
||||
<exclude>**/**/OutputTestListener.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -14,9 +14,11 @@ import java.io.File;
|
|||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -30,6 +32,12 @@ import org.eclipse.che.api.testing.shared.TestResult;
|
|||
import org.eclipse.che.dto.server.DtoFactory;
|
||||
import org.eclipse.che.plugin.testing.classpath.server.TestClasspathProvider;
|
||||
import org.eclipse.che.plugin.testing.classpath.server.TestClasspathRegistry;
|
||||
import org.eclipse.che.plugin.testing.junit.server.listener.AbstractTestListener;
|
||||
import org.eclipse.che.plugin.testing.junit.server.listener.OutputTestListener;
|
||||
|
||||
import javassist.util.proxy.MethodFilter;
|
||||
import javassist.util.proxy.MethodHandler;
|
||||
import javassist.util.proxy.ProxyFactory;
|
||||
|
||||
/**
|
||||
* JUnit implementation for the test runner service.
|
||||
|
|
@ -45,13 +53,14 @@ import org.eclipse.che.plugin.testing.classpath.server.TestClasspathRegistry;
|
|||
* </pre>
|
||||
*
|
||||
* @author Mirage Abeysekara
|
||||
* @author David Festal
|
||||
*/
|
||||
public class JUnitTestRunner implements TestRunner {
|
||||
|
||||
private static final String JUNIT4X_RUNNER_CLASS = "org.junit.runner.JUnitCore";
|
||||
private static final String JUNIT3X_RUNNER_CLASS = "junit.textui.TestRunner";
|
||||
private ClassLoader projectClassLoader;
|
||||
private ProjectManager projectManager;
|
||||
private static final String JUNIT4X_RUNNER_CLASS = "org.junit.runner.JUnitCore";
|
||||
private static final String JUNIT3X_RUNNER_CLASS = "junit.textui.TestRunner";
|
||||
private ClassLoader projectClassLoader;
|
||||
private ProjectManager projectManager;
|
||||
private TestClasspathRegistry classpathRegistry;
|
||||
|
||||
@Inject
|
||||
|
|
@ -74,32 +83,59 @@ public class JUnitTestRunner implements TestRunner {
|
|||
if (projectManager != null) {
|
||||
projectType = projectManager.getProject(projectPath).getType();
|
||||
}
|
||||
|
||||
ClassLoader currentClassLoader = this.getClass().getClassLoader();
|
||||
TestClasspathProvider classpathProvider = classpathRegistry.getTestClasspathProvider(projectType);
|
||||
projectClassLoader = classpathProvider.getClassLoader(projectAbsolutePath, updateClasspath);
|
||||
TestResult testResult;
|
||||
URLClassLoader providedClassLoader = (URLClassLoader)classpathProvider.getClassLoader(projectAbsolutePath, projectPath, updateClasspath);
|
||||
projectClassLoader = new URLClassLoader(providedClassLoader.getURLs(), null) {
|
||||
@Override
|
||||
protected Class< ? > findClass(String name) throws ClassNotFoundException {
|
||||
if (name.startsWith("javassist.")) {
|
||||
return currentClassLoader.loadClass(name);
|
||||
}
|
||||
return super.findClass(name);
|
||||
}
|
||||
};
|
||||
|
||||
boolean isJUnit4Compatible = false;
|
||||
boolean isJUnit3Compatible = false;
|
||||
|
||||
try {
|
||||
Class.forName(JUNIT4X_RUNNER_CLASS, true, projectClassLoader);
|
||||
if (runClass) {
|
||||
String fqn = testParameters.get("fqn");
|
||||
testResult = run4x(fqn);
|
||||
} else {
|
||||
testResult = runAll4x(projectAbsolutePath);
|
||||
}
|
||||
return testResult;
|
||||
isJUnit4Compatible = true;
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
try {
|
||||
Class.forName(JUNIT3X_RUNNER_CLASS, true, projectClassLoader);
|
||||
if (runClass) {
|
||||
String fqn = testParameters.get("fqn");
|
||||
testResult = run3x(fqn);
|
||||
} else {
|
||||
testResult = runAll3x(projectAbsolutePath);
|
||||
}
|
||||
return testResult;
|
||||
isJUnit3Compatible = true;
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return null;
|
||||
|
||||
boolean useJUnitV3API = false;
|
||||
if (!isJUnit4Compatible) {
|
||||
if (!isJUnit3Compatible) {
|
||||
throw new ClassNotFoundException("JUnit classes not found in the following project classpath: "
|
||||
+ Arrays.asList(providedClassLoader.getURLs()));
|
||||
} else {
|
||||
useJUnitV3API = true;
|
||||
}
|
||||
}
|
||||
|
||||
String currentWorkingDir = System.getProperty("user.dir");
|
||||
try {
|
||||
System.setProperty("user.dir", projectAbsolutePath);
|
||||
TestResult testResult;
|
||||
if (runClass) {
|
||||
String fqn = testParameters.get("fqn");
|
||||
testResult = useJUnitV3API ? run3x(fqn) : run4x(fqn);
|
||||
} else {
|
||||
testResult = useJUnitV3API ? runAll3x(projectAbsolutePath) : runAll4x(projectAbsolutePath);
|
||||
}
|
||||
return testResult;
|
||||
} finally {
|
||||
System.setProperty("user.dir", currentWorkingDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -112,7 +148,7 @@ public class JUnitTestRunner implements TestRunner {
|
|||
|
||||
private TestResult run4x(String testClass) throws Exception {
|
||||
ClassLoader classLoader = projectClassLoader;
|
||||
Class<?> clsTest = Class.forName(testClass, true, classLoader);
|
||||
Class< ? > clsTest = Class.forName(testClass, true, classLoader);
|
||||
return run4xTestClasses(clsTest);
|
||||
}
|
||||
|
||||
|
|
@ -129,7 +165,7 @@ public class JUnitTestRunner implements TestRunner {
|
|||
@SuppressWarnings("rawtypes")
|
||||
List<Class> testableClasses = new ArrayList<>();
|
||||
for (String className : testClassNames) {
|
||||
Class<?> clazz = Class.forName(className, false, projectClassLoader);
|
||||
Class< ? > clazz = Class.forName(className, false, projectClassLoader);
|
||||
if (isTestable4x(clazz)) {
|
||||
testableClasses.add(clazz);
|
||||
}
|
||||
|
|
@ -137,7 +173,7 @@ public class JUnitTestRunner implements TestRunner {
|
|||
return run4xTestClasses(testableClasses.toArray(new Class[testableClasses.size()]));
|
||||
}
|
||||
|
||||
private boolean isTestable4x(Class<?> clazz) throws ClassNotFoundException {
|
||||
private boolean isTestable4x(Class< ? > clazz) throws ClassNotFoundException {
|
||||
for (Method method : clazz.getDeclaredMethods()) {
|
||||
for (Annotation annotation : method.getAnnotations()) {
|
||||
if (annotation.annotationType().getName().equals("org.junit.Test")) {
|
||||
|
|
@ -148,24 +184,107 @@ public class JUnitTestRunner implements TestRunner {
|
|||
return false;
|
||||
}
|
||||
|
||||
private TestResult run4xTestClasses(Class<?>... classes) throws Exception {
|
||||
private Object create4xTestListener(ClassLoader loader, Class< ? > listenerClass, AbstractTestListener delegate) throws Exception {
|
||||
ProxyFactory f = new ProxyFactory();
|
||||
f.setSuperclass(listenerClass);
|
||||
f.setFilter(new MethodFilter() {
|
||||
@Override
|
||||
public boolean isHandled(Method m) {
|
||||
String methodName = m.getName();
|
||||
switch (methodName) {
|
||||
case "testStarted":
|
||||
case "testFinished":
|
||||
case "testFailure":
|
||||
case "testAssumptionFailure":
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
Class< ? > c = f.createClass();
|
||||
MethodHandler mi = new MethodHandler() {
|
||||
@Override
|
||||
public Object invoke(Object self, Method m, Method method, Object[] args) throws Throwable {
|
||||
String methodName = m.getName();
|
||||
Object description = null;
|
||||
Throwable throwable = null;
|
||||
|
||||
switch (methodName) {
|
||||
case "testStarted":
|
||||
case "testFinished":
|
||||
description = args[0];
|
||||
throwable = null;
|
||||
break;
|
||||
case "testFailure":
|
||||
case "testAssumptionFailure":
|
||||
description = args[0].getClass().getMethod("getDescription", new Class< ? >[0]).invoke(args[0]);
|
||||
throwable = (Throwable)args[0].getClass().getMethod("getException", new Class< ? >[0]).invoke(args[0]);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
String testKey = (String)description.getClass().getMethod("getDisplayName", new Class< ? >[0]).invoke(description);
|
||||
String testName = testKey;
|
||||
switch (methodName) {
|
||||
case "testStarted":
|
||||
delegate.startTest(testKey, testName);
|
||||
break;
|
||||
|
||||
case "testFinished":
|
||||
delegate.endTest(testKey, testName);
|
||||
break;
|
||||
|
||||
case "testFailure":
|
||||
delegate.addFailure(testKey, throwable);
|
||||
break;
|
||||
|
||||
case "testAssumptionFailure":
|
||||
delegate.addError(testKey, throwable);
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Object listener = c.getConstructor().newInstance();
|
||||
((javassist.util.proxy.Proxy)listener).setHandler(mi);
|
||||
return listener;
|
||||
}
|
||||
|
||||
private TestResult run4xTestClasses(Class< ? >... classes) throws Exception {
|
||||
ClassLoader classLoader = projectClassLoader;
|
||||
Class<?> clsJUnitCore = Class.forName("org.junit.runner.JUnitCore", true, classLoader);
|
||||
Class<?> clsResult = Class.forName("org.junit.runner.Result", true, classLoader);
|
||||
Class<?> clsFailure = Class.forName("org.junit.runner.notification.Failure", true, classLoader);
|
||||
Class<?> clsDescription = Class.forName("org.junit.runner.Description", true, classLoader);
|
||||
Class<?> clsThrowable = Class.forName("java.lang.Throwable", true, classLoader);
|
||||
Class<?> clsStackTraceElement = Class.forName("java.lang.StackTraceElement", true, classLoader);
|
||||
Object result = clsJUnitCore.getMethod("runClasses", Class[].class).invoke(null, new Object[] { classes });
|
||||
Class< ? > clsJUnitCore = Class.forName("org.junit.runner.JUnitCore", true, classLoader);
|
||||
Class< ? > clsResult = Class.forName("org.junit.runner.Result", true, classLoader);
|
||||
Class< ? > clsFailure = Class.forName("org.junit.runner.notification.Failure", true, classLoader);
|
||||
Class< ? > clsDescription = Class.forName("org.junit.runner.Description", true, classLoader);
|
||||
Class< ? > clsThrowable = Class.forName("java.lang.Throwable", true, classLoader);
|
||||
Class< ? > clsStackTraceElement = Class.forName("java.lang.StackTraceElement", true, classLoader);
|
||||
Class< ? > clsTestRunner = Class.forName("org.junit.runner.notification.RunListener", true, classLoader);
|
||||
Object jUnitCore = clsJUnitCore.getConstructor().newInstance();
|
||||
|
||||
Object result;
|
||||
try (OutputTestListener outputListener = new OutputTestListener(this.getClass().getName() + ".run4xTestClasses")) {
|
||||
Object testListener = create4xTestListener(classLoader, clsTestRunner, outputListener);
|
||||
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
|
||||
try {
|
||||
Thread.currentThread().setContextClassLoader(projectClassLoader);
|
||||
clsJUnitCore.getMethod("addListener", clsTestRunner).invoke(jUnitCore, testListener);
|
||||
result = clsJUnitCore.getMethod("run", Class[].class).invoke(jUnitCore, new Object[]{classes});
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(tccl);
|
||||
clsJUnitCore.getMethod("removeListener", clsTestRunner).invoke(jUnitCore, testListener);
|
||||
}
|
||||
}
|
||||
|
||||
TestResult dtoResult = DtoFactory.getInstance().createDto(TestResult.class);
|
||||
boolean isSuccess = (Boolean) clsResult.getMethod("wasSuccessful").invoke(result);
|
||||
List<?> failures = (List<?>) clsResult.getMethod("getFailures").invoke(result);
|
||||
boolean isSuccess = (Boolean)clsResult.getMethod("wasSuccessful").invoke(result);
|
||||
List< ? > failures = (List< ? >)clsResult.getMethod("getFailures").invoke(result);
|
||||
List<Failure> jUnitFailures = new ArrayList<>();
|
||||
for (Object failure : failures) {
|
||||
Failure dtoFailure = DtoFactory.getInstance().createDto(Failure.class);
|
||||
String message = (String) clsFailure.getMethod("getMessage").invoke(failure);
|
||||
String message = (String)clsFailure.getMethod("getMessage").invoke(failure);
|
||||
Object description = clsFailure.getMethod("getDescription").invoke(failure);
|
||||
String failClassName = (String) clsDescription.getMethod("getClassName").invoke(description);
|
||||
String failClassName = (String)clsDescription.getMethod("getClassName").invoke(description);
|
||||
Object exception = clsFailure.getMethod("getException").invoke(failure);
|
||||
Object stackTrace = clsThrowable.getMethod("getStackTrace").invoke(exception);
|
||||
String failMethod = "";
|
||||
|
|
@ -174,15 +293,15 @@ public class JUnitTestRunner implements TestRunner {
|
|||
int length = Array.getLength(stackTrace);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object stackElement = Array.get(stackTrace, i);
|
||||
String failClass = (String) clsStackTraceElement.getMethod("getClassName").invoke(stackElement);
|
||||
String failClass = (String)clsStackTraceElement.getMethod("getClassName").invoke(stackElement);
|
||||
if (failClass.equals(failClassName)) {
|
||||
failMethod = (String) clsStackTraceElement.getMethod("getMethodName").invoke(stackElement);
|
||||
failLine = (Integer) clsStackTraceElement.getMethod("getLineNumber").invoke(stackElement);
|
||||
failMethod = (String)clsStackTraceElement.getMethod("getMethodName").invoke(stackElement);
|
||||
failLine = (Integer)clsStackTraceElement.getMethod("getLineNumber").invoke(stackElement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
String trace = (String) clsFailure.getMethod("getTrace").invoke(failure);
|
||||
String trace = (String)clsFailure.getMethod("getTrace").invoke(failure);
|
||||
dtoFailure.setFailingClass(failClassName);
|
||||
dtoFailure.setFailingMethod(failMethod);
|
||||
dtoFailure.setFailingLine(failLine);
|
||||
|
|
@ -199,7 +318,7 @@ public class JUnitTestRunner implements TestRunner {
|
|||
|
||||
private TestResult run3x(String testClass) throws Exception {
|
||||
ClassLoader classLoader = projectClassLoader;
|
||||
Class<?> clsTest = Class.forName(testClass, true, classLoader);
|
||||
Class< ? > clsTest = Class.forName(testClass, true, classLoader);
|
||||
return run3xTestClasses(clsTest);
|
||||
|
||||
}
|
||||
|
|
@ -217,7 +336,7 @@ public class JUnitTestRunner implements TestRunner {
|
|||
@SuppressWarnings("rawtypes")
|
||||
List<Class> testableClasses = new ArrayList<>();
|
||||
for (String className : testClassNames) {
|
||||
Class<?> clazz = Class.forName(className, false, projectClassLoader);
|
||||
Class< ? > clazz = Class.forName(className, false, projectClassLoader);
|
||||
if (isTestable3x(clazz)) {
|
||||
testableClasses.add(clazz);
|
||||
}
|
||||
|
|
@ -225,33 +344,97 @@ public class JUnitTestRunner implements TestRunner {
|
|||
return run3xTestClasses(testableClasses.toArray(new Class[testableClasses.size()]));
|
||||
}
|
||||
|
||||
private boolean isTestable3x(Class<?> clazz) throws ClassNotFoundException {
|
||||
Class<?> superClass = Class.forName("junit.framework.TestCase", true, projectClassLoader);
|
||||
private boolean isTestable3x(Class< ? > clazz) throws ClassNotFoundException {
|
||||
Class< ? > superClass = Class.forName("junit.framework.TestCase", true, projectClassLoader);
|
||||
return superClass.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
private TestResult run3xTestClasses(Class<?>... classes) throws Exception {
|
||||
private Object create3xTestListener(ClassLoader loader, Class< ? > listenerClass, AbstractTestListener delegate) throws Exception {
|
||||
ProxyFactory f = new ProxyFactory();
|
||||
f.setSuperclass(Object.class);
|
||||
f.setInterfaces(new Class< ? >[]{listenerClass});
|
||||
f.setFilter(new MethodFilter() {
|
||||
@Override
|
||||
public boolean isHandled(Method m) {
|
||||
String methodName = m.getName();
|
||||
switch (methodName) {
|
||||
case "startTest":
|
||||
case "endTest":
|
||||
case "addError":
|
||||
case "addFailure":
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
Class< ? > c = f.createClass();
|
||||
MethodHandler mi = new MethodHandler() {
|
||||
public Object invoke(Object self, Method method, Method proceed, Object[] args) throws Throwable {
|
||||
String testKey = args[0].getClass().toString();
|
||||
String testName = args[0].getClass().getName();
|
||||
String methodName = method.getName();
|
||||
switch (methodName) {
|
||||
case "startTest":
|
||||
delegate.startTest(testKey, testName);
|
||||
break;
|
||||
|
||||
case "endTest":
|
||||
delegate.endTest(testKey, testName);
|
||||
break;
|
||||
|
||||
case "addError":
|
||||
delegate.addError(testKey, (Throwable)args[1]);
|
||||
break;
|
||||
|
||||
case "addFailure":
|
||||
delegate.addFailure(testKey, (Throwable)args[1]);
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Object listener = c.getConstructor().newInstance();
|
||||
((javassist.util.proxy.Proxy)listener).setHandler(mi);
|
||||
return listener;
|
||||
}
|
||||
|
||||
private TestResult run3xTestClasses(Class< ? >... classes) throws Exception {
|
||||
ClassLoader classLoader = projectClassLoader;
|
||||
Class<?> clsTestSuite = Class.forName("junit.framework.TestSuite", true, classLoader);
|
||||
Class<?> clsTestResult = Class.forName("junit.framework.TestResult", true, classLoader);
|
||||
Class<?> clsThrowable = Class.forName("java.lang.Throwable", true, classLoader);
|
||||
Class<?> clsStackTraceElement = Class.forName("java.lang.StackTraceElement", true, classLoader);
|
||||
Class<?> clsFailure = Class.forName("junit.framework.TestFailure", true, classLoader);
|
||||
Object testSuite = clsTestSuite.newInstance();
|
||||
Object testResult = clsTestResult.newInstance();
|
||||
for (Class<?> testClass : classes) {
|
||||
clsTestSuite.getMethod("addTestSuite", Class.class).invoke(testSuite, testClass);
|
||||
Class< ? > clsTestSuite = Class.forName("junit.framework.TestSuite", true, classLoader);
|
||||
Class< ? > clsTestResult = Class.forName("junit.framework.TestResult", true, classLoader);
|
||||
Class< ? > clsThrowable = Class.forName("java.lang.Throwable", true, classLoader);
|
||||
Class< ? > clsStackTraceElement = Class.forName("java.lang.StackTraceElement", true, classLoader);
|
||||
Class< ? > clsFailure = Class.forName("junit.framework.TestFailure", true, classLoader);
|
||||
Object testSuite = clsTestSuite.getConstructor().newInstance();
|
||||
Object testResult = clsTestResult.getConstructor().newInstance();
|
||||
Class< ? > clsTestListener = Class.forName("junit.framework.TestListener", true, classLoader);
|
||||
|
||||
try (OutputTestListener outputListener = new OutputTestListener(this.getClass().getName() + ".run3xTestClasses")) {
|
||||
Object testListener = create3xTestListener(classLoader, clsTestListener, outputListener);
|
||||
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
|
||||
try {
|
||||
Thread.currentThread().setContextClassLoader(projectClassLoader);
|
||||
clsTestResult.getMethod("addListener", clsTestListener).invoke(
|
||||
testResult, testListener);
|
||||
for (Class< ? > testClass : classes) {
|
||||
clsTestSuite.getMethod("addTestSuite", Class.class).invoke(testSuite, testClass);
|
||||
}
|
||||
clsTestSuite.getMethod("run", clsTestResult).invoke(testSuite, testResult);
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(tccl);
|
||||
clsTestResult.getMethod("removeListener", clsTestListener).invoke(
|
||||
testResult, testListener);
|
||||
}
|
||||
}
|
||||
clsTestSuite.getMethod("run", clsTestResult).invoke(testSuite, testResult);
|
||||
TestResult dtoResult = DtoFactory.getInstance().createDto(TestResult.class);
|
||||
boolean isSuccess = (Boolean) clsTestResult.getMethod("wasSuccessful").invoke(testResult);
|
||||
Enumeration<?> failures = (Enumeration<?>) clsTestResult.getMethod("failures").invoke(testResult);
|
||||
boolean isSuccess = (Boolean)clsTestResult.getMethod("wasSuccessful").invoke(testResult);
|
||||
Enumeration< ? > failures = (Enumeration< ? >)clsTestResult.getMethod("failures").invoke(testResult);
|
||||
List<Failure> jUnitFailures = new ArrayList<>();
|
||||
while (failures.hasMoreElements()) {
|
||||
Failure dtoFailure = DtoFactory.getInstance().createDto(Failure.class);
|
||||
Object failure = failures.nextElement();
|
||||
String message = (String) clsFailure.getMethod("exceptionMessage").invoke(failure);
|
||||
String trace = (String) clsFailure.getMethod("trace").invoke(failure);
|
||||
String message = (String)clsFailure.getMethod("exceptionMessage").invoke(failure);
|
||||
String trace = (String)clsFailure.getMethod("trace").invoke(failure);
|
||||
Object failClassObject = clsFailure.getMethod("failedTest").invoke(failure);
|
||||
String failClassName = failClassObject.getClass().getName();
|
||||
Object exception = clsFailure.getMethod("thrownException").invoke(failure);
|
||||
|
|
@ -262,10 +445,10 @@ public class JUnitTestRunner implements TestRunner {
|
|||
int length = Array.getLength(stackTrace);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object arrayElement = Array.get(stackTrace, i);
|
||||
String failClass = (String) clsStackTraceElement.getMethod("getClassName").invoke(arrayElement);
|
||||
String failClass = (String)clsStackTraceElement.getMethod("getClassName").invoke(arrayElement);
|
||||
if (failClass.equals(failClassName)) {
|
||||
failMethod = (String) clsStackTraceElement.getMethod("getMethodName").invoke(arrayElement);
|
||||
failLine = (Integer) clsStackTraceElement.getMethod("getLineNumber").invoke(arrayElement);
|
||||
failMethod = (String)clsStackTraceElement.getMethod("getMethodName").invoke(arrayElement);
|
||||
failLine = (Integer)clsStackTraceElement.getMethod("getLineNumber").invoke(arrayElement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 RedHat, Inc.
|
||||
* 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:
|
||||
* RedHat, Inc. - initial commit
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.testing.junit.server.listener;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Listener abstraction for the testing services to report their progress.
|
||||
*
|
||||
* @author David Festal
|
||||
*/
|
||||
public abstract class AbstractTestListener {
|
||||
static public class TestSummary {
|
||||
private int errors;
|
||||
private int failures;
|
||||
|
||||
public TestSummary() {
|
||||
this.errors = 0;
|
||||
this.failures = 0;
|
||||
}
|
||||
|
||||
public void addError() {
|
||||
errors++;
|
||||
}
|
||||
|
||||
public void addFailure() {
|
||||
failures++;
|
||||
}
|
||||
|
||||
public int getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
public int getFailures() {
|
||||
return failures;
|
||||
}
|
||||
|
||||
public boolean succeeded() {
|
||||
return failures == 0 && errors == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder()
|
||||
.append(failures)
|
||||
.append(" failures and ")
|
||||
.append(errors)
|
||||
.append(" errors")
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
HashMap<String, AbstractTestListener.TestSummary> runningTests = new HashMap<>();
|
||||
|
||||
public synchronized void startTest(String testKey, String testName) {
|
||||
runningTests.put(testKey, null);
|
||||
startedTest(testKey, testName);
|
||||
}
|
||||
|
||||
public synchronized void endTest(String testKey, String testName) {
|
||||
AbstractTestListener.TestSummary summary = runningTests.remove(testKey);
|
||||
endedTest(testKey, testName, summary);
|
||||
}
|
||||
|
||||
protected abstract void startedTest(String testKey, String testName);
|
||||
|
||||
protected abstract void endedTest(String testKey, String testName, AbstractTestListener.TestSummary summary);
|
||||
|
||||
protected abstract void addedFailure(String testKey, Throwable throwable);
|
||||
|
||||
protected abstract void addedError(String testKey, Throwable throwable);
|
||||
|
||||
private synchronized AbstractTestListener.TestSummary getOrCreateTestSummary(String testKey) {
|
||||
AbstractTestListener.TestSummary summary = runningTests.get(testKey);
|
||||
if (summary == null) {
|
||||
summary = new TestSummary();
|
||||
runningTests.put(testKey, summary);
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
|
||||
public void addFailure(String testKey, Throwable throwable) {
|
||||
getOrCreateTestSummary(testKey).addFailure();
|
||||
addedFailure(testKey, throwable);
|
||||
}
|
||||
|
||||
public void addError(String testKey, Throwable throwable) {
|
||||
getOrCreateTestSummary(testKey).addError();
|
||||
addedError(testKey, throwable);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 RedHat, Inc.
|
||||
* 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:
|
||||
* RedHat, Inc. - initial commit
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.testing.junit.server.listener;
|
||||
|
||||
import static org.eclipse.che.api.testing.shared.Constants.TESTING_OUTPUT_CHANNEL_NAME;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import org.eclipse.che.api.core.util.WebsocketMessageConsumer;
|
||||
import org.eclipse.che.api.testing.server.handler.TestingOutputImpl;
|
||||
import org.eclipse.che.api.testing.shared.TestingOutput;
|
||||
import org.eclipse.che.dto.server.DtoFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Listener for the testing services to report their progress to the Che output view.
|
||||
*
|
||||
* @author David Festal
|
||||
*/
|
||||
public class OutputTestListener extends AbstractTestListener implements AutoCloseable {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractTestListener.class);
|
||||
private static final String consumeErrorMessage = "An exception occured while trying to send a 'TestingOutput' "
|
||||
+ "object through web sockets on the following channel: "
|
||||
+ TESTING_OUTPUT_CHANNEL_NAME;
|
||||
|
||||
private WebsocketMessageConsumer<TestingOutput> consumer = new WebsocketMessageConsumer<>(TESTING_OUTPUT_CHANNEL_NAME);
|
||||
private String stackTraceRoot;
|
||||
|
||||
public OutputTestListener(String strackTraceRoot) {
|
||||
this.stackTraceRoot = strackTraceRoot;
|
||||
writeLine("Starting Test Session", TestingOutput.LineType.SESSION_START);
|
||||
}
|
||||
|
||||
private void writeLine(String line, TestingOutput.LineType lineType) {
|
||||
try {
|
||||
consumer.consume(DtoFactory.cloneDto(new TestingOutputImpl(line, lineType)));
|
||||
} catch (IOException e) {
|
||||
LOG.error(consumeErrorMessage, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
writeLine("Finished Test Session", TestingOutput.LineType.SESSION_END);
|
||||
consumer.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startedTest(String testKey, String testName) {
|
||||
writeLine("[Starting Test] " + testName, TestingOutput.LineType.DETAIL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endedTest(String testKey, String testName, TestSummary summary) {
|
||||
TestingOutput.LineType lineType;
|
||||
String detailText;
|
||||
if (summary == null || summary.succeeded()) {
|
||||
lineType = TestingOutput.LineType.SUCCESS;
|
||||
detailText = "successfully";
|
||||
} else {
|
||||
detailText = "with " + summary;
|
||||
if (summary.getErrors() > 0) {
|
||||
lineType = TestingOutput.LineType.ERROR;
|
||||
} else {
|
||||
lineType = TestingOutput.LineType.FAILURE;
|
||||
}
|
||||
}
|
||||
writeLine("[Finished Test] " + testName + " " + detailText, lineType);
|
||||
|
||||
}
|
||||
|
||||
private void addProblem(String testKey, Throwable throwable, boolean isError) {
|
||||
StringWriter sw = new StringWriter();
|
||||
TestingOutput.LineType lineType = isError ? TestingOutput.LineType.ERROR
|
||||
: TestingOutput.LineType.FAILURE;
|
||||
try (PrintWriter w = new PrintWriter(sw)) {
|
||||
throwable.printStackTrace(w);
|
||||
}
|
||||
writeLine(" [" + lineType.name() + "]", lineType);
|
||||
for (String line : sw.getBuffer().toString().split("\\n")) {
|
||||
if (line.contains(stackTraceRoot)) {
|
||||
break;
|
||||
}
|
||||
writeLine(" " + line, TestingOutput.LineType.DETAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addedFailure(String testKey, Throwable throwable) {
|
||||
addProblem(testKey, throwable, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addedError(String testKey, Throwable throwable) {
|
||||
addProblem(testKey, throwable, true);
|
||||
}
|
||||
}
|
||||
|
|
@ -79,7 +79,7 @@ public class TestNGRunner implements TestRunner {
|
|||
projectType = projectManager.getProject(projectPath).getType();
|
||||
}
|
||||
TestClasspathProvider classpathProvider = classpathRegistry.getTestClasspathProvider(projectType);
|
||||
projectClassLoader = classpathProvider.getClassLoader(projectAbsolutePath, updateClasspath);
|
||||
projectClassLoader = classpathProvider.getClassLoader(projectAbsolutePath, projectPath, updateClasspath);
|
||||
TestResult testResult;
|
||||
if (runClass) {
|
||||
String fqn = testParameters.get("fqn");
|
||||
|
|
|
|||
|
|
@ -72,6 +72,10 @@
|
|||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-java-ext-lang-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-machine-ext-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.plugin</groupId>
|
||||
<artifactId>che-plugin-maven-shared</artifactId>
|
||||
|
|
@ -117,6 +121,20 @@
|
|||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/**/TestingHandler.java</exclude>
|
||||
<exclude>**/**/ExecutorPromiseMocker.java</exclude>
|
||||
<exclude>**/**/PromiseMocker.java</exclude>
|
||||
<exclude>**/**/FunctionAnswer.java</exclude>
|
||||
<exclude>**/**/MockitoPrinter.java</exclude>
|
||||
<exclude>**/**/TestServiceClientTest.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
|
|
|
|||
|
|
@ -10,17 +10,40 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.testing.ide;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.che.api.core.model.machine.Machine;
|
||||
import org.eclipse.che.api.promises.client.Operation;
|
||||
import org.eclipse.che.api.promises.client.OperationException;
|
||||
import org.eclipse.che.api.promises.client.Promise;
|
||||
import org.eclipse.che.api.promises.client.PromiseError;
|
||||
import org.eclipse.che.api.promises.client.PromiseProvider;
|
||||
import org.eclipse.che.api.promises.client.js.Executor;
|
||||
import org.eclipse.che.api.promises.client.js.Executor.ExecutorBody;
|
||||
import org.eclipse.che.api.promises.client.js.JsPromiseError;
|
||||
import org.eclipse.che.api.promises.client.js.RejectFunction;
|
||||
import org.eclipse.che.api.promises.client.js.ResolveFunction;
|
||||
import org.eclipse.che.api.testing.shared.TestResult;
|
||||
import org.eclipse.che.ide.MimeType;
|
||||
import org.eclipse.che.ide.api.app.AppContext;
|
||||
import org.eclipse.che.ide.api.command.CommandImpl;
|
||||
import org.eclipse.che.ide.api.command.CommandManager;
|
||||
import org.eclipse.che.ide.api.machine.ExecAgentCommandManager;
|
||||
import org.eclipse.che.ide.api.macro.MacroProcessor;
|
||||
import org.eclipse.che.ide.api.notification.StatusNotification;
|
||||
import org.eclipse.che.ide.dto.DtoFactory;
|
||||
import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandConsoleFactory;
|
||||
import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandOutputConsole;
|
||||
import org.eclipse.che.ide.extension.machine.client.processes.panel.ProcessesPanelPresenter;
|
||||
import org.eclipse.che.ide.rest.AsyncRequestFactory;
|
||||
import org.eclipse.che.ide.rest.DtoUnmarshallerFactory;
|
||||
import org.eclipse.che.ide.rest.HTTPHeader;
|
||||
|
||||
import com.google.gwt.http.client.URL;
|
||||
import com.google.gwt.regexp.shared.MatchResult;
|
||||
import com.google.gwt.regexp.shared.RegExp;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
|
|
@ -28,25 +51,180 @@ import com.google.inject.Singleton;
|
|||
* Client for calling test services
|
||||
*
|
||||
* @author Mirage Abeysekara
|
||||
* @author David Festal
|
||||
*/
|
||||
@Singleton
|
||||
public class TestServiceClient {
|
||||
|
||||
private final AppContext appContext;
|
||||
private final AsyncRequestFactory asyncRequestFactory;
|
||||
private final DtoUnmarshallerFactory dtoUnmarshallerFactory;
|
||||
private final static RegExp mavenCleanBuildPattern =
|
||||
RegExp.compile("(.*)mvn +clean +install +(\\-f +\\$\\{current\\.project\\.path\\}.*)");
|
||||
|
||||
public static final String PROJECT_BUILD_NOT_STARTED_MESSAGE = "The project build could not be started (see Build output). "
|
||||
+ "Test run is cancelled.\n"
|
||||
+ "You should probably check the settings of the 'test-compile' command.";
|
||||
|
||||
public static final String PROJECT_BUILD_FAILED_MESSAGE = "The project build failed (see Build output). "
|
||||
+ "Test run is cancelled.\n"
|
||||
+ "You might want to check the settings of the 'test-compile' command.";
|
||||
|
||||
public static final String EXECUTING_TESTS_MESSAGE = "Executing test session.";
|
||||
|
||||
|
||||
private final AppContext appContext;
|
||||
private final AsyncRequestFactory asyncRequestFactory;
|
||||
private final DtoUnmarshallerFactory dtoUnmarshallerFactory;
|
||||
private final CommandManager commandManager;
|
||||
private final ExecAgentCommandManager execAgentCommandManager;
|
||||
private final PromiseProvider promiseProvider;
|
||||
private final MacroProcessor macroProcessor;
|
||||
private final CommandConsoleFactory commandConsoleFactory;
|
||||
private final ProcessesPanelPresenter processesPanelPresenter;
|
||||
|
||||
|
||||
@Inject
|
||||
public TestServiceClient(AppContext appContext,
|
||||
public TestServiceClient(AppContext appContext,
|
||||
AsyncRequestFactory asyncRequestFactory,
|
||||
DtoUnmarshallerFactory dtoUnmarshallerFactory) {
|
||||
DtoUnmarshallerFactory dtoUnmarshallerFactory,
|
||||
DtoFactory dtoFactory,
|
||||
CommandManager commandManager,
|
||||
ExecAgentCommandManager execAgentCommandManager,
|
||||
PromiseProvider promiseProvider,
|
||||
MacroProcessor macroProcessor,
|
||||
CommandConsoleFactory commandConsoleFactory,
|
||||
ProcessesPanelPresenter processesPanelPresenter) {
|
||||
this.appContext = appContext;
|
||||
this.asyncRequestFactory = asyncRequestFactory;
|
||||
this.dtoUnmarshallerFactory = dtoUnmarshallerFactory;
|
||||
this.commandManager = commandManager;
|
||||
this.execAgentCommandManager = execAgentCommandManager;
|
||||
this.promiseProvider = promiseProvider;
|
||||
this.macroProcessor = macroProcessor;
|
||||
this.commandConsoleFactory = commandConsoleFactory;
|
||||
this.processesPanelPresenter = processesPanelPresenter;
|
||||
}
|
||||
|
||||
public Promise<CommandImpl> getOrCreateTestCompileCommand() {
|
||||
List<CommandImpl> commands = commandManager.getCommands();
|
||||
for (CommandImpl command : commands) {
|
||||
if (command.getName() != null && command.getName().startsWith("test-compile") && "mvn".equals(command.getType())) {
|
||||
return promiseProvider.resolve(command);
|
||||
}
|
||||
}
|
||||
for (CommandImpl command : commands) {
|
||||
if ("build".equals(command.getName()) && "mvn".equals(command.getType())) {
|
||||
String commandLine = command.getCommandLine();
|
||||
MatchResult result = mavenCleanBuildPattern.exec(commandLine);
|
||||
if (result != null) {
|
||||
String testCompileCommandLine = mavenCleanBuildPattern.replace(commandLine, "$1mvn test-compile $2");
|
||||
return commandManager.create("test-compile", testCompileCommandLine, "mvn", new HashMap<String, String>());
|
||||
}
|
||||
}
|
||||
}
|
||||
return promiseProvider.resolve(null);
|
||||
}
|
||||
|
||||
public Promise<TestResult> getTestResult(String projectPath, String testFramework, Map<String, String> parameters) {
|
||||
return getTestResult(projectPath, testFramework, parameters, null);
|
||||
}
|
||||
|
||||
Promise<TestResult> promiseFromExecutorBody(ExecutorBody<TestResult> executorBody) {
|
||||
return promiseProvider.create(Executor.create(executorBody));
|
||||
}
|
||||
|
||||
PromiseError promiseFromThrowable(Throwable t) {
|
||||
return JsPromiseError.create(t);
|
||||
}
|
||||
|
||||
Promise<TestResult> runTestsAfterCompilation(String projectPath,
|
||||
String testFramework,
|
||||
Map<String, String> parameters,
|
||||
StatusNotification statusNotification,
|
||||
Promise<CommandImpl> compileCommand) {
|
||||
return compileCommand.thenPromise(command -> {
|
||||
final Machine machine;
|
||||
if (command == null) {
|
||||
machine = null;
|
||||
} else {
|
||||
machine = appContext.getDevMachine().getDescriptor();
|
||||
}
|
||||
if (machine == null) {
|
||||
if (statusNotification != null) {
|
||||
statusNotification.setContent("Executing the tests without preliminary compilation.");
|
||||
}
|
||||
return sendTests(projectPath, testFramework, parameters);
|
||||
}
|
||||
|
||||
if (statusNotification != null) {
|
||||
statusNotification.setContent("Compiling the project before starting the test session.");
|
||||
}
|
||||
return promiseFromExecutorBody(new ExecutorBody<TestResult>() {
|
||||
boolean compiled = false;
|
||||
|
||||
@Override
|
||||
public void apply(final ResolveFunction<TestResult> resolve, RejectFunction reject) {
|
||||
macroProcessor.expandMacros(command.getCommandLine()).then(new Operation<String>() {
|
||||
@Override
|
||||
public void apply(String expandedCommandLine) throws OperationException {
|
||||
CommandImpl expandedCommand = new CommandImpl(command.getName(), expandedCommandLine,
|
||||
command.getType(), command.getAttributes());
|
||||
|
||||
final CommandOutputConsole console = commandConsoleFactory.create(expandedCommand, machine);
|
||||
final String machineId = machine.getId();
|
||||
|
||||
processesPanelPresenter.addCommandOutput(machineId, console);
|
||||
execAgentCommandManager.startProcess(machineId, expandedCommand)
|
||||
.then(startResonse -> {
|
||||
if (!startResonse.getAlive()) {
|
||||
reject.apply(promiseFromThrowable(new Throwable(PROJECT_BUILD_NOT_STARTED_MESSAGE)));
|
||||
}
|
||||
})
|
||||
.thenIfProcessStartedEvent(console.getProcessStartedOperation())
|
||||
.thenIfProcessStdErrEvent(evt -> {
|
||||
if (evt.getText().contains("BUILD SUCCESS")) {
|
||||
compiled = true;
|
||||
}
|
||||
console.getStdErrOperation().apply(evt);
|
||||
})
|
||||
.thenIfProcessStdOutEvent(evt -> {
|
||||
if (evt.getText().contains("BUILD SUCCESS")) {
|
||||
compiled = true;
|
||||
}
|
||||
console.getStdOutOperation().apply(evt);
|
||||
})
|
||||
.thenIfProcessDiedEvent(evt -> {
|
||||
console.getProcessDiedOperation().apply(evt);
|
||||
if (compiled) {
|
||||
if (statusNotification != null) {
|
||||
statusNotification.setContent(EXECUTING_TESTS_MESSAGE);
|
||||
}
|
||||
sendTests(projectPath,
|
||||
testFramework,
|
||||
parameters).then(new Operation<TestResult>() {
|
||||
@Override
|
||||
public void apply(TestResult result) throws OperationException {
|
||||
resolve.apply(result);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
reject.apply(promiseFromThrowable(new Throwable(PROJECT_BUILD_FAILED_MESSAGE)));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public Promise<TestResult> getTestResult(String projectPath,
|
||||
String testFramework,
|
||||
Map<String, String> parameters,
|
||||
StatusNotification statusNotification) {
|
||||
return runTestsAfterCompilation(projectPath, testFramework, parameters, statusNotification,
|
||||
getOrCreateTestCompileCommand());
|
||||
}
|
||||
|
||||
public Promise<TestResult> sendTests(String projectPath, String testFramework, Map<String, String> parameters) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (parameters != null) {
|
||||
for (Map.Entry<String, String> e : parameters.entrySet()) {
|
||||
|
|
@ -57,9 +235,9 @@ public class TestServiceClient {
|
|||
}
|
||||
}
|
||||
String url = appContext.getDevMachine().getWsAgentBaseUrl() + "/che/testing/run/?projectPath=" + projectPath
|
||||
+ "&testFramework=" + testFramework + "&" + sb.toString();
|
||||
+ "&testFramework=" + testFramework + "&" + sb.toString();
|
||||
return asyncRequestFactory.createGetRequest(url).header(HTTPHeader.ACCEPT, MimeType.APPLICATION_JSON)
|
||||
.send(dtoUnmarshallerFactory.newUnmarshaller(TestResult.class));
|
||||
.send(dtoUnmarshallerFactory.newUnmarshaller(TestResult.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import java.util.Set;
|
|||
import org.eclipse.che.ide.api.action.ActionManager;
|
||||
import org.eclipse.che.ide.api.action.DefaultActionGroup;
|
||||
import org.eclipse.che.ide.api.extension.Extension;
|
||||
import org.eclipse.che.plugin.testing.ide.handler.TestingHandler;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
|
@ -34,7 +35,8 @@ public class TestingExtension {
|
|||
@Inject
|
||||
public TestingExtension(ActionManager actionManager,
|
||||
TestLocalizationConstant localization,
|
||||
Set<TestAction> testActions) {
|
||||
Set<TestAction> testActions,
|
||||
TestingHandler testingHandler) {
|
||||
DefaultActionGroup runMenu = (DefaultActionGroup) actionManager.getAction(GROUP_RUN);
|
||||
DefaultActionGroup testMainMenu = new DefaultActionGroup(localization.actionGroupMenuName(), true,
|
||||
actionManager);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,117 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 RedHat, Inc.
|
||||
* 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:
|
||||
* RedHat, Inc. - initial commit
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.testing.ide.handler;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.web.bindery.event.shared.EventBus;
|
||||
|
||||
import org.eclipse.che.api.promises.client.Operation;
|
||||
import org.eclipse.che.api.promises.client.OperationException;
|
||||
import org.eclipse.che.api.testing.shared.TestingOutput;
|
||||
import org.eclipse.che.ide.api.app.AppContext;
|
||||
import org.eclipse.che.ide.api.machine.WsAgentStateController;
|
||||
import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent;
|
||||
import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler;
|
||||
import org.eclipse.che.ide.dto.DtoFactory;
|
||||
import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandConsoleFactory;
|
||||
import org.eclipse.che.ide.extension.machine.client.outputspanel.console.DefaultOutputConsole;
|
||||
import org.eclipse.che.ide.extension.machine.client.processes.panel.ProcessesPanelPresenter;
|
||||
import org.eclipse.che.ide.util.loging.Log;
|
||||
import org.eclipse.che.ide.websocket.MessageBus;
|
||||
import org.eclipse.che.ide.websocket.WebSocketException;
|
||||
import org.eclipse.che.ide.websocket.events.MessageHandler;
|
||||
|
||||
import static org.eclipse.che.api.testing.shared.Constants.TESTING_OUTPUT_CHANNEL_NAME;;
|
||||
|
||||
/**
|
||||
* Handler which receives messages from the Testing tools.
|
||||
*
|
||||
* @author David Festal
|
||||
*/
|
||||
@Singleton
|
||||
public class TestingHandler {
|
||||
|
||||
private final EventBus eventBus;
|
||||
private final DtoFactory factory;
|
||||
private final ProcessesPanelPresenter processesPanelPresenter;
|
||||
private final CommandConsoleFactory commandConsoleFactory;
|
||||
private final AppContext appContext;
|
||||
|
||||
@Inject
|
||||
public TestingHandler(EventBus eventBus,
|
||||
DtoFactory factory,
|
||||
WsAgentStateController wsAgentStateController,
|
||||
ProcessesPanelPresenter processesPanelPresenter,
|
||||
CommandConsoleFactory commandConsoleFactory,
|
||||
AppContext appContext) {
|
||||
this.eventBus = eventBus;
|
||||
this.factory = factory;
|
||||
this.processesPanelPresenter = processesPanelPresenter;
|
||||
this.commandConsoleFactory = commandConsoleFactory;
|
||||
this.appContext = appContext;
|
||||
|
||||
handleOperations(factory, wsAgentStateController);
|
||||
}
|
||||
|
||||
private void handleOperations(final DtoFactory factory, final WsAgentStateController wsAgentStateController) {
|
||||
eventBus.addHandler(WsAgentStateEvent.TYPE, new WsAgentStateHandler() {
|
||||
@Override
|
||||
public void onWsAgentStarted(WsAgentStateEvent event) {
|
||||
wsAgentStateController.getMessageBus().then(new Operation<MessageBus>() {
|
||||
@Override
|
||||
public void apply(MessageBus messageBus) throws OperationException {
|
||||
handleTestingOutput(messageBus);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWsAgentStopped(WsAgentStateEvent event) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleTestingOutput(final MessageBus messageBus) {
|
||||
final DefaultOutputConsole outputConsole = (DefaultOutputConsole)commandConsoleFactory.create("Tests");
|
||||
try {
|
||||
messageBus.subscribe(TESTING_OUTPUT_CHANNEL_NAME, new MessageHandler() {
|
||||
@Override
|
||||
public void onMessage(String message) {
|
||||
Log.info(getClass(), message);
|
||||
TestingOutput archetypeOutput = factory.createDtoFromJson(message, TestingOutput.class);
|
||||
switch (archetypeOutput.getState()) {
|
||||
case SESSION_START:
|
||||
processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), outputConsole);
|
||||
outputConsole.clearOutputsButtonClicked();
|
||||
case DETAIL:
|
||||
outputConsole.printText(archetypeOutput.getOutput());
|
||||
break;
|
||||
case SUCCESS:
|
||||
outputConsole.printText(archetypeOutput.getOutput(), "green");
|
||||
break;
|
||||
case ERROR:
|
||||
outputConsole.printText(archetypeOutput.getOutput(), "red");
|
||||
break;
|
||||
case FAILURE:
|
||||
outputConsole.printText(archetypeOutput.getOutput(), "darkred");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (WebSocketException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 RedHat, Inc.
|
||||
* 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:
|
||||
* RedHat, Inc. - initial commit
|
||||
*******************************************************************************/package org.eclipse.che.plugin.testing.ide;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.eclipse.che.api.promises.client.PromiseError;
|
||||
import org.eclipse.che.api.promises.client.js.Executor;
|
||||
import org.eclipse.che.api.promises.client.js.RejectFunction;
|
||||
import org.eclipse.che.api.promises.client.js.ResolveFunction;
|
||||
import org.mockito.Matchers;
|
||||
|
||||
/**
|
||||
* Utility class that allows mocking a Che Promise from an Executor.ExecutorBody.
|
||||
*
|
||||
* @author David Festal
|
||||
*/
|
||||
public class ExecutorPromiseMocker<T> extends PromiseMocker<T> {
|
||||
private final ResolveFunction<T> resolveFunction;
|
||||
private final RejectFunction rejectFunction;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ExecutorPromiseMocker(final Executor.ExecutorBody<T> executorBody,
|
||||
final BiFunction<T, PromiseMocker<T>, Void> onResolved,
|
||||
final BiFunction<PromiseError, PromiseMocker<T>, Void> onRejected) {
|
||||
super();
|
||||
resolveFunction = (ResolveFunction<T>) mock(ResolveFunction.class);
|
||||
rejectFunction = mock(RejectFunction.class);
|
||||
|
||||
doAnswer(new FunctionAnswer<T, Void>(resolvedValue-> {
|
||||
onResolved.apply(resolvedValue, this);
|
||||
return null;
|
||||
})).when(resolveFunction).apply(Matchers.<T>any());
|
||||
|
||||
doAnswer(new FunctionAnswer<PromiseError, Void>(promiseError -> {
|
||||
onRejected.apply(promiseError, this);
|
||||
return null;
|
||||
})).when(rejectFunction).apply(any(PromiseError.class));
|
||||
}
|
||||
|
||||
public ResolveFunction<T> getResolveFunction() {
|
||||
return resolveFunction;
|
||||
}
|
||||
|
||||
public RejectFunction getRejectFunction() {
|
||||
return rejectFunction;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 RedHat, Inc.
|
||||
* 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:
|
||||
* RedHat, Inc. - initial commit
|
||||
*******************************************************************************/package org.eclipse.che.plugin.testing.ide;
|
||||
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
/**
|
||||
* Mockito Answer that applies a given function to the first argument of
|
||||
* the answer InvocationOnMock argument.
|
||||
*
|
||||
* @author David Festal
|
||||
*/
|
||||
public class FunctionAnswer<ArgumentType, Return> implements Answer<Return> {
|
||||
private java.util.function.Function<ArgumentType, Return> apply;
|
||||
public FunctionAnswer(java.util.function.Function<ArgumentType, Return> apply) {
|
||||
this.apply = apply;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Return answer(InvocationOnMock invocation) throws Throwable {
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentType arg = (ArgumentType)invocation.getArguments()[0];
|
||||
return apply.apply(arg);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 RedHat, Inc.
|
||||
* 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:
|
||||
* RedHat, Inc. - initial commit
|
||||
*******************************************************************************/package org.eclipse.che.plugin.testing.ide;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.internal.debugging.MockitoDebuggerImpl;
|
||||
|
||||
/**
|
||||
* Interface that allows printing the invocations made on
|
||||
* all mocked / spied fields.
|
||||
*
|
||||
* @author David Festal
|
||||
*/
|
||||
public interface MockitoPrinter {
|
||||
default void printInvocationsOnAllMockedFields() {
|
||||
new MockitoDebuggerImpl().printInvocations(Arrays.asList(this.getClass().getDeclaredFields()).stream().filter(field -> {
|
||||
return field.isAnnotationPresent(Mock.class);
|
||||
}).map(field -> {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
return field.get(this);
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}).filter(field -> field != null).toArray(Object[]::new));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 RedHat, Inc.
|
||||
* 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:
|
||||
* RedHat, Inc. - initial commit
|
||||
*******************************************************************************/package org.eclipse.che.plugin.testing.ide;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.eclipse.che.api.promises.client.Function;
|
||||
import org.eclipse.che.api.promises.client.Operation;
|
||||
import org.eclipse.che.api.promises.client.OperationException;
|
||||
import org.eclipse.che.api.promises.client.Promise;
|
||||
import org.eclipse.che.api.promises.client.PromiseError;
|
||||
import org.mockito.Matchers;
|
||||
|
||||
/**
|
||||
* Mockito mock provider for Che Promise objects.
|
||||
*
|
||||
* @author David Festal
|
||||
*/
|
||||
public class PromiseMocker<T> {
|
||||
final private Promise<T> promise;
|
||||
|
||||
public PromiseMocker(Promise<T> promise) {
|
||||
this.promise = promise;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public PromiseMocker() {
|
||||
this.promise = (Promise<T>) mock(Promise.class);
|
||||
}
|
||||
|
||||
public Promise<T> getPromise() {
|
||||
return promise;
|
||||
}
|
||||
public <B> PromiseMocker<T> applyOnThenPromise(T value) {
|
||||
when(promise.thenPromise(Matchers.<Function<T, Promise<B>>> any())).then(new FunctionAnswer<Function<T, Promise<B>>, Promise<B>>(function -> {
|
||||
try {
|
||||
return function.apply(value);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
return this;
|
||||
}
|
||||
|
||||
public PromiseMocker<T> applyOnThenOperation(T value) {
|
||||
when(promise.then(Matchers.<Operation<T>> any())).then(new FunctionAnswer<Operation<T>, Promise<T>>( op -> {
|
||||
try {
|
||||
op.apply(value);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return promise;
|
||||
}));
|
||||
return this;
|
||||
}
|
||||
|
||||
public PromiseMocker<T> applyOnCatchErrorOperation(PromiseError error) {
|
||||
when(promise.catchError(Matchers.<Operation<PromiseError>> any())).then(new FunctionAnswer<Operation<PromiseError>, Promise<T>>(op -> {
|
||||
try {
|
||||
op.apply(error);
|
||||
} catch (OperationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return promise;
|
||||
}));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,466 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 RedHat, Inc.
|
||||
* 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:
|
||||
* RedHat, Inc. - initial commit
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.testing.ide;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyMapOf;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.che.api.core.model.machine.Command;
|
||||
import org.eclipse.che.api.core.model.machine.Machine;
|
||||
import org.eclipse.che.api.machine.shared.dto.execagent.ProcessStartResponseDto;
|
||||
import org.eclipse.che.api.machine.shared.dto.execagent.event.DtoWithPid;
|
||||
import org.eclipse.che.api.machine.shared.dto.execagent.event.ProcessDiedEventDto;
|
||||
import org.eclipse.che.api.machine.shared.dto.execagent.event.ProcessStartedEventDto;
|
||||
import org.eclipse.che.api.machine.shared.dto.execagent.event.ProcessStdErrEventDto;
|
||||
import org.eclipse.che.api.machine.shared.dto.execagent.event.ProcessStdOutEventDto;
|
||||
import org.eclipse.che.api.promises.client.Operation;
|
||||
import org.eclipse.che.api.promises.client.OperationException;
|
||||
import org.eclipse.che.api.promises.client.Promise;
|
||||
import org.eclipse.che.api.promises.client.PromiseError;
|
||||
import org.eclipse.che.api.promises.client.PromiseProvider;
|
||||
import org.eclipse.che.api.promises.client.js.Executor;
|
||||
import org.eclipse.che.api.testing.shared.TestResult;
|
||||
import org.eclipse.che.ide.api.app.AppContext;
|
||||
import org.eclipse.che.ide.api.command.CommandImpl;
|
||||
import org.eclipse.che.ide.api.command.CommandManager;
|
||||
import org.eclipse.che.ide.api.machine.DevMachine;
|
||||
import org.eclipse.che.ide.api.machine.ExecAgentCommandManager;
|
||||
import org.eclipse.che.ide.api.machine.execagent.ExecAgentPromise;
|
||||
import org.eclipse.che.ide.api.macro.MacroProcessor;
|
||||
import org.eclipse.che.ide.api.notification.StatusNotification;
|
||||
import org.eclipse.che.ide.dto.DtoFactory;
|
||||
import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandConsoleFactory;
|
||||
import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandOutputConsole;
|
||||
import org.eclipse.che.ide.extension.machine.client.processes.panel.ProcessesPanelPresenter;
|
||||
import org.eclipse.che.ide.rest.AsyncRequestFactory;
|
||||
import org.eclipse.che.ide.rest.DtoUnmarshallerFactory;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Matchers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.Spy;
|
||||
|
||||
import com.google.gwtmockito.GwtMockitoTestRunner;
|
||||
|
||||
/**
|
||||
* Test for the TestServiceClient class.
|
||||
*
|
||||
* @author David Festal
|
||||
*/
|
||||
@RunWith(GwtMockitoTestRunner.class)
|
||||
public class TestServiceClientTest implements MockitoPrinter {
|
||||
|
||||
// Context
|
||||
|
||||
@Mock
|
||||
private AppContext appContext;
|
||||
@Mock
|
||||
private AsyncRequestFactory asyncRequestFactory;
|
||||
@Mock
|
||||
private DtoUnmarshallerFactory dtoUnmarshallerFactory;
|
||||
@Mock
|
||||
private CommandManager commandManager;
|
||||
@Mock
|
||||
private ExecAgentCommandManager execAgentCommandManager;
|
||||
@Mock
|
||||
private PromiseProvider promiseProvider;
|
||||
@Mock
|
||||
private MacroProcessor macroProcessor;
|
||||
@Mock
|
||||
private CommandConsoleFactory commandConsoleFactory;
|
||||
@Mock
|
||||
private ProcessesPanelPresenter processesPanelPresenter;
|
||||
@Mock
|
||||
private DtoFactory dtoFactory;
|
||||
|
||||
@Mock
|
||||
private StatusNotification statusNotification;
|
||||
@Mock
|
||||
private DevMachine devMachine;
|
||||
@Mock
|
||||
private Machine machine;
|
||||
@Mock
|
||||
private CommandOutputConsole commandOutputConsole;
|
||||
|
||||
private TestServiceClient testServiceClient = null;
|
||||
|
||||
@Spy
|
||||
private final List<DtoWithPid> consoleEvents = new ArrayList<>();
|
||||
|
||||
private static final String rootOfProjects = "/projects";
|
||||
private Map<String, String> parameters = new HashMap<>();
|
||||
private String testFramework = "junit";
|
||||
private String projectPath = "sampleProject";
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private Map<Class< ? >, Operation> operationsOnProcessEvents = new HashMap<>();
|
||||
|
||||
@Before
|
||||
public void initMocks() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
testServiceClient = spy(new TestServiceClient(appContext, asyncRequestFactory, dtoUnmarshallerFactory, dtoFactory, commandManager,
|
||||
execAgentCommandManager, promiseProvider, macroProcessor, commandConsoleFactory,
|
||||
processesPanelPresenter));
|
||||
|
||||
doReturn(new PromiseMocker<TestResult>().getPromise()).when(testServiceClient).sendTests(anyString(), anyString(),
|
||||
anyMapOf(String.class, String.class));
|
||||
doAnswer(new FunctionAnswer<Executor.ExecutorBody<TestResult>, Promise<TestResult>>(executorBody -> {
|
||||
ExecutorPromiseMocker<TestResult> mocker = new ExecutorPromiseMocker<TestResult>(executorBody,
|
||||
(testResult, thisMocker) -> {
|
||||
thisMocker.applyOnThenOperation(testResult);
|
||||
return null;
|
||||
},
|
||||
(promiseError, thisMocker) -> {
|
||||
thisMocker.applyOnCatchErrorOperation(promiseError);
|
||||
return null;
|
||||
});
|
||||
|
||||
executorBody.apply(mocker.getResolveFunction(), mocker.getRejectFunction());
|
||||
|
||||
return mocker.getPromise();
|
||||
})).when(testServiceClient).promiseFromExecutorBody(Matchers.<Executor.ExecutorBody<TestResult>> any());
|
||||
|
||||
doAnswer(new FunctionAnswer<Throwable, PromiseError>(throwable -> {
|
||||
PromiseError promiseError = mock(PromiseError.class);
|
||||
when(promiseError.getCause()).thenReturn(throwable);
|
||||
return promiseError;
|
||||
})).when(testServiceClient).promiseFromThrowable(any(Throwable.class));
|
||||
|
||||
when(appContext.getDevMachine()).thenReturn(devMachine);
|
||||
when(machine.getId()).thenReturn("DevMachineId");
|
||||
|
||||
doAnswer(new FunctionAnswer<String, Promise<String>>(commandLine -> {
|
||||
String processedCommandLine = commandLine.replace("${current.project.path}", rootOfProjects + "/" + projectPath);
|
||||
return new PromiseMocker<String>().applyOnThenOperation(processedCommandLine).getPromise();
|
||||
})).when(macroProcessor).expandMacros(anyString());
|
||||
|
||||
when(commandConsoleFactory.create(any(CommandImpl.class), any(Machine.class))).then(createCall -> {
|
||||
CommandOutputConsole commandOutputConsole = mock(CommandOutputConsole.class);
|
||||
when(commandOutputConsole.getProcessStartedOperation()).thenReturn(processStartedEvent -> {
|
||||
consoleEvents.add(processStartedEvent);
|
||||
});
|
||||
when(commandOutputConsole.getProcessDiedOperation()).thenReturn(processDiedEvent -> {
|
||||
consoleEvents.add(processDiedEvent);
|
||||
});
|
||||
when(commandOutputConsole.getStdErrOperation()).thenReturn(processStdErrEvent -> {
|
||||
consoleEvents.add(processStdErrEvent);
|
||||
});
|
||||
when(commandOutputConsole.getStdOutOperation()).thenReturn(processStdOutEvent -> {
|
||||
consoleEvents.add(processStdOutEvent);
|
||||
});
|
||||
return commandOutputConsole;
|
||||
});
|
||||
consoleEvents.clear();
|
||||
|
||||
when(execAgentCommandManager.startProcess(anyString(), any(Command.class))).then(startProcessCall -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
ExecAgentPromise<ProcessStartResponseDto> execAgentPromise =
|
||||
(ExecAgentPromise<ProcessStartResponseDto>)mock(ExecAgentPromise.class);
|
||||
class ProcessEventForward<DtoType> extends FunctionAnswer<Operation<DtoType>, ExecAgentPromise<ProcessStartResponseDto>> {
|
||||
public ProcessEventForward(Class<DtoType> dtoClass) {
|
||||
super(new java.util.function.Function<Operation<DtoType>, ExecAgentPromise<ProcessStartResponseDto>>() {
|
||||
@Override
|
||||
public ExecAgentPromise<ProcessStartResponseDto> apply(Operation<DtoType> op) {
|
||||
operationsOnProcessEvents.put(dtoClass, op);
|
||||
return execAgentPromise;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
when(execAgentPromise.then(any())).then(new ProcessEventForward<>(ProcessStartResponseDto.class));
|
||||
when(execAgentPromise.thenIfProcessStartedEvent(any())).then(new ProcessEventForward<>(ProcessStartedEventDto.class));
|
||||
when(execAgentPromise.thenIfProcessDiedEvent(any())).then(new ProcessEventForward<>(ProcessDiedEventDto.class));
|
||||
when(execAgentPromise.thenIfProcessStdErrEvent(any())).then(new ProcessEventForward<>(ProcessStdErrEventDto.class));
|
||||
when(execAgentPromise.thenIfProcessStdOutEvent(any())).then(new ProcessEventForward<>(ProcessStdOutEventDto.class));
|
||||
|
||||
return execAgentPromise;
|
||||
});
|
||||
operationsOnProcessEvents.clear();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void triggerProcessEvents(DtoWithPid... processEvents) {
|
||||
for (DtoWithPid event : processEvents) {
|
||||
operationsOnProcessEvents.entrySet().stream().filter(entry -> {
|
||||
return entry.getKey().isAssignableFrom(event.getClass());
|
||||
}).map(Map.Entry::getValue).forEach(op -> {
|
||||
try {
|
||||
op.apply(event);
|
||||
} catch (OperationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createCompileCommandFromStandardMavenCommands() {
|
||||
when(commandManager.getCommands()).thenReturn(asList(new CommandImpl("run",
|
||||
"mvn run -f ${current.project.path}",
|
||||
"mvn"),
|
||||
new CommandImpl("build",
|
||||
"mvn clean install -f ${current.project.path}",
|
||||
"mvn")));
|
||||
testServiceClient.getOrCreateTestCompileCommand();
|
||||
verify(commandManager).create("test-compile",
|
||||
"mvn test-compile -f ${current.project.path}",
|
||||
"mvn",
|
||||
Collections.emptyMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createCompileCommandFromSCLEnabledMavenBuildCommand() {
|
||||
when(commandManager.getCommands()).thenReturn(asList(new CommandImpl("build",
|
||||
"scl enable rh-maven33 'mvn clean install -f ${current.project.path}'",
|
||||
"mvn")));
|
||||
testServiceClient.getOrCreateTestCompileCommand();
|
||||
verify(commandManager).create("test-compile",
|
||||
"scl enable rh-maven33 'mvn test-compile -f ${current.project.path}'",
|
||||
"mvn",
|
||||
Collections.emptyMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reuseExistingCompileCommand() {
|
||||
CommandImpl existingCompileCommand = new CommandImpl("test-compile",
|
||||
"mvn test-compile -f ${current.project.path}",
|
||||
"mvn");
|
||||
when(commandManager.getCommands()).thenReturn(asList(new CommandImpl("run",
|
||||
"mvn run -f ${current.project.path}",
|
||||
"mvn"),
|
||||
new CommandImpl("build",
|
||||
"mvn clean install -f ${current.project.path}",
|
||||
"mvn"),
|
||||
existingCompileCommand));
|
||||
|
||||
testServiceClient.getOrCreateTestCompileCommand();
|
||||
|
||||
verify(promiseProvider).resolve(existingCompileCommand);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noBuildCommand() {
|
||||
when(commandManager.getCommands()).thenReturn(asList(new CommandImpl("customBuild",
|
||||
"mvn clean install -f ${current.project.path}",
|
||||
"mvn")));
|
||||
|
||||
testServiceClient.getOrCreateTestCompileCommand();
|
||||
|
||||
verify(promiseProvider).resolve(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildCommandNotAMavenCommand() {
|
||||
when(commandManager.getCommands()).thenReturn(asList(new CommandImpl("build",
|
||||
"mvn clean install -f ${current.project.path}",
|
||||
"someOtherType")));
|
||||
|
||||
testServiceClient.getOrCreateTestCompileCommand();
|
||||
|
||||
verify(promiseProvider).resolve(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mavenBuildCommandHasNoCleanInstallPart() {
|
||||
when(commandManager.getCommands()).thenReturn(asList(new CommandImpl("build",
|
||||
"mvn clean SomeOtherGoalInTeMiddle install -f ${current.project.path}",
|
||||
"mvn")));
|
||||
|
||||
testServiceClient.getOrCreateTestCompileCommand();
|
||||
|
||||
verify(promiseProvider).resolve(null);
|
||||
}
|
||||
|
||||
private Promise<CommandImpl> createCommandPromise(CommandImpl command) {
|
||||
return new PromiseMocker<CommandImpl>().applyOnThenPromise(command).getPromise();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runTestsDirectlyBecauseNoCompilationCommand() {
|
||||
Promise<CommandImpl> compileCommandPromise = createCommandPromise(null);
|
||||
testServiceClient.runTestsAfterCompilation(projectPath, testFramework, parameters, statusNotification, compileCommandPromise);
|
||||
|
||||
verify(statusNotification).setContent("Executing the tests without preliminary compilation.");
|
||||
verify(execAgentCommandManager, never()).startProcess(anyString(), Matchers.<Command> any());
|
||||
verify(testServiceClient).sendTests(projectPath, testFramework, parameters);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runTestsDirectlyBecauseNoDevMachine() {
|
||||
Promise<CommandImpl> compileCommandPromise = createCommandPromise(new CommandImpl("test-compile",
|
||||
"mvn test-compile -f ${current.project.path}",
|
||||
"mvn"));
|
||||
|
||||
when(devMachine.getDescriptor()).thenReturn(null);
|
||||
|
||||
testServiceClient.runTestsAfterCompilation(projectPath, testFramework, parameters, statusNotification, compileCommandPromise);
|
||||
|
||||
verify(statusNotification).setContent("Executing the tests without preliminary compilation.");
|
||||
verify(execAgentCommandManager, never()).startProcess(anyString(), Matchers.<Command> any());
|
||||
verify(testServiceClient).sendTests(projectPath, testFramework, parameters);
|
||||
}
|
||||
|
||||
private ProcessStartResponseDto processStartResponse(boolean alive) {
|
||||
ProcessStartResponseDto event = mock(ProcessStartResponseDto.class);
|
||||
when(event.getAlive()).thenReturn(alive);
|
||||
return event;
|
||||
}
|
||||
|
||||
private ProcessStartedEventDto processStarted() {
|
||||
ProcessStartedEventDto event = mock(ProcessStartedEventDto.class);
|
||||
when(event.toString()).thenReturn("Started");
|
||||
return event;
|
||||
}
|
||||
|
||||
private ProcessDiedEventDto processDied() {
|
||||
ProcessDiedEventDto event = mock(ProcessDiedEventDto.class);
|
||||
when(event.toString()).thenReturn("Died");
|
||||
return event;
|
||||
}
|
||||
|
||||
private ProcessStdErrEventDto processStdErr(final String text) {
|
||||
ProcessStdErrEventDto event = mock(ProcessStdErrEventDto.class);
|
||||
when(event.getText()).thenReturn(text);
|
||||
when(event.toString()).thenReturn("StdErr - " + text);
|
||||
return event;
|
||||
}
|
||||
|
||||
private ProcessStdOutEventDto processStdOut(String text) {
|
||||
ProcessStdOutEventDto event = mock(ProcessStdOutEventDto.class);
|
||||
when(event.getText()).thenReturn(text);
|
||||
when(event.toString()).thenReturn("StdOut - " + text);
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void cancelledTestsBecauseCompilationNotStarted() {
|
||||
Promise<CommandImpl> compileCommandPromise = createCommandPromise(new CommandImpl(
|
||||
"test-compile",
|
||||
"mvn test-compile -f ${current.project.path}",
|
||||
"mvn"));
|
||||
|
||||
when(devMachine.getDescriptor()).thenReturn(machine);
|
||||
|
||||
Promise<TestResult> result = testServiceClient.runTestsAfterCompilation(projectPath, testFramework, parameters, statusNotification,
|
||||
compileCommandPromise);
|
||||
|
||||
triggerProcessEvents(processStartResponse(false));
|
||||
|
||||
verify(testServiceClient, never()).sendTests(anyString(), anyString(), anyMapOf(String.class, String.class));
|
||||
verify(statusNotification).setContent("Compiling the project before starting the test session.");
|
||||
result.catchError(new Operation<PromiseError>() {
|
||||
@Override
|
||||
public void apply(PromiseError promiseError) throws OperationException {
|
||||
Throwable cause = promiseError.getCause();
|
||||
Assert.assertNotNull(cause);
|
||||
Assert.assertEquals(TestServiceClient.PROJECT_BUILD_NOT_STARTED_MESSAGE, cause.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancelledTestsBecauseCompilationFailed() {
|
||||
Promise<CommandImpl> compileCommandPromise = createCommandPromise(new CommandImpl(
|
||||
"test-compile",
|
||||
"mvn test-compile -f ${current.project.path}",
|
||||
"mvn"));
|
||||
|
||||
when(devMachine.getDescriptor()).thenReturn(machine);
|
||||
|
||||
Promise<TestResult> result = testServiceClient.runTestsAfterCompilation(projectPath, testFramework, parameters, statusNotification,
|
||||
compileCommandPromise);
|
||||
|
||||
triggerProcessEvents(processStartResponse(true),
|
||||
processStarted(),
|
||||
processStdErr("A small warning"),
|
||||
processStdOut("BUILD FAILURE"),
|
||||
processDied());
|
||||
|
||||
verify(testServiceClient, never()).sendTests(anyString(), anyString(), anyMapOf(String.class, String.class));
|
||||
verify(statusNotification).setContent("Compiling the project before starting the test session.");
|
||||
result.catchError(new Operation<PromiseError>() {
|
||||
@Override
|
||||
public void apply(PromiseError promiseError) throws OperationException {
|
||||
Throwable cause = promiseError.getCause();
|
||||
Assert.assertNotNull(cause);
|
||||
Assert.assertEquals(TestServiceClient.PROJECT_BUILD_FAILED_MESSAGE, cause.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void sucessfulTestsAfterCompilation() {
|
||||
|
||||
Promise<CommandImpl> compileCommandPromise = createCommandPromise(new CommandImpl(
|
||||
"test-compile",
|
||||
"mvn test-compile -f ${current.project.path}",
|
||||
"mvn"));
|
||||
|
||||
when(devMachine.getDescriptor()).thenReturn(machine);
|
||||
|
||||
Promise<TestResult> resultPromise = testServiceClient.runTestsAfterCompilation(projectPath, testFramework, parameters,
|
||||
statusNotification,
|
||||
compileCommandPromise);
|
||||
|
||||
triggerProcessEvents(processStartResponse(true),
|
||||
processStarted(),
|
||||
processStdErr("A small warning"),
|
||||
processStdOut("BUILD SUCCESS"),
|
||||
processDied());
|
||||
|
||||
verify(testServiceClient).sendTests(projectPath, testFramework, parameters);
|
||||
verify(statusNotification).setContent("Compiling the project before starting the test session.");
|
||||
verify(execAgentCommandManager).startProcess(
|
||||
"DevMachineId",
|
||||
new CommandImpl(
|
||||
"test-compile",
|
||||
"mvn test-compile -f " + rootOfProjects + "/" + projectPath,
|
||||
"mvn"));
|
||||
verify(statusNotification).setContent(TestServiceClient.EXECUTING_TESTS_MESSAGE);
|
||||
resultPromise.then(testResult -> {
|
||||
Assert.assertNotNull(testResult);
|
||||
});
|
||||
|
||||
ArrayList<String> eventStrings = new ArrayList<>();
|
||||
for (DtoWithPid event : consoleEvents) {
|
||||
eventStrings.add(event.toString());
|
||||
}
|
||||
Assert.assertEquals(eventStrings,
|
||||
Arrays.asList("Started",
|
||||
"StdErr - A small warning",
|
||||
"StdOut - BUILD SUCCESS",
|
||||
"Died"));
|
||||
}
|
||||
}
|
||||
|
|
@ -37,5 +37,17 @@
|
|||
<directory>src/main/java</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/**/TestingOutput.java</exclude>
|
||||
<exclude>**/**/Constants.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 RedHat, Inc.
|
||||
* 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:
|
||||
* RedHat, Inc. - initial commit
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.che.api.testing.shared;
|
||||
|
||||
/**
|
||||
* @author David Festal
|
||||
*/
|
||||
public class Constants {
|
||||
|
||||
/** Name of WebSocket channel for the Testing output */
|
||||
public final static String TESTING_OUTPUT_CHANNEL_NAME = "testing:output";
|
||||
|
||||
private Constants() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 RedHat, Inc.
|
||||
* 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:
|
||||
* RedHat, Inc. - initial commit
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.api.testing.shared;
|
||||
|
||||
import org.eclipse.che.dto.shared.DTO;
|
||||
|
||||
/**
|
||||
* Provide the output of Testing tools.
|
||||
*
|
||||
* @author David Festal
|
||||
*/
|
||||
@DTO
|
||||
public interface TestingOutput {
|
||||
|
||||
enum LineType {
|
||||
SESSION_START,
|
||||
DETAIL,
|
||||
SUCCESS,
|
||||
ERROR,
|
||||
FAILURE,
|
||||
SESSION_END,
|
||||
}
|
||||
|
||||
/**
|
||||
* Output line
|
||||
* @return
|
||||
*/
|
||||
String getOutput();
|
||||
|
||||
/**
|
||||
* for a success notification line will be State.SUCCESS
|
||||
* for a failure notification line will be State.FAILURE
|
||||
* for an error notification will be State.ERROR
|
||||
* for all other lines will be State.DETAIL
|
||||
* @return
|
||||
*/
|
||||
LineType getState();
|
||||
|
||||
}
|
||||
|
|
@ -111,6 +111,15 @@
|
|||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/**/TestingOutputImpl.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-dto-maven-plugin</artifactId>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 RedHat, Inc.
|
||||
* 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:
|
||||
* RedHat, Inc. - initial commit
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.api.testing.server.handler;
|
||||
|
||||
import org.eclipse.che.api.testing.shared.TestingOutput;
|
||||
|
||||
/**
|
||||
* @author David Festal
|
||||
*/
|
||||
public class TestingOutputImpl implements TestingOutput {
|
||||
|
||||
public TestingOutputImpl(String output, LineType lineType) {
|
||||
this.output = output;
|
||||
this.lineType = lineType;
|
||||
}
|
||||
|
||||
private String output;
|
||||
private LineType lineType;
|
||||
|
||||
@Override
|
||||
public String getOutput() {
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LineType getState() {
|
||||
return lineType;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue