From 02ae5f29c1da7bcbcaf82076e6f38dd8c1128096 Mon Sep 17 00:00:00 2001 From: davidfestal Date: Wed, 22 Feb 2017 18:39:11 +0100 Subject: [PATCH 01/22] Provide JUnit test real-time output in a `Tests` output view. Signed-off-by: davidfestal --- .../che-plugin-testing-junit-server/pom.xml | 18 +++ .../junit/server/AbstractTestListener.java | 91 +++++++++++ .../testing/junit/server/JUnitTestRunner.java | 151 +++++++++++++++++- .../junit/server/OutputTestListener.java | 102 ++++++++++++ .../che-plugin-testing-ide/pom.xml | 13 ++ .../plugin/testing/ide/TestingExtension.java | 4 +- .../testing/ide/handler/TestingHandler.java | 116 ++++++++++++++ wsagent/che-core-api-testing-shared/pom.xml | 12 ++ .../che/api/testing/shared/Constants.java | 25 +++ .../che/api/testing/shared/TestingOutput.java | 45 ++++++ wsagent/che-core-api-testing/pom.xml | 9 ++ .../server/handler/TestingOutputImpl.java | 37 +++++ 12 files changed, 616 insertions(+), 7 deletions(-) create mode 100644 plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/AbstractTestListener.java create mode 100644 plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/OutputTestListener.java create mode 100644 plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java create mode 100644 wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/Constants.java create mode 100644 wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/TestingOutput.java create mode 100644 wsagent/che-core-api-testing/src/main/java/org/eclipse/che/api/testing/server/handler/TestingOutputImpl.java diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml index 4f47d70269e..ab3ac608b56 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml @@ -33,6 +33,10 @@ javax.inject javax.inject + + org.eclipse.che.core + che-core-api-core + org.eclipse.che.core che-core-api-dto @@ -58,4 +62,18 @@ che-plugin-testing-classpath-server + + + + com.mycila + license-maven-plugin + + + **/**/AbstractTestListener.java + **/**/OutputTestListener.java + + + + + diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/AbstractTestListener.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/AbstractTestListener.java new file mode 100644 index 00000000000..fc8420103ea --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/AbstractTestListener.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * 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; + +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 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); + } +} \ No newline at end of file diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java index f76dbed8d7c..eb48656b5a4 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java @@ -13,7 +13,9 @@ import java.io.File; import java.lang.annotation.Annotation; import java.lang.reflect.Array; +import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; @@ -45,6 +47,7 @@ * * * @author Mirage Abeysekara + * @author David Festal */ public class JUnitTestRunner implements TestRunner { @@ -148,6 +151,67 @@ private boolean isTestable4x(Class clazz) throws ClassNotFoundException { return false; } + private Object create4xTestListener(ClassLoader loader, Class listenerClass, AbstractTestListener delegate) { + return Proxy.newProxyInstance(loader, new Class[] {listenerClass}, new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String methodName = method.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; + } + + if (description == null || throwable == null) { + return null; + } + + String testKey = (String) description.getClass().getMethod("getDisplayName", new Class[0]).invoke(args[0]); + 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) args[1]); + break; + + case "equals": + if (Proxy.isProxyClass(args[0].getClass())) { + return this.equals(Proxy.getInvocationHandler(args[0])); + } else { + return false; + } + + case "hasCode": + return this.hashCode(); + } + + return null; + } + }); + } + private TestResult run4xTestClasses(Class... classes) throws Exception { ClassLoader classLoader = projectClassLoader; Class clsJUnitCore = Class.forName("org.junit.runner.JUnitCore", true, classLoader); @@ -156,7 +220,22 @@ private TestResult run4xTestClasses(Class... classes) throws Exception { 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 clsTestRunner = Class.forName("org.junit.runner.notification.RunListener", true, classLoader); + + Object result; + try(OutputTestListener outputListener = new OutputTestListener(this.getClass().getName()+".run4xTestClasses")) { + Object testListener = create4xTestListener(classLoader, clsTestRunner, outputListener); + try { + clsJUnitCore.getMethod("addListener", clsTestRunner).invoke(testListener); + result = clsJUnitCore.getMethod("runClasses", Class[].class).invoke(null, new Object[] { classes }); + } + finally { + if (testListener != null) { + clsJUnitCore.getMethod("removeListener", clsTestRunner).invoke(testListener); + } + } + } + TestResult dtoResult = DtoFactory.getInstance().createDto(TestResult.class); boolean isSuccess = (Boolean) clsResult.getMethod("wasSuccessful").invoke(result); List failures = (List) clsResult.getMethod("getFailures").invoke(result); @@ -230,6 +309,50 @@ private boolean isTestable3x(Class clazz) throws ClassNotFoundException { return superClass.isAssignableFrom(clazz); } + private Object create3xTestListener(ClassLoader loader, Class listenerClass, AbstractTestListener delegate) { + return Proxy.newProxyInstance(loader, new Class[] {listenerClass}, new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, 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; + + case "equals": + if (Proxy.isProxyClass(args[0].getClass())) { + return this.equals(Proxy.getInvocationHandler(args[0])); + } else { + return false; + } + + case "hasCode": + return this.hashCode(); + } + + return null; + } + }); + } + + // TODO : Do the same thing on JUnit 4 tests + // Look into the fact that we might use the Java model to get the classpath (or better, the ClasspathService) + // Commit knowing that the tests are missing + // Test VertX private TestResult run3xTestClasses(Class... classes) throws Exception { ClassLoader classLoader = projectClassLoader; Class clsTestSuite = Class.forName("junit.framework.TestSuite", true, classLoader); @@ -237,12 +360,28 @@ private TestResult run3xTestClasses(Class... classes) throws Exception { 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); + 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); + clsTestResult.getMethod("addListener", clsTestListener).invoke( + testResult, testListener); + try { + for (Class testClass : classes) { + clsTestSuite.getMethod("addTestSuite", Class.class).invoke(testSuite, testClass); + } + + clsTestSuite.getMethod("run", clsTestResult).invoke(testSuite, testResult); + } + finally { + if (testListener != null) { + 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); diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/OutputTestListener.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/OutputTestListener.java new file mode 100644 index 00000000000..3012774864a --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/OutputTestListener.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * 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; + +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.eclipse.che.plugin.testing.junit.server.AbstractTestListener.TestSummary; + +/** + * 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 WebsocketMessageConsumer consumer = new WebsocketMessageConsumer<>(TESTING_OUTPUT_CHANNEL_NAME) ; + private String stackTraceRoot; + + public OutputTestListener(String strackTraceRoot) { + this.stackTraceRoot = strackTraceRoot; + } + + private void writeLine(String line, TestingOutput.LineType lineType) { + try { + consumer.consume(DtoFactory.cloneDto(new TestingOutputImpl(line, lineType))); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + public void close() throws Exception { + 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); + } +} \ No newline at end of file diff --git a/plugins/plugin-testing/che-plugin-testing-ide/pom.xml b/plugins/plugin-testing/che-plugin-testing-ide/pom.xml index 8a422f31e84..bb2459ac45d 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/pom.xml +++ b/plugins/plugin-testing/che-plugin-testing-ide/pom.xml @@ -72,6 +72,10 @@ org.eclipse.che.plugin che-plugin-java-ext-lang-client + + org.eclipse.che.plugin + che-plugin-machine-ext-client + org.eclipse.che.plugin che-plugin-maven-shared @@ -117,6 +121,15 @@ + + com.mycila + license-maven-plugin + + + **/**/TestingHandler.java + + + org.apache.maven.plugins maven-dependency-plugin diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestingExtension.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestingExtension.java index 5f8e0e7e17b..7bc0ebf1611 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestingExtension.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestingExtension.java @@ -18,6 +18,7 @@ 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 testActions) { + Set testActions, + TestingHandler testingHandler) { DefaultActionGroup runMenu = (DefaultActionGroup) actionManager.getAction(GROUP_RUN); DefaultActionGroup testMainMenu = new DefaultActionGroup(localization.actionGroupMenuName(), true, actionManager); diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java new file mode 100644 index 00000000000..49a8b3dbc19 --- /dev/null +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * 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() { + @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); + processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), outputConsole); + switch (archetypeOutput.getState()) { + 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(); + } + } + +} diff --git a/wsagent/che-core-api-testing-shared/pom.xml b/wsagent/che-core-api-testing-shared/pom.xml index 2f8324dd354..660915003b7 100644 --- a/wsagent/che-core-api-testing-shared/pom.xml +++ b/wsagent/che-core-api-testing-shared/pom.xml @@ -37,5 +37,17 @@ src/main/java + + + com.mycila + license-maven-plugin + + + **/**/TestingOutput.java + **/**/Constants.java + + + + diff --git a/wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/Constants.java b/wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/Constants.java new file mode 100644 index 00000000000..82f0d3ff96c --- /dev/null +++ b/wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/Constants.java @@ -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() { + } + +} diff --git a/wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/TestingOutput.java b/wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/TestingOutput.java new file mode 100644 index 00000000000..87265e669ab --- /dev/null +++ b/wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/TestingOutput.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * 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 { + DETAIL, + SUCCESS, + ERROR, + FAILURE + } + + /** + * 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(); + +} diff --git a/wsagent/che-core-api-testing/pom.xml b/wsagent/che-core-api-testing/pom.xml index ff84068485c..730e6b3dd6c 100644 --- a/wsagent/che-core-api-testing/pom.xml +++ b/wsagent/che-core-api-testing/pom.xml @@ -111,6 +111,15 @@ + + com.mycila + license-maven-plugin + + + **/**/TestingOutputImpl.java + + + org.eclipse.che.core che-core-api-dto-maven-plugin diff --git a/wsagent/che-core-api-testing/src/main/java/org/eclipse/che/api/testing/server/handler/TestingOutputImpl.java b/wsagent/che-core-api-testing/src/main/java/org/eclipse/che/api/testing/server/handler/TestingOutputImpl.java new file mode 100644 index 00000000000..95dfc4503fa --- /dev/null +++ b/wsagent/che-core-api-testing/src/main/java/org/eclipse/che/api/testing/server/handler/TestingOutputImpl.java @@ -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; + } +} From cc4469a44a16914656af98ed5da145fe941d7813 Mon Sep 17 00:00:00 2001 From: David Festal Date: Fri, 24 Feb 2017 20:24:33 +0100 Subject: [PATCH 02/22] - Use Javassit to correctly create the test listeners for JUnit (JUnit 4 `RunListener` is a class, not an interface, so that and simple `Proxy` cannot be used. - Set the thread context classloader to the project classloader during the time of the test (required for VertX support for example) - Add test session start and stop events in the `AbstractTestListener` - Clear the `Tests` output view when a new test is started Signed-off-by: David Festal --- .../che-plugin-testing-junit-server/pom.xml | 4 + .../testing/junit/server/JUnitTestRunner.java | 198 +++++++++++------- .../{ => listener}/AbstractTestListener.java | 2 +- .../{ => listener}/OutputTestListener.java | 5 +- .../testing/ide/handler/TestingHandler.java | 2 + .../che/api/testing/shared/TestingOutput.java | 4 +- 6 files changed, 132 insertions(+), 83 deletions(-) rename plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/{ => listener}/AbstractTestListener.java (97%) rename plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/{ => listener}/OutputTestListener.java (93%) diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml index ab3ac608b56..d7c11112c81 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml @@ -61,6 +61,10 @@ org.eclipse.che.plugin che-plugin-testing-classpath-server + + org.javassist + javassist + diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java index eb48656b5a4..91ec041a3f5 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java @@ -13,12 +13,12 @@ import java.io.File; import java.lang.annotation.Annotation; import java.lang.reflect.Array; -import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; -import java.lang.reflect.Proxy; +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; @@ -32,6 +32,12 @@ 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. @@ -77,32 +83,53 @@ public TestResult execute(Map testParameters) throws Exception { 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, 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; + } + } + + TestResult testResult; + if (runClass) { + String fqn = testParameters.get("fqn"); + testResult = useJUnitV3API ? run3x(fqn) : run4x(fqn); + } else { + testResult = useJUnitV3API ? runAll3x(projectAbsolutePath) : runAll4x(projectAbsolutePath); + } + return testResult; } /** @@ -151,11 +178,28 @@ private boolean isTestable4x(Class clazz) throws ClassNotFoundException { return false; } - private Object create4xTestListener(ClassLoader loader, Class listenerClass, AbstractTestListener delegate) { - return Proxy.newProxyInstance(loader, new Class[] {listenerClass}, new InvocationHandler() { - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - String methodName = method.getName(); + 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; @@ -170,15 +214,12 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl 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; } - - if (description == null || throwable == null) { - return null; - } - String testKey = (String) description.getClass().getMethod("getDisplayName", new Class[0]).invoke(args[0]); + String testKey = (String) description.getClass().getMethod("getDisplayName", new Class[0]).invoke(description); String testName = testKey; - switch (methodName) { case "testStarted": delegate.startTest(testKey, testName); @@ -193,23 +234,15 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl break; case "testAssumptionFailure": - delegate.addError(testKey, (Throwable) args[1]); + delegate.addError(testKey, throwable); break; - - case "equals": - if (Proxy.isProxyClass(args[0].getClass())) { - return this.equals(Proxy.getInvocationHandler(args[0])); - } else { - return false; - } - - case "hasCode": - return this.hashCode(); - } - + } return null; } - }); + }; + Object listener = c.getConstructor().newInstance(); + ((javassist.util.proxy.Proxy)listener).setHandler(mi); + return listener; } private TestResult run4xTestClasses(Class... classes) throws Exception { @@ -221,18 +254,20 @@ private TestResult run4xTestClasses(Class... classes) throws Exception { 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 { - clsJUnitCore.getMethod("addListener", clsTestRunner).invoke(testListener); - result = clsJUnitCore.getMethod("runClasses", Class[].class).invoke(null, new Object[] { classes }); + Thread.currentThread().setContextClassLoader(projectClassLoader); + clsJUnitCore.getMethod("addListener", clsTestRunner).invoke(jUnitCore, testListener); + result = clsJUnitCore.getMethod("run", Class[].class).invoke(jUnitCore, new Object[] { classes }); } finally { - if (testListener != null) { - clsJUnitCore.getMethod("removeListener", clsTestRunner).invoke(testListener); - } + Thread.currentThread().setContextClassLoader(tccl); + clsJUnitCore.getMethod("removeListener", clsTestRunner).invoke(jUnitCore, testListener); } } @@ -309,10 +344,27 @@ private boolean isTestable3x(Class clazz) throws ClassNotFoundException { return superClass.isAssignableFrom(clazz); } - private Object create3xTestListener(ClassLoader loader, Class listenerClass, AbstractTestListener delegate) { - return Proxy.newProxyInstance(loader, new Class[] {listenerClass}, new InvocationHandler() { - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + 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(); @@ -332,27 +384,15 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl case "addFailure": delegate.addFailure(testKey, (Throwable) args[1]); break; - - case "equals": - if (Proxy.isProxyClass(args[0].getClass())) { - return this.equals(Proxy.getInvocationHandler(args[0])); - } else { - return false; - } - - case "hasCode": - return this.hashCode(); - } - - return null; + } + return null; } - }); + }; + Object listener = c.getConstructor().newInstance(); + ((javassist.util.proxy.Proxy)listener).setHandler(mi); + return listener; } - // TODO : Do the same thing on JUnit 4 tests - // Look into the fact that we might use the Java model to get the classpath (or better, the ClasspathService) - // Commit knowing that the tests are missing - // Test VertX private TestResult run3xTestClasses(Class... classes) throws Exception { ClassLoader classLoader = projectClassLoader; Class clsTestSuite = Class.forName("junit.framework.TestSuite", true, classLoader); @@ -366,20 +406,20 @@ private TestResult run3xTestClasses(Class... classes) throws Exception { try(OutputTestListener outputListener = new OutputTestListener(this.getClass().getName()+".run3xTestClasses")) { Object testListener = create3xTestListener(classLoader, clsTestListener, outputListener); - clsTestResult.getMethod("addListener", clsTestListener).invoke( - testResult, testListener); - try { + 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 { - if (testListener != null) { - clsTestResult.getMethod("removeListener", clsTestListener).invoke( - testResult, testListener); - } + Thread.currentThread().setContextClassLoader(tccl); + clsTestResult.getMethod("removeListener", clsTestListener).invoke( + testResult, testListener); } } TestResult dtoResult = DtoFactory.getInstance().createDto(TestResult.class); diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/AbstractTestListener.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/AbstractTestListener.java similarity index 97% rename from plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/AbstractTestListener.java rename to plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/AbstractTestListener.java index fc8420103ea..b2600473d0c 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/AbstractTestListener.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/AbstractTestListener.java @@ -8,7 +8,7 @@ * Contributors: * RedHat, Inc. - initial commit *******************************************************************************/ -package org.eclipse.che.plugin.testing.junit.server; +package org.eclipse.che.plugin.testing.junit.server.listener; import java.util.HashMap; diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/OutputTestListener.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java similarity index 93% rename from plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/OutputTestListener.java rename to plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java index 3012774864a..cf0344e9f5f 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/OutputTestListener.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java @@ -8,7 +8,7 @@ * Contributors: * RedHat, Inc. - initial commit *******************************************************************************/ -package org.eclipse.che.plugin.testing.junit.server; +package org.eclipse.che.plugin.testing.junit.server.listener; import static org.eclipse.che.api.testing.shared.Constants.TESTING_OUTPUT_CHANNEL_NAME; @@ -20,7 +20,6 @@ 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.eclipse.che.plugin.testing.junit.server.AbstractTestListener.TestSummary; /** * Listener for the testing services to report their progress to the Che output view. @@ -33,6 +32,7 @@ public class OutputTestListener extends AbstractTestListener implements AutoClos public OutputTestListener(String strackTraceRoot) { this.stackTraceRoot = strackTraceRoot; + writeLine("Starting Test Session", TestingOutput.LineType.SESSION_START); } private void writeLine(String line, TestingOutput.LineType lineType) { @@ -46,6 +46,7 @@ private void writeLine(String line, TestingOutput.LineType lineType) { @Override public void close() throws Exception { + writeLine("Finished Test Session", TestingOutput.LineType.SESSION_END); consumer.close(); } diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java index 49a8b3dbc19..13c87b2d8b6 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java @@ -91,6 +91,8 @@ public void onMessage(String message) { TestingOutput archetypeOutput = factory.createDtoFromJson(message, TestingOutput.class); processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), outputConsole); switch (archetypeOutput.getState()) { + case SESSION_START: + outputConsole.clearOutputsButtonClicked(); case DETAIL: outputConsole.printText(archetypeOutput.getOutput()); break; diff --git a/wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/TestingOutput.java b/wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/TestingOutput.java index 87265e669ab..913c0e6e5ed 100644 --- a/wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/TestingOutput.java +++ b/wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/TestingOutput.java @@ -21,10 +21,12 @@ public interface TestingOutput { enum LineType { + SESSION_START, DETAIL, SUCCESS, ERROR, - FAILURE + FAILURE, + SESSION_END, } /** From a2316bfe5da399b3f545364b4ee758ba571ed9eb Mon Sep 17 00:00:00 2001 From: David Festal Date: Tue, 28 Feb 2017 15:31:49 +0100 Subject: [PATCH 03/22] Try using the ClasspathService instead of Maven ... ... to retrieve the Java project classpath. Signed-off-by: David Festal --- .../pom.xml | 4 + .../server/MavenTestClasspathProvider.java | 76 +++++++++++++++++-- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/pom.xml b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/pom.xml index 4e651875749..86eda59010e 100644 --- a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/pom.xml +++ b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/pom.xml @@ -37,6 +37,10 @@ org.eclipse.che.core che-core-commons-inject + + org.eclipse.che.plugin + che-plugin-java-ext-lang-server + org.eclipse.che.plugin che-plugin-testing-classpath-server diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java index 7c756b21f22..bcefcd519bb 100644 --- a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java +++ b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java @@ -10,20 +10,30 @@ *******************************************************************************/ 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.Collections; import java.util.List; +import java.util.stream.Collectors; +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.ClasspathService; import org.eclipse.che.plugin.testing.classpath.server.TestClasspathProvider; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +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. @@ -31,8 +41,14 @@ * @author Mirage Abeysekara */ public class MavenTestClasspathProvider implements TestClasspathProvider { - - /** + private ClasspathService classpathService; + + @Inject + public MavenTestClasspathProvider(ClasspathService classpathService) { + this.classpathService = classpathService; + } + + /** * {@inheritDoc} */ @Override @@ -72,8 +88,52 @@ private boolean buildClasspath(String projectPath) throws IOException, Interrupt } + private Stream toResolvedClassPath(Stream rawClasspath) { + return rawClasspath.flatMap(dto -> { + if (dto.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { + return toResolvedClassPath(dto.getExpandedEntries().stream()); + } else { + return Stream.of(dto); + } + }); + } + private List getProjectClasspath(String projectPath) throws IOException { - List classUrls = new ArrayList<>(); + String relativeProject = projectPath.substring(ResourcesPlugin.getPathToWorkspace().length()); + try { + IContainer root = ResourcesPlugin.getWorkspace().getRoot(); + return toResolvedClassPath(classpathService.getClasspath(relativeProject).stream()) + .map(dto -> { + try { + String dtoPath = dto.getPath(); + File path; + switch(dto.getEntryKind()) { + case IClasspathEntry.CPE_LIBRARY: + IResource res = root.findMember(new Path(dtoPath)); + if (res == null) { + path = new File(dtoPath); + break; + } + case IClasspathEntry.CPE_SOURCE: + path = new File(root.getLocation().toFile(), dtoPath); + break; + default: + path = new File(dtoPath); + } + return path.toURI().toURL(); + } catch (MalformedURLException e) { + return null; + } + }) + .filter(url -> url != null) + .collect(Collectors.toList()); + } catch (JavaModelException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return Collections.emptyList(); +/* + List classUrls = new ArrayList<>(); File cpFile = Paths.get(projectPath, "target", "test.classpath.maven").toFile(); FileReader fileReader = new FileReader(cpFile); BufferedReader bufferedReader = new BufferedReader(fileReader); @@ -84,8 +144,10 @@ private List getProjectClasspath(String projectPath) throws IOException { } 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; +*/ } } From 6cdbd060988bd3c7fa16a1f184ac3eefce53dabb Mon Sep 17 00:00:00 2001 From: David Festal Date: Wed, 1 Mar 2017 16:02:53 +0100 Subject: [PATCH 04/22] Only add the Command output at test session start. This avoids blinking each time a line is added. Signed-off-by: David Festal --- .../eclipse/che/plugin/testing/ide/handler/TestingHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java index 13c87b2d8b6..f4da85b3166 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java @@ -89,9 +89,9 @@ private void handleTestingOutput(final MessageBus messageBus) { public void onMessage(String message) { Log.info(getClass(), message); TestingOutput archetypeOutput = factory.createDtoFromJson(message, TestingOutput.class); - processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), outputConsole); switch (archetypeOutput.getState()) { case SESSION_START: + processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), outputConsole); outputConsole.clearOutputsButtonClicked(); case DETAIL: outputConsole.printText(archetypeOutput.getOutput()); From c2a7241a0d8e65779cee50244a63105d871e407b Mon Sep 17 00:00:00 2001 From: David Festal Date: Wed, 1 Mar 2017 16:09:03 +0100 Subject: [PATCH 05/22] Set the current working directory to the project root during test This is necessary for all the tests that, usually started with `mvn`, assume they are started in the project root directory, and have all write permissions on the current directory. Without this commit Vertx tests fail with an `IllegateStateException` because Vertx cannot create its cache directory in the current working directory (see https://github.com/mlabuda/vertx-with-che for a vertX test project). Signed-off-by: David Festal --- .../testing/junit/server/JUnitTestRunner.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java index 91ec041a3f5..738a653ecae 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java @@ -122,14 +122,20 @@ protected Class findClass(String name) throws ClassNotFoundException { } } - TestResult testResult; - if (runClass) { - String fqn = testParameters.get("fqn"); - testResult = useJUnitV3API ? run3x(fqn) : run4x(fqn); - } else { - testResult = useJUnitV3API ? runAll3x(projectAbsolutePath) : runAll4x(projectAbsolutePath); + 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); } - return testResult; } /** From b36c5ec5732ebea4683c1448ea1b9468442c5f94 Mon Sep 17 00:00:00 2001 From: David Festal Date: Wed, 1 Mar 2017 16:12:34 +0100 Subject: [PATCH 06/22] Use `ClasspathService` instead of running the maven dependencies plugin in order to build the classpath required to run tests. This is much faster. Signed-off-by: David Festal --- .../server/MavenTestClasspathProvider.java | 123 +++++++----------- 1 file changed, 45 insertions(+), 78 deletions(-) diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java index bcefcd519bb..1d88bb3eaf0 100644 --- a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java +++ b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java @@ -11,24 +11,19 @@ package org.eclipse.che.plugin.testing.classpath.maven.server; import java.io.File; -import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; +import java.nio.file.Paths; 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.ClasspathService; import org.eclipse.che.plugin.testing.classpath.server.TestClasspathProvider; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IResource; 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; @@ -39,6 +34,8 @@ * Maven implementation for the test classpath provider. * * @author Mirage Abeysekara + * @author David Festal + * */ public class MavenTestClasspathProvider implements TestClasspathProvider { private ClasspathService classpathService; @@ -53,16 +50,11 @@ public MavenTestClasspathProvider(ClasspathService classpathService) { */ @Override public ClassLoader getClassLoader(String projectPath, boolean updateClasspath) throws Exception { - List classUrls; 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(projectPath).toArray(URL[]::new), null); + } catch (JavaModelException e) { + throw new Exception("Failed to build the classpath for testing project: " + projectPath, e); } - return new URLClassLoader(classUrls.toArray(new URL[classUrls.size()]), null); } /** @@ -73,21 +65,6 @@ public String getProjectType() { 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 toResolvedClassPath(Stream rawClasspath) { return rawClasspath.flatMap(dto -> { if (dto.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { @@ -98,56 +75,46 @@ private Stream toResolvedClassPath(Stream }); } - private List getProjectClasspath(String projectPath) throws IOException { + private Stream getProjectClasspath(String projectPath) throws JavaModelException { String relativeProject = projectPath.substring(ResourcesPlugin.getPathToWorkspace().length()); - try { - IContainer root = ResourcesPlugin.getWorkspace().getRoot(); - return toResolvedClassPath(classpathService.getClasspath(relativeProject).stream()) - .map(dto -> { - try { - String dtoPath = dto.getPath(); - File path; - switch(dto.getEntryKind()) { - case IClasspathEntry.CPE_LIBRARY: - IResource res = root.findMember(new Path(dtoPath)); - if (res == null) { - path = new File(dtoPath); - break; - } - case IClasspathEntry.CPE_SOURCE: - path = new File(root.getLocation().toFile(), dtoPath); - break; - default: + IContainer root = ResourcesPlugin.getWorkspace().getRoot(); + return toResolvedClassPath(classpathService.getClasspath(relativeProject).stream()) + .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 = new File(root.getLocation().toFile(), dtoPath); } - return path.toURI().toURL(); - } catch (MalformedURLException e) { - return null; - } - }) - .filter(url -> url != null) - .collect(Collectors.toList()); - } catch (JavaModelException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return Collections.emptyList(); -/* - List 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; -*/ + break; + case IClasspathEntry.CPE_SOURCE: + IPath projectRelativePath = new Path(dtoPath).removeFirstSegments(1); + String projectRelativePathStr = projectRelativePath.toString(); + switch(projectRelativePathStr) { + case "src/main/java": + path = Paths.get(projectPath, "target", "classes").toFile(); + break; + case "src/test/java": + path = Paths.get(projectPath, "target", "test-classes").toFile(); + break; + default: + path = new File(root.getLocation().toFile(), dtoPath); + } + break; + default: + path = new File(dtoPath); + } + return path.toURI().toURL(); + } catch (MalformedURLException e) { + return null; + } + }) + .filter(url -> url != null) + .distinct(); } } From c7a7fc8dd0c903723bd97cd74a7e9c0ebdd8f6c4 Mon Sep 17 00:00:00 2001 From: David Festal Date: Wed, 1 Mar 2017 19:01:52 +0100 Subject: [PATCH 07/22] Abstract the real test run in a single class used by all action classes Signed-off-by: David Festal --- .../pom.xml | 16 +++- .../junit/ide/action/RunAllTestAction.java | 66 ++++++--------- .../ide/action/RunClassContextTestAction.java | 65 ++++++--------- .../junit/ide/action/RunClassTestAction.java | 66 ++++++--------- .../ide/action/RunTestActionDelegate.java | 82 +++++++++++++++++++ 5 files changed, 175 insertions(+), 120 deletions(-) create mode 100644 plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/pom.xml b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/pom.xml index 86eda59010e..3a1000bfd9a 100644 --- a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/pom.xml +++ b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/pom.xml @@ -30,20 +30,32 @@ guice-multibindings - org.eclipse.che.core - che-core-api-core + org.eclipse.birt.runtime + org.eclipse.equinox.common org.eclipse.che.core che-core-commons-inject + + org.eclipse.che.lib + org-eclipse-jdt-core-repack + org.eclipse.che.plugin che-plugin-java-ext-lang-server + + org.eclipse.che.plugin + che-plugin-java-ext-lang-shared + org.eclipse.che.plugin che-plugin-testing-classpath-server + + org.eclipse.che.plugin + org.eclipse.core.resources + diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunAllTestAction.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunAllTestAction.java index cce6e1bb5ab..cbc3bc2188c 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunAllTestAction.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunAllTestAction.java @@ -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; @@ -40,12 +29,15 @@ /** * * @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 RunTestActionDelegate delegate; @Inject public RunAllTestAction(JUnitTestResources resources, @@ -61,38 +53,32 @@ public RunAllTestAction(JUnitTestResources resources, 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 parameters = new HashMap<>(); - parameters.put("updateClasspath", "true"); - Promise testResultPromise = service.getTestResult(project.getPath(), "junit", parameters); - testResultPromise.then(new Operation() { - @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() { - @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; + } } diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassContextTestAction.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassContextTestAction.java index 8954cafc98f..6aa2f2df980 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassContextTestAction.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassContextTestAction.java @@ -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 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; @@ -48,14 +37,17 @@ /** * * @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 RunTestActionDelegate delegate; @Inject public RunClassContextTestAction(JUnitTestResources resources, @@ -72,45 +64,20 @@ public RunClassContextTestAction(JUnitTestResources resources, 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 Object possibleNode = selection.getHeadElement(); if (possibleNode instanceof FileNode) { VirtualFile file = ((FileNode) possibleNode).getData(); - final Project project = appContext.getRootProject(); String fqn = JavaUtil.resolveFQN(file); Map parameters = new HashMap<>(); parameters.put("fqn", fqn); parameters.put("runClass", "true"); - parameters.put("updateClasspath", "true"); - Promise testResultPromise = service.getTestResult(project.getPath(), "junit", parameters); - testResultPromise.then(new Operation() { - @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() { - @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); } } @@ -135,4 +102,24 @@ public void updateInPerspective(@NotNull ActionEvent e) { && "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; + } } diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassTestAction.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassTestAction.java index 511a10bb578..be96f128125 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassTestAction.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassTestAction.java @@ -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; @@ -43,13 +32,16 @@ /** * * @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 RunTestActionDelegate delegate; @Inject public RunClassTestAction(JUnitTestResources resources, @@ -65,13 +57,11 @@ public RunClassTestAction(JUnitTestResources resources, 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 +69,7 @@ public void actionPerformed(ActionEvent e) { parameters.put("fqn", fqn); parameters.put("runClass", "true"); parameters.put("updateClasspath", "true"); - Promise testResultPromise = service.getTestResult(project.getPath(), "junit", parameters); - testResultPromise.then(new Operation() { - @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() { - @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 +77,24 @@ protected void updateProjectAction(ActionEvent e) { 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; + } } diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java new file mode 100644 index 00000000000..a6fa87c4e1b --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * 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 { + 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 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 testResultPromise = source.getService().getTestResult(project.getPath(), "junit", parameters); + testResultPromise.then(new Operation() { + @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() { + @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); + } + }); + } +} From 0f430e45df7952dbbd63508da37b75914117e936 Mon Sep 17 00:00:00 2001 From: dfestal Date: Fri, 3 Mar 2017 15:19:07 +0100 Subject: [PATCH 08/22] Fix format Signed-off-by: David Festal --- .../testing/junit/server/JUnitTestRunner.java | 386 +++++++++--------- .../server/listener/AbstractTestListener.java | 151 +++---- .../server/listener/OutputTestListener.java | 135 +++--- 3 files changed, 339 insertions(+), 333 deletions(-) diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java index 738a653ecae..61a78595c56 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java @@ -57,10 +57,10 @@ */ 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 @@ -83,23 +83,23 @@ public TestResult execute(Map testParameters) throws Exception { if (projectManager != null) { projectType = projectManager.getProject(projectPath).getType(); } - + ClassLoader currentClassLoader = this.getClass().getClassLoader(); TestClasspathProvider classpathProvider = classpathRegistry.getTestClasspathProvider(projectType); - URLClassLoader providedClassLoader = (URLClassLoader) classpathProvider.getClassLoader(projectAbsolutePath, updateClasspath); + URLClassLoader providedClassLoader = (URLClassLoader)classpathProvider.getClassLoader(projectAbsolutePath, 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; + @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); isJUnit4Compatible = true; @@ -111,17 +111,17 @@ protected Class findClass(String name) throws ClassNotFoundException { isJUnit3Compatible = true; } catch (Exception ignored) { } - + 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; - } + 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); @@ -148,7 +148,7 @@ public String getName() { 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); } @@ -165,7 +165,7 @@ private TestResult runAll4x(String projectAbsolutePath) throws Exception { @SuppressWarnings("rawtypes") List 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); } @@ -173,7 +173,7 @@ private TestResult runAll4x(String projectAbsolutePath) throws Exception { 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")) { @@ -184,108 +184,107 @@ private boolean isTestable4x(Class clazz) throws ClassNotFoundException { return false; } - private Object create4xTestListener(ClassLoader loader, Class listenerClass, AbstractTestListener delegate) 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; + @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 { + + 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); - Class clsTestRunner = Class.forName("org.junit.runner.notification.RunListener", true, classLoader); + 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); + 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 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 = ""; @@ -294,15 +293,15 @@ private TestResult run4xTestClasses(Class... classes) throws Exception { 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); @@ -319,7 +318,7 @@ private TestResult run4xTestClasses(Class... classes) throws Exception { 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); } @@ -337,7 +336,7 @@ private TestResult runAll3x(String projectAbsolutePath) throws Exception { @SuppressWarnings("rawtypes") List 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); } @@ -345,98 +344,97 @@ private TestResult runAll3x(String projectAbsolutePath) throws Exception { 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 Object create3xTestListener(ClassLoader loader, Class listenerClass, AbstractTestListener delegate) 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.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; + @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 { + + 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); + 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); + Class< ? > clsTestListener = Class.forName("junit.framework.TestListener", true, classLoader); - try(OutputTestListener outputListener = new OutputTestListener(this.getClass().getName()+".run3xTestClasses")) { + 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) { + 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); + } finally { + Thread.currentThread().setContextClassLoader(tccl); + clsTestResult.getMethod("removeListener", clsTestListener).invoke( + testResult, testListener); } } 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 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); @@ -447,10 +445,10 @@ private TestResult run3xTestClasses(Class... classes) throws Exception { 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; } } diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/AbstractTestListener.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/AbstractTestListener.java index b2600473d0c..d3ca068229f 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/AbstractTestListener.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/AbstractTestListener.java @@ -18,74 +18,83 @@ * @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 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); - } -} \ No newline at end of file + 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 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); + } +} + diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java index cf0344e9f5f..25f6733b4eb 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java @@ -27,77 +27,76 @@ * @author David Festal */ public class OutputTestListener extends AbstractTestListener implements AutoCloseable { - private WebsocketMessageConsumer 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 WebsocketMessageConsumer consumer = new WebsocketMessageConsumer<>(TESTING_OUTPUT_CHANNEL_NAME); + private String stackTraceRoot; - private void writeLine(String line, TestingOutput.LineType lineType) { - try { - consumer.consume(DtoFactory.cloneDto(new TestingOutputImpl(line, lineType))); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } + public OutputTestListener(String strackTraceRoot) { + this.stackTraceRoot = strackTraceRoot; + writeLine("Starting Test Session", TestingOutput.LineType.SESSION_START); + } - @Override - public void close() throws Exception { - writeLine("Finished Test Session", TestingOutput.LineType.SESSION_END); - consumer.close(); - } + private void writeLine(String line, TestingOutput.LineType lineType) { + try { + consumer.consume(DtoFactory.cloneDto(new TestingOutputImpl(line, lineType))); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } - @Override - protected void startedTest(String testKey, String testName) { - writeLine("[Starting Test] " + testName, TestingOutput.LineType.DETAIL); - } + @Override + public void close() throws Exception { + writeLine("Finished Test Session", TestingOutput.LineType.SESSION_END); + consumer.close(); + } - @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); - - } + @Override + protected void startedTest(String testKey, String testName) { + writeLine("[Starting Test] " + testName, TestingOutput.LineType.DETAIL); + } - 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 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); - @Override - protected void addedError(String testKey, Throwable throwable) { - addProblem(testKey, throwable, true); - } -} \ No newline at end of file + } + + 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); + } +} From 239c490da6db815b84a25c9e97873c525899fff4 Mon Sep 17 00:00:00 2001 From: dfestal Date: Fri, 3 Mar 2017 15:37:28 +0100 Subject: [PATCH 09/22] Call `LOG` instead of ` System.println`. Signed-off-by: David Festal --- .../testing/junit/server/listener/OutputTestListener.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java index 25f6733b4eb..40dd94188fe 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java @@ -20,6 +20,8 @@ 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. @@ -27,6 +29,8 @@ * @author David Festal */ public class OutputTestListener extends AbstractTestListener implements AutoCloseable { + private static final Logger LOG = LoggerFactory.getLogger(AbstractTestListener.class); + private WebsocketMessageConsumer consumer = new WebsocketMessageConsumer<>(TESTING_OUTPUT_CHANNEL_NAME); private String stackTraceRoot; @@ -39,8 +43,7 @@ private void writeLine(String line, TestingOutput.LineType lineType) { try { consumer.consume(DtoFactory.cloneDto(new TestingOutputImpl(line, lineType))); } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + LOG.error("An exception occured while trying to send a 'TestingOutput' object through web sockets on the following channel: " + TESTING_OUTPUT_CHANNEL_NAME, e); } } From 8780bfbc47c03c5d06c39c7792c3fc8c30779963 Mon Sep 17 00:00:00 2001 From: dfestal Date: Fri, 3 Mar 2017 15:45:56 +0100 Subject: [PATCH 10/22] Sort POMs Signed-off-by: David Festal --- .../che-plugin-testing-junit-server/pom.xml | 40 +++++++++---------- .../che-plugin-testing-ide/pom.xml | 26 ++++++------ wsagent/che-core-api-testing-shared/pom.xml | 24 +++++------ wsagent/che-core-api-testing/pom.xml | 18 ++++----- 4 files changed, 54 insertions(+), 54 deletions(-) diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml index d7c11112c81..123ef42b872 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml @@ -33,10 +33,10 @@ javax.inject javax.inject - - org.eclipse.che.core - che-core-api-core - + + org.eclipse.che.core + che-core-api-core + org.eclipse.che.core che-core-api-dto @@ -61,23 +61,23 @@ org.eclipse.che.plugin che-plugin-testing-classpath-server - - org.javassist - javassist - + + org.javassist + javassist + - - - com.mycila - license-maven-plugin - - - **/**/AbstractTestListener.java - **/**/OutputTestListener.java - - - - + + + com.mycila + license-maven-plugin + + + **/**/AbstractTestListener.java + **/**/OutputTestListener.java + + + + diff --git a/plugins/plugin-testing/che-plugin-testing-ide/pom.xml b/plugins/plugin-testing/che-plugin-testing-ide/pom.xml index bb2459ac45d..a0b70a61065 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/pom.xml +++ b/plugins/plugin-testing/che-plugin-testing-ide/pom.xml @@ -72,10 +72,10 @@ org.eclipse.che.plugin che-plugin-java-ext-lang-client - - org.eclipse.che.plugin - che-plugin-machine-ext-client - + + org.eclipse.che.plugin + che-plugin-machine-ext-client + org.eclipse.che.plugin che-plugin-maven-shared @@ -121,15 +121,15 @@ - - com.mycila - license-maven-plugin - - - **/**/TestingHandler.java - - - + + com.mycila + license-maven-plugin + + + **/**/TestingHandler.java + + + org.apache.maven.plugins maven-dependency-plugin diff --git a/wsagent/che-core-api-testing-shared/pom.xml b/wsagent/che-core-api-testing-shared/pom.xml index 660915003b7..319a46e8486 100644 --- a/wsagent/che-core-api-testing-shared/pom.xml +++ b/wsagent/che-core-api-testing-shared/pom.xml @@ -37,17 +37,17 @@ src/main/java - - - com.mycila - license-maven-plugin - - - **/**/TestingOutput.java - **/**/Constants.java - - - - + + + com.mycila + license-maven-plugin + + + **/**/TestingOutput.java + **/**/Constants.java + + + + diff --git a/wsagent/che-core-api-testing/pom.xml b/wsagent/che-core-api-testing/pom.xml index 730e6b3dd6c..b6951b8b735 100644 --- a/wsagent/che-core-api-testing/pom.xml +++ b/wsagent/che-core-api-testing/pom.xml @@ -111,15 +111,15 @@ - - com.mycila - license-maven-plugin - - - **/**/TestingOutputImpl.java - - - + + com.mycila + license-maven-plugin + + + **/**/TestingOutputImpl.java + + + org.eclipse.che.core che-core-api-dto-maven-plugin From 3eda7efdd4b11f7bb9d45e58c3ac1add8a1f7311 Mon Sep 17 00:00:00 2001 From: David Festal Date: Fri, 3 Mar 2017 17:32:42 +0100 Subject: [PATCH 11/22] Further fix format Signed-off-by: David Festal --- .../server/MavenTestClasspathProvider.java | 112 +++++++++--------- .../junit/ide/action/RunAllTestAction.java | 45 ++++--- .../ide/action/RunClassContextTestAction.java | 53 ++++----- .../junit/ide/action/RunClassTestAction.java | 43 ++++--- .../ide/action/RunTestActionDelegate.java | 14 ++- .../testing/ide/handler/TestingHandler.java | 23 ++-- .../server/handler/TestingOutputImpl.java | 28 ++--- 7 files changed, 157 insertions(+), 161 deletions(-) diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java index 1d88bb3eaf0..5b1da858443 100644 --- a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java +++ b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java @@ -35,17 +35,16 @@ * * @author Mirage Abeysekara * @author David Festal - * */ public class MavenTestClasspathProvider implements TestClasspathProvider { - private ClasspathService classpathService; - - @Inject - public MavenTestClasspathProvider(ClasspathService classpathService) { - this.classpathService = classpathService; - } - - /** + private ClasspathService classpathService; + + @Inject + public MavenTestClasspathProvider(ClasspathService classpathService) { + this.classpathService = classpathService; + } + + /** * {@inheritDoc} */ @Override @@ -66,55 +65,54 @@ public String getProjectType() { } private Stream toResolvedClassPath(Stream rawClasspath) { - return rawClasspath.flatMap(dto -> { - if (dto.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { - return toResolvedClassPath(dto.getExpandedEntries().stream()); - } else { - return Stream.of(dto); - } - }); + return rawClasspath.flatMap(dto -> { + if (dto.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { + return toResolvedClassPath(dto.getExpandedEntries().stream()); + } else { + return Stream.of(dto); + } + }); } - + private Stream getProjectClasspath(String projectPath) throws JavaModelException { - String relativeProject = projectPath.substring(ResourcesPlugin.getPathToWorkspace().length()); - IContainer root = ResourcesPlugin.getWorkspace().getRoot(); - return toResolvedClassPath(classpathService.getClasspath(relativeProject).stream()) - .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 = new File(root.getLocation().toFile(), dtoPath); - } - break; - case IClasspathEntry.CPE_SOURCE: - IPath projectRelativePath = new Path(dtoPath).removeFirstSegments(1); - String projectRelativePathStr = projectRelativePath.toString(); - switch(projectRelativePathStr) { - case "src/main/java": - path = Paths.get(projectPath, "target", "classes").toFile(); - break; - case "src/test/java": - path = Paths.get(projectPath, "target", "test-classes").toFile(); - break; - default: - path = new File(root.getLocation().toFile(), dtoPath); - } - break; - default: - path = new File(dtoPath); - } - return path.toURI().toURL(); - } catch (MalformedURLException e) { - return null; - } - }) - .filter(url -> url != null) - .distinct(); + String relativeProject = projectPath.substring(ResourcesPlugin.getPathToWorkspace().length()); + IContainer root = ResourcesPlugin.getWorkspace().getRoot(); + Stream rawClasspath = classpathService.getClasspath(relativeProject).stream(); + Stream 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 = new File(root.getLocation().toFile(), dtoPath); + } + break; + case IClasspathEntry.CPE_SOURCE: + IPath projectRelativePath = new Path(dtoPath).removeFirstSegments(1); + String projectRelativePathStr = projectRelativePath.toString(); + switch (projectRelativePathStr) { + case "src/main/java": + path = Paths.get(projectPath, "target", "classes").toFile(); + break; + case "src/test/java": + path = Paths.get(projectPath, "target", "test-classes").toFile(); + break; + default: + path = new File(root.getLocation().toFile(), dtoPath); + } + break; + default: + path = new File(dtoPath); + } + return path.toURI().toURL(); + } catch (MalformedURLException e) { + return null; + } + }).filter(url -> url != null).distinct(); } } diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunAllTestAction.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunAllTestAction.java index cbc3bc2188c..fe4a79bfc9f 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunAllTestAction.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunAllTestAction.java @@ -27,17 +27,16 @@ import com.google.inject.Inject; /** - * * @author Mirage Abeysekara * @author David Festal */ public class RunAllTestAction extends JavaEditorAction - implements RunTestActionDelegate.Source { + implements RunTestActionDelegate.Source { private final NotificationManager notificationManager; - private TestResultPresenter presenter; - private final TestServiceClient service; - private RunTestActionDelegate delegate; + private TestResultPresenter presenter; + private final TestServiceClient service; + private RunTestActionDelegate delegate; @Inject public RunAllTestAction(JUnitTestResources resources, @@ -48,7 +47,7 @@ public RunAllTestAction(JUnitTestResources resources, TestServiceClient service, JUnitTestLocalizationConstant localization) { super(localization.actionRunAllTitle(), localization.actionRunAllDescription(), resources.testAllIcon(), - editorAgent, fileTypeRegistry); + editorAgent, fileTypeRegistry); this.notificationManager = notificationManager; this.editorAgent = editorAgent; this.presenter = presenter; @@ -61,24 +60,24 @@ public void actionPerformed(ActionEvent e) { Map parameters = new HashMap<>(); delegate.doRunTests(e, parameters); } - - @Override - public NotificationManager getNotificationManager() { - return notificationManager; - } - @Override - public AppContext getAppContext() { - return appContext; - } + @Override + public NotificationManager getNotificationManager() { + return notificationManager; + } + + @Override + public AppContext getAppContext() { + return appContext; + } - @Override - public TestServiceClient getService() { - return service; - } + @Override + public TestServiceClient getService() { + return service; + } - @Override - public TestResultPresenter getPresenter() { - return presenter; - } + @Override + public TestResultPresenter getPresenter() { + return presenter; + } } diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassContextTestAction.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassContextTestAction.java index 6aa2f2df980..1d593537fc6 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassContextTestAction.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassContextTestAction.java @@ -35,19 +35,18 @@ import com.google.inject.Inject; /** - * * @author Mirage Abeysekara * @author David Festal */ public class RunClassContextTestAction extends AbstractPerspectiveAction - implements RunTestActionDelegate.Source { + implements RunTestActionDelegate.Source { private final NotificationManager notificationManager; private final TestResultPresenter presenter; - private final TestServiceClient service; - private final AppContext appContext; - private final SelectionAgent selectionAgent; - private RunTestActionDelegate delegate; + private final TestServiceClient service; + private final AppContext appContext; + private final SelectionAgent selectionAgent; + private RunTestActionDelegate delegate; @Inject public RunClassContextTestAction(JUnitTestResources resources, @@ -58,7 +57,7 @@ public RunClassContextTestAction(JUnitTestResources resources, 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; @@ -69,10 +68,10 @@ public RunClassContextTestAction(JUnitTestResources resources, @Override public void actionPerformed(ActionEvent e) { - final Selection selection = selectionAgent.getSelection(); + final Selection< ? > selection = selectionAgent.getSelection(); final Object possibleNode = selection.getHeadElement(); if (possibleNode instanceof FileNode) { - VirtualFile file = ((FileNode) possibleNode).getData(); + VirtualFile file = ((FileNode)possibleNode).getData(); String fqn = JavaUtil.resolveFQN(file); Map parameters = new HashMap<>(); parameters.put("fqn", fqn); @@ -88,7 +87,7 @@ public void updateInPerspective(@NotNull ActionEvent e) { 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; @@ -99,27 +98,27 @@ public void updateInPerspective(@NotNull ActionEvent e) { } 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 NotificationManager getNotificationManager() { + return notificationManager; + } - @Override - public AppContext getAppContext() { - return appContext; - } + @Override + public AppContext getAppContext() { + return appContext; + } - @Override - public TestServiceClient getService() { - return service; - } + @Override + public TestServiceClient getService() { + return service; + } - @Override - public TestResultPresenter getPresenter() { - return presenter; - } + @Override + public TestResultPresenter getPresenter() { + return presenter; + } } diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassTestAction.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassTestAction.java index be96f128125..d169ef9d2bc 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassTestAction.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassTestAction.java @@ -30,18 +30,17 @@ import com.google.inject.Inject; /** - * * @author Mirage Abeysekara * @author David Festal */ public class RunClassTestAction extends JavaEditorAction -implements RunTestActionDelegate.Source { + implements RunTestActionDelegate.Source { private final NotificationManager notificationManager; - private final EditorAgent editorAgent; + private final EditorAgent editorAgent; private final TestResultPresenter presenter; - private final TestServiceClient service; - private RunTestActionDelegate delegate; + private final TestServiceClient service; + private RunTestActionDelegate delegate; @Inject public RunClassTestAction(JUnitTestResources resources, @@ -52,7 +51,7 @@ public RunClassTestAction(JUnitTestResources resources, TestServiceClient service, JUnitTestLocalizationConstant localization) { super(localization.actionRunClassTitle(), localization.actionRunClassDescription(), resources.testIcon(), - editorAgent, fileTypeRegistry); + editorAgent, fileTypeRegistry); this.notificationManager = notificationManager; this.editorAgent = editorAgent; this.presenter = presenter; @@ -78,23 +77,23 @@ protected void updateProjectAction(ActionEvent e) { e.getPresentation().setVisible(true); } - @Override - public NotificationManager getNotificationManager() { - return notificationManager; - } + @Override + public NotificationManager getNotificationManager() { + return notificationManager; + } - @Override - public AppContext getAppContext() { - return appContext; - } + @Override + public AppContext getAppContext() { + return appContext; + } - @Override - public TestServiceClient getService() { - return service; - } + @Override + public TestServiceClient getService() { + return service; + } - @Override - public TestResultPresenter getPresenter() { - return presenter; - } + @Override + public TestResultPresenter getPresenter() { + return presenter; + } } diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java index a6fa87c4e1b..89db571dbec 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java @@ -31,25 +31,27 @@ import org.eclipse.che.plugin.testing.ide.view.TestResultPresenter; /** - * * @author Mirage Abeysekara * @author David Festal */ public class RunTestActionDelegate { Source source; - + public interface Source { NotificationManager getNotificationManager(); + AppContext getAppContext(); + TestServiceClient getService(); + TestResultPresenter getPresenter(); } - + public RunTestActionDelegate( - Source source) { + Source source) { this.source = source; } - + public void doRunTests(ActionEvent e, Map parameters) { final StatusNotification notification = new StatusNotification("Running Tests...", PROGRESS, FLOAT_MODE); source.getNotificationManager().notify(notification); @@ -73,7 +75,7 @@ public void apply(TestResult result) throws OperationException { @Override public void apply(PromiseError exception) throws OperationException { final String errorMessage = (exception.getMessage() != null) ? exception.getMessage() - : "Failed to run test cases"; + : "Failed to run test cases"; notification.setContent(errorMessage); notification.setStatus(FAIL); } diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java index f4da85b3166..03049ae76d2 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/handler/TestingHandler.java @@ -48,11 +48,11 @@ public class TestingHandler { @Inject public TestingHandler(EventBus eventBus, - DtoFactory factory, - WsAgentStateController wsAgentStateController, - ProcessesPanelPresenter processesPanelPresenter, - CommandConsoleFactory commandConsoleFactory, - AppContext appContext) { + DtoFactory factory, + WsAgentStateController wsAgentStateController, + ProcessesPanelPresenter processesPanelPresenter, + CommandConsoleFactory commandConsoleFactory, + AppContext appContext) { this.eventBus = eventBus; this.factory = factory; this.processesPanelPresenter = processesPanelPresenter; @@ -80,9 +80,8 @@ public void onWsAgentStopped(WsAgentStateEvent event) { }); } - private void handleTestingOutput(final MessageBus messageBus) { - final DefaultOutputConsole outputConsole = (DefaultOutputConsole) commandConsoleFactory.create("Tests"); - + private void handleTestingOutput(final MessageBus messageBus) { + final DefaultOutputConsole outputConsole = (DefaultOutputConsole)commandConsoleFactory.create("Tests"); try { messageBus.subscribe(TESTING_OUTPUT_CHANNEL_NAME, new MessageHandler() { @Override @@ -90,9 +89,9 @@ public void onMessage(String message) { Log.info(getClass(), message); TestingOutput archetypeOutput = factory.createDtoFromJson(message, TestingOutput.class); switch (archetypeOutput.getState()) { - case SESSION_START: + case SESSION_START: processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), outputConsole); - outputConsole.clearOutputsButtonClicked(); + outputConsole.clearOutputsButtonClicked(); case DETAIL: outputConsole.printText(archetypeOutput.getOutput()); break; @@ -100,10 +99,10 @@ public void onMessage(String message) { outputConsole.printText(archetypeOutput.getOutput(), "green"); break; case ERROR: - outputConsole.printText(archetypeOutput.getOutput(),"red"); + outputConsole.printText(archetypeOutput.getOutput(), "red"); break; case FAILURE: - outputConsole.printText(archetypeOutput.getOutput(),"darkred"); + outputConsole.printText(archetypeOutput.getOutput(), "darkred"); break; default: break; diff --git a/wsagent/che-core-api-testing/src/main/java/org/eclipse/che/api/testing/server/handler/TestingOutputImpl.java b/wsagent/che-core-api-testing/src/main/java/org/eclipse/che/api/testing/server/handler/TestingOutputImpl.java index 95dfc4503fa..4941449ba2c 100644 --- a/wsagent/che-core-api-testing/src/main/java/org/eclipse/che/api/testing/server/handler/TestingOutputImpl.java +++ b/wsagent/che-core-api-testing/src/main/java/org/eclipse/che/api/testing/server/handler/TestingOutputImpl.java @@ -16,22 +16,22 @@ * @author David Festal */ public class TestingOutputImpl implements TestingOutput { - + public TestingOutputImpl(String output, LineType lineType) { - this.output = output; - this.lineType = lineType; - } + this.output = output; + this.lineType = lineType; + } - private String output; - private LineType lineType; + private String output; + private LineType lineType; - @Override - public String getOutput() { - return output; - } + @Override + public String getOutput() { + return output; + } - @Override - public LineType getState() { - return lineType; - } + @Override + public LineType getState() { + return lineType; + } } From 022a430360657b60f4477116dc6411f5b4226107 Mon Sep 17 00:00:00 2001 From: David Festal Date: Fri, 3 Mar 2017 17:42:03 +0100 Subject: [PATCH 12/22] Some fields should have been made `final` Signed-off-by: David Festal --- .../testing/junit/ide/action/RunAllTestAction.java | 8 ++++---- .../junit/ide/action/RunClassContextTestAction.java | 12 ++++++------ .../testing/junit/ide/action/RunClassTestAction.java | 10 +++++----- .../junit/ide/action/RunTestActionDelegate.java | 5 ++--- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunAllTestAction.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunAllTestAction.java index fe4a79bfc9f..247ef6d6cb4 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunAllTestAction.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunAllTestAction.java @@ -33,10 +33,10 @@ public class RunAllTestAction extends JavaEditorAction implements RunTestActionDelegate.Source { - private final NotificationManager notificationManager; - private TestResultPresenter presenter; - private final TestServiceClient service; - private RunTestActionDelegate delegate; + private final NotificationManager notificationManager; + private final TestResultPresenter presenter; + private final TestServiceClient service; + private final RunTestActionDelegate delegate; @Inject public RunAllTestAction(JUnitTestResources resources, diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassContextTestAction.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassContextTestAction.java index 1d593537fc6..cba220ca06b 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassContextTestAction.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassContextTestAction.java @@ -41,12 +41,12 @@ 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 RunTestActionDelegate delegate; + 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, diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassTestAction.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassTestAction.java index d169ef9d2bc..39cd070dd2b 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassTestAction.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunClassTestAction.java @@ -36,11 +36,11 @@ 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 RunTestActionDelegate delegate; + 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, diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java index 89db571dbec..24030ab0909 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java @@ -35,7 +35,7 @@ * @author David Festal */ public class RunTestActionDelegate { - Source source; + private final Source source; public interface Source { NotificationManager getNotificationManager(); @@ -47,8 +47,7 @@ public interface Source { TestResultPresenter getPresenter(); } - public RunTestActionDelegate( - Source source) { + public RunTestActionDelegate(Source source) { this.source = source; } From 22bab7718fa82933bfb7d3dd8bb7fe9cbd793bf0 Mon Sep 17 00:00:00 2001 From: David Festal Date: Fri, 3 Mar 2017 18:05:27 +0100 Subject: [PATCH 13/22] Avoid string concatenation in log messages --- .../junit/server/listener/OutputTestListener.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java index 40dd94188fe..8323033499a 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/OutputTestListener.java @@ -29,9 +29,12 @@ * @author David Festal */ public class OutputTestListener extends AbstractTestListener implements AutoCloseable { - private static final Logger LOG = LoggerFactory.getLogger(AbstractTestListener.class); + 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 consumer = new WebsocketMessageConsumer<>(TESTING_OUTPUT_CHANNEL_NAME); + private WebsocketMessageConsumer consumer = new WebsocketMessageConsumer<>(TESTING_OUTPUT_CHANNEL_NAME); private String stackTraceRoot; public OutputTestListener(String strackTraceRoot) { @@ -43,7 +46,7 @@ private void writeLine(String line, TestingOutput.LineType lineType) { try { consumer.consume(DtoFactory.cloneDto(new TestingOutputImpl(line, lineType))); } catch (IOException e) { - LOG.error("An exception occured while trying to send a 'TestingOutput' object through web sockets on the following channel: " + TESTING_OUTPUT_CHANNEL_NAME, e); + LOG.error(consumeErrorMessage, e); } } From 8c718b280bf1ecf02e4e5d4617deb2f8bc7a5fc0 Mon Sep 17 00:00:00 2001 From: David Festal Date: Fri, 3 Mar 2017 20:42:42 +0100 Subject: [PATCH 14/22] Fixed a missing dependency --- .../che-plugin-testing-junit-server/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml index 123ef42b872..b7cb1798387 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml @@ -65,6 +65,11 @@ org.javassist javassist + + org.slf4j + slf4j-api + 1.7.6 + From 131bf87ae0b5f637ca3380216b57fe69a4189090 Mon Sep 17 00:00:00 2001 From: David Festal Date: Fri, 3 Mar 2017 21:29:43 +0100 Subject: [PATCH 15/22] Remove the explicit version --- .../plugin-testing-junit/che-plugin-testing-junit-server/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml index b7cb1798387..04461acc6da 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/pom.xml @@ -68,7 +68,6 @@ org.slf4j slf4j-api - 1.7.6 From 4f0c8e35f540740e12b17eeab5aa8292a09e83b5 Mon Sep 17 00:00:00 2001 From: David Festal Date: Fri, 3 Mar 2017 21:30:47 +0100 Subject: [PATCH 16/22] remove extra new line --- .../testing/junit/server/listener/AbstractTestListener.java | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/AbstractTestListener.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/AbstractTestListener.java index d3ca068229f..8c193abd711 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/AbstractTestListener.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/listener/AbstractTestListener.java @@ -97,4 +97,3 @@ public void addError(String testKey, Throwable throwable) { addedError(testKey, throwable); } } - From f87c3c74f6420a4c11b52fb8cba9fd27061f2a37 Mon Sep 17 00:00:00 2001 From: David Festal Date: Mon, 6 Mar 2017 15:22:37 +0100 Subject: [PATCH 17/22] Also pass the workspace-relative project path to the classpath provider Signed-off-by: David Festal --- .../server/MavenTestClasspathProvider.java | 29 ++++++++++--------- .../server/TestClasspathProvider.java | 8 +++-- .../testing/junit/server/JUnitTestRunner.java | 2 +- .../testing/testng/server/TestNGRunner.java | 2 +- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java index 5b1da858443..3a96d293df3 100644 --- a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java +++ b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java @@ -48,11 +48,11 @@ public MavenTestClasspathProvider(ClasspathService classpathService) { * {@inheritDoc} */ @Override - public ClassLoader getClassLoader(String projectPath, boolean updateClasspath) throws Exception { + public ClassLoader getClassLoader(String projectAbsolutePath, String projectRelativePath, boolean updateClasspath) throws Exception { try { - return new URLClassLoader(getProjectClasspath(projectPath).toArray(URL[]::new), null); + return new URLClassLoader(getProjectClasspath(projectAbsolutePath, projectRelativePath), null); } catch (JavaModelException e) { - throw new Exception("Failed to build the classpath for testing project: " + projectPath, e); + throw new Exception("Failed to build the classpath for testing project: " + projectRelativePath, e); } } @@ -74,10 +74,13 @@ private Stream toResolvedClassPath(Stream }); } - private Stream getProjectClasspath(String projectPath) throws JavaModelException { - String relativeProject = projectPath.substring(ResourcesPlugin.getPathToWorkspace().length()); - IContainer root = ResourcesPlugin.getWorkspace().getRoot(); - Stream rawClasspath = classpathService.getClasspath(relativeProject).stream(); + private IContainer getWorkspaceRoot() { + return ResourcesPlugin.getWorkspace().getRoot(); + } + + public URL[] getProjectClasspath(String projectAbsolutePath, String projectRelativePath) throws JavaModelException { + IContainer root = getWorkspaceRoot(); + Stream rawClasspath = classpathService.getClasspath(projectRelativePath).stream(); Stream resolvedClasspath = toResolvedClassPath(rawClasspath); return resolvedClasspath.map(dto -> { try { @@ -93,14 +96,14 @@ private Stream getProjectClasspath(String projectPath) throws JavaModelExce } break; case IClasspathEntry.CPE_SOURCE: - IPath projectRelativePath = new Path(dtoPath).removeFirstSegments(1); - String projectRelativePathStr = projectRelativePath.toString(); - switch (projectRelativePathStr) { + IPath relativePathFromProjectRoot = new Path(dtoPath).removeFirstSegments(1); + String relativePathFromProjectRootStr = relativePathFromProjectRoot.toString(); + switch (relativePathFromProjectRootStr) { case "src/main/java": - path = Paths.get(projectPath, "target", "classes").toFile(); + path = Paths.get(projectAbsolutePath, "target", "classes").toFile(); break; case "src/test/java": - path = Paths.get(projectPath, "target", "test-classes").toFile(); + path = Paths.get(projectAbsolutePath, "target", "test-classes").toFile(); break; default: path = new File(root.getLocation().toFile(), dtoPath); @@ -113,6 +116,6 @@ private Stream getProjectClasspath(String projectPath) throws JavaModelExce } catch (MalformedURLException e) { return null; } - }).filter(url -> url != null).distinct(); + }).filter(url -> url != null).distinct().toArray(URL[]::new); } } diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-server/src/main/java/org/eclipse/che/plugin/testing/classpath/server/TestClasspathProvider.java b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-server/src/main/java/org/eclipse/che/plugin/testing/classpath/server/TestClasspathProvider.java index 553c1c04e31..5e9a0345791 100644 --- a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-server/src/main/java/org/eclipse/che/plugin/testing/classpath/server/TestClasspathProvider.java +++ b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-server/src/main/java/org/eclipse/che/plugin/testing/classpath/server/TestClasspathProvider.java @@ -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. diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java index 61a78595c56..538cb515fe2 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/JUnitTestRunner.java @@ -86,7 +86,7 @@ public TestResult execute(Map testParameters) throws Exception { ClassLoader currentClassLoader = this.getClass().getClassLoader(); TestClasspathProvider classpathProvider = classpathRegistry.getTestClasspathProvider(projectType); - URLClassLoader providedClassLoader = (URLClassLoader)classpathProvider.getClassLoader(projectAbsolutePath, updateClasspath); + URLClassLoader providedClassLoader = (URLClassLoader)classpathProvider.getClassLoader(projectAbsolutePath, projectPath, updateClasspath); projectClassLoader = new URLClassLoader(providedClassLoader.getURLs(), null) { @Override protected Class< ? > findClass(String name) throws ClassNotFoundException { diff --git a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/main/java/org/eclipse/che/plugin/testing/testng/server/TestNGRunner.java b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/main/java/org/eclipse/che/plugin/testing/testng/server/TestNGRunner.java index 153cd423d98..3c0652d61ac 100644 --- a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/main/java/org/eclipse/che/plugin/testing/testng/server/TestNGRunner.java +++ b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/main/java/org/eclipse/che/plugin/testing/testng/server/TestNGRunner.java @@ -79,7 +79,7 @@ public TestResult execute(Map testParameters) throws Exception { 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"); From 8c00de8cb364c8e849eb539f93c2bb6dc5fd66c0 Mon Sep 17 00:00:00 2001 From: David Festal Date: Tue, 7 Mar 2017 18:00:39 +0100 Subject: [PATCH 18/22] Test for the maven classpath provider Signed-off-by: David Festal --- .../java/server/rest/ClasspathService.java | 30 ++-- .../rest/ClasspathServiceInterface.java | 29 ++++ .../pom.xml | 69 +++++++- .../server/MavenTestClasspathProvider.java | 19 +-- .../MavenTestClasspathProviderTest.java | 154 ++++++++++++++++++ 5 files changed, 268 insertions(+), 33 deletions(-) create mode 100644 plugins/plugin-java/che-plugin-java-ext-lang-server/src/main/java/org/eclipse/che/plugin/java/server/rest/ClasspathServiceInterface.java create mode 100644 plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/test/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProviderTest.java diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/main/java/org/eclipse/che/plugin/java/server/rest/ClasspathService.java b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/main/java/org/eclipse/che/plugin/java/server/rest/ClasspathService.java index f92b788bc9f..a63d6c58186 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/main/java/org/eclipse/che/plugin/java/server/rest/ClasspathService.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/main/java/org/eclipse/che/plugin/java/server/rest/ClasspathService.java @@ -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.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 getClasspath(@QueryParam("projectpath") String projectPath) throws JavaModelException { diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-server/src/main/java/org/eclipse/che/plugin/java/server/rest/ClasspathServiceInterface.java b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/main/java/org/eclipse/che/plugin/java/server/rest/ClasspathServiceInterface.java new file mode 100644 index 00000000000..73ff117c2de --- /dev/null +++ b/plugins/plugin-java/che-plugin-java-ext-lang-server/src/main/java/org/eclipse/che/plugin/java/server/rest/ClasspathServiceInterface.java @@ -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 getClasspath(String projectPath) throws JavaModelException; +} diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/pom.xml b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/pom.xml index 3a1000bfd9a..e817b44e95b 100644 --- a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/pom.xml +++ b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/pom.xml @@ -30,32 +30,85 @@ guice-multibindings - org.eclipse.birt.runtime - org.eclipse.equinox.common + org.eclipse.birt.runtime + org.eclipse.equinox.common org.eclipse.che.core che-core-commons-inject - org.eclipse.che.lib - org-eclipse-jdt-core-repack + org.eclipse.che.lib + org-eclipse-jdt-core-repack + + + org.eclipse.jdt.core + org.eclipse.tycho + + org.eclipse.che.plugin che-plugin-java-ext-lang-server - org.eclipse.che.plugin - che-plugin-java-ext-lang-shared + org.eclipse.che.plugin + che-plugin-java-ext-lang-shared org.eclipse.che.plugin che-plugin-testing-classpath-server - org.eclipse.che.plugin - org.eclipse.core.resources + org.eclipse.che.plugin + org.eclipse.core.resources + + + junit + junit + test + + + org.hamcrest + hamcrest-core + test + + + org.mockito + mockito-core + test + + src/main/java + src/test/java + target/classes + + + src/test/resources + + + + + com.mycila + license-maven-plugin + + + **/**/MavenTestClasspathProviderTest.java + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.apache.maven.surefire + surefire-junit47 + ${version.surefire.plugin} + + + + + diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java index 3a96d293df3..d32d938cc6a 100644 --- a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java +++ b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/main/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProvider.java @@ -18,10 +18,10 @@ import java.util.stream.Stream; import org.eclipse.che.ide.ext.java.shared.dto.classpath.ClasspathEntryDto; -import org.eclipse.che.plugin.java.server.rest.ClasspathService; +import org.eclipse.che.plugin.java.server.rest.ClasspathServiceInterface; import org.eclipse.che.plugin.testing.classpath.server.TestClasspathProvider; -import org.eclipse.core.resources.IContainer; 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; @@ -37,10 +37,10 @@ * @author David Festal */ public class MavenTestClasspathProvider implements TestClasspathProvider { - private ClasspathService classpathService; + private ClasspathServiceInterface classpathService; @Inject - public MavenTestClasspathProvider(ClasspathService classpathService) { + public MavenTestClasspathProvider(ClasspathServiceInterface classpathService) { this.classpathService = classpathService; } @@ -50,7 +50,7 @@ public MavenTestClasspathProvider(ClasspathService classpathService) { @Override public ClassLoader getClassLoader(String projectAbsolutePath, String projectRelativePath, boolean updateClasspath) throws Exception { try { - return new URLClassLoader(getProjectClasspath(projectAbsolutePath, projectRelativePath), null); + return new URLClassLoader(getProjectClasspath(projectAbsolutePath, projectRelativePath, getWorkspaceRoot()), null); } catch (JavaModelException e) { throw new Exception("Failed to build the classpath for testing project: " + projectRelativePath, e); } @@ -74,12 +74,11 @@ private Stream toResolvedClassPath(Stream }); } - private IContainer getWorkspaceRoot() { + private IWorkspaceRoot getWorkspaceRoot() { return ResourcesPlugin.getWorkspace().getRoot(); } - public URL[] getProjectClasspath(String projectAbsolutePath, String projectRelativePath) throws JavaModelException { - IContainer root = getWorkspaceRoot(); + public URL[] getProjectClasspath(String projectAbsolutePath, String projectRelativePath, IWorkspaceRoot root) throws JavaModelException { Stream rawClasspath = classpathService.getClasspath(projectRelativePath).stream(); Stream resolvedClasspath = toResolvedClassPath(rawClasspath); return resolvedClasspath.map(dto -> { @@ -92,7 +91,7 @@ public URL[] getProjectClasspath(String projectAbsolutePath, String projectRelat if (res == null) { path = new File(dtoPath); } else { - path = new File(root.getLocation().toFile(), dtoPath); + path = res.getLocation().toFile(); } break; case IClasspathEntry.CPE_SOURCE: @@ -106,7 +105,7 @@ public URL[] getProjectClasspath(String projectAbsolutePath, String projectRelat path = Paths.get(projectAbsolutePath, "target", "test-classes").toFile(); break; default: - path = new File(root.getLocation().toFile(), dtoPath); + path = Paths.get(projectAbsolutePath, "target", "classes").toFile(); } break; default: diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/test/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProviderTest.java b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/test/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProviderTest.java new file mode 100644 index 00000000000..fdbafb61eea --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-classpath/che-plugin-testing-classpath-maven-server/src/test/java/org/eclipse/che/plugin/testing/classpath/maven/server/MavenTestClasspathProviderTest.java @@ -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 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 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 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 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); + } +} From d6900e668d148a2aa0eaedcd52f49ce1cf2bce10 Mon Sep 17 00:00:00 2001 From: David Festal Date: Tue, 7 Mar 2017 18:31:00 +0100 Subject: [PATCH 19/22] `test-compile` the project using maven before executing the tests... ... sending the build output to the a command view, and execute the tests only if compilation succeeded. Signed-off-by: David Festal --- .../ide/action/RunTestActionDelegate.java | 2 +- .../plugin/testing/ide/TestServiceClient.java | 161 +++++++++++++++++- 2 files changed, 155 insertions(+), 8 deletions(-) diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java index 24030ab0909..e92e1e4bdc6 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/action/RunTestActionDelegate.java @@ -56,7 +56,7 @@ public void doRunTests(ActionEvent e, Map parameters) { source.getNotificationManager().notify(notification); final Project project = source.getAppContext().getRootProject(); parameters.put("updateClasspath", "true"); - Promise testResultPromise = source.getService().getTestResult(project.getPath(), "junit", parameters); + Promise testResultPromise = source.getService().getTestResult(project.getPath(), "junit", parameters, notification); testResultPromise.then(new Operation() { @Override public void apply(TestResult result) throws OperationException { diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestServiceClient.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestServiceClient.java index 9f8050d4940..1b08ba7f1a9 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestServiceClient.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestServiceClient.java @@ -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.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.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; @@ -32,21 +55,145 @@ @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\\}.*)"); + + 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 getOrCreateTestCompileCommand(String projectPath) { + List 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()); + } + } + } + return promiseProvider.resolve(null); } public Promise getTestResult(String projectPath, String testFramework, Map parameters) { + return getTestResult(projectPath, testFramework, parameters, null); + } + + public Promise getTestResult(String projectPath, String testFramework, Map parameters, StatusNotification statusNotification) { + return getOrCreateTestCompileCommand(projectPath) + .thenPromise(new Function>() { + @Override + public Promise apply(CommandImpl command) { + if(command == null) { + return sendTests(projectPath, testFramework, parameters); + } else { + final Machine machine = appContext.getDevMachine().getDescriptor(); + if (machine == null) { + return sendTests(projectPath, testFramework, parameters); + } + + if (statusNotification != null) { + statusNotification.setContent("Compiling the project before starting the test session."); + } + return promiseProvider.create(Executor.create(new ExecutorBody(){ + boolean compiled = false; + @Override + public void apply(final ResolveFunction resolve, RejectFunction reject) { + macroProcessor.expandMacros(command.getCommandLine()).then(new Operation() { + @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(JsPromiseError.create(new Throwable("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."))); + } + }) + .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 test session."); + } + sendTests(projectPath, testFramework, parameters) + .then(new Operation() { + @Override + public void apply(TestResult result) throws OperationException { + resolve.apply(result); + } }); + } else { + reject.apply(JsPromiseError.create(new Throwable("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 Promise sendTests(String projectPath, String testFramework, Map parameters) { StringBuilder sb = new StringBuilder(); if (parameters != null) { for (Map.Entry e : parameters.entrySet()) { @@ -57,9 +204,9 @@ public Promise getTestResult(String projectPath, String testFramewor } } 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)); } } From ba8a29312593423538e2d69c28cda6084c29f76a Mon Sep 17 00:00:00 2001 From: David Festal Date: Thu, 9 Mar 2017 20:49:31 +0100 Subject: [PATCH 20/22] Refactor a bit to ease the build of the tests Signed-off-by: David Festal --- .../plugin/testing/ide/TestServiceClient.java | 183 ++++++++++-------- 1 file changed, 107 insertions(+), 76 deletions(-) diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestServiceClient.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestServiceClient.java index 1b08ba7f1a9..7bbe588a683 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestServiceClient.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestServiceClient.java @@ -15,10 +15,10 @@ import java.util.Map; import org.eclipse.che.api.core.model.machine.Machine; -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.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; @@ -51,6 +51,7 @@ * Client for calling test services * * @author Mirage Abeysekara + * @author David Festal */ @Singleton public class TestServiceClient { @@ -58,6 +59,17 @@ public class TestServiceClient { 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; @@ -67,7 +79,7 @@ public class TestServiceClient { private final MacroProcessor macroProcessor; private final CommandConsoleFactory commandConsoleFactory; private final ProcessesPanelPresenter processesPanelPresenter; - + @Inject public TestServiceClient(AppContext appContext, @@ -91,7 +103,7 @@ public TestServiceClient(AppContext appContext, this.processesPanelPresenter = processesPanelPresenter; } - public Promise getOrCreateTestCompileCommand(String projectPath) { + public Promise getOrCreateTestCompileCommand() { List commands = commandManager.getCommands(); for (CommandImpl command : commands) { if (command.getName() != null && command.getName().startsWith("test-compile") && "mvn".equals(command.getType())) { @@ -115,84 +127,103 @@ public Promise getTestResult(String projectPath, String testFramewor return getTestResult(projectPath, testFramework, parameters, null); } - public Promise getTestResult(String projectPath, String testFramework, Map parameters, StatusNotification statusNotification) { - return getOrCreateTestCompileCommand(projectPath) - .thenPromise(new Function>() { - @Override - public Promise apply(CommandImpl command) { - if(command == null) { - return sendTests(projectPath, testFramework, parameters); - } else { - final Machine machine = appContext.getDevMachine().getDescriptor(); - if (machine == null) { - return sendTests(projectPath, testFramework, parameters); - } - - if (statusNotification != null) { - statusNotification.setContent("Compiling the project before starting the test session."); - } - return promiseProvider.create(Executor.create(new ExecutorBody(){ - boolean compiled = false; + Promise promiseFromExecutorBody(ExecutorBody executorBody) { + return promiseProvider.create(Executor.create(executorBody)); + } + + PromiseError promiseFromThrowable(Throwable t) { + return JsPromiseError.create(t); + } + + Promise runTestsAfterCompilation(String projectPath, + String testFramework, + Map parameters, + StatusNotification statusNotification, + Promise 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() { + boolean compiled = false; + + @Override + public void apply(final ResolveFunction resolve, RejectFunction reject) { + macroProcessor.expandMacros(command.getCommandLine()).then(new Operation() { @Override - public void apply(final ResolveFunction resolve, RejectFunction reject) { - macroProcessor.expandMacros(command.getCommandLine()).then(new Operation() { - @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(JsPromiseError.create(new Throwable("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."))); - } - }) - .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 test session."); - } - sendTests(projectPath, testFramework, parameters) - .then(new Operation() { - @Override - public void apply(TestResult result) throws OperationException { - resolve.apply(result); - } }); - } else { - reject.apply(JsPromiseError.create(new Throwable("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 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() { + @Override + public void apply(TestResult result) throws OperationException { + resolve.apply(result); + } + }); + } else { + reject.apply(promiseFromThrowable(new Throwable(PROJECT_BUILD_FAILED_MESSAGE))); + } + }); } - })); + }); } - } - + }); }); } - + + public Promise getTestResult(String projectPath, + String testFramework, + Map parameters, + StatusNotification statusNotification) { + return runTestsAfterCompilation(projectPath, testFramework, parameters, statusNotification, + getOrCreateTestCompileCommand()); + } + public Promise sendTests(String projectPath, String testFramework, Map parameters) { StringBuilder sb = new StringBuilder(); if (parameters != null) { From 5a698ac9aed88f54c6eb98372db493ef39b3ec8b Mon Sep 17 00:00:00 2001 From: David Festal Date: Thu, 9 Mar 2017 20:51:51 +0100 Subject: [PATCH 21/22] Tests for the ` TestServiceClient` This includes some utility mocking classes that could be useful in other contexts. Signed-off-by: David Festal --- .../che-plugin-testing-ide/pom.xml | 5 + .../testing/ide/ExecutorPromiseMocker.java | 59 +++ .../plugin/testing/ide/FunctionAnswer.java | 33 ++ .../plugin/testing/ide/MockitoPrinter.java | 37 ++ .../che/plugin/testing/ide/PromiseMocker.java | 77 +++ .../testing/ide/TestServiceClientTest.java | 466 ++++++++++++++++++ 6 files changed, 677 insertions(+) create mode 100644 plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/ExecutorPromiseMocker.java create mode 100644 plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/FunctionAnswer.java create mode 100644 plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/MockitoPrinter.java create mode 100644 plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/PromiseMocker.java create mode 100644 plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/TestServiceClientTest.java diff --git a/plugins/plugin-testing/che-plugin-testing-ide/pom.xml b/plugins/plugin-testing/che-plugin-testing-ide/pom.xml index a0b70a61065..0e6ee853fcf 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/pom.xml +++ b/plugins/plugin-testing/che-plugin-testing-ide/pom.xml @@ -127,6 +127,11 @@ **/**/TestingHandler.java + **/**/ExecutorPromiseMocker.java + **/**/PromiseMocker.java + **/**/FunctionAnswer.java + **/**/MockitoPrinter.java + **/**/TestServiceClientTest.java diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/ExecutorPromiseMocker.java b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/ExecutorPromiseMocker.java new file mode 100644 index 00000000000..55513813063 --- /dev/null +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/ExecutorPromiseMocker.java @@ -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 extends PromiseMocker { + private final ResolveFunction resolveFunction; + private final RejectFunction rejectFunction; + + @SuppressWarnings("unchecked") + public ExecutorPromiseMocker(final Executor.ExecutorBody executorBody, + final BiFunction, Void> onResolved, + final BiFunction, Void> onRejected) { + super(); + resolveFunction = (ResolveFunction) mock(ResolveFunction.class); + rejectFunction = mock(RejectFunction.class); + + doAnswer(new FunctionAnswer(resolvedValue-> { + onResolved.apply(resolvedValue, this); + return null; + })).when(resolveFunction).apply(Matchers.any()); + + doAnswer(new FunctionAnswer(promiseError -> { + onRejected.apply(promiseError, this); + return null; + })).when(rejectFunction).apply(any(PromiseError.class)); + } + + public ResolveFunction getResolveFunction() { + return resolveFunction; + } + + public RejectFunction getRejectFunction() { + return rejectFunction; + } +} \ No newline at end of file diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/FunctionAnswer.java b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/FunctionAnswer.java new file mode 100644 index 00000000000..fbf84f4489c --- /dev/null +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/FunctionAnswer.java @@ -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 implements Answer { + private java.util.function.Function apply; + public FunctionAnswer(java.util.function.Function apply) { + this.apply = apply; + } + + @Override + public Return answer(InvocationOnMock invocation) throws Throwable { + @SuppressWarnings("unchecked") + ArgumentType arg = (ArgumentType)invocation.getArguments()[0]; + return apply.apply(arg); + } +} \ No newline at end of file diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/MockitoPrinter.java b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/MockitoPrinter.java new file mode 100644 index 00000000000..3b164dc8ebb --- /dev/null +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/MockitoPrinter.java @@ -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)); + } +} \ No newline at end of file diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/PromiseMocker.java b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/PromiseMocker.java new file mode 100644 index 00000000000..70230ca6f28 --- /dev/null +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/PromiseMocker.java @@ -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 { + final private Promise promise; + + public PromiseMocker(Promise promise) { + this.promise = promise; + } + + @SuppressWarnings("unchecked") + public PromiseMocker() { + this.promise = (Promise) mock(Promise.class); + } + + public Promise getPromise() { + return promise; + } + public PromiseMocker applyOnThenPromise(T value) { + when(promise.thenPromise(Matchers.>> any())).then(new FunctionAnswer>, Promise>(function -> { + try { + return function.apply(value); + } catch(Exception e) { + e.printStackTrace(); + } + return null; + })); + return this; + } + + public PromiseMocker applyOnThenOperation(T value) { + when(promise.then(Matchers.> any())).then(new FunctionAnswer, Promise>( op -> { + try { + op.apply(value); + } catch(Exception e) { + e.printStackTrace(); + } + return promise; + })); + return this; + } + + public PromiseMocker applyOnCatchErrorOperation(PromiseError error) { + when(promise.catchError(Matchers.> any())).then(new FunctionAnswer, Promise>(op -> { + try { + op.apply(error); + } catch (OperationException e) { + e.printStackTrace(); + } + return promise; + })); + return this; + } +} \ No newline at end of file diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/TestServiceClientTest.java b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/TestServiceClientTest.java new file mode 100644 index 00000000000..df472c25b7e --- /dev/null +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/TestServiceClientTest.java @@ -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 consoleEvents = new ArrayList<>(); + + private static final String rootOfProjects = "/projects"; + private Map parameters = new HashMap<>(); + private String testFramework = "junit"; + private String projectPath = "sampleProject"; + + @SuppressWarnings("rawtypes") + private Map, 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().getPromise()).when(testServiceClient).sendTests(anyString(), anyString(), + anyMapOf(String.class, String.class)); + doAnswer(new FunctionAnswer, Promise>(executorBody -> { + ExecutorPromiseMocker mocker = new ExecutorPromiseMocker(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.> any()); + + doAnswer(new FunctionAnswer(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>(commandLine -> { + String processedCommandLine = commandLine.replace("${current.project.path}", rootOfProjects + "/" + projectPath); + return new PromiseMocker().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 execAgentPromise = + (ExecAgentPromise)mock(ExecAgentPromise.class); + class ProcessEventForward extends FunctionAnswer, ExecAgentPromise> { + public ProcessEventForward(Class dtoClass) { + super(new java.util.function.Function, ExecAgentPromise>() { + @Override + public ExecAgentPromise apply(Operation 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 createCommandPromise(CommandImpl command) { + return new PromiseMocker().applyOnThenPromise(command).getPromise(); + } + + @Test + public void runTestsDirectlyBecauseNoCompilationCommand() { + Promise 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. any()); + verify(testServiceClient).sendTests(projectPath, testFramework, parameters); + } + + @Test + public void runTestsDirectlyBecauseNoDevMachine() { + Promise 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. 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 compileCommandPromise = createCommandPromise(new CommandImpl( + "test-compile", + "mvn test-compile -f ${current.project.path}", + "mvn")); + + when(devMachine.getDescriptor()).thenReturn(machine); + + Promise 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() { + @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 compileCommandPromise = createCommandPromise(new CommandImpl( + "test-compile", + "mvn test-compile -f ${current.project.path}", + "mvn")); + + when(devMachine.getDescriptor()).thenReturn(machine); + + Promise 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() { + @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 compileCommandPromise = createCommandPromise(new CommandImpl( + "test-compile", + "mvn test-compile -f ${current.project.path}", + "mvn")); + + when(devMachine.getDescriptor()).thenReturn(machine); + + Promise 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 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")); + } +} From 0bf39a014e7e399f0e55819c1b1117128854d0b2 Mon Sep 17 00:00:00 2001 From: David Festal Date: Thu, 9 Mar 2017 23:31:33 +0100 Subject: [PATCH 22/22] Add new line at the end of the file as requested by @skabashnyuk Signed-off-by: David Festal --- .../java/org/eclipse/che/plugin/testing/ide/FunctionAnswer.java | 2 +- .../java/org/eclipse/che/plugin/testing/ide/MockitoPrinter.java | 2 +- .../java/org/eclipse/che/plugin/testing/ide/PromiseMocker.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/FunctionAnswer.java b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/FunctionAnswer.java index fbf84f4489c..d80c63f4711 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/FunctionAnswer.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/FunctionAnswer.java @@ -30,4 +30,4 @@ public Return answer(InvocationOnMock invocation) throws Throwable { ArgumentType arg = (ArgumentType)invocation.getArguments()[0]; return apply.apply(arg); } -} \ No newline at end of file +} diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/MockitoPrinter.java b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/MockitoPrinter.java index 3b164dc8ebb..8303bb49e0e 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/MockitoPrinter.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/MockitoPrinter.java @@ -34,4 +34,4 @@ default void printInvocationsOnAllMockedFields() { } }).filter(field -> field != null).toArray(Object[]::new)); } -} \ No newline at end of file +} diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/PromiseMocker.java b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/PromiseMocker.java index 70230ca6f28..f33d2341c0e 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/PromiseMocker.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/PromiseMocker.java @@ -74,4 +74,4 @@ public PromiseMocker applyOnCatchErrorOperation(PromiseError error) { })); return this; } -} \ No newline at end of file +}