diff --git a/agents/che-core-api-agent/src/test/resources/agents-launchers-tests-arbitraryuser.bats b/agents/che-core-api-agent/src/test/resources/agents-launchers-tests-arbitraryuser.bats new file mode 100644 index 0000000000..e30b105668 --- /dev/null +++ b/agents/che-core-api-agent/src/test/resources/agents-launchers-tests-arbitraryuser.bats @@ -0,0 +1,62 @@ +#!/usr/bin/env bats +# Copyright (c) 2012-2017 Red Hat, 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: +# Mario +# +# How to run this script: +# cd +# export CHE_BASE_DIR=$(pwd) +# export LAUNCHER_SCRIPT_TO_TEST=wsagent/agent/src/main/resources/org.eclipse.che.ws-agent.script.sh +# export BATS_TEST_SCRIPT=agents/che-core-api-agent/src/test/resources/agents-launchers-tests-arbitraryuser.bats +# export DOCKER_IMAGE=rhche/centos_jdk8 +# docker run -ti --rm -e CHE_BASE_DIR -e LAUNCHER_SCRIPT_TO_TEST -e DOCKER_IMAGE \ +# -v ${CHE_BASE_DIR}/${BATS_TEST_SCRIPT}:/scripts/launcher_tests.bats \ +# -v ${CHE_BASE_DIR}/dockerfiles:/dockerfiles \ +# -v /var/run/docker.sock:/var/run/docker.sock \ +# eclipse/che-bats bats /scripts/launcher_tests.bats +# + +load '/bats-support/load.bash' +load '/bats-assert/load.bash' +. /dockerfiles/cli/tests/test_base.sh + +CONTAINER_NAME="test" + +script_host_path=${CHE_BASE_DIR}/${LAUNCHER_SCRIPT_TO_TEST} + +root_msg="I am root" +not_root_msg="I am a not root" +sudoer_msg="I am a sudoer" +not_sudoer_msg="I am a not a sudoer" +test_snippet="source <(grep -iE -A3 'is_current_user_root\(\)|is_current_user_sudoer\(\)|set_sudo_command\(\)' /launch.sh | grep -v -- "^--$"); is_current_user_root && echo -n '${root_msg} ' || echo -n '${not_root_msg} '; is_current_user_sudoer && echo '${sudoer_msg}' || echo -n '${not_sudoer_msg} '; set_sudo_command; echo SUDO=\${SUDO}" +user="100000" + +# Kill running che server instance if there is any to be able to run tests +setup() { + kill_running_named_container ${CONTAINER_NAME} + remove_named_container ${CONTAINER_NAME} + docker run --security-opt no-new-privileges --user=${user} --name="${CONTAINER_NAME}" -d -v ${script_host_path}:/launch.sh "${DOCKER_IMAGE}" +} + +teardown() { + kill_running_named_container "${CONTAINER_NAME}" + remove_named_container ${CONTAINER_NAME} +} + +@test "should deduce that's not a sudoer nor root when ${LAUNCHER_SCRIPT_TO_TEST} is run as an arbitrary user" { + #GIVEN + expected_msg="${not_root_msg} ${not_sudoer_msg} SUDO=" + + #WHEN + run docker exec --user=${user} "${CONTAINER_NAME}" bash -c "${test_snippet}" + + #THEN + assert_success + assert_output ${expected_msg} +} + diff --git a/agents/che-core-api-agent/src/test/resources/agents-launchers-tests.bats b/agents/che-core-api-agent/src/test/resources/agents-launchers-tests.bats new file mode 100644 index 0000000000..86c4bad246 --- /dev/null +++ b/agents/che-core-api-agent/src/test/resources/agents-launchers-tests.bats @@ -0,0 +1,76 @@ +#!/usr/bin/env bats +# Copyright (c) 2012-2017 Red Hat, 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: +# Mario +# +# How to run this script: +# cd +# export CHE_BASE_DIR=$(pwd) +# export LAUNCHER_SCRIPT_TO_TEST=wsagent/agent/src/main/resources/org.eclipse.che.ws-agent.script.sh +# export BATS_TEST_SCRIPT=agents/che-core-api-agent/src/test/resources/agents-launchers-tests.bats +# export DOCKER_IMAGE=eclipse/centos_jdk8 +# docker run -ti --rm -e CHE_BASE_DIR -e LAUNCHER_SCRIPT_TO_TEST -e DOCKER_IMAGE \ +# -v ${CHE_BASE_DIR}/${BATS_TEST_SCRIPT}:/scripts/launcher_tests.bats \ +# -v ${CHE_BASE_DIR}/dockerfiles:/dockerfiles \ +# -v /var/run/docker.sock:/var/run/docker.sock \ +# eclipse/che-bats bats /scripts/launcher_tests.bats +# + +load '/bats-support/load.bash' +load '/bats-assert/load.bash' +. /dockerfiles/cli/tests/test_base.sh + +CONTAINER_NAME="batssshscripttest" + +script_host_path=${CHE_BASE_DIR}/${LAUNCHER_SCRIPT_TO_TEST} +root_msg="I am root" +not_root_msg="I am a not root" +sudoer_msg="I am a sudoer" +not_sudoer_msg="I am a not a sudoer" +#test_snippet="source <(grep -iE -A3 'is_current_user_root\(\)|is_current_user_sudoer\(\)' /launch.sh | grep -v -- "^--$"); is_current_user_root && echo -n '${root_msg} ' || echo -n '${not_root_msg} '; is_current_user_sudoer && echo '${sudoer_msg}' || echo '${not_sudoer_msg}'" +test_snippet="source <(grep -iE -A3 'is_current_user_root\(\)|is_current_user_sudoer\(\)|set_sudo_command\(\)' /launch.sh | grep -v -- "^--$"); is_current_user_root && echo -n '${root_msg} ' || echo -n '${not_root_msg} '; is_current_user_sudoer && echo -n '${sudoer_msg} ' || echo '${not_sudoer_msg}'; set_sudo_command; echo SUDO=\${SUDO}" + +# Kill running che server instance if there is any to be able to run tests +setup() { + kill_running_named_container ${CONTAINER_NAME} + remove_named_container ${CONTAINER_NAME} + docker run --name="${CONTAINER_NAME}" -d -v ${script_host_path}:/launch.sh "${DOCKER_IMAGE}" +} + +teardown() { + kill_running_named_container "${CONTAINER_NAME}" + remove_named_container ${CONTAINER_NAME} +} + +@test "should deduce that's root and sudoer when ${LAUNCHER_SCRIPT_TO_TEST} is run as root" { + #GIVEN + user="root" + expected_msg="${root_msg} ${sudoer_msg} SUDO=" + + #WHEN + run docker exec --user=${user} "${CONTAINER_NAME}" bash -c "${test_snippet}" + + #THEN + assert_success +# assert_output --partial ${expected_msg} + assert_output ${expected_msg} +} + +@test "should deduce that's not root but sudoer when ${LAUNCHER_SCRIPT_TO_TEST} is run as user with UID 1000" { + #GIVEN + user="1000" + expected_msg="${not_root_msg} ${sudoer_msg} SUDO=sudo -E" + + #WHEN + run docker exec --user=${user} "${CONTAINER_NAME}" bash -c "${test_snippet}" + + #THEN + assert_success +# assert_output --partial ${expected_msg} + assert_output ${expected_msg} +} diff --git a/agents/che-core-api-agent/src/test/resources/run_launcher_bats_tests.sh b/agents/che-core-api-agent/src/test/resources/run_launcher_bats_tests.sh new file mode 100755 index 0000000000..9d075626eb --- /dev/null +++ b/agents/che-core-api-agent/src/test/resources/run_launcher_bats_tests.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# +# 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 +# + +#images=(bitnami/che-codeigniter:3.1.3-r6 bitnami/che-express:4.15.3-r2 bitnami/che-java-play:1.3.12-r3 bitnami/che-laravel:5.4.23-r1 bitnami/che-rails:5.1.2-r0 bitnami/che-swift:3.1.1-r0 bitnami/che-symfony:3.3.2-r0 eclipse/centos_jdk8 eclipse/cpp_gcc eclipse/debian_jdk8 eclipse/debian_jre eclipse/dotnet_core eclipse/hadoop-dev eclipse/kotlin eclipse/node eclipse/php eclipse/php:5.6 eclipse/php:gae eclipse/selenium eclipse/ubuntu_android eclipse/ubuntu_go eclipse/ubuntu_jdk8 eclipse/ubuntu_jre eclipse/ubuntu_python:2.7 eclipse/ubuntu_python:gae_python2.7 eclipse/ubuntu_python:latest eclipse/ubuntu_rails kaloyanraev/che-zendserver registry.centos.org/che-stacks/centos-go registry.centos.org/che-stacks/centos-nodejs registry.centos.org/che-stacks/spring-boot registry.centos.org/che-stacks/vertx registry.centos.org/che-stacks/wildfly-swarm tomitribe/ubuntu_tomee_173_jdk8 registry.centos.org/che-stacks/centos-git) +#arbitrary_images=(rhche/centos_jdk8 rhche/vertx rhche/ubuntu_jdk8 rhche/centos-nodejs rhche/spring-boot rhche/wildfly-swarm) +images=(eclipse/centos_jdk8) +arbitrary_images=(rhche/centos_jdk8) + +run_bats_test() { + export CHE_BASE_DIR=$(pwd) + export BATS_TEST_SCRIPT=${1} + export LAUNCHER_SCRIPT_TO_TEST=${2} + export DOCKER_IMAGE=${3} + docker run -ti --rm -e CHE_BASE_DIR -e LAUNCHER_SCRIPT_TO_TEST -e DOCKER_IMAGE \ + -v ${CHE_BASE_DIR}/${BATS_TEST_SCRIPT}:/scripts/launcher_tests.bats \ + -v ${CHE_BASE_DIR}/dockerfiles:/dockerfiles \ + -v /var/run/docker.sock:/var/run/docker.sock \ + eclipse/che-bats bats /scripts/launcher_tests.bats +} + +for image in "${images[@]}"; do + launcher_script_to_test="wsagent/agent/src/main/resources/org.eclipse.che.ws-agent.script.sh" + bats_test_script="agents/che-core-api-agent/src/test/resources/agents-launchers-tests.bats" + echo "RUNNING LAUNCHER BATS TESTS FOR IMAGE ${image}" + run_bats_test "${bats_test_script}" "${launcher_script_to_test}" "${image}" +done + +for arbitrary_image in "${arbitrary_images[@]}"; do + launcher_script_to_test="wsagent/agent/src/main/resources/org.eclipse.che.ws-agent.script.sh" + bats_test_script="agents/che-core-api-agent/src/test/resources/agents-launchers-tests-arbitraryuser.bats" + echo "RUNNING LAUNCHER BATS TESTS FOR IMAGE ${arbitrary_image}" + run_bats_test "${bats_test_script}" "${launcher_script_to_test}" "${arbitrary_image}" +done diff --git a/agents/exec/src/main/resources/org.eclipse.che.exec.script.sh b/agents/exec/src/main/resources/org.eclipse.che.exec.script.sh index c81f075007..3edaf640a5 100644 --- a/agents/exec/src/main/resources/org.eclipse.che.exec.script.sh +++ b/agents/exec/src/main/resources/org.eclipse.che.exec.script.sh @@ -9,8 +9,21 @@ # Codenvy, S.A. - initial API and implementation # + +is_current_user_root() { + test "$(id -u)" = 0 +} + +is_current_user_sudoer() { + sudo -n true > /dev/null 2>&1 +} + +set_sudo_command() { + if is_current_user_sudoer && ! is_current_user_root; then SUDO="sudo -E"; else unset SUDO; fi +} + +set_sudo_command unset PACKAGES -unset SUDO command -v tar >/dev/null 2>&1 || { PACKAGES=${PACKAGES}" tar"; } CURL_INSTALLED=false WGET_INSTALLED=false @@ -23,8 +36,6 @@ if [ ${CURL_INSTALLED} = false ] && [ ${WGET_INSTALLED} = false ]; then CURL_INSTALLED=true fi -test "$(id -u)" = 0 || SUDO="sudo -E" - CHE_DIR=$HOME/che LOCAL_AGENT_BINARIES_URI='/mnt/che/exec-agent/exec-agent-${PREFIX}.tar.gz' DOWNLOAD_AGENT_BINARIES_URI='${WORKSPACE_MASTER_URI}/agent-binaries/${PREFIX}/exec/exec-agent-${PREFIX}.tar.gz' diff --git a/agents/ls-csharp/src/main/resources/org.eclipse.che.ls.csharp.script.sh b/agents/ls-csharp/src/main/resources/org.eclipse.che.ls.csharp.script.sh index 72749405e3..65b957fec6 100644 --- a/agents/ls-csharp/src/main/resources/org.eclipse.che.ls.csharp.script.sh +++ b/agents/ls-csharp/src/main/resources/org.eclipse.che.ls.csharp.script.sh @@ -9,11 +9,22 @@ # Codenvy, S.A. - initial API and implementation # +is_current_user_root() { + test "$(id -u)" = 0 +} + +is_current_user_sudoer() { + sudo -n true > /dev/null 2>&1 +} + +set_sudo_command() { + if is_current_user_sudoer && ! is_current_user_root; then SUDO="sudo -E"; else unset SUDO; fi +} + +set_sudo_command unset PACKAGES -unset SUDO command -v tar >/dev/null 2>&1 || { PACKAGES=${PACKAGES}" tar"; } command -v curl >/dev/null 2>&1 || { PACKAGES=${PACKAGES}" curl"; } -test "$(id -u)" = 0 || SUDO="sudo -E" AGENT_BINARIES_URI=https://codenvy.com/update/repository/public/download/org.eclipse.che.ls.csharp.binaries CHE_DIR=$HOME/che diff --git a/agents/ls-json/src/main/resources/org.eclipse.che.ls.json.script.sh b/agents/ls-json/src/main/resources/org.eclipse.che.ls.json.script.sh index cba2615117..04d1b25e92 100644 --- a/agents/ls-json/src/main/resources/org.eclipse.che.ls.json.script.sh +++ b/agents/ls-json/src/main/resources/org.eclipse.che.ls.json.script.sh @@ -9,11 +9,22 @@ # Codenvy, S.A. - initial API and implementation # +is_current_user_root() { + test "$(id -u)" = 0 +} + +is_current_user_sudoer() { + sudo -n true > /dev/null 2>&1 +} + +set_sudo_command() { + if is_current_user_sudoer && ! is_current_user_root; then SUDO="sudo -E"; else unset SUDO; fi +} + +set_sudo_command unset PACKAGES -unset SUDO command -v tar >/dev/null 2>&1 || { PACKAGES=${PACKAGES}" tar"; } command -v curl >/dev/null 2>&1 || { PACKAGES=${PACKAGES}" curl"; } -test "$(id -u)" = 0 || SUDO="sudo -E" AGENT_BINARIES_URI=https://codenvy.com/update/repository/public/download/org.eclipse.che.ls.json.binaries CHE_DIR=$HOME/che diff --git a/agents/ls-php/src/main/resources/org.eclipse.che.ls.php.script.sh b/agents/ls-php/src/main/resources/org.eclipse.che.ls.php.script.sh index 73ca1cb081..700b993d58 100644 --- a/agents/ls-php/src/main/resources/org.eclipse.che.ls.php.script.sh +++ b/agents/ls-php/src/main/resources/org.eclipse.che.ls.php.script.sh @@ -9,11 +9,22 @@ # Codenvy, S.A. - initial API and implementation # +is_current_user_root() { + test "$(id -u)" = 0 +} + +is_current_user_sudoer() { + sudo -n true > /dev/null 2>&1 +} + +set_sudo_command() { + if is_current_user_sudoer && ! is_current_user_root; then SUDO="sudo -E"; else unset SUDO; fi +} + +set_sudo_command unset PACKAGES -unset SUDO command -v tar >/dev/null 2>&1 || { PACKAGES=${PACKAGES}" tar"; } command -v curl >/dev/null 2>&1 || { PACKAGES=${PACKAGES}" curl"; } -test "$(id -u)" = 0 || SUDO="sudo -E" AGENT_BINARIES_URI=https://codenvy.com/update/repository/public/download/org.eclipse.che.ls.php.binaries CHE_DIR=$HOME/che diff --git a/agents/ls-python/src/main/resources/org.eclipse.che.ls.python.script.sh b/agents/ls-python/src/main/resources/org.eclipse.che.ls.python.script.sh index ff9383b7be..532f3d4152 100644 --- a/agents/ls-python/src/main/resources/org.eclipse.che.ls.python.script.sh +++ b/agents/ls-python/src/main/resources/org.eclipse.che.ls.python.script.sh @@ -9,16 +9,26 @@ # Codenvy, S.A. - initial API and implementation # +is_current_user_root() { + test "$(id -u)" = 0 +} + +is_current_user_sudoer() { + sudo -n true > /dev/null 2>&1 +} + +set_sudo_command() { + if is_current_user_sudoer && ! is_current_user_root; then SUDO="sudo -E"; else unset SUDO; fi +} + +set_sudo_command unset PACKAGES -unset SUDO unset PYTHON_DEPS command -v tar >/dev/null 2>&1 || { PACKAGES=${PACKAGES}" tar"; } command -v curl >/dev/null 2>&1 || { PACKAGES=${PACKAGES}" curl"; } command -v python3.5 >/dev/null 2>&1 || { PYTHON_DEPS=${PYTHON_DEPS}" python3.5"; } command -v pip3 >/dev/null 2>&1 || { PYTHON_DEPS=${PYTHON_DEPS}" pip3"; } -test "$(id -u)" = 0 || SUDO="sudo -E" - AGENT_BINARIES_URI=https://codenvy.com/update/repository/public/download/org.eclipse.che.ls.python.binaries CHE_DIR=$HOME/che LS_DIR=${CHE_DIR}/ls-python diff --git a/agents/ls-typescript/src/main/resources/org.eclipse.che.ls.typescript.script.sh b/agents/ls-typescript/src/main/resources/org.eclipse.che.ls.typescript.script.sh index e9ae076dfd..6b390498f8 100644 --- a/agents/ls-typescript/src/main/resources/org.eclipse.che.ls.typescript.script.sh +++ b/agents/ls-typescript/src/main/resources/org.eclipse.che.ls.typescript.script.sh @@ -9,11 +9,22 @@ # Codenvy, S.A. - initial API and implementation # +is_current_user_root() { + test "$(id -u)" = 0 +} + +is_current_user_sudoer() { + sudo -n true > /dev/null 2>&1 +} + +set_sudo_command() { + if is_current_user_sudoer && ! is_current_user_root; then SUDO="sudo -E"; else unset SUDO; fi +} + +set_sudo_command unset PACKAGES -unset SUDO command -v tar >/dev/null 2>&1 || { PACKAGES=${PACKAGES}" tar"; } command -v curl >/dev/null 2>&1 || { PACKAGES=${PACKAGES}" curl"; } -test "$(id -u)" = 0 || SUDO="sudo -E" AGENT_BINARIES_URI=https://codenvy.com/update/repository/public/download/org.eclipse.che.ls.typescript.binaries CHE_DIR=$HOME/che diff --git a/agents/ssh/src/main/resources/org.eclipse.che.ssh.script.sh b/agents/ssh/src/main/resources/org.eclipse.che.ssh.script.sh index 2d344c109c..d6605c22da 100644 --- a/agents/ssh/src/main/resources/org.eclipse.che.ssh.script.sh +++ b/agents/ssh/src/main/resources/org.eclipse.che.ssh.script.sh @@ -9,9 +9,20 @@ # Codenvy, S.A. - initial API and implementation # -unset SUDO +is_current_user_root() { + test "$(id -u)" = 0 +} + +is_current_user_sudoer() { + sudo -n true > /dev/null 2>&1 +} + +set_sudo_command() { + if is_current_user_sudoer && ! is_current_user_root; then SUDO="sudo -E"; else unset SUDO; fi +} + +set_sudo_command unset PACKAGES -test "$(id -u)" = 0 || SUDO="sudo -E" if [ -f /etc/centos-release ]; then FILE="/etc/centos-release" diff --git a/agents/terminal/src/main/resources/org.eclipse.che.terminal.script.sh b/agents/terminal/src/main/resources/org.eclipse.che.terminal.script.sh index 18142fa3fb..32be493017 100644 --- a/agents/terminal/src/main/resources/org.eclipse.che.terminal.script.sh +++ b/agents/terminal/src/main/resources/org.eclipse.che.terminal.script.sh @@ -9,8 +9,20 @@ # Codenvy, S.A. - initial API and implementation # +is_current_user_root() { + test "$(id -u)" = 0 +} + +is_current_user_sudoer() { + sudo -n true > /dev/null 2>&1 +} + +set_sudo_command() { + if is_current_user_sudoer && ! is_current_user_root; then SUDO="sudo -E"; else unset SUDO; fi +} + +set_sudo_command unset PACKAGES -unset SUDO command -v tar >/dev/null 2>&1 || { PACKAGES=${PACKAGES}" tar"; } CURL_INSTALLED=false WGET_INSTALLED=false @@ -23,8 +35,6 @@ if [ ${CURL_INSTALLED} = false ] && [ ${WGET_INSTALLED} = false ]; then CURL_INSTALLED=true fi -test "$(id -u)" = 0 || SUDO="sudo -E" - CHE_DIR=$HOME/che LOCAL_AGENT_BINARIES_URI='/mnt/che/terminal/websocket-terminal-${PREFIX}.tar.gz' DOWNLOAD_AGENT_BINARIES_URI='${WORKSPACE_MASTER_URI}/agent-binaries/${PREFIX}/terminal/websocket-terminal-${PREFIX}.tar.gz' diff --git a/agents/unison/src/main/resources/org.eclipse.che.unison.script.sh b/agents/unison/src/main/resources/org.eclipse.che.unison.script.sh index 13c0aeeebc..bebdc2e637 100644 --- a/agents/unison/src/main/resources/org.eclipse.che.unison.script.sh +++ b/agents/unison/src/main/resources/org.eclipse.che.unison.script.sh @@ -9,9 +9,20 @@ # Codenvy, S.A. - initial API and implementation # -unset SUDO +is_current_user_root() { + test "$(id -u)" = 0 +} + +is_current_user_sudoer() { + sudo -n true > /dev/null 2>&1 +} + +set_sudo_command() { + if is_current_user_sudoer && ! is_current_user_root; then SUDO="sudo -E"; else unset SUDO; fi +} + +set_sudo_command unset PACKAGES -test "$(id -u)" = 0 || SUDO="sudo -E" if [ -f /etc/centos-release ]; then FILE="/etc/centos-release" diff --git a/assembly/assembly-ide-war/pom.xml b/assembly/assembly-ide-war/pom.xml index fa8f0b8efc..0763c489bb 100644 --- a/assembly/assembly-ide-war/pom.xml +++ b/assembly/assembly-ide-war/pom.xml @@ -191,10 +191,18 @@ org.eclipse.che.plugin che-plugin-testing-ide + + org.eclipse.che.plugin + che-plugin-testing-junit-ide + org.eclipse.che.plugin che-plugin-testing-phpunit-ide + + org.eclipse.che.plugin + che-plugin-testing-testng-ide + org.eclipse.che.plugin che-plugin-web-ext-web diff --git a/ide/che-core-ide-stacks/src/main/resources/stacks.json b/ide/che-core-ide-stacks/src/main/resources/stacks.json index 584ddae474..17446fadfa 100644 --- a/ide/che-core-ide-stacks/src/main/resources/stacks.json +++ b/ide/che-core-ide-stacks/src/main/resources/stacks.json @@ -2422,6 +2422,7 @@ "machines": { "dev-machine": { "installers": [ + "org.eclipse.che.exec", "org.eclipse.che.terminal", "org.eclipse.che.ws-agent", "org.eclipse.che.ssh" diff --git a/plugins/plugin-maven/che-plugin-maven-server/pom.xml b/plugins/plugin-maven/che-plugin-maven-server/pom.xml index bc4c5a5f39..6a5c5f282b 100644 --- a/plugins/plugin-maven/che-plugin-maven-server/pom.xml +++ b/plugins/plugin-maven/che-plugin-maven-server/pom.xml @@ -86,10 +86,6 @@ org.eclipse.che.core che-core-commons-inject - - org.eclipse.che.core - che-core-commons-inject - org.eclipse.che.core che-core-commons-lang diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/pom.xml b/plugins/plugin-testing-java/plugin-testing-classpath/pom.xml index 7c383092bb..8cbcdbbe08 100644 --- a/plugins/plugin-testing-java/plugin-testing-classpath/pom.xml +++ b/plugins/plugin-testing-java/plugin-testing-classpath/pom.xml @@ -21,6 +21,10 @@ che-plugin-testing-classpath Che Plugin :: Java Testing :: Classpath + + com.google.guava + guava + com.google.inject guice diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/src/main/java/org/eclipse/che/plugin/java/testing/AbstractJavaTestRunner.java b/plugins/plugin-testing-java/plugin-testing-classpath/src/main/java/org/eclipse/che/plugin/java/testing/AbstractJavaTestRunner.java index 16650e5f93..af132395fd 100644 --- a/plugins/plugin-testing-java/plugin-testing-classpath/src/main/java/org/eclipse/che/plugin/java/testing/AbstractJavaTestRunner.java +++ b/plugins/plugin-testing-java/plugin-testing-classpath/src/main/java/org/eclipse/che/plugin/java/testing/AbstractJavaTestRunner.java @@ -12,6 +12,7 @@ package org.eclipse.che.plugin.java.testing; import org.eclipse.che.api.testing.server.framework.TestRunner; import org.eclipse.che.api.testing.shared.TestDetectionContext; +import org.eclipse.che.api.testing.shared.TestExecutionContext; import org.eclipse.che.api.testing.shared.TestPosition; import org.eclipse.che.dto.server.DtoFactory; import org.eclipse.core.resources.IProject; @@ -37,6 +38,8 @@ import java.util.Collections; import java.util.List; import java.util.Random; +import static java.util.Collections.emptyList; + /** * Abstract java test runner. * Can recognize test methods, find java project and compilation unit by path. @@ -48,10 +51,12 @@ public abstract class AbstractJavaTestRunner implements TestRunner { protected static final String JAVA_EXECUTABLE = "java"; private int debugPort = -1; - private String workspacePath; + private String workspacePath; + private JavaTestFinder javaTestFinder; - public AbstractJavaTestRunner(String workspacePath) { + public AbstractJavaTestRunner(String workspacePath, JavaTestFinder javaTestFinder) { this.workspacePath = workspacePath; + this.javaTestFinder = javaTestFinder; } @Override @@ -105,8 +110,18 @@ public abstract class AbstractJavaTestRunner implements TestRunner { .withTestBodyLength(sourceRange.getLength()); } + /** + * Verify if the method is test method. + * + * @param method + * method declaration + * @param compilationUnit + * compilation unit of the method + * @return {@code true} if the method is test method otherwise returns {@code false} + */ protected abstract boolean isTestMethod(IMethod method, ICompilationUnit compilationUnit); + /** Returns {@link IJavaProject} by path */ protected IJavaProject getJavaProject(String projectPath) { IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectPath); return JavaModelManager.getJavaModelManager().getJavaModel().getJavaProject(project); @@ -131,7 +146,7 @@ public abstract class AbstractJavaTestRunner implements TestRunner { return path; } - protected ICompilationUnit findCompilationUnitByPath(IJavaProject javaProject, String filePath) { + private ICompilationUnit findCompilationUnitByPath(IJavaProject javaProject, String filePath) { try { IClasspathEntry[] resolvedClasspath = javaProject.getResolvedClasspath(false); IPath packageRootPath = null; @@ -163,6 +178,44 @@ public abstract class AbstractJavaTestRunner implements TestRunner { } } + /** + * Creates test suite which should be ran. + * + * @param context + * information about test runner + * @param javaProject + * current project + * @param methodAnnotation + * java annotation which describes test method in the test framework + * @param classAnnotation + * java annotation which describes test class in the test framework + * @return list of full qualified names of test classes. + * If it is the declaration of a test method it should be: parent fqn + '#' + method name (a.b.c.ClassName#methodName) + */ + protected List createTestSuite(TestExecutionContext context, + IJavaProject javaProject, + String methodAnnotation, + String classAnnotation) { + switch (context.getContextType()) { + case FILE: + return javaTestFinder.findTestClassDeclaration(findCompilationUnitByPath(javaProject, context.getFilePath())); + case FOLDER: + return javaTestFinder.findClassesInPackage(javaProject, + context.getFilePath(), + methodAnnotation, + classAnnotation); + case PROJECT: + return javaTestFinder.findClassesInProject(javaProject, + methodAnnotation, + classAnnotation); + case CURSOR_POSITION: + return javaTestFinder.findTestMethodDeclaration(findCompilationUnitByPath(javaProject, context.getFilePath()), + context.getCursorOffset()); + } + + return emptyList(); + } + @Override public int getDebugPort() { return debugPort; diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/src/main/java/org/eclipse/che/plugin/java/testing/AnnotationSearchRequestor.java b/plugins/plugin-testing-java/plugin-testing-classpath/src/main/java/org/eclipse/che/plugin/java/testing/AnnotationSearchRequestor.java new file mode 100644 index 0000000000..d67dda19f0 --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-classpath/src/main/java/org/eclipse/che/plugin/java/testing/AnnotationSearchRequestor.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * 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.testing; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IMember; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.ITypeHierarchy; +import org.eclipse.jdt.core.search.SearchMatch; +import org.eclipse.jdt.core.search.SearchRequestor; + +import java.util.Collection; + +/** + * Request for searching test classes. + */ +public class AnnotationSearchRequestor extends SearchRequestor { + + private final Collection fResult; + private final ITypeHierarchy fHierarchy; + + AnnotationSearchRequestor(ITypeHierarchy hierarchy, Collection result) { + fHierarchy = hierarchy; + fResult = result; + } + + @Override + public void acceptSearchMatch(SearchMatch match) throws CoreException { + if (match.getAccuracy() == SearchMatch.A_ACCURATE && !match.isInsideDocComment()) { + Object element = match.getElement(); + if (element instanceof IType || element instanceof IMethod) { + IMember member = (IMember)element; + IType type = member.getElementType() == IJavaElement.TYPE ? (IType)member : member.getDeclaringType(); + addTypeAndSubtypes(type); + } + } + } + + private void addTypeAndSubtypes(IType type) { + if (fResult.add(type)) { + IType[] subclasses = fHierarchy.getSubclasses(type); + for (IType subclass : subclasses) { + addTypeAndSubtypes(subclass); + } + } + } +} diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/src/main/java/org/eclipse/che/plugin/java/testing/JavaTestAnnotations.java b/plugins/plugin-testing-java/plugin-testing-classpath/src/main/java/org/eclipse/che/plugin/java/testing/JavaTestAnnotations.java new file mode 100644 index 0000000000..625ee4c018 --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-classpath/src/main/java/org/eclipse/che/plugin/java/testing/JavaTestAnnotations.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * 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.testing; + +import org.eclipse.jdt.core.dom.IAnnotationBinding; +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.ITypeBinding; + +/** + * Describes annotations for JUnit4x an TestNG. + */ +public class JavaTestAnnotations { + public static final JavaTestAnnotations TESTNG_TEST = new JavaTestAnnotations("org.testng.annotations.Test"); + public static final JavaTestAnnotations JUNIT4X_RUN_WITH = new JavaTestAnnotations("org.junit.runner.RunWith"); + public static final JavaTestAnnotations JUNIT4X_TEST = new JavaTestAnnotations("org.junit.Test"); + + private final String fName; + + private JavaTestAnnotations(String name) { + fName = name; + } + + /** + * Returns name of the annotation. + * + * @return name of the annotation + */ + public String getName() { + return fName; + } + + private boolean annotates(IAnnotationBinding[] annotations) { + for (IAnnotationBinding annotation : annotations) { + ITypeBinding annotationType = annotation.getAnnotationType(); + if (annotationType != null && (annotationType.getQualifiedName().equals(fName))) { + return true; + } + } + return false; + } + + /** + * Check if type annotated as test type. + * + * @param type + * type which should be checked + * @return {@code true} if type annotated as test otherwise returns {@code false} + */ + public boolean annotatesTypeOrSuperTypes(ITypeBinding type) { + while (type != null) { + if (annotates(type.getAnnotations())) { + return true; + } + type= type.getSuperclass(); + } + return false; + } + + /** + * Find method which annotated as test method. + * + * @param type + * type which contains methods + * @return {@code true} if least one has test annotation otherwise returns {@code false} + */ + public boolean annotatesAtLeastOneMethod(ITypeBinding type) { + while (type != null) { + IMethodBinding[] declaredMethods= type.getDeclaredMethods(); + for (int i= 0; i < declaredMethods.length; i++) { + IMethodBinding curr= declaredMethods[i]; + if (annotates(curr.getAnnotations())) { + return true; + } + } + type= type.getSuperclass(); + } + return false; + } +} diff --git a/plugins/plugin-testing-java/plugin-testing-classpath/src/main/java/org/eclipse/che/plugin/java/testing/JavaTestFinder.java b/plugins/plugin-testing-java/plugin-testing-classpath/src/main/java/org/eclipse/che/plugin/java/testing/JavaTestFinder.java new file mode 100644 index 0000000000..2c2718ba65 --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-classpath/src/main/java/org/eclipse/che/plugin/java/testing/JavaTestFinder.java @@ -0,0 +1,271 @@ +/******************************************************************************* + * 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.testing; + +import com.google.inject.Singleton; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Path; +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.IAnnotation; +import org.eclipse.jdt.core.IClassFile; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IImportDeclaration; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.IRegion; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.ITypeHierarchy; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.search.IJavaSearchConstants; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.SearchEngine; +import org.eclipse.jdt.core.search.SearchParticipant; +import org.eclipse.jdt.core.search.SearchPattern; +import org.eclipse.jdt.core.search.SearchRequestor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; + +/** + * Class which finds test classes and test methods for java test frameworks. + */ +@Singleton +public class JavaTestFinder { + private static final Logger LOG = LoggerFactory.getLogger(JavaTestFinder.class); + + /** + * Finds test method related to the cursor position. + * + * @param compilationUnit + * compilation unit of class + * @param cursorOffset + * cursor position + * @return declaration of test method which should be ran. (Example: full.qualified.name.of.Class#methodName) + */ + public List findTestMethodDeclaration(ICompilationUnit compilationUnit, + int cursorOffset) { + IType primaryType = compilationUnit.findPrimaryType(); + String qualifiedName = primaryType.getFullyQualifiedName(); + try { + IJavaElement element = compilationUnit.getElementAt(cursorOffset); + if (element instanceof IMethod) { + IMethod method = (IMethod)element; + qualifiedName = qualifiedName + '#' + method.getElementName(); + } + } catch (JavaModelException e) { + LOG.debug("Can't read a method.", e); + } + return singletonList(qualifiedName); + } + + /** + * Finds test class declaration. + * + * @param compilationUnit + * compilation unit of class + * @return declaration of test class which should be ran. + */ + public List findTestClassDeclaration(ICompilationUnit compilationUnit) { + IType primaryType = compilationUnit.findPrimaryType(); + return singletonList(primaryType.getFullyQualifiedName()); + } + + /** + * Finds test classes in package. + * + * @param javaProject + * java project + * @param packagePath + * package path + * @param testMethodAnnotation + * java annotation which describes test method in the test framework + * @param testClassAnnotation + * java annotation which describes test class in the test framework + * @return list of test classes which should be ran. + */ + public List findClassesInPackage(IJavaProject javaProject, + String packagePath, + String testMethodAnnotation, + String testClassAnnotation) { + IPackageFragment packageFragment = null; + try { + packageFragment = javaProject.findPackageFragment(new Path(packagePath)); + } catch (JavaModelException e) { + LOG.info("Can't find package.", e); + } + return packageFragment == null ? emptyList() : findClassesInContainer(packageFragment, testMethodAnnotation, testClassAnnotation); + } + + /** + * Finds test classes in project. + * + * @param project + * java project + * @param testMethodAnnotation + * java annotation which describes test method in the test framework + * @param testClassAnnotation + * java annotation which describes test class in the test framework + * @return list of test classes which should be ran. + */ + public List findClassesInProject(IJavaProject project, String testMethodAnnotation, String testClassAnnotation) { + return findClassesInContainer(project, testMethodAnnotation, testClassAnnotation); + } + + /** + * Check if a method is test method. + * + * @param method + * method which should be checked + * @param compilationUnit + * parent of the method + * @param testAnnotation + * java annotation which describes test method in the test framework + * @return {@code true} if the method is test method + */ + public boolean isTest(IMethod method, ICompilationUnit compilationUnit, String testAnnotation) { + try { + IAnnotation[] annotations = method.getAnnotations(); + IAnnotation test = null; + for (IAnnotation annotation : annotations) { + String annotationElementName = annotation.getElementName(); + if ("Test".equals(annotationElementName)) { + test = annotation; + break; + } + if (testAnnotation.equals(annotationElementName)) { + return true; + } + } + return test != null && isImportOfTestAnnotationExist(compilationUnit, testAnnotation); + } catch (JavaModelException e) { + LOG.info("Can't read method's annotations.", e); + return false; + } + } + + private boolean isImportOfTestAnnotationExist(ICompilationUnit compilationUnit, String testAnnotation) { + try { + IImportDeclaration[] imports = compilationUnit.getImports(); + for (IImportDeclaration importDeclaration : imports) { + String elementName = importDeclaration.getElementName(); + if (testAnnotation.equals(elementName)) { + return true; + } + if (importDeclaration.isOnDemand() && + testAnnotation.startsWith(elementName.substring(0, elementName.length() - 3))) { //remove .* + return true; + } + } + } catch (JavaModelException e) { + LOG.info("Can't read class imports.", e); + return false; + } + return false; + } + + private List findClassesInContainer(IJavaElement container, String testMethodAnnotation, String testClassAnnotation) { + List result = new LinkedList<>(); + IRegion region = getRegion(container); + try { + ITypeHierarchy hierarchy = JavaCore.newTypeHierarchy(region, null, null); + IType[] allClasses = hierarchy.getAllClasses(); + + // search for all types with references to RunWith and Test and all subclasses + HashSet candidates = new HashSet<>(allClasses.length); + SearchRequestor requestor = new AnnotationSearchRequestor(hierarchy, candidates); + + IJavaSearchScope scope = SearchEngine.createJavaSearchScope(allClasses, IJavaSearchScope.SOURCES); + int matchRule = SearchPattern.R_CASE_SENSITIVE; + + SearchPattern testPattern = SearchPattern.createPattern(testMethodAnnotation, + IJavaSearchConstants.ANNOTATION_TYPE, + IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE, + matchRule); + + + SearchPattern runWithPattern = isNullOrEmpty(testClassAnnotation) + ? testPattern + : SearchPattern.createPattern(testClassAnnotation, + IJavaSearchConstants.ANNOTATION_TYPE, + IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE, + matchRule); + + + SearchPattern annotationsPattern = SearchPattern.createOrPattern(runWithPattern, testPattern); + SearchParticipant[] searchParticipants = new SearchParticipant[]{SearchEngine.getDefaultSearchParticipant()}; + new SearchEngine().search(annotationsPattern, searchParticipants, scope, requestor, null); + + // find all classes in the region + for (IType candidate : candidates) { + if (isAccessibleClass(candidate) && !Flags.isAbstract(candidate.getFlags()) && region.contains(candidate)) { + result.add(candidate.getFullyQualifiedName()); + } + } + } catch ( + CoreException e) + + { + LOG.info("Can't build project hierarchy.", e); + } + + return result; + } + + private IRegion getRegion(IJavaElement element) { + IRegion result = JavaCore.newRegion(); + if (element.getElementType() == IJavaElement.JAVA_PROJECT) { + //for projects only add the contained source folders + try { + IPackageFragmentRoot[] packageFragmentRoots = ((IJavaProject)element).getPackageFragmentRoots(); + for (IPackageFragmentRoot packageFragmentRoot : packageFragmentRoots) { + if (!packageFragmentRoot.isArchive()) { + result.add(packageFragmentRoot); + } + } + } catch (JavaModelException e) { + LOG.info("Can't read source folders.", e); + } + } else { + result.add(element); + } + return result; + } + + private static boolean isAccessibleClass(IType type) throws JavaModelException { + int flags = type.getFlags(); + if (Flags.isInterface(flags)) { + return false; + } + IJavaElement parent = type.getParent(); + while (true) { + if (parent instanceof ICompilationUnit || parent instanceof IClassFile) { + return true; + } + if (!(parent instanceof IType) || !Flags.isStatic(flags) || !Flags.isPublic(flags)) { + return false; + } + flags = ((IType)parent).getFlags(); + parent = parent.getParent(); + } + } +} diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/pom.xml b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/pom.xml new file mode 100644 index 0000000000..2110029e29 --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/pom.xml @@ -0,0 +1,72 @@ + + + + 4.0.0 + + che-plugin-testing-junit + org.eclipse.che.plugin + 5.16.0-SNAPSHOT + + che-plugin-testing-junit-ide + Che Plugin :: Java Testing :: JUnit IDE + + + com.google.inject + guice + + + javax.validation + validation-api + + + org.eclipse.che.core + che-core-commons-gwt + + + org.eclipse.che.core + che-core-ide-api + + + org.eclipse.che.plugin + che-plugin-testing-ide + + + org.vectomatic + lib-gwt-svg + + + com.google.gwt + gwt-user + provided + + + com.google.gwt.inject + gin + provided + + + + + + src/main/java + + **/*.java + + + + src/main/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/JUnitTestAction.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/JUnitTestAction.java new file mode 100644 index 0000000000..2e592119e1 --- /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/JUnitTestAction.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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; + +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.action.Action; +import org.eclipse.che.ide.api.action.ActionManager; +import org.eclipse.che.ide.api.action.DefaultActionGroup; +import org.eclipse.che.plugin.testing.ide.TestAction; +import org.eclipse.che.plugin.testing.junit.ide.action.DebugJUnitTestAction; +import org.eclipse.che.plugin.testing.junit.ide.action.RunJUnitTestAction; + +/** + * Registrar of JUnit run/debug actions. + */ +public class JUnitTestAction implements TestAction { + public static final String TEST_ACTION_RUN = "TestJUnitActionRun"; + public static final String TEST_ACTION_DEBUG = "TestJUnitActionDebug"; + private final Action runTestAction; + private final Action debugTestAction; + + @Inject + public JUnitTestAction(ActionManager actionManager, + RunJUnitTestAction runJUnitTestAction, + DebugJUnitTestAction debugJUnitTestAction) { + actionManager.registerAction(TEST_ACTION_RUN, runJUnitTestAction); + actionManager.registerAction(TEST_ACTION_DEBUG, debugJUnitTestAction); + this.runTestAction = runJUnitTestAction; + this.debugTestAction = debugJUnitTestAction; + } + + @Override + public void addMainMenuItems(DefaultActionGroup testMainMenu) { + testMainMenu.add(runTestAction); + testMainMenu.add(debugTestAction); + } + + @Override + public void addContextMenuItems(DefaultActionGroup testContextMenu) { + testContextMenu.add(runTestAction); + testContextMenu.add(debugTestAction); + } +} 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/JUnitTestLocalizationConstant.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/JUnitTestLocalizationConstant.java new file mode 100644 index 0000000000..0942db42bd --- /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/JUnitTestLocalizationConstant.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * 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; + +import com.google.gwt.i18n.client.Messages; + +/** + * Localization constants. Interface to represent the constants defined in resource bundle: + * 'JUnitTestLocalizationConstant.properties'. + */ +public interface JUnitTestLocalizationConstant extends Messages { + + @Key("action.run.title") + String actionRunTestTitle(); + + @Key("action.run.description") + String actionRunTestDescription(); + + @Key("action.debug.title") + String actionDebugTestTitle(); + + @Key("action.debug.description") + String actionDebugDescription(); +} 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/JUnitTestResources.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/JUnitTestResources.java new file mode 100644 index 0000000000..30290604e8 --- /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/JUnitTestResources.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * 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; + +import com.google.gwt.resources.client.ClientBundle; + +import org.vectomatic.dom.svg.ui.SVGResource; +/** + * Resource bundle for JUnit module. + */ +public interface JUnitTestResources extends ClientBundle { + + @Source("org/eclipse/che/plugin/testing/junit/ide/svg/test.svg") + SVGResource testIcon(); + +} 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/DebugJUnitTestAction.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/DebugJUnitTestAction.java new file mode 100644 index 0000000000..0370397ecc --- /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/DebugJUnitTestAction.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * 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 com.google.inject.Inject; +import com.google.web.bindery.event.shared.EventBus; + +import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.action.Presentation; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.debug.DebugConfigurationsManager; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.dto.DtoFactory; +import org.eclipse.che.ide.util.Pair; +import org.eclipse.che.plugin.testing.ide.TestServiceClient; +import org.eclipse.che.plugin.testing.ide.action.RunDebugTestAbstractAction; +import org.eclipse.che.plugin.testing.ide.handler.TestingHandler; +import org.eclipse.che.plugin.testing.ide.view2.TestResultPresenter; +import org.eclipse.che.plugin.testing.junit.ide.JUnitTestLocalizationConstant; +import org.eclipse.che.plugin.testing.junit.ide.JUnitTestResources; + +import javax.validation.constraints.NotNull; + +import static java.util.Collections.singletonList; +import static org.eclipse.che.ide.part.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID; + +/** + * The action for activation debugger for JUnit test. + */ +public class DebugJUnitTestAction extends RunDebugTestAbstractAction { + @Inject + public DebugJUnitTestAction(JUnitTestResources resources, + EventBus eventBus, + TestServiceClient client, + TestingHandler testingHandler, + DtoFactory dtoFactory, + NotificationManager notificationManager, + DebugConfigurationsManager debugConfigurationsManager, + AppContext appContext, + TestResultPresenter testResultPresenter, + JUnitTestLocalizationConstant localization) { + super(eventBus, + testResultPresenter, + testingHandler, + debugConfigurationsManager, + client, + dtoFactory, + appContext, + notificationManager, + singletonList(PROJECT_PERSPECTIVE_ID), + localization.actionDebugDescription(), + localization.actionDebugTestTitle(), + resources.testIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + Pair frameworkAndTestName = Pair.of(JUNIT_FRAMEWORK_NAME, null); + actionPerformed(frameworkAndTestName, true); + } + + @Override + public void updateInPerspective(@NotNull ActionEvent e) { + Presentation presentation = e.getPresentation(); + presentation.setVisible(!isEditorInFocus); + if (!isEditorInFocus) { + analyzeProjectTreeSelection(); + } + presentation.setEnabled(isEnable); + } + +} 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/RunJUnitTestAction.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/RunJUnitTestAction.java new file mode 100644 index 0000000000..493ca2a1c1 --- /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/RunJUnitTestAction.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * 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 com.google.inject.Inject; +import com.google.web.bindery.event.shared.EventBus; + +import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.action.Presentation; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.debug.DebugConfigurationsManager; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.dto.DtoFactory; +import org.eclipse.che.ide.util.Pair; +import org.eclipse.che.plugin.testing.ide.TestServiceClient; +import org.eclipse.che.plugin.testing.ide.action.RunDebugTestAbstractAction; +import org.eclipse.che.plugin.testing.ide.handler.TestingHandler; +import org.eclipse.che.plugin.testing.ide.view2.TestResultPresenter; +import org.eclipse.che.plugin.testing.junit.ide.JUnitTestLocalizationConstant; +import org.eclipse.che.plugin.testing.junit.ide.JUnitTestResources; + +import javax.validation.constraints.NotNull; + +import static java.util.Collections.singletonList; +import static org.eclipse.che.ide.part.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID; + +/** + * The action for running JUnit test. + */ +public class RunJUnitTestAction extends RunDebugTestAbstractAction { + + @Inject + public RunJUnitTestAction(JUnitTestResources resources, + EventBus eventBus, + TestingHandler testingHandler, + TestResultPresenter testResultPresenter, + DebugConfigurationsManager debugConfigurationsManager, + TestServiceClient client, + AppContext appContext, + DtoFactory dtoFactory, + NotificationManager notificationManager, + JUnitTestLocalizationConstant localization) { + super(eventBus, + testResultPresenter, + testingHandler, + debugConfigurationsManager, + client, + dtoFactory, + appContext, + notificationManager, + singletonList(PROJECT_PERSPECTIVE_ID), + localization.actionRunTestDescription(), + localization.actionRunTestTitle(), + resources.testIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + Pair frameworkAndTestName = Pair.of(JUNIT_FRAMEWORK_NAME, null); + actionPerformed(frameworkAndTestName, false); + } + + @Override + public void updateInPerspective(@NotNull ActionEvent e) { + Presentation presentation = e.getPresentation(); + presentation.setVisible(!isEditorInFocus); + if (!isEditorInFocus) { + analyzeProjectTreeSelection(); + } + presentation.setEnabled(isEnable); + } +} 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/inject/JUnitGinModule.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/java/org/eclipse/che/plugin/testing/junit/ide/inject/JUnitGinModule.java new file mode 100644 index 0000000000..cb47de9345 --- /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/inject/JUnitGinModule.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.testing.junit.ide.inject; + +import com.google.gwt.inject.client.AbstractGinModule; +import com.google.gwt.inject.client.multibindings.GinMultibinder; + +import org.eclipse.che.ide.api.extension.ExtensionGinModule; +import org.eclipse.che.plugin.testing.ide.TestAction; +import org.eclipse.che.plugin.testing.junit.ide.JUnitTestAction; + +/** + * Gin module for JUnit extension. + */ +@ExtensionGinModule +public class JUnitGinModule extends AbstractGinModule { + @Override + protected void configure() { + GinMultibinder.newSetBinder(binder(), TestAction.class).addBinding().to(JUnitTestAction.class); + } +} diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/resources/org/eclipse/che/plugin/testing/junit/JUnit.gwt.xml b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/resources/org/eclipse/che/plugin/testing/junit/JUnit.gwt.xml new file mode 100644 index 0000000000..f838358478 --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/resources/org/eclipse/che/plugin/testing/junit/JUnit.gwt.xml @@ -0,0 +1,21 @@ + + + + + + + + + + diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/resources/org/eclipse/che/plugin/testing/junit/ide/JUnitTestLocalizationConstant.properties b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/resources/org/eclipse/che/plugin/testing/junit/ide/JUnitTestLocalizationConstant.properties new file mode 100644 index 0000000000..51544a2e51 --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/resources/org/eclipse/che/plugin/testing/junit/ide/JUnitTestLocalizationConstant.properties @@ -0,0 +1,20 @@ +# +# 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 +# + + + +##### Actions ##### +action.run.title = Run JUnit Test +action.run.description = Run JUnit tests + +action.debug.title = Debug JUnit Test +action.debug.description = Debug JUnit tests + diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/resources/org/eclipse/che/plugin/testing/junit/ide/svg/test.svg b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/resources/org/eclipse/che/plugin/testing/junit/ide/svg/test.svg new file mode 100644 index 0000000000..79b385d2dd --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-ide/src/main/resources/org/eclipse/che/plugin/testing/junit/ide/svg/test.svg @@ -0,0 +1,18 @@ + + + + + + + diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/TestingMessageHelper.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/TestingMessageHelper.java index d0ba251172..daabc6c263 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/TestingMessageHelper.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/TestingMessageHelper.java @@ -60,13 +60,9 @@ public class TestingMessageHelper { * * @param out * output stream - * @param description - * information about test cass */ - public static void rootPresentation(PrintStream out, Description description) { - out.println(create(ROOT_NAME, - new Pair(NAME, "Default Suite"), - new Pair(LOCATION, "file://" + description.getClassName()))); + public static void rootPresentation(PrintStream out) { + out.println(create(ROOT_NAME, new Pair(NAME, "Default Suite"))); } /** @@ -150,7 +146,7 @@ public class TestingMessageHelper { public static void testSuiteStarted(PrintStream out, Description description) { out.println(create(TEST_SUITE_STARTED, new Pair(NAME, escape(description.getClassName())), - new Pair(LOCATION, escape(description.getClassName())))); + new Pair(LOCATION, "java:test://" + escape(description.getClassName())))); } /** diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/CheJUnitCoreRunner.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/CheJUnitCoreRunner.java index 067ceb18b2..9d40f90225 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/CheJUnitCoreRunner.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/CheJUnitCoreRunner.java @@ -13,10 +13,12 @@ package org.eclipse.che.junit.junit4; import org.eclipse.che.junit.TestingMessageHelper; import org.eclipse.che.junit.junit4.listeners.CheJUnitTestListener; import org.eclipse.che.junit.junit4.listeners.JUnitExecutionListener; -import org.junit.runner.Description; import org.junit.runner.JUnitCore; -import org.junit.runner.Request; -import org.junit.runner.Runner; +import org.junit.runner.Result; +import org.junit.runner.notification.RunListener; +import org.junit.runner.notification.RunNotifier; + +import java.util.List; /** * Custom JUnit4 runner that reports results visa {@link CheJUnitTestListener}. @@ -33,28 +35,37 @@ public class CheJUnitCoreRunner extends JUnitCore { * (for example full.qualified.ClassName#methodName) */ public void run(String[] suites) { - Request request = TestRunnerUtil.buildRequest(suites); - if (request == null) { + createListener(); + + List newSuites = TestRunnerUtil.createTestReferences(suites); + + if (newSuites.isEmpty()) { TestingMessageHelper.reporterAttached(System.out); - System.err.print("No test found to run."); - } else { - Runner runner = request.getRunner(); - Description description = runner.getDescription(); - - if (cheJUnitTestListener != null) { - cheJUnitTestListener.suiteTreeStarted(description); - cheJUnitTestListener.suiteSendTree(description); - cheJUnitTestListener.suiteTreeEnded(description); - } - - super.run(request); + return; } + + RunNotifier runNotifier = new RunNotifier(); + runNotifier.addListener(new JUnitExecutionListener(cheJUnitTestListener)); + cheJUnitTestListener.testRunStarted(); + + for (JUnit4TestReference jUnit4TestReference : newSuites) { + jUnit4TestReference.sendTree(cheJUnitTestListener); + } + + Result result = new Result(); + final RunListener listener = result.createListener(); + runNotifier.addListener(listener); + + for (JUnit4TestReference testReference : newSuites) { + testReference.run(runNotifier); + } + runNotifier.fireTestRunFinished(result); } /** * Creates custom listener {@link CheJUnitTestListener} and adds it to */ - public void createListener() { + private void createListener() { cheJUnitTestListener = new CheJUnitTestListener(); this.addListener(new JUnitExecutionListener(cheJUnitTestListener)); } diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/CheJUnitLauncher.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/CheJUnitLauncher.java index 79589a4263..7325392eea 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/CheJUnitLauncher.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/CheJUnitLauncher.java @@ -23,12 +23,11 @@ public class CheJUnitLauncher { * arrays of tests to be executed */ public static void main(String[] args) { - CheJUnitCoreRunner jUnitCore = new CheJUnitCoreRunner(); - jUnitCore.createListener(); if (args.length == 0) { TestingMessageHelper.reporterAttached(System.out); System.err.print("No test found to run."); } else { + CheJUnitCoreRunner jUnitCore = new CheJUnitCoreRunner(); jUnitCore.run(args); } } diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/JUnit4TestReference.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/JUnit4TestReference.java new file mode 100644 index 0000000000..fc58393fba --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/JUnit4TestReference.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * 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.junit.junit4; + +import org.eclipse.che.junit.junit4.listeners.CheJUnitTestListener; +import org.junit.runner.Description; +import org.junit.runner.Runner; +import org.junit.runner.notification.RunNotifier; + +/** + * Describes request of the test runner. + */ +public class JUnit4TestReference { + private final Runner runner; + private final Description description; + + public JUnit4TestReference(Runner runner, Description root) { + this.runner = runner; + description = root; + } + + /** Returns count of the test methods. */ + public int countTestCases() { + return countTestCases(description); + } + + /** Returns a {@link Runner} for this Request */ + public Runner getRunner() { + return runner; + } + + /** @return a {@link Description} showing the tests to be run by the receiver. */ + public Description getDescription() { + return description; + } + + /** + * Run the tests for this runner. + * + * @param runNotifier + * will be notified of events while tests are being run--tests being + * started, finishing, and failing + */ + public void run(RunNotifier runNotifier) { + runner.run(runNotifier); + } + + /** Sends tree structure of the current test. */ + public void sendTree(CheJUnitTestListener listener) { + if(description.isTest()) + + listener.suiteTreeStarted(description); + listener.suiteSendTree(description); + listener.suiteTreeEnded(description); + } + + @Override + public String toString() { + return description.toString(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof JUnit4TestReference)) + return false; + + JUnit4TestReference ref = (JUnit4TestReference)obj; + return (ref.description.equals(description)); + } + + @Override + public int hashCode() { + return description.hashCode(); + } + + private int countTestCases(Description description) { + if (description.isTest()) { + return 1; + } else { + int result = 0; + for (Description child : description.getChildren()) { + result += countTestCases(child); + } + return result; + } + } +} diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/TestRunnerUtil.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/TestRunnerUtil.java index 6d7c31de9a..5973bd4298 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/TestRunnerUtil.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/TestRunnerUtil.java @@ -11,66 +11,76 @@ package org.eclipse.che.junit.junit4; import org.junit.runner.Request; +import org.junit.runner.Runner; import java.util.LinkedList; import java.util.List; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; + /** * Utility class for building test executing request. */ public class TestRunnerUtil { /** - * Creates a request which contains all tests to be executed. + * Build list of {@clink JUnit4TestReference}. * - * @param args - * array of test classes or test method (if args.length == 1) to be executed - * @return an abstract description of tests to be run + * @param suites + * array of test classes or test method (if args.length == 1) to execute + * @return list of {@link JUnit4TestReference} */ - public static Request buildRequest(String[] args) { - if (args.length == 0) { - return null; - } - if (args.length == 1) { - String suite = args[0]; + public static List createTestReferences(String[] suites) { + if (suites.length == 0) { + return emptyList(); + } else if (suites.length == 1) { + String suite = suites[0]; int separatorIndex = suite.indexOf('#'); return separatorIndex == -1 ? getRequestForClass(suite) : getRequestForOneMethod(suite, separatorIndex); } - return getRequestForClasses(args); + return getRequestForClasses(suites); } - private static Request getRequestForOneMethod(String suite, int separatorIndex) { + private static List getRequestForOneMethod(String suite, int separatorIndex) { try { Class suiteClass = Class.forName(suite.substring(0, separatorIndex)); String method = suite.substring(separatorIndex + 1); - return Request.method(suiteClass, method); + Request request = Request.method(suiteClass, method); + Runner runner = request.getRunner(); + return singletonList(new JUnit4TestReference(runner, runner.getDescription())); } catch (ClassNotFoundException e) { - System.err.print("No test found to run. Args is 0"); - return null; + System.err.print("No test found to run."); + return emptyList(); } } - private static Request getRequestForClass(String suite) { + private static List getRequestForClass(String suite) { try { - return Request.aClass(Class.forName(suite)); + Request request = Request.aClass(Class.forName(suite)); + Runner runner = request.getRunner(); + return singletonList(new JUnit4TestReference(runner, runner.getDescription())); } catch (ClassNotFoundException e) { - System.err.print("No test found to run. Args is 0"); - return null; + System.err.print("No test found to run."); + return emptyList(); } } - private static Request getRequestForClasses(String[] args) { - List> suites = new LinkedList<>(); + private static List getRequestForClasses(String[] args) { + List suites = new LinkedList<>(); for (String classFqn : args) { try { Class aClass = Class.forName(classFqn); - suites.add(aClass); + Request request = Request.aClass(aClass); + Runner runner = request.getRunner(); + suites.add(new JUnit4TestReference(runner, runner.getDescription())); } catch (ClassNotFoundException ignored) { } } if (suites.isEmpty()) { - return null; + System.err.print("No test found to run."); + return emptyList(); } - return Request.classes(suites.toArray(new Class[suites.size()])); + return suites; } } diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/listeners/CheJUnitTestListener.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/listeners/CheJUnitTestListener.java index 115d2c46f9..b16f7d76bd 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/listeners/CheJUnitTestListener.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/listeners/CheJUnitTestListener.java @@ -32,12 +32,9 @@ public class CheJUnitTestListener { /** * Called before any tests have been run. - * - * @param description - * describes the tests to be run */ - public void testRunStarted(Description description) { - TestingMessageHelper.rootPresentation(out, description); + public void testRunStarted() { + TestingMessageHelper.rootPresentation(out); } /** @@ -129,9 +126,11 @@ public class CheJUnitTestListener { if (description.isTest()) { TestingMessageHelper.treeNode(out, description); } else { + suiteTreeStarted(description); for (Description child : description.getChildren()) { suiteSendTree(child); } + suiteTreeEnded(description); } } diff --git a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/listeners/JUnitExecutionListener.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/listeners/JUnitExecutionListener.java index aa46126bed..dbf8adc2dd 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/listeners/JUnitExecutionListener.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-runtime/src/main/java/org/eclipse/che/junit/junit4/listeners/JUnitExecutionListener.java @@ -31,7 +31,7 @@ public class JUnitExecutionListener extends RunListener { @Override public void testRunStarted(Description description) throws Exception { - delegate.testRunStarted(description); + delegate.testRunStarted(); } @Override 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/junit4/JUnit4TestRunner.java b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/junit4/JUnit4TestRunner.java index 0c7c3e0635..5b2cd11595 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/junit4/JUnit4TestRunner.java +++ b/plugins/plugin-testing-java/plugin-testing-junit/che-plugin-testing-junit-server/src/main/java/org/eclipse/che/plugin/testing/junit/server/junit4/JUnit4TestRunner.java @@ -20,19 +20,17 @@ import org.eclipse.che.commons.lang.execution.CommandLine; import org.eclipse.che.commons.lang.execution.ExecutionException; import org.eclipse.che.commons.lang.execution.JavaParameters; import org.eclipse.che.commons.lang.execution.ProcessHandler; +import org.eclipse.che.junit.junit4.CheJUnitCoreRunner; import org.eclipse.che.plugin.java.testing.AbstractJavaTestRunner; import org.eclipse.che.plugin.java.testing.ClasspathUtil; +import org.eclipse.che.plugin.java.testing.JavaTestAnnotations; +import org.eclipse.che.plugin.java.testing.JavaTestFinder; import org.eclipse.che.plugin.java.testing.ProjectClasspathProvider; import org.eclipse.jdt.core.Flags; -import org.eclipse.jdt.core.IAnnotation; import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.IImportDeclaration; -import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.che.junit.junit4.CheJUnitCoreRunner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,18 +46,20 @@ import java.util.Set; public class JUnit4TestRunner extends AbstractJavaTestRunner { private static final Logger LOG = LoggerFactory.getLogger(JUnit4TestRunner.class); - private static final String JUNIT_TEST_ANNOTATION = "org.junit.Test"; - private static final String JUNIT_TEST_NAME = "junit"; - private static final String MAIN_CLASS_NAME = "org.eclipse.che.junit.junit4.CheJUnitLauncher"; + private static final String JUNIT_TEST_NAME = "junit"; + private static final String MAIN_CLASS_NAME = "org.eclipse.che.junit.junit4.CheJUnitLauncher"; private String workspacePath; + private JavaTestFinder javaTestFinder; private ProjectClasspathProvider classpathProvider; @Inject public JUnit4TestRunner(@Named("che.user.workspaces.storage") String workspacePath, + JavaTestFinder javaTestFinder, ProjectClasspathProvider classpathProvider) { - super(workspacePath); + super(workspacePath, javaTestFinder); this.workspacePath = workspacePath; + this.javaTestFinder = javaTestFinder; this.classpathProvider = classpathProvider; } @@ -82,15 +82,14 @@ public class JUnit4TestRunner extends AbstractJavaTestRunner { public boolean isTestMethod(IMethod method, ICompilationUnit compilationUnit) { try { int flags = method.getFlags(); - if (method.isConstructor() || - !Flags.isPublic(flags) || - Flags.isAbstract(flags) || - Flags.isStatic(flags) || - !"V".equals(method.getReturnType())) { // 'V' is void signature - return false; - } + // 'V' is void signature + return !(method.isConstructor() || + !Flags.isPublic(flags) || + Flags.isAbstract(flags) || + Flags.isStatic(flags) || + !"V".equals(method.getReturnType())) + && javaTestFinder.isTest(method, compilationUnit, JavaTestAnnotations.JUNIT4X_TEST.getName()); - return isTest(method, compilationUnit); } catch (JavaModelException ignored) { return false; } @@ -108,8 +107,13 @@ public class JUnit4TestRunner extends AbstractJavaTestRunner { classPath.add(ClasspathUtil.getJarPathForClass(CheJUnitCoreRunner.class)); parameters.getClassPath().addAll(classPath); - String suite = createTestSuite(context, javaProject); - parameters.getParametersList().add(suite); + List suite = createTestSuite(context, + javaProject, + JavaTestAnnotations.JUNIT4X_TEST.getName(), + JavaTestAnnotations.JUNIT4X_RUN_WITH.getName()); + for (String element : suite) { + parameters.getParametersList().add(element); + } if (context.isDebugModeEnable()) { generateDebuggerPort(); parameters.getVmParameters().add("-Xdebug"); @@ -125,94 +129,6 @@ public class JUnit4TestRunner extends AbstractJavaTestRunner { return null; } - private String createTestSuite(TestExecutionContext context, IJavaProject javaProject) { - switch (context.getTestType()) { - case FILE: - return createClassRequest(javaProject, context.getFilePath()); - case FOLDER: - return createPackageRequest(javaProject, context.getFilePath()); - case PROJECT: - return createProjectRequest(javaProject); - case CURSOR_POSITION: - return createMethodRequest(javaProject, context.getFilePath(), context.getCursorOffset()); - } - - return null; - } - - private String createMethodRequest(IJavaProject javaProject, String filePath, int cursorOffset) { - ICompilationUnit compilationUnit = findCompilationUnitByPath(javaProject, filePath); - IType primaryType = compilationUnit.findPrimaryType(); - String qualifiedName = primaryType.getFullyQualifiedName(); - try { - IJavaElement element = compilationUnit.getElementAt(cursorOffset); - if (element instanceof IMethod) { - IMethod method = (IMethod)element; - qualifiedName = qualifiedName + '#' + method.getElementName(); - } - } catch (JavaModelException e) { - LOG.debug("Can't read a method.", e); - } - return qualifiedName; - } - - private String createProjectRequest(IJavaProject javaProject) { - //TODO add suite to run all tests from the project - return null; - } - - private String createPackageRequest(IJavaProject javaProject, String filePath) { - //TODO add suite to run all tests from the package - return null; - } - - private String createClassRequest(IJavaProject javaProject, String filePath) { - ICompilationUnit compilationUnit = findCompilationUnitByPath(javaProject, filePath); - IType primaryType = compilationUnit.findPrimaryType(); - return primaryType.getFullyQualifiedName(); - } - - private boolean isTest(IMethod method, ICompilationUnit compilationUnit) { - try { - IAnnotation[] annotations = method.getAnnotations(); - IAnnotation test = null; - for (IAnnotation annotation : annotations) { - String annotationElementName = annotation.getElementName(); - if ("Test".equals(annotationElementName)) { - test = annotation; - break; - } - if (JUNIT_TEST_ANNOTATION.equals(annotationElementName)) { - return true; - } - } - return test != null && isImportOfTestAnnotationExist(compilationUnit); - } catch (JavaModelException e) { - LOG.info("Can't read method's annotations.", e); - return false; - } - } - - private boolean isImportOfTestAnnotationExist(ICompilationUnit compilationUnit) { - try { - IImportDeclaration[] imports = compilationUnit.getImports(); - for (IImportDeclaration importDeclaration : imports) { - String elementName = importDeclaration.getElementName(); - if (JUNIT_TEST_ANNOTATION.equals(elementName)) { - return true; - } - if (importDeclaration.isOnDemand() && - JUNIT_TEST_ANNOTATION.startsWith(elementName.substring(0, elementName.length() - 3))) { //remove .* - return true; - } - } - } catch (JavaModelException e) { - LOG.info("Can't read class imports.", e); - return false; - } - return false; - } - @Override @Deprecated public TestResult execute(Map testParameters) throws Exception { diff --git a/plugins/plugin-testing-java/plugin-testing-junit/pom.xml b/plugins/plugin-testing-java/plugin-testing-junit/pom.xml index 7d7d8f0d96..542154f475 100644 --- a/plugins/plugin-testing-java/plugin-testing-junit/pom.xml +++ b/plugins/plugin-testing-java/plugin-testing-junit/pom.xml @@ -22,6 +22,7 @@ pom Che Plugin :: Java Testing :: JUnit Parent + che-plugin-testing-junit-ide che-plugin-testing-junit-server che-plugin-testing-junit-runtime diff --git a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/pom.xml b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/pom.xml new file mode 100644 index 0000000000..99a3b5f111 --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/pom.xml @@ -0,0 +1,72 @@ + + + + 4.0.0 + + che-plugin-testing-testng + org.eclipse.che.plugin + 5.16.0-SNAPSHOT + + che-plugin-testing-testng-ide + Che Plugin :: Java Testing :: TestNG IDE + + + com.google.inject + guice + + + javax.validation + validation-api + + + org.eclipse.che.core + che-core-commons-gwt + + + org.eclipse.che.core + che-core-ide-api + + + org.eclipse.che.plugin + che-plugin-testing-ide + + + org.vectomatic + lib-gwt-svg + + + com.google.gwt + gwt-user + provided + + + com.google.gwt.inject + gin + provided + + + + + + src/main/java + + **/*.java + + + + src/main/resources + + + + diff --git a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/TestNgLocalizationConstant.java b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/TestNgLocalizationConstant.java new file mode 100644 index 0000000000..4eee2efb40 --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/TestNgLocalizationConstant.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * 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.testng.ide; + +import com.google.gwt.i18n.client.Messages; + +/** + * Localization constants. Interface to represent the constants defined in resource bundle: + * 'TestNgTestLocalizationConstant.properties'. + */ +public interface TestNgLocalizationConstant extends Messages { + + @Key("action.testNg.run.title") + String actionRunTestTitle(); + + @Key("action.testNg.run.description") + String actionRunTestDescription(); + + @Key("action.testNg.debug.title") + String actionDebugTestTitle(); + + @Key("action.testNg.debug.description") + String actionDebugDescription(); +} diff --git a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/TestNgResources.java b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/TestNgResources.java new file mode 100644 index 0000000000..f8da014506 --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/TestNgResources.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * 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.testng.ide; + +import com.google.gwt.resources.client.ClientBundle; + +import org.vectomatic.dom.svg.ui.SVGResource; +/** + * Resource bundle for TestNg extension. + */ +public interface TestNgResources extends ClientBundle { + + @Source("org/eclipse/che/plugin/testing/testng/ide/svg/test.svg") + SVGResource testIcon(); + +} diff --git a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/TestNgTestAction.java b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/TestNgTestAction.java new file mode 100644 index 0000000000..ffc6596517 --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/TestNgTestAction.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * 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.testng.ide; + +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.action.Action; +import org.eclipse.che.ide.api.action.ActionManager; +import org.eclipse.che.ide.api.action.DefaultActionGroup; +import org.eclipse.che.plugin.testing.ide.TestAction; +import org.eclipse.che.plugin.testing.testng.ide.action.DebugTestNgTestAction; +import org.eclipse.che.plugin.testing.testng.ide.action.RunTestNgTestAction; + +/** + * Registrar for run/debug actions. + */ +public class TestNgTestAction implements TestAction { + public static final String TEST_ACTION_RUN = "TestNgActionRun"; + public static final String TEST_ACTION_DEBUG = "TestNgActionDebug"; + + private final Action runTestAction; + private final Action debugTestAction; + + @Inject + public TestNgTestAction(ActionManager actionManager, + RunTestNgTestAction runTestNgTestAction, + DebugTestNgTestAction debugTestNgTestAction) { + actionManager.registerAction(TEST_ACTION_RUN, runTestNgTestAction); + actionManager.registerAction(TEST_ACTION_DEBUG, debugTestNgTestAction); + this.runTestAction = runTestNgTestAction; + this.debugTestAction = debugTestNgTestAction; + } + + @Override + public void addMainMenuItems(DefaultActionGroup testMainMenu) { + testMainMenu.add(runTestAction); + testMainMenu.add(debugTestAction); + } + + @Override + public void addContextMenuItems(DefaultActionGroup testContextMenu) { + testContextMenu.add(runTestAction); + testContextMenu.add(debugTestAction); + } +} diff --git a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/action/DebugTestNgTestAction.java b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/action/DebugTestNgTestAction.java new file mode 100644 index 0000000000..1d6ebdd49d --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/action/DebugTestNgTestAction.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * 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.testng.ide.action; + +import com.google.inject.Inject; +import com.google.web.bindery.event.shared.EventBus; + +import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.action.Presentation; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.debug.DebugConfigurationsManager; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.dto.DtoFactory; +import org.eclipse.che.ide.util.Pair; +import org.eclipse.che.plugin.testing.ide.TestServiceClient; +import org.eclipse.che.plugin.testing.ide.action.RunDebugTestAbstractAction; +import org.eclipse.che.plugin.testing.ide.handler.TestingHandler; +import org.eclipse.che.plugin.testing.ide.view2.TestResultPresenter; +import org.eclipse.che.plugin.testing.testng.ide.TestNgLocalizationConstant; +import org.eclipse.che.plugin.testing.testng.ide.TestNgResources; + +import javax.validation.constraints.NotNull; + +import static java.util.Collections.singletonList; +import static org.eclipse.che.ide.part.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID; + +/** + * Action for debugging TestNg test. + */ +public class DebugTestNgTestAction extends RunDebugTestAbstractAction { + @Inject + public DebugTestNgTestAction(TestNgResources resources, + EventBus eventBus, + TestServiceClient client, + TestingHandler testingHandler, + DtoFactory dtoFactory, + NotificationManager notificationManager, + DebugConfigurationsManager debugConfigurationsManager, + AppContext appContext, + TestResultPresenter testResultPresenter, + TestNgLocalizationConstant localization) { + super(eventBus, + testResultPresenter, + testingHandler, + debugConfigurationsManager, + client, + dtoFactory, + appContext, + notificationManager, + singletonList(PROJECT_PERSPECTIVE_ID), + localization.actionDebugDescription(), + localization.actionDebugTestTitle(), + resources.testIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + Pair frameworkAndTestName = Pair.of(TESTNG_FRAMEWORK_NAME, null); + actionPerformed(frameworkAndTestName, true); + } + + @Override + public void updateInPerspective(@NotNull ActionEvent e) { + Presentation presentation = e.getPresentation(); + presentation.setVisible(!isEditorInFocus); + if (!isEditorInFocus) { + analyzeProjectTreeSelection(); + } + presentation.setEnabled(isEnable); + } +} diff --git a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/action/RunTestNgTestAction.java b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/action/RunTestNgTestAction.java new file mode 100644 index 0000000000..96c0e525e9 --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/action/RunTestNgTestAction.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * 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.testng.ide.action; + +import com.google.inject.Inject; +import com.google.web.bindery.event.shared.EventBus; + +import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.action.Presentation; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.debug.DebugConfigurationsManager; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.dto.DtoFactory; +import org.eclipse.che.ide.util.Pair; +import org.eclipse.che.plugin.testing.ide.TestServiceClient; +import org.eclipse.che.plugin.testing.ide.action.RunDebugTestAbstractAction; +import org.eclipse.che.plugin.testing.ide.handler.TestingHandler; +import org.eclipse.che.plugin.testing.ide.view2.TestResultPresenter; +import org.eclipse.che.plugin.testing.testng.ide.TestNgLocalizationConstant; +import org.eclipse.che.plugin.testing.testng.ide.TestNgResources; + +import javax.validation.constraints.NotNull; + +import static java.util.Collections.singletonList; +import static org.eclipse.che.ide.part.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID; + +/** + * Action for running TestNg test. + */ +public class RunTestNgTestAction extends RunDebugTestAbstractAction { + @Inject + public RunTestNgTestAction(TestNgResources resources, + EventBus eventBus, + DebugConfigurationsManager debugConfigurationsManager, + TestServiceClient client, + TestingHandler testingHandler, + DtoFactory dtoFactory, + NotificationManager notificationManager, + AppContext appContext, + TestResultPresenter testResultPresenter, + TestNgLocalizationConstant localization) { + super(eventBus, + testResultPresenter, + testingHandler, + debugConfigurationsManager, + client, + dtoFactory, + appContext, + notificationManager, + singletonList(PROJECT_PERSPECTIVE_ID), + localization.actionRunTestDescription(), + localization.actionRunTestTitle(), + resources.testIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + Pair frameworkAndTestName = Pair.of(TESTNG_FRAMEWORK_NAME, null); + actionPerformed(frameworkAndTestName, false); + } + + @Override + public void updateInPerspective(@NotNull ActionEvent e) { + Presentation presentation = e.getPresentation(); + presentation.setVisible(!isEditorInFocus); + if (!isEditorInFocus) { + analyzeProjectTreeSelection(); + } + presentation.setEnabled(isEnable); + } +} diff --git a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/inject/TestNgGinModule.java b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/inject/TestNgGinModule.java new file mode 100644 index 0000000000..0473535499 --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/java/org/eclipse/che/plugin/testing/testng/ide/inject/TestNgGinModule.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.testing.testng.ide.inject; + +import com.google.gwt.inject.client.AbstractGinModule; +import com.google.gwt.inject.client.multibindings.GinMultibinder; + +import org.eclipse.che.ide.api.extension.ExtensionGinModule; +import org.eclipse.che.plugin.testing.ide.TestAction; +import org.eclipse.che.plugin.testing.testng.ide.TestNgTestAction; + +/** + * Gin module for TestNg extension. + */ +@ExtensionGinModule +public class TestNgGinModule extends AbstractGinModule { + @Override + protected void configure() { + GinMultibinder.newSetBinder(binder(), TestAction.class).addBinding().to(TestNgTestAction.class); + } +} diff --git a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/resources/org/eclipse/che/plugin/testing/testng/TestNG.gwt.xml b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/resources/org/eclipse/che/plugin/testing/testng/TestNG.gwt.xml new file mode 100644 index 0000000000..f838358478 --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/resources/org/eclipse/che/plugin/testing/testng/TestNG.gwt.xml @@ -0,0 +1,21 @@ + + + + + + + + + + diff --git a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/resources/org/eclipse/che/plugin/testing/testng/ide/TestNgLocalizationConstant.properties b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/resources/org/eclipse/che/plugin/testing/testng/ide/TestNgLocalizationConstant.properties new file mode 100644 index 0000000000..0a5005f709 --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/resources/org/eclipse/che/plugin/testing/testng/ide/TestNgLocalizationConstant.properties @@ -0,0 +1,20 @@ +# +# 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 +# + + + +##### Actions ##### +action.testNg.run.title = Run TestNG Test +action.testNg.run.description = Run TestNG tests + +action.testNg.debug.title = Debug TestNG Test +action.testNg.debug.description = Debug TestNG tests + diff --git a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/resources/org/eclipse/che/plugin/testing/testng/ide/svg/test.svg b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/resources/org/eclipse/che/plugin/testing/testng/ide/svg/test.svg new file mode 100644 index 0000000000..79b385d2dd --- /dev/null +++ b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-ide/src/main/resources/org/eclipse/che/plugin/testing/testng/ide/svg/test.svg @@ -0,0 +1,18 @@ + + + + + + + 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 4687779392..3ff7074182 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 @@ -24,44 +24,48 @@ import org.eclipse.che.commons.lang.execution.JavaParameters; import org.eclipse.che.commons.lang.execution.ProcessHandler; import org.eclipse.che.plugin.java.testing.AbstractJavaTestRunner; import org.eclipse.che.plugin.java.testing.ClasspathUtil; +import org.eclipse.che.plugin.java.testing.JavaTestAnnotations; +import org.eclipse.che.plugin.java.testing.JavaTestFinder; import org.eclipse.che.plugin.java.testing.ProjectClasspathProvider; -import org.eclipse.jdt.core.IAnnotation; import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.IImportDeclaration; -import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.JavaModelException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.testng.annotations.Test; import javax.inject.Inject; import java.io.File; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonList; + /** * TestNG implementation for the test runner service. */ public class TestNGRunner extends AbstractJavaTestRunner { - private static final String TESTNG_NAME = "testng"; - private static final String TEST_ANNOTATION_FQN = Test.class.getName(); - private static final Logger LOG = LoggerFactory.getLogger(TestNGRunner.class); + private static final String TESTNG_NAME = "testng"; + private static final Logger LOG = LoggerFactory.getLogger(TestNGRunner.class); + private static final String JAVA_IO_TMPDIR = "java.io.tmpdir"; + private String workspacePath; + private JavaTestFinder javaTestFinder; private final ProjectClasspathProvider classpathProvider; private final TestNGSuiteUtil suiteUtil; @Inject public TestNGRunner(@Named("che.user.workspaces.storage") String workspacePath, + JavaTestFinder javaTestFinder, ProjectClasspathProvider classpathProvider, TestNGSuiteUtil suiteUtil) { - super(workspacePath); + super(workspacePath, javaTestFinder); this.workspacePath = workspacePath; + this.javaTestFinder = javaTestFinder; this.classpathProvider = classpathProvider; this.suiteUtil = suiteUtil; } @@ -134,54 +138,47 @@ public class TestNGRunner extends AbstractJavaTestRunner { } private File createSuite(TestExecutionContext context, IJavaProject javaProject) { - switch (context.getTestType()) { + List testSuite = createTestSuite(context, javaProject, JavaTestAnnotations.TESTNG_TEST.getName(), ""); + + Map> classes = buildTestNgSuite(testSuite, context); + + return suiteUtil.writeSuite(System.getProperty(JAVA_IO_TMPDIR), javaProject.getElementName(), classes); + } + + private Map> buildTestNgSuite(List tests, TestExecutionContext context) { + switch (context.getContextType()) { case FILE: - return createClassSuite(javaProject, context.getFilePath()); case FOLDER: - return createPackageSuite(javaProject, context.getFilePath()); case PROJECT: - return createProjectSuite(javaProject); + return createContainerSuite(tests); case CURSOR_POSITION: - return createMethodSuite(javaProject, context.getFilePath(), context.getCursorOffset()); + return createMethodSuite(tests); + default: + return emptyMap(); + } + } + + private Map> createMethodSuite(List tests) { + if (tests.isEmpty()) { + return Collections.emptyMap(); } - return null; + String testMethodDeclaration = tests.get(0); + int separatorIndex = testMethodDeclaration.indexOf('#'); + + return Collections.singletonMap(testMethodDeclaration.substring(0, separatorIndex), + singletonList(testMethodDeclaration.substring(separatorIndex + 1))); } - private File createMethodSuite(IJavaProject javaProject, String filePath, int cursorOffset) { - ICompilationUnit compilationUnit = findCompilationUnitByPath(javaProject, filePath); - IType primaryType = compilationUnit.findPrimaryType(); - String qualifiedName = primaryType.getFullyQualifiedName(); - List methods = new ArrayList<>(); - try { - IJavaElement element = compilationUnit.getElementAt(cursorOffset); - if (element instanceof IMethod) { - IMethod method = (IMethod)element; - methods.add(method.getElementName()); - } - } catch (JavaModelException e) { - LOG.debug("Can't read a method.", e); + private Map> createContainerSuite(List tests) { + if (tests.isEmpty()) { + return emptyMap(); } - Map> classes = Collections.singletonMap(qualifiedName, methods); - return suiteUtil.writeSuite(System.getProperty("java.io.tmpdir"), javaProject.getElementName(), classes); - } - - private File createProjectSuite(IJavaProject javaProject) { - //TODO add suite to run all tests from project - return null; - } - - private File createPackageSuite(IJavaProject javaProject, String packagePath) { - //TODO add suite to run all tests from package - return null; - } - - private File createClassSuite(IJavaProject javaProject, String filePath) { - ICompilationUnit compilationUnit = findCompilationUnitByPath(javaProject, filePath); - IType primaryType = compilationUnit.findPrimaryType(); - String qualifiedName = primaryType.getFullyQualifiedName(); - Map> classes = Collections.singletonMap(qualifiedName, null); - return suiteUtil.writeSuite(System.getProperty("java.io.tmpdir"), javaProject.getElementName(), classes); + Map> classes = new HashMap<>(tests.size()); + for (String testClass : tests) { + classes.put(testClass, null); + } + return classes; } /** @@ -194,45 +191,6 @@ public class TestNGRunner extends AbstractJavaTestRunner { @Override protected boolean isTestMethod(IMethod method, ICompilationUnit compilationUnit) { - try { - IAnnotation[] annotations = method.getAnnotations(); - IAnnotation test = null; - for (IAnnotation annotation : annotations) { - if (annotation.getElementName().equals("Test")) { - test = annotation; - break; - } - if (annotation.getElementName().equals(TEST_ANNOTATION_FQN)) { - return true; - } - } - - if (test == null) { - return false; - } - - IImportDeclaration[] imports = compilationUnit.getImports(); - for (IImportDeclaration importDeclaration : imports) { - if (importDeclaration.getElementName().equals(TEST_ANNOTATION_FQN)) { - return true; - } - } - - for (IImportDeclaration importDeclaration : imports) { - if (importDeclaration.isOnDemand()) { - String elementName = importDeclaration.getElementName(); - elementName = elementName.substring(0, elementName.length() - 3); //remove .* - if (TEST_ANNOTATION_FQN.startsWith(elementName)) { - return true; - } - - } - } - - return false; - } catch (JavaModelException e) { - LOG.info("Can't read method annotations.", e); - return false; - } + return javaTestFinder.isTest(method, compilationUnit, JavaTestAnnotations.TESTNG_TEST.getName()); } } diff --git a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/test/java/org/ecipse/che/plugin/testing/testng/server/TestNGRunnerTest.java b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/test/java/org/ecipse/che/plugin/testing/testng/server/TestNGRunnerTest.java index 9fbef89e4c..e3ed779b73 100644 --- a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/test/java/org/ecipse/che/plugin/testing/testng/server/TestNGRunnerTest.java +++ b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/test/java/org/ecipse/che/plugin/testing/testng/server/TestNGRunnerTest.java @@ -22,6 +22,7 @@ import org.eclipse.che.api.testing.shared.TestExecutionContext; import org.eclipse.che.jdt.core.launching.JREContainerInitializer; import org.eclipse.che.jdt.core.resources.ResourceChangedEvent; import org.eclipse.che.plugin.java.testing.ClasspathUtil; +import org.eclipse.che.plugin.java.testing.JavaTestFinder; import org.eclipse.che.plugin.java.testing.ProjectClasspathProvider; import org.eclipse.che.plugin.testing.testng.server.TestNGRunner; import org.eclipse.che.plugin.testing.testng.server.TestNGSuiteUtil; @@ -43,6 +44,7 @@ public class TestNGRunnerTest extends BaseTest { private MethodNameConfigurator startMethodNameConfigurator; private ParamsConfigurator startParamsConfigurator; private SendConfiguratorFromOne startSendConfiguratorFromOne; + private JavaTestFinder testNGTestFinder; private RequestTransmitter transmitter; private TestNGRunner runner; @@ -50,12 +52,13 @@ public class TestNGRunnerTest extends BaseTest { @BeforeMethod public void setUp() throws Exception { startEndpointIdConfigurator = mock(EndpointIdConfigurator.class); + testNGTestFinder = mock(JavaTestFinder.class); startMethodNameConfigurator = mock(MethodNameConfigurator.class); startParamsConfigurator = mock(ParamsConfigurator.class); startSendConfiguratorFromOne = mock(SendConfiguratorFromOne.class); transmitter = mock(RequestTransmitter.class); - runner = new TestNGRunner("", new ProjectClasspathProvider(""), new TestNGSuiteUtil()); + runner = new TestNGRunner("", testNGTestFinder, new ProjectClasspathProvider(""), new TestNGSuiteUtil()); } @Test() @@ -85,7 +88,7 @@ public class TestNGRunnerTest extends BaseTest { DtoServerImpls.TestExecutionContextImpl context = new DtoServerImpls.TestExecutionContextImpl(); context.setDebugModeEnable(false); - context.setTestType(TestExecutionContext.TestType.FILE); + context.setContextType(TestExecutionContext.ContextType.FILE); context.setProjectPath("/Test"); context.setFilePath("/Test/src/tests/TestNGTest.java"); assertEquals("testng", runner.getName()); diff --git a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/test/java/org/ecipse/che/plugin/testing/testng/server/TestNGTestDiscoveryTest.java b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/test/java/org/ecipse/che/plugin/testing/testng/server/TestNGTestDiscoveryTest.java index be00c67f89..1b13d4bcd3 100644 --- a/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/test/java/org/ecipse/che/plugin/testing/testng/server/TestNGTestDiscoveryTest.java +++ b/plugins/plugin-testing-java/plugin-testing-testng/che-plugin-testing-testng-server/src/test/java/org/ecipse/che/plugin/testing/testng/server/TestNGTestDiscoveryTest.java @@ -12,6 +12,7 @@ package org.ecipse.che.plugin.testing.testng.server; import org.eclipse.che.api.testing.shared.TestDetectionContext; import org.eclipse.che.api.testing.shared.TestPosition; +import org.eclipse.che.plugin.java.testing.JavaTestFinder; import org.eclipse.che.plugin.testing.testng.server.TestNGRunner; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaProject; @@ -32,12 +33,14 @@ import static org.fest.assertions.Assertions.assertThat; public class TestNGTestDiscoveryTest extends BaseTest { private IJavaProject javaProject; + private JavaTestFinder testNGTestFinder; private IPackageFragment packageFragment; @BeforeMethod public void setUp() throws Exception { javaProject = createJavaProject("testDiscovery", "bin"); + testNGTestFinder = new JavaTestFinder(); IPackageFragmentRoot packageFragmentRoot = addSourceContainer(javaProject, "src", "bin"); javaProject.setRawClasspath(getTestNgClassPath("/testDiscovery/src"), null); @@ -65,7 +68,7 @@ public class TestNGTestDiscoveryTest extends BaseTest { ICompilationUnit compilationUnit = packageFragment.createCompilationUnit("T.java", buf.toString(), false, null); compilationUnit.reconcile(0, true, DefaultWorkingCopyOwner.PRIMARY, null); - TestNGRunner runner = new TestNGRunner("", null, null); + TestNGRunner runner = new TestNGRunner("", testNGTestFinder, null, null); List testPositions = runner.detectTests(new MockTestDetectionContext("/testDiscovery", "/testDiscovery/src/test/T.java", -1)); @@ -94,7 +97,7 @@ public class TestNGTestDiscoveryTest extends BaseTest { ICompilationUnit compilationUnit = packageFragment.createCompilationUnit("T.java", buf.toString(), false, null); compilationUnit.reconcile(0, true, DefaultWorkingCopyOwner.PRIMARY, null); - TestNGRunner runner = new TestNGRunner("", null, null); + TestNGRunner runner = new TestNGRunner("", testNGTestFinder, null, null); List testPositions = runner.detectTests(new MockTestDetectionContext("/testDiscovery", "/testDiscovery/src/test/T.java", -1)); @@ -118,7 +121,7 @@ public class TestNGTestDiscoveryTest extends BaseTest { ICompilationUnit compilationUnit = packageFragment.createCompilationUnit("T.java", buf.toString(), false, null); compilationUnit.reconcile(0, true, DefaultWorkingCopyOwner.PRIMARY, null); - TestNGRunner runner = new TestNGRunner("", null, null); + TestNGRunner runner = new TestNGRunner("", testNGTestFinder, null, null); List testPositions = runner.detectTests(new MockTestDetectionContext("/testDiscovery", "/testDiscovery/src/test/T.java", -1)); @@ -143,7 +146,7 @@ public class TestNGTestDiscoveryTest extends BaseTest { ICompilationUnit compilationUnit = packageFragment.createCompilationUnit("T.java", buf.toString(), false, null); compilationUnit.reconcile(0, true, DefaultWorkingCopyOwner.PRIMARY, null); - TestNGRunner runner = new TestNGRunner("", null, null); + TestNGRunner runner = new TestNGRunner("", testNGTestFinder, null, null); List testPositions = runner.detectTests(new MockTestDetectionContext("/testDiscovery", "/testDiscovery/src/test/T.java", -1)); @@ -167,7 +170,7 @@ public class TestNGTestDiscoveryTest extends BaseTest { ICompilationUnit compilationUnit = packageFragment.createCompilationUnit("T.java", buf.toString(), false, null); compilationUnit.reconcile(0, true, DefaultWorkingCopyOwner.PRIMARY, null); - TestNGRunner runner = new TestNGRunner("", null, null); + TestNGRunner runner = new TestNGRunner("", testNGTestFinder, null, null); List testPositions = runner.detectTests(new MockTestDetectionContext("/testDiscovery", "/testDiscovery/src/test/T.java", -1)); diff --git a/plugins/plugin-testing-java/plugin-testing-testng/pom.xml b/plugins/plugin-testing-java/plugin-testing-testng/pom.xml index 9c94aa683b..3a8287dd24 100644 --- a/plugins/plugin-testing-java/plugin-testing-testng/pom.xml +++ b/plugins/plugin-testing-java/plugin-testing-testng/pom.xml @@ -22,6 +22,7 @@ pom Che Plugin :: Java Testing :: TestNG Parent + che-plugin-testing-testng-ide che-plugin-testing-testng-runtime che-plugin-testing-testng-server diff --git a/plugins/plugin-testing/che-plugin-testing-ide/pom.xml b/plugins/plugin-testing/che-plugin-testing-ide/pom.xml index cf7a988e24..751f0309fa 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/pom.xml +++ b/plugins/plugin-testing/che-plugin-testing-ide/pom.xml @@ -64,10 +64,6 @@ org.eclipse.che.core che-core-api-model - - org.eclipse.che.core - che-core-api-project-shared - org.eclipse.che.core che-core-api-testing-shared diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestAction.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestAction.java index 4feca34d49..a910547fea 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestAction.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestAction.java @@ -19,7 +19,6 @@ import org.eclipse.che.ide.api.action.DefaultActionGroup; * * @author Mirage Abeysekara */ -@Deprecated public interface TestAction { /** diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestResources.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestResources.java index 4f6dd13911..f2d8adf5d1 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestResources.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestResources.java @@ -21,7 +21,6 @@ import org.vectomatic.dom.svg.ui.SVGResource; public interface TestResources extends ClientBundle { @Source("org/eclipse/che/plugin/testing/ide/svg/test.svg") - @Deprecated SVGResource testIcon(); @Source("org/eclipse/che/plugin/testing/ide/svg/test_all.svg") 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 7b063aaca5..4bec8c8706 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 @@ -77,8 +77,7 @@ public class TestingExtension { testAction.addContextMenuItems(testContextMenu); testContextMenu.addSeparator(); } - testContextMenu.add(runTestAction); - testContextMenu.add(debugTestAction); + explorerMenu.addSeparator(); explorerMenu.add(testContextMenu); explorerMenu.addSeparator(); diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/action/DebugTestAction.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/action/DebugTestAction.java index affb2c0bf1..cf43864c9c 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/action/DebugTestAction.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/action/DebugTestAction.java @@ -13,63 +13,41 @@ package org.eclipse.che.plugin.testing.ide.action; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; -import org.eclipse.che.api.core.jsonrpc.commons.JsonRpcError; -import org.eclipse.che.api.core.jsonrpc.commons.JsonRpcPromise; -import org.eclipse.che.api.project.shared.dto.ProjectTypeDto; -import org.eclipse.che.api.testing.shared.TestExecutionContext; -import org.eclipse.che.api.testing.shared.TestLaunchResult; import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.action.Presentation; import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.api.debug.DebugConfiguration; import org.eclipse.che.ide.api.debug.DebugConfigurationsManager; import org.eclipse.che.ide.api.notification.NotificationManager; -import org.eclipse.che.ide.api.notification.StatusNotification; -import org.eclipse.che.ide.api.project.type.ProjectTypeRegistry; -import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.util.Pair; import org.eclipse.che.plugin.testing.ide.TestResources; import org.eclipse.che.plugin.testing.ide.TestServiceClient; import org.eclipse.che.plugin.testing.ide.handler.TestingHandler; -import org.eclipse.che.plugin.testing.ide.model.GeneralTestingEventsProcessor; import org.eclipse.che.plugin.testing.ide.view2.TestResultPresenter; import javax.inject.Inject; +import javax.validation.constraints.NotNull; -import static java.lang.Boolean.TRUE; -import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; -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.part.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID; /** Action that allows to run tests from current editor. */ @Singleton public class DebugTestAction extends RunDebugTestAbstractAction { - private final TestServiceClient client; - private final DebugConfigurationsManager debugConfigurationsManager; - private final ProjectTypeRegistry projectTypeRegistry; - private final AppContext appContext; - private final NotificationManager notificationManager; - private final TestingHandler testingHandler; - private final TestResultPresenter testResultPresenter; - - private Pair frameworkAndTestName; - @Inject public DebugTestAction(EventBus eventBus, TestServiceClient client, DebugConfigurationsManager debugConfigurationsManager, DtoFactory dtoFactory, TestResources testResources, - ProjectTypeRegistry projectTypeRegistry, AppContext appContext, NotificationManager notificationManager, TestingHandler testingHandler, TestResultPresenter testResultPresenter) { super(eventBus, + testResultPresenter, + testingHandler, + debugConfigurationsManager, client, dtoFactory, appContext, @@ -78,71 +56,19 @@ public class DebugTestAction extends RunDebugTestAbstractAction { "Debug Test", "Debug Test", testResources.debugIcon()); - this.client = client; - this.debugConfigurationsManager = debugConfigurationsManager; - this.projectTypeRegistry = projectTypeRegistry; - this.appContext = appContext; - this.notificationManager = notificationManager; - this.testingHandler = testingHandler; - this.testResultPresenter = testResultPresenter; } @Override public void actionPerformed(ActionEvent e) { - final StatusNotification notification = new StatusNotification("Debugging Tests...", PROGRESS, FLOAT_MODE); - notificationManager.notify(notification); - - frameworkAndTestName = getTestingFrameworkAndTestName(); - TestExecutionContext context = createTestExecutionContext(frameworkAndTestName); - - context.withDebugModeEnable(TRUE); - - GeneralTestingEventsProcessor eventsProcessor = new GeneralTestingEventsProcessor(frameworkAndTestName.first, - testResultPresenter.getRootState()); - testingHandler.setProcessor(eventsProcessor); - eventsProcessor.addListener(testResultPresenter.getEventListener()); - - JsonRpcPromise testResultPromise = client.runTests(context); - testResultPromise.onSuccess(result -> onTestRanSuccessfully(result, eventsProcessor, notification)) - .onFailure(exception -> onTestRanUnsuccessfully(exception, notification)); + Pair frameworkAndTestName = getTestingFrameworkAndTestName(); + actionPerformed(frameworkAndTestName, true); } - private void onTestRanSuccessfully(TestLaunchResult result, - GeneralTestingEventsProcessor eventsProcessor, - StatusNotification notification) { - notification.setStatus(SUCCESS); - if (result.isSuccess()) { - notification.setTitle("Test runner executed successfully."); - testResultPresenter.handleResponse(); - - Project rootProject = appContext.getRootProject(); - String type = rootProject.getType(); - ProjectTypeDto projectType = projectTypeRegistry.getProjectType(type); - - if (projectType.getParents().contains("java")) { - runRemoteJavaDebugger(eventsProcessor, result.getDebugPort()); - } - } else { - notification.setTitle("Test runner failed to execute."); - } - } - - private void runRemoteJavaDebugger(GeneralTestingEventsProcessor eventsProcessor, int port) { - DebugConfiguration debugger = debugConfigurationsManager.createConfiguration("jdb", - frameworkAndTestName.first, - "localhost", - port, - emptyMap()); - eventsProcessor.setDebuggerConfiguration(debugger, debugConfigurationsManager); - - debugConfigurationsManager.apply(debugger); - } - - private void onTestRanUnsuccessfully(JsonRpcError exception, StatusNotification notification) { - final String errorMessage = (exception.getMessage() != null) ? exception.getMessage() - : "Failed to run test cases"; - notification.setContent(errorMessage); - notification.setStatus(FAIL); + @Override + public void updateInPerspective(@NotNull ActionEvent event) { + Presentation presentation = event.getPresentation(); + presentation.setVisible(isEditorInFocus); + presentation.setEnabled(isEnable); } } diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/action/RunDebugTestAbstractAction.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/action/RunDebugTestAbstractAction.java index ebbad18267..945a884d97 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/action/RunDebugTestAbstractAction.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/action/RunDebugTestAbstractAction.java @@ -10,80 +10,117 @@ *******************************************************************************/ package org.eclipse.che.plugin.testing.ide.action; +import com.google.common.base.Optional; import com.google.web.bindery.event.shared.EventBus; +import org.eclipse.che.api.core.jsonrpc.commons.JsonRpcError; +import org.eclipse.che.api.core.jsonrpc.commons.JsonRpcPromise; import org.eclipse.che.api.testing.shared.TestDetectionContext; import org.eclipse.che.api.testing.shared.TestExecutionContext; +import org.eclipse.che.api.testing.shared.TestLaunchResult; import org.eclipse.che.api.testing.shared.TestPosition; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.ide.api.action.AbstractPerspectiveAction; import org.eclipse.che.ide.api.action.ActionEvent; -import org.eclipse.che.ide.api.action.Presentation; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.debug.DebugConfiguration; +import org.eclipse.che.ide.api.debug.DebugConfigurationsManager; import org.eclipse.che.ide.api.editor.texteditor.TextEditor; import org.eclipse.che.ide.api.parts.ActivePartChangedEvent; import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.api.notification.StatusNotification; +import org.eclipse.che.ide.api.parts.PartPresenter; +import org.eclipse.che.ide.api.resources.Container; import org.eclipse.che.ide.api.resources.Project; +import org.eclipse.che.ide.api.resources.Resource; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.ext.java.client.editor.JavaReconsilerEvent; +import org.eclipse.che.ide.ext.java.client.resource.SourceFolderMarker; +import org.eclipse.che.ide.ext.java.client.util.JavaUtil; import org.eclipse.che.ide.util.Pair; import org.eclipse.che.ide.util.loging.Log; import org.eclipse.che.plugin.testing.ide.TestServiceClient; +import org.eclipse.che.plugin.testing.ide.handler.TestingHandler; +import org.eclipse.che.plugin.testing.ide.model.GeneralTestingEventsProcessor; +import org.eclipse.che.plugin.testing.ide.view2.TestResultPresenter; import org.vectomatic.dom.svg.ui.SVGResource; import javax.validation.constraints.NotNull; import java.util.List; -import static org.eclipse.che.api.testing.shared.TestExecutionContext.TestType.CURSOR_POSITION; +import static java.util.Collections.emptyMap; +import static org.eclipse.che.api.testing.shared.TestExecutionContext.ContextType.CURSOR_POSITION; +import static org.eclipse.che.api.testing.shared.TestExecutionContext.ContextType.PROJECT; +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.api.resources.Resource.FILE; +import static org.eclipse.che.ide.ext.java.client.util.JavaUtil.isJavaFile; /** Abstract action that analyzes active editor and makes run/debug test actions active if some test methods are exist. */ public abstract class RunDebugTestAbstractAction extends AbstractPerspectiveAction { - TextEditor currentEditor; + public static final String JUNIT_FRAMEWORK_NAME = "junit"; + public static final String TESTNG_FRAMEWORK_NAME = "testng"; - private TestExecutionContext.TestType testType; - private List testPosition; - private boolean hasTests; - private TestServiceClient client; - private DtoFactory dtoFactory; - private AppContext appContext; - private NotificationManager notificationManager; + private TextEditor currentEditor; + private List testPosition; + private TestResultPresenter testResultPresenter; + private TestingHandler testingHandler; + private DebugConfigurationsManager debugConfigurationsManager; + private TestServiceClient client; + private DtoFactory dtoFactory; + private AppContext appContext; + private NotificationManager notificationManager; + private TestExecutionContext.ContextType contextType; + private String selectedNodePath; - RunDebugTestAbstractAction(EventBus eventBus, - TestServiceClient client, - DtoFactory dtoFactory, - AppContext appContext, - NotificationManager notificationManager, - @Nullable List perspectives, - @NotNull String description, - @NotNull String text, - SVGResource icon) { + protected boolean isEnable; + protected boolean isEditorInFocus; + + public RunDebugTestAbstractAction(EventBus eventBus, + TestResultPresenter testResultPresenter, + TestingHandler testingHandler, + DebugConfigurationsManager debugConfigurationsManager, + TestServiceClient client, + DtoFactory dtoFactory, + AppContext appContext, + NotificationManager notificationManager, + @Nullable List perspectives, + @NotNull String description, + @NotNull String text, + SVGResource icon) { super(perspectives, text, description, null, icon); + this.testResultPresenter = testResultPresenter; + this.testingHandler = testingHandler; + this.debugConfigurationsManager = debugConfigurationsManager; this.client = client; this.dtoFactory = dtoFactory; this.appContext = appContext; this.notificationManager = notificationManager; - hasTests = false; + isEnable = false; eventBus.addHandler(JavaReconsilerEvent.TYPE, event -> detectTests(event.getEditor())); eventBus.addHandler(ActivePartChangedEvent.TYPE, event -> { - if (event.getActivePart() instanceof TextEditor) { - testType = CURSOR_POSITION; - TextEditor activeEditor = (TextEditor)event.getActivePart(); + PartPresenter activePart = event.getActivePart(); + if (activePart instanceof TextEditor) { + isEditorInFocus = true; + contextType = CURSOR_POSITION; + TextEditor activeEditor = (TextEditor)activePart; if (activeEditor.getEditorInput().getFile().getName().endsWith(".java")) { detectTests(activeEditor); } else { - hasTests = false; + isEnable = false; } + } else { + isEditorInFocus = false; } }); } @Override - public void updateInPerspective(@NotNull ActionEvent event) { - Presentation presentation = event.getPresentation(); - presentation.setEnabled(hasTests); - } + public abstract void updateInPerspective(@NotNull ActionEvent event); @Override public abstract void actionPerformed(ActionEvent e); @@ -95,11 +132,11 @@ public abstract class RunDebugTestAbstractAction extends AbstractPerspectiveActi context.setOffset(currentEditor.getCursorOffset()); context.setProjectPath(appContext.getRootProject().getPath()); client.detectTests(context).onSuccess(testDetectionResult -> { - hasTests = testDetectionResult.isTestFile(); + isEnable = testDetectionResult.isTestFile(); testPosition = testDetectionResult.getTestPosition(); }).onFailure(jsonRpcError -> { Log.error(getClass(), jsonRpcError); - hasTests = false; + isEnable = false; notificationManager.notify("Can't detect test methods"); }); } @@ -111,14 +148,20 @@ public abstract class RunDebugTestAbstractAction extends AbstractPerspectiveActi * name of the test framework * @return test execution context */ - protected TestExecutionContext createTestExecutionContext(Pair frameworkAndTestName) { + protected TestExecutionContext createTestExecutionContext(Pair frameworkAndTestName, + TestExecutionContext.ContextType contextType, + String selectedNodePath) { final Project project = appContext.getRootProject(); TestExecutionContext context = dtoFactory.createDto(TestExecutionContext.class); context.setProjectPath(project.getPath()); - context.setTestType(testType); - context.setFilePath(currentEditor.getEditorInput().getFile().getLocation().toString()); - context.setCursorOffset(currentEditor.getCursorOffset()); + context.setContextType(contextType); + if (contextType == CURSOR_POSITION) { + context.setFilePath(currentEditor.getEditorInput().getFile().getLocation().toString()); + context.setCursorOffset(currentEditor.getCursorOffset()); + } else { + context.setFilePath(selectedNodePath); + } context.setFrameworkName(frameworkAndTestName.first); return context; @@ -139,4 +182,106 @@ public abstract class RunDebugTestAbstractAction extends AbstractPerspectiveActi } return Pair.of(testPosition.iterator().next().getFrameworkName(), null); } + + /** + * Runs an action. + * + * @param frameworkAndTestName + * contains name of the test framework and test methods + * @param isDebugMode + * is {@code true} if the action uses for debugging + */ + protected void actionPerformed(Pair frameworkAndTestName, boolean isDebugMode) { + final StatusNotification notification = new StatusNotification("Running Tests...", PROGRESS, FLOAT_MODE); + notificationManager.notify(notification); + + TestExecutionContext context = createTestExecutionContext(frameworkAndTestName, contextType, selectedNodePath); + context.withDebugModeEnable(isDebugMode); + + GeneralTestingEventsProcessor eventsProcessor = new GeneralTestingEventsProcessor(frameworkAndTestName.first, + testResultPresenter.getRootState()); + testingHandler.setProcessor(eventsProcessor); + eventsProcessor.addListener(testResultPresenter.getEventListener()); + + JsonRpcPromise testResultPromise = client.runTests(context); + testResultPromise.onSuccess(result -> onTestRanSuccessfully(result, + eventsProcessor, + notification, + frameworkAndTestName.first, + isDebugMode)) + .onFailure(exception -> onTestRanFailed(exception, notification)); + } + + /** + * Analyzes project tree selection. Needs for detecting context type for the test runner. + */ + protected void analyzeProjectTreeSelection() { + Resource[] resources = appContext.getResources(); + if (resources == null || resources.length > 1) { + isEnable = false; + return; + } + + Resource resource = resources[0]; + if (resource.isProject() && JavaUtil.isJavaProject((Project)resource)) { + contextType = PROJECT; + isEnable = true; + return; + } + + Project project = resource.getProject(); + if (!JavaUtil.isJavaProject(project)) { + isEnable = false; + return; + } + + Optional srcFolder = resource.getParentWithMarker(SourceFolderMarker.ID); + if (!srcFolder.isPresent() || resource.getLocation().equals(srcFolder.get().getLocation())) { + isEnable = false; + return; + } + + if (resource.getResourceType() == FILE && isJavaFile(resource)) { + contextType = TestExecutionContext.ContextType.FILE; + } else if (resource instanceof Container) { + contextType = TestExecutionContext.ContextType.FOLDER; + } + selectedNodePath = resource.getLocation().toString(); + isEnable = true; + } + + private void onTestRanSuccessfully(TestLaunchResult result, + GeneralTestingEventsProcessor eventsProcessor, + StatusNotification notification, + String frameworkName, + boolean isDebugMode) { + notification.setStatus(SUCCESS); + if (result.isSuccess()) { + notification.setTitle("Test runner executed successfully."); + testResultPresenter.handleResponse(); + if (isDebugMode) { + runRemoteJavaDebugger(eventsProcessor, frameworkName, result.getDebugPort()); + } + } else { + notification.setTitle("Test runner failed to execute."); + } + } + + private void onTestRanFailed(JsonRpcError exception, StatusNotification notification) { + final String errorMessage = (exception.getMessage() != null) ? exception.getMessage() + : "Failed to run test cases"; + notification.setContent(errorMessage); + notification.setStatus(FAIL); + } + + private void runRemoteJavaDebugger(GeneralTestingEventsProcessor eventsProcessor, String frameworkName, int port) { + DebugConfiguration debugger = debugConfigurationsManager.createConfiguration("jdb", + frameworkName, + "localhost", + port, + emptyMap()); + eventsProcessor.setDebuggerConfiguration(debugger, debugConfigurationsManager); + + debugConfigurationsManager.apply(debugger); + } } diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/action/RunTestAction.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/action/RunTestAction.java index cb07ecb611..9ddf5e6d91 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/action/RunTestAction.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/action/RunTestAction.java @@ -13,40 +13,27 @@ package org.eclipse.che.plugin.testing.ide.action; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; -import org.eclipse.che.api.core.jsonrpc.commons.JsonRpcError; -import org.eclipse.che.api.core.jsonrpc.commons.JsonRpcPromise; -import org.eclipse.che.api.testing.shared.TestExecutionContext; -import org.eclipse.che.api.testing.shared.TestLaunchResult; import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.action.Presentation; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.debug.DebugConfigurationsManager; import org.eclipse.che.ide.api.notification.NotificationManager; -import org.eclipse.che.ide.api.notification.StatusNotification; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.util.Pair; import org.eclipse.che.plugin.testing.ide.TestResources; import org.eclipse.che.plugin.testing.ide.TestServiceClient; import org.eclipse.che.plugin.testing.ide.handler.TestingHandler; -import org.eclipse.che.plugin.testing.ide.model.GeneralTestingEventsProcessor; import org.eclipse.che.plugin.testing.ide.view2.TestResultPresenter; import javax.inject.Inject; +import javax.validation.constraints.NotNull; -import static java.lang.Boolean.FALSE; import static java.util.Collections.singletonList; -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.part.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID; /** Action that allows to run tests from current editor. */ @Singleton public class RunTestAction extends RunDebugTestAbstractAction { - private final TestServiceClient client; - private final NotificationManager notificationManager; - private final TestingHandler testingHandler; - private final TestResultPresenter testResultPresenter; - @Inject public RunTestAction(EventBus eventBus, TestServiceClient client, @@ -54,9 +41,13 @@ public class RunTestAction extends RunDebugTestAbstractAction { TestResources testResources, AppContext appContext, NotificationManager notificationManager, + DebugConfigurationsManager debugConfigurationsManager, TestingHandler testingHandler, TestResultPresenter testResultPresenter) { super(eventBus, + testResultPresenter, + testingHandler, + debugConfigurationsManager, client, dtoFactory, appContext, @@ -65,45 +56,19 @@ public class RunTestAction extends RunDebugTestAbstractAction { "Run Test", "Run Test", testResources.testIcon()); - this.client = client; - this.notificationManager = notificationManager; - this.testingHandler = testingHandler; - this.testResultPresenter = testResultPresenter; } @Override public void actionPerformed(ActionEvent e) { - final StatusNotification notification = new StatusNotification("Running Tests...", PROGRESS, FLOAT_MODE); - notificationManager.notify(notification); - Pair frameworkAndTestName = getTestingFrameworkAndTestName(); - TestExecutionContext context = createTestExecutionContext(frameworkAndTestName); - context.withDebugModeEnable(FALSE); - - GeneralTestingEventsProcessor eventsProcessor = new GeneralTestingEventsProcessor(frameworkAndTestName.first, - testResultPresenter.getRootState()); - testingHandler.setProcessor(eventsProcessor); - eventsProcessor.addListener(testResultPresenter.getEventListener()); - - JsonRpcPromise testResultPromise = client.runTests(context); - testResultPromise.onSuccess(result -> onTestRanSuccessfully(result, notification)) - .onFailure(exception -> onTestRanUnsuccessfully(exception, notification)); + actionPerformed(frameworkAndTestName, false); } - private void onTestRanSuccessfully(TestLaunchResult result, StatusNotification notification) { - notification.setStatus(SUCCESS); - if (result.isSuccess()) { - notification.setTitle("Test runner executed successfully."); - testResultPresenter.handleResponse(); - } else { - notification.setTitle("Test runner failed to execute."); - } + @Override + public void updateInPerspective(@NotNull ActionEvent event) { + Presentation presentation = event.getPresentation(); + presentation.setVisible(isEditorInFocus); + presentation.setEnabled(isEnable); } - private void onTestRanUnsuccessfully(JsonRpcError exception, StatusNotification notification) { - final String errorMessage = (exception.getMessage() != null) ? exception.getMessage() - : "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/action/RunTestActionDelegate.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/action/RunTestActionDelegate.java deleted file mode 100644 index f6a2068e3c..0000000000 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/action/RunTestActionDelegate.java +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************************************* - * 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.ide.action; - -import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; -import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL; -import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PROGRESS; -import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS; - -import java.util.Map; - -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.api.promises.client.Promise; -import org.eclipse.che.api.promises.client.PromiseError; -import org.eclipse.che.api.testing.shared.TestResult; -import org.eclipse.che.ide.api.action.ActionEvent; -import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.api.notification.NotificationManager; -import org.eclipse.che.ide.api.notification.StatusNotification; -import org.eclipse.che.ide.api.resources.Project; -import org.eclipse.che.plugin.testing.ide.TestServiceClient; -import org.eclipse.che.plugin.testing.ide.view.TestResultPresenter; - -/** - * @author Mirage Abeysekara - * @author David Festal - */ -public class RunTestActionDelegate { - private final Source source; - - public interface Source { - NotificationManager getNotificationManager(); - - AppContext getAppContext(); - - TestServiceClient getService(); - - TestResultPresenter getPresenter(); - - String getTestingFramework(); - } - - 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(), source.getTestingFramework(), parameters, notification); - 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); - } - }); - } -} diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/model/GeneralTestingEventsProcessor.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/model/GeneralTestingEventsProcessor.java index bdc0e2e5ee..922d0c1a6d 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/model/GeneralTestingEventsProcessor.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/model/GeneralTestingEventsProcessor.java @@ -43,8 +43,9 @@ public class GeneralTestingEventsProcessor extends AbstractTestingEventsProcesso private final Set currentChildren = new LinkedHashSet<>(); private final Map testNameToTestState = new HashMap<>(); private final List buildTreeEvents = new ArrayList<>(); + private boolean gettingChildren = true; - private boolean gettingChildren = true; + private TestState lastTreeState; private boolean treeBuildBeforeStart = false; private TestLocator testLocator = null; @@ -54,6 +55,7 @@ public class GeneralTestingEventsProcessor extends AbstractTestingEventsProcesso public GeneralTestingEventsProcessor(String testFrameworkName, TestRootState testRootState) { super(testFrameworkName); this.testRootState = testRootState; + this.lastTreeState = testRootState; } @Override @@ -67,9 +69,12 @@ public class GeneralTestingEventsProcessor extends AbstractTestingEventsProcesso public void onTestSuiteStarted(TestSuiteStartedEvent event) { String name = event.getName(); String location = event.getLocation(); - TestState currentSuite = getCurrentSuite(); - if (currentSuite.getName().equals(name) && treeBuildBeforeStart) { - return; + TestState currentSuite; + if (treeBuildBeforeStart) { + findState(testRootState, name); + currentSuite = lastTreeState; + } else { + currentSuite = getCurrentSuite(); } TestState newState; if (location == null) { @@ -92,10 +97,28 @@ public class GeneralTestingEventsProcessor extends AbstractTestingEventsProcesso } gettingChildren = true; - testSuiteStack.push(newState); + if (treeBuildBeforeStart) { + testSuiteStack.add(newState); + } else { + testSuiteStack.push(newState); + } callSuiteStarted(newState); } + private void findState(TestState currentState, String name) { + List children = currentState.getChildren(); + for (TestState state : children) { + if (state.getName().equals(name)) { + lastTreeState = currentState; + return; + } + } + + for (TestState state : children) { + findState(state, name); + } + } + @Override public void onTestSuiteFinished(TestSuiteFinishedEvent event) { TestState suite = testSuiteStack.pop(event.getName()); @@ -244,15 +267,19 @@ public class GeneralTestingEventsProcessor extends AbstractTestingEventsProcesso @Override public void onSuiteTreeStarted(String suiteName, String location) { treeBuildBeforeStart = true; - TestState currentSuite = getCurrentSuite(); TestState newSuite = new TestState(suiteName, true, location); if (testLocator != null) { newSuite.setTestLocator(testLocator); } - currentSuite.addChild(newSuite); + if (TestRootState.ROOT.equals(lastTreeState.getName())) { + testRootState.addChild(newSuite); + } else { + lastTreeState.addChild(newSuite); + } - testSuiteStack.push(newSuite); + lastTreeState = newSuite; + testSuiteStack.add(newSuite); callSuiteTreeStarted(newSuite); } @@ -272,7 +299,11 @@ public class GeneralTestingEventsProcessor extends AbstractTestingEventsProcesso @Override public void onSuiteTreeEnded(String suiteName) { - buildTreeEvents.add(() -> testSuiteStack.pop(suiteName)); + if (!(TestRootState.ROOT.equals(lastTreeState.getName()))) { + lastTreeState = lastTreeState.getParent(); + } + + testSuiteStack.pop(suiteName); } @Override @@ -284,7 +315,7 @@ public class GeneralTestingEventsProcessor extends AbstractTestingEventsProcesso newState.setTestLocator(testLocator); } - TestState currentSuite = getCurrentSuite(); + TestState currentSuite = testSuiteStack.peekLast(); currentSuite.setTreeBuildBeforeStart(); currentSuite.addChild(newState); diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/model/TestRootState.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/model/TestRootState.java index 9a895ff60b..ef4ab7beb5 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/model/TestRootState.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/model/TestRootState.java @@ -14,6 +14,7 @@ package org.eclipse.che.plugin.testing.ide.model; * Describes test root state. */ public class TestRootState extends TestState { + public static final String ROOT = "Root"; private boolean testReporterAttached; @@ -22,7 +23,7 @@ public class TestRootState extends TestState { private String comment; public TestRootState() { - super("Root", true, null); + super(ROOT, true, null); } public boolean isTestReporterAttached() { diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/model/TestSuiteStack.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/model/TestSuiteStack.java index 6e426282e3..f525694bb5 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/model/TestSuiteStack.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/model/TestSuiteStack.java @@ -22,15 +22,51 @@ public class TestSuiteStack { private Deque stack = new ArrayDeque<>(); + /** + * Pushes an element onto the stack at the head of this deque. + * + * @param state + * new test state + */ public void push(TestState state) { stack.push(state); } + /** + * Inserts the specified element at the tail of this deque. + * + * @param state + * new test state + */ + public void add(TestState state) { + stack.add(state); + } + + /** + * Retrieves, but does not remove, the last element of this deque, + * or returns {@code null} if this deque is empty. + */ + public TestState peekLast() { + return stack.peekLast(); + } + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque (in other words, the first element of this deque), or + * returns {@code null} if this deque is empty. + */ public TestState getCurrent() { return stack.peek(); } - + /** + * Pops an element from the stack represented by this deque. In other + * words, removes and returns the first element of this deque. + * + * @param suiteName + * name of suite + * @return element from the stack which has same name + */ public TestState pop(String suiteName) { if (stack.isEmpty()) { Log.error(getClass(), "Test suite stack is empty, unexpected suite name: " + suiteName); @@ -67,10 +103,19 @@ public class TestSuiteStack { return state; } + /** + * Returns true if this collection contains no elements. + * + * @return true if this collection contains no elements + */ public boolean isEmpty() { return stack.isEmpty(); } + /** + * Removes all of the elements from this collection (optional operation). + * The collection will be empty after this method returns. + */ public void clear() { stack.clear(); } diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/view2/PrinterOutputConsole.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/view2/PrinterOutputConsole.java index 4a348a24fb..4911d5ba19 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/view2/PrinterOutputConsole.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/view2/PrinterOutputConsole.java @@ -20,11 +20,9 @@ import org.eclipse.che.plugin.testing.ide.model.TestState; import javax.inject.Inject; /** - * + * Represents an output console for test results. */ public class PrinterOutputConsole extends OutputConsoleViewImpl implements Printer { - - private TestState currentTest; @Inject @@ -47,6 +45,7 @@ public class PrinterOutputConsole extends OutputConsoleViewImpl implements Print } else { print(text, false); } + enableAutoScroll(true); } @Override diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/view2/TestResultViewImpl.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/view2/TestResultViewImpl.java index 74ffcfab26..8d033984f3 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/view2/TestResultViewImpl.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/view2/TestResultViewImpl.java @@ -59,9 +59,9 @@ public class TestResultViewImpl extends BaseView @UiField(provided = true) SplitLayoutPanel splitLayoutPanel; @UiField - FlowPanel navigationPanel; + FlowPanel navigationPanel; private Tree resultTree; - private int lastWentLine = 0; + private int lastWentLine = 0; private boolean showFailuresOnly = false; private TestRootState testRootState; @@ -95,7 +95,7 @@ public class TestResultViewImpl extends BaseView resultTree.getSelectionModel().addSelectionHandler(event -> { Node methodNode = event.getSelectedItem(); if (methodNode instanceof TestStateNode) { - outputConsole.testSelected(((TestStateNode) methodNode).getTestState()); + outputConsole.testSelected(((TestStateNode)methodNode).getTestState()); } }); @@ -131,9 +131,11 @@ public class TestResultViewImpl extends BaseView TestStateNode parentStateNode = findNodeByState(parent); if (parentStateNode != null) { Node parentStateNodeParent = parentStateNode.getParent(); + resultTree.refresh(parentStateNode); + int parentIndex = resultTree.getNodeStorage().indexOf(parentStateNode); resultTree.getNodeStorage().remove(parentStateNode); if (parentStateNodeParent != null) { - resultTree.getNodeStorage().add(parentStateNodeParent, parentStateNode); + resultTree.getNodeStorage().insert(parentStateNodeParent, parentIndex, parentStateNode); } else { resultTree.getNodeStorage().add(parentStateNode); } @@ -150,7 +152,7 @@ public class TestResultViewImpl extends BaseView private TestStateNode findNodeByState(TestState parent) { for (Node node : resultTree.getNodeStorage().getAll()) { if (node instanceof TestStateNode) { - TestStateNode stateNode = (TestStateNode) node; + TestStateNode stateNode = (TestStateNode)node; if (stateNode.getTestState().equals(parent)) { return stateNode; } @@ -170,7 +172,7 @@ public class TestResultViewImpl extends BaseView @Override public void onSuiteTreeNodeAdded(TestState testState) { - addSuiteOrTest(testState); + //addSuiteOrTest(testState); } @Override diff --git a/pom.xml b/pom.xml index 3986b10eb2..6803cf8af5 100644 --- a/pom.xml +++ b/pom.xml @@ -950,6 +950,11 @@ che-plugin-testing-ide ${che.version} + + org.eclipse.che.plugin + che-plugin-testing-junit-ide + ${che.version} + org.eclipse.che.plugin che-plugin-testing-junit-runtime @@ -970,6 +975,11 @@ che-plugin-testing-phpunit-server ${che.version} + + org.eclipse.che.plugin + che-plugin-testing-testng-ide + ${che.version} + org.eclipse.che.plugin che-plugin-testing-testng-runtime diff --git a/wsagent/agent/src/main/resources/org.eclipse.che.ws-agent.script.sh b/wsagent/agent/src/main/resources/org.eclipse.che.ws-agent.script.sh index 49b30de877..705c9b01a4 100644 --- a/wsagent/agent/src/main/resources/org.eclipse.che.ws-agent.script.sh +++ b/wsagent/agent/src/main/resources/org.eclipse.che.ws-agent.script.sh @@ -9,8 +9,20 @@ # Codenvy, S.A. - initial API and implementation # +is_current_user_root() { + test "$(id -u)" = 0 +} + +is_current_user_sudoer() { + sudo -n true > /dev/null 2>&1 +} + +set_sudo_command() { + if is_current_user_sudoer && ! is_current_user_root; then SUDO="sudo -E"; else unset SUDO; fi +} + +set_sudo_command unset PACKAGES -unset SUDO command -v tar >/dev/null 2>&1 || { PACKAGES=${PACKAGES}" tar"; } CURL_INSTALLED=false WGET_INSTALLED=false @@ -23,8 +35,6 @@ if [ ${CURL_INSTALLED} = false ] && [ ${WGET_INSTALLED} = false ]; then CURL_INSTALLED=true fi -test "$(id -u)" = 0 || SUDO="sudo -E" - LOCAL_AGENT_BINARIES_URI="/mnt/che/ws-agent.tar.gz" DOWNLOAD_AGENT_BINARIES_URI='${WORKSPACE_MASTER_URI}/agent-binaries/ws-agent.tar.gz' diff --git a/wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/TestExecutionContext.java b/wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/TestExecutionContext.java index a991ee0a0d..a3edb8b24c 100644 --- a/wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/TestExecutionContext.java +++ b/wsagent/che-core-api-testing-shared/src/main/java/org/eclipse/che/api/testing/shared/TestExecutionContext.java @@ -34,9 +34,9 @@ public interface TestExecutionContext { void setFilePath(String filePath); /** returns type of the test. */ - TestType getTestType(); + ContextType getContextType(); - void setTestType(TestType testType); + void setContextType(ContextType contextType); /** returns cursor position. */ int getCursorOffset(); @@ -50,7 +50,7 @@ public interface TestExecutionContext { TestExecutionContext withDebugModeEnable(Boolean enable); - enum TestType { + enum ContextType { FILE, FOLDER, PROJECT, CURSOR_POSITION } }