diff --git a/java.json b/java.json index f8a13fad..951a0b8c 100644 --- a/java.json +++ b/java.json @@ -1,6 +1,6 @@ { "id": "java", - "version": "0.11.4", + "version": "0.12.0", "description": "Java support for gauge", "install": { "windows": [], diff --git a/pom.xml b/pom.xml index 71357668..57e8ff3a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ gauge-java com.thoughtworks.gauge gauge-java - 0.11.4 + 0.12.0 Java plugin for Gauge https://github.com/getgauge/gauge-java diff --git a/src/main/java/com/thoughtworks/gauge/SkipScenarioException.java b/src/main/java/com/thoughtworks/gauge/SkipScenarioException.java new file mode 100644 index 00000000..c64960ee --- /dev/null +++ b/src/main/java/com/thoughtworks/gauge/SkipScenarioException.java @@ -0,0 +1,12 @@ +package com.thoughtworks.gauge; + +public class SkipScenarioException extends RuntimeException { + public SkipScenarioException(String message) { + super(message); + } + + @SuppressWarnings("unused") + public SkipScenarioException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/com/thoughtworks/gauge/execution/AbstractExecutionStage.java b/src/main/java/com/thoughtworks/gauge/execution/AbstractExecutionStage.java index ac8bacfa..8537ac3e 100644 --- a/src/main/java/com/thoughtworks/gauge/execution/AbstractExecutionStage.java +++ b/src/main/java/com/thoughtworks/gauge/execution/AbstractExecutionStage.java @@ -20,10 +20,12 @@ public Spec.ProtoExecutionResult executeNext(Spec.ProtoExecutionResult previousS protected Spec.ProtoExecutionResult mergeExecResults(Spec.ProtoExecutionResult previousStageResult, Spec.ProtoExecutionResult execResult) { long execTime = execResult.getExecutionTime() + previousStageResult.getExecutionTime(); boolean failed = execResult.getFailed() | previousStageResult.getFailed(); + boolean skipped = execResult.getSkipScenario() | previousStageResult.getSkipScenario(); Spec.ProtoExecutionResult.Builder builder = Spec.ProtoExecutionResult.newBuilder(); builder.setExecutionTime(execTime); builder.setFailed(failed); + builder.setSkipScenario(skipped); if (previousStageResult.getFailed()) { builder.setErrorMessage(previousStageResult.getErrorMessage()); builder.setErrorType(previousStageResult.getErrorType()); diff --git a/src/main/java/com/thoughtworks/gauge/execution/MethodExecutor.java b/src/main/java/com/thoughtworks/gauge/execution/MethodExecutor.java index 4304ef13..5d18d691 100644 --- a/src/main/java/com/thoughtworks/gauge/execution/MethodExecutor.java +++ b/src/main/java/com/thoughtworks/gauge/execution/MethodExecutor.java @@ -7,6 +7,7 @@ import com.thoughtworks.gauge.ClassInstanceManager; import com.thoughtworks.gauge.ContinueOnFailure; +import com.thoughtworks.gauge.SkipScenarioException; import com.thoughtworks.gauge.Util; import com.thoughtworks.gauge.screenshot.ScreenshotFactory; import gauge.messages.Spec; @@ -14,7 +15,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Method; -import java.util.Set; +import java.util.Optional; public class MethodExecutor { private final ClassInstanceManager instanceManager; @@ -31,17 +32,29 @@ public Spec.ProtoExecutionResult execute(Method method, Object... args) { long endTime = System.currentTimeMillis(); return Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(endTime - startTime).build(); } catch (Throwable e) { - boolean recoverable = method.isAnnotationPresent(ContinueOnFailure.class); - Class[] continuableExceptions = new Class[]{}; - if (recoverable) { - continuableExceptions = method.getAnnotation(ContinueOnFailure.class).value(); + long execTime = System.currentTimeMillis() - startTime; + + if (e.getCause() instanceof SkipScenarioException) { + return createSkippedExecResult(execTime, (SkipScenarioException) e.getCause()); } - long endTime = System.currentTimeMillis(); - return createFailureExecResult(endTime - startTime, e, recoverable, continuableExceptions); + + Class[] continuableExceptions = Optional.ofNullable(method.getAnnotation(ContinueOnFailure.class)) + .map(ContinueOnFailure::value). + orElseGet(() -> new Class[]{}); + + return createFailureExecResult(execTime, e, method.isAnnotationPresent(ContinueOnFailure.class), continuableExceptions); } } - private Spec.ProtoExecutionResult createFailureExecResult(long execTime, Throwable e, boolean recoverable, Class[] continuableExceptions) { + private Spec.ProtoExecutionResult createSkippedExecResult(long execTime, SkipScenarioException cause) { + return Spec.ProtoExecutionResult.newBuilder() + .setSkipScenario(true) + .addMessage(Optional.ofNullable(cause.getMessage()).orElse("SKIPPED")) + .setExecutionTime(execTime) + .build(); + } + + private Spec.ProtoExecutionResult createFailureExecResult(long execTime, Throwable e, boolean recoverable, Class[] continuableExceptions) { Spec.ProtoExecutionResult.Builder builder = Spec.ProtoExecutionResult.newBuilder().setFailed(true); if (Util.shouldTakeFailureScreenshot()) { String screenshotFileName = new ScreenshotFactory(instanceManager).getScreenshotBytes(); @@ -49,7 +62,7 @@ private Spec.ProtoExecutionResult createFailureExecResult(long execTime, Throwab } if (e.getCause() != null) { builder.setRecoverableError(false); - for (Class c : continuableExceptions) { + for (Class c : continuableExceptions) { if (c.isAssignableFrom(e.getCause().getClass()) && recoverable) { builder.setRecoverableError(true); break; @@ -74,16 +87,4 @@ private String formatStackTrace(Throwable t) { t.printStackTrace(new PrintWriter(out)); return out.toString(); } - - public Spec.ProtoExecutionResult executeMethods(Set methods, Object... args) { - long totalExecutionTime = 0; - for (Method method : methods) { - Spec.ProtoExecutionResult result = execute(method, args); - totalExecutionTime += result.getExecutionTime(); - if (result.getFailed()) { - return result; - } - } - return Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(totalExecutionTime).build(); - } } diff --git a/src/test/java/com/thoughtworks/gauge/execution/AbstractExecutionStageTest.java b/src/test/java/com/thoughtworks/gauge/execution/AbstractExecutionStageTest.java index f2029cad..0eae7281 100644 --- a/src/test/java/com/thoughtworks/gauge/execution/AbstractExecutionStageTest.java +++ b/src/test/java/com/thoughtworks/gauge/execution/AbstractExecutionStageTest.java @@ -6,6 +6,7 @@ package com.thoughtworks.gauge.execution; import gauge.messages.Spec; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -21,94 +22,141 @@ public void testMergingSimpleResultsBothPassing() throws Exception { assertEquals(2100, result.getExecutionTime()); } - @Test - public void testMergingResultsPreviousFailing() throws Exception { - String screenShot = "1"; - - Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(true). - setExecutionTime(100). - setRecoverableError(false). - setErrorMessage("Previous failed"). - setStackTrace("Previous stacktrace"). - setFailureScreenshotFile(screenShot).build(); - Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(1100).build(); - Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current); + @Nested + public class Failing { + + @Test + public void testMergingResultsPreviousFailing() throws Exception { + String screenShot = "1"; + + Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(true) + .setExecutionTime(100) + .setRecoverableError(false) + .setErrorMessage("Previous failed") + .setStackTrace("Previous stacktrace") + .setFailureScreenshotFile(screenShot).build(); + Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(1100).build(); + Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current); + + assertTrue(result.getFailed()); + assertEquals(1200, result.getExecutionTime()); + assertEquals("Previous failed", result.getErrorMessage()); + assertEquals("Previous stacktrace", result.getStackTrace()); + assertFalse(result.getRecoverableError()); + assertEquals(screenShot, result.getFailureScreenshotFile()); + } - assertTrue(result.getFailed()); - assertEquals(1200, result.getExecutionTime()); - assertEquals("Previous failed", result.getErrorMessage()); - assertEquals("Previous stacktrace", result.getStackTrace()); - assertFalse(result.getRecoverableError()); - assertEquals(screenShot, result.getFailureScreenshotFile()); - } + @Test + public void testMergingResultsCurrentFailing() throws Exception { + String screenShot = "2"; + + Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(100).build(); + Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(true) + .setExecutionTime(100) + .setRecoverableError(false) + .setErrorMessage("current failed") + .setStackTrace("current stacktrace") + .setFailureScreenshotFile(screenShot).build(); + Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current); + + assertTrue(result.getFailed()); + assertEquals(200, result.getExecutionTime()); + assertEquals("current failed", result.getErrorMessage()); + assertEquals("current stacktrace", result.getStackTrace()); + assertFalse(result.getRecoverableError()); + assertEquals(screenShot, result.getFailureScreenshotFile()); + } - @Test - public void testMergingResultsCurrentFailing() throws Exception { - String screenShot = "2"; - - Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(100).build(); - Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(true). - setExecutionTime(100). - setRecoverableError(false). - setErrorMessage("current failed"). - setStackTrace("current stacktrace"). - setFailureScreenshotFile(screenShot).build(); - Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current); + @Test + public void testMergingResultsBothFailing() throws Exception { + String screenShotPrevious = "2"; + String screenShotCurrent = "hello"; + + Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(true) + .setExecutionTime(1001) + .setRecoverableError(true) + .setErrorMessage("previous failed") + .setStackTrace("previous stacktrace") + .setFailureScreenshotFile(screenShotPrevious).build(); + Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(true) + .setExecutionTime(1002) + .setRecoverableError(false) + .setErrorMessage("current failed") + .setStackTrace("current stacktrace") + .setFailureScreenshotFile(screenShotCurrent).build(); + Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current); + + assertTrue(result.getFailed()); + assertEquals(2003, result.getExecutionTime()); + assertEquals("previous failed", result.getErrorMessage()); + assertEquals("previous stacktrace", result.getStackTrace()); + assertFalse(result.getRecoverableError()); + assertEquals(screenShotPrevious, result.getFailureScreenshotFile()); + } - assertTrue(result.getFailed()); - assertEquals(200, result.getExecutionTime()); - assertEquals("current failed", result.getErrorMessage()); - assertEquals("current stacktrace", result.getStackTrace()); - assertFalse(result.getRecoverableError()); - assertEquals(screenShot, result.getFailureScreenshotFile()); + @Test + public void testMergingResultsCurrentFailingAndIsRecoverable() throws Exception { + String screenShotCurrent = "screenShotCurrent.png"; + + Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(1001).build(); + Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(true) + .setExecutionTime(1002) + .setRecoverableError(true) + .setErrorMessage("current failed") + .setStackTrace("current stacktrace") + .setFailureScreenshotFile(screenShotCurrent).build(); + Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current); + + assertTrue(result.getFailed()); + assertEquals(2003, result.getExecutionTime()); + assertEquals("current failed", result.getErrorMessage()); + assertEquals("current stacktrace", result.getStackTrace()); + assertTrue(result.getRecoverableError()); + assertEquals(screenShotCurrent, result.getFailureScreenshotFile()); + } } - @Test - public void testMergingResultsBothFailing() throws Exception { - String screenShotPrevious = "2"; - String screenShotCurrent = "hello"; - - Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(true). - setExecutionTime(1001). - setRecoverableError(true). - setErrorMessage("previous failed"). - setStackTrace("previous stacktrace"). - setFailureScreenshotFile(screenShotPrevious).build(); - Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(true). - setExecutionTime(1002). - setRecoverableError(false). - setErrorMessage("current failed"). - setStackTrace("current stacktrace"). - setFailureScreenshotFile(screenShotCurrent).build(); - Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current); + @Nested + public class Skipped { - assertTrue(result.getFailed()); - assertEquals(2003, result.getExecutionTime()); - assertEquals("previous failed", result.getErrorMessage()); - assertEquals("previous stacktrace", result.getStackTrace()); - assertFalse(result.getRecoverableError()); - assertEquals(screenShotPrevious, result.getFailureScreenshotFile()); - } + @Test + public void testMergingResultsPreviousSkipped() throws Exception { + Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setSkipScenario(true) + .setExecutionTime(100) + .build(); + Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setSkipScenario(false).setExecutionTime(1100).build(); + Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current); - @Test - public void testMergingResultsCurrentFailingAndIsRecoverable() throws Exception { - String screenShotCurrent = "screenShotCurrent.png"; - - Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(1001).build(); - Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(true). - setExecutionTime(1002). - setRecoverableError(true). - setErrorMessage("current failed"). - setStackTrace("current stacktrace"). - setFailureScreenshotFile(screenShotCurrent).build(); - Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current); + assertTrue(result.getSkipScenario()); + assertEquals(1200, result.getExecutionTime()); + } + + @Test + public void testMergingResultsCurrentSkipped() throws Exception { + Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setSkipScenario(false).setExecutionTime(100).build(); + Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setSkipScenario(true) + .setExecutionTime(100) + .build(); + Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current); + + assertTrue(result.getSkipScenario()); + assertEquals(200, result.getExecutionTime()); + } + + @Test + public void testMergingResultsBothSkipped() throws Exception { + Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setSkipScenario(true) + .setExecutionTime(1001) + .build(); + Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setSkipScenario(true) + .setExecutionTime(1002) + .build(); + Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current); + + assertTrue(result.getSkipScenario()); + assertEquals(2003, result.getExecutionTime()); + } - assertTrue(result.getFailed()); - assertEquals(2003, result.getExecutionTime()); - assertEquals("current failed", result.getErrorMessage()); - assertEquals("current stacktrace", result.getStackTrace()); - assertTrue(result.getRecoverableError()); - assertEquals(screenShotCurrent, result.getFailureScreenshotFile()); } private static class TestExecutionStage extends AbstractExecutionStage { diff --git a/src/test/java/com/thoughtworks/gauge/execution/StepExecutionStageTest.java b/src/test/java/com/thoughtworks/gauge/execution/StepExecutionStageTest.java index f9083ac3..67199c6c 100644 --- a/src/test/java/com/thoughtworks/gauge/execution/StepExecutionStageTest.java +++ b/src/test/java/com/thoughtworks/gauge/execution/StepExecutionStageTest.java @@ -19,6 +19,7 @@ import java.lang.reflect.Method; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; @@ -181,6 +182,30 @@ public void testFailingStepMethodExecutionWithNoCOF() throws Exception { assertEquals("java.lang.RuntimeException: my exception", result.getErrorMessage()); } + @Test + public void testStepMethodExecutionWithSkipScenarioException() throws Exception { + Messages.ExecuteStepRequest executeStepRequest = Messages.ExecuteStepRequest.newBuilder() + .setParsedStepText("skip me") + .setActualStepText("skip me") + .build(); + + StepExecutionStage executionStage = new StepExecutionStage( + executeStepRequest, + new ClassInstanceManager(), + new ParameterParsingChain(), + mock(StepRegistry.class) + ); + + MethodExecutor methodExecutor = new MethodExecutor(new ClassInstanceManager()); + Method skipMethod = this.getClass().getMethod("skipScenarioStep"); + + Spec.ProtoExecutionResult result = executionStage.executeStepMethod(methodExecutor, skipMethod); + + assertFalse(result.getFailed()); + assertTrue(result.getSkipScenario()); + assertThat(result.getMessageList()).containsExactly("skipping this scenario due to unmet condition"); + } + @ContinueOnFailure public void foo() { throw new RuntimeException("my exception"); @@ -222,4 +247,8 @@ public Object table(Object table) { // Test methods checking methodExecutor with params return null; } + + public void skipScenarioStep() { + throw new com.thoughtworks.gauge.SkipScenarioException("skipping this scenario due to unmet condition"); + } }