Skip to content

Commit 88790fc

Browse files
serhatozdursunmehmetozdursunchadlwilson
authored
feat: add support for skipping scenarios via SkipScenarioException (#924)
* feat: add support for skipping scenarios via SkipScenarioException - Introduced `SkipScenarioException` in the Gauge API to allow users to skip scenarios programmatically. - Updated `MethodExecutor` to catch `SkipScenarioException` and return a `ProtoExecutionResult` with `skipScenario=true`, an appropriate message, and no failure flag. - Added unit test `testStepMethodExecutionWithSkipScenarioException` in `StepExecutionStageTest.java` to verify the behavior. This implements the feature request from issue #691 by allowing steps to skip execution cleanly using `Gauge.skip("reason")`. Signed-off-by: mehmetozdursun <[email protected]> Signed-off-by: serhatozdursun <[email protected]> * fix mergeExecResults for a missing skipped flag Signed-off-by: serhatozdursun <[email protected]> * Update AbstractExecutionStage.java fix the format issue which cause the fail Signed-off-by: serhatozdursun <[email protected]> * Bump up gauge-java version Signed-off-by: serhatozdursun <[email protected]> * Tidy handling of scenario skipping; adding additional merge tests Signed-off-by: Chad Wilson <[email protected]> --------- Signed-off-by: mehmetozdursun <[email protected]> Signed-off-by: serhatozdursun <[email protected]> Signed-off-by: Chad Wilson <[email protected]> Co-authored-by: mehmetozdursun <[email protected]> Co-authored-by: Chad Wilson <[email protected]>
1 parent 5182282 commit 88790fc

File tree

7 files changed

+195
-103
lines changed

7 files changed

+195
-103
lines changed

java.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"id": "java",
3-
"version": "0.11.4",
3+
"version": "0.12.0",
44
"description": "Java support for gauge",
55
"install": {
66
"windows": [],

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<name>gauge-java</name>
55
<groupId>com.thoughtworks.gauge</groupId>
66
<artifactId>gauge-java</artifactId>
7-
<version>0.11.4</version>
7+
<version>0.12.0</version>
88
<description>Java plugin for Gauge</description>
99
<url>https://github.com/getgauge/gauge-java</url>
1010
<dependencyManagement>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.thoughtworks.gauge;
2+
3+
public class SkipScenarioException extends RuntimeException {
4+
public SkipScenarioException(String message) {
5+
super(message);
6+
}
7+
8+
@SuppressWarnings("unused")
9+
public SkipScenarioException(String message, Throwable cause) {
10+
super(message, cause);
11+
}
12+
}

src/main/java/com/thoughtworks/gauge/execution/AbstractExecutionStage.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ public Spec.ProtoExecutionResult executeNext(Spec.ProtoExecutionResult previousS
2020
protected Spec.ProtoExecutionResult mergeExecResults(Spec.ProtoExecutionResult previousStageResult, Spec.ProtoExecutionResult execResult) {
2121
long execTime = execResult.getExecutionTime() + previousStageResult.getExecutionTime();
2222
boolean failed = execResult.getFailed() | previousStageResult.getFailed();
23+
boolean skipped = execResult.getSkipScenario() | previousStageResult.getSkipScenario();
2324

2425
Spec.ProtoExecutionResult.Builder builder = Spec.ProtoExecutionResult.newBuilder();
2526
builder.setExecutionTime(execTime);
2627
builder.setFailed(failed);
28+
builder.setSkipScenario(skipped);
2729
if (previousStageResult.getFailed()) {
2830
builder.setErrorMessage(previousStageResult.getErrorMessage());
2931
builder.setErrorType(previousStageResult.getErrorType());

src/main/java/com/thoughtworks/gauge/execution/MethodExecutor.java

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77

88
import com.thoughtworks.gauge.ClassInstanceManager;
99
import com.thoughtworks.gauge.ContinueOnFailure;
10+
import com.thoughtworks.gauge.SkipScenarioException;
1011
import com.thoughtworks.gauge.Util;
1112
import com.thoughtworks.gauge.screenshot.ScreenshotFactory;
1213
import gauge.messages.Spec;
1314

1415
import java.io.PrintWriter;
1516
import java.io.StringWriter;
1617
import java.lang.reflect.Method;
17-
import java.util.Set;
18+
import java.util.Optional;
1819

1920
public class MethodExecutor {
2021
private final ClassInstanceManager instanceManager;
@@ -31,25 +32,37 @@ public Spec.ProtoExecutionResult execute(Method method, Object... args) {
3132
long endTime = System.currentTimeMillis();
3233
return Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(endTime - startTime).build();
3334
} catch (Throwable e) {
34-
boolean recoverable = method.isAnnotationPresent(ContinueOnFailure.class);
35-
Class[] continuableExceptions = new Class[]{};
36-
if (recoverable) {
37-
continuableExceptions = method.getAnnotation(ContinueOnFailure.class).value();
35+
long execTime = System.currentTimeMillis() - startTime;
36+
37+
if (e.getCause() instanceof SkipScenarioException) {
38+
return createSkippedExecResult(execTime, (SkipScenarioException) e.getCause());
3839
}
39-
long endTime = System.currentTimeMillis();
40-
return createFailureExecResult(endTime - startTime, e, recoverable, continuableExceptions);
40+
41+
Class<?>[] continuableExceptions = Optional.ofNullable(method.getAnnotation(ContinueOnFailure.class))
42+
.map(ContinueOnFailure::value).
43+
orElseGet(() -> new Class<?>[]{});
44+
45+
return createFailureExecResult(execTime, e, method.isAnnotationPresent(ContinueOnFailure.class), continuableExceptions);
4146
}
4247
}
4348

44-
private Spec.ProtoExecutionResult createFailureExecResult(long execTime, Throwable e, boolean recoverable, Class[] continuableExceptions) {
49+
private Spec.ProtoExecutionResult createSkippedExecResult(long execTime, SkipScenarioException cause) {
50+
return Spec.ProtoExecutionResult.newBuilder()
51+
.setSkipScenario(true)
52+
.addMessage(Optional.ofNullable(cause.getMessage()).orElse("SKIPPED"))
53+
.setExecutionTime(execTime)
54+
.build();
55+
}
56+
57+
private Spec.ProtoExecutionResult createFailureExecResult(long execTime, Throwable e, boolean recoverable, Class<?>[] continuableExceptions) {
4558
Spec.ProtoExecutionResult.Builder builder = Spec.ProtoExecutionResult.newBuilder().setFailed(true);
4659
if (Util.shouldTakeFailureScreenshot()) {
4760
String screenshotFileName = new ScreenshotFactory(instanceManager).getScreenshotBytes();
4861
builder.setFailureScreenshotFile(screenshotFileName);
4962
}
5063
if (e.getCause() != null) {
5164
builder.setRecoverableError(false);
52-
for (Class c : continuableExceptions) {
65+
for (Class<?> c : continuableExceptions) {
5366
if (c.isAssignableFrom(e.getCause().getClass()) && recoverable) {
5467
builder.setRecoverableError(true);
5568
break;
@@ -74,16 +87,4 @@ private String formatStackTrace(Throwable t) {
7487
t.printStackTrace(new PrintWriter(out));
7588
return out.toString();
7689
}
77-
78-
public Spec.ProtoExecutionResult executeMethods(Set<Method> methods, Object... args) {
79-
long totalExecutionTime = 0;
80-
for (Method method : methods) {
81-
Spec.ProtoExecutionResult result = execute(method, args);
82-
totalExecutionTime += result.getExecutionTime();
83-
if (result.getFailed()) {
84-
return result;
85-
}
86-
}
87-
return Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(totalExecutionTime).build();
88-
}
8990
}

src/test/java/com/thoughtworks/gauge/execution/AbstractExecutionStageTest.java

Lines changed: 128 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package com.thoughtworks.gauge.execution;
77

88
import gauge.messages.Spec;
9+
import org.junit.jupiter.api.Nested;
910
import org.junit.jupiter.api.Test;
1011

1112
import static org.junit.jupiter.api.Assertions.*;
@@ -21,94 +22,141 @@ public void testMergingSimpleResultsBothPassing() throws Exception {
2122
assertEquals(2100, result.getExecutionTime());
2223
}
2324

24-
@Test
25-
public void testMergingResultsPreviousFailing() throws Exception {
26-
String screenShot = "1";
27-
28-
Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(true).
29-
setExecutionTime(100).
30-
setRecoverableError(false).
31-
setErrorMessage("Previous failed").
32-
setStackTrace("Previous stacktrace").
33-
setFailureScreenshotFile(screenShot).build();
34-
Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(1100).build();
35-
Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current);
25+
@Nested
26+
public class Failing {
27+
28+
@Test
29+
public void testMergingResultsPreviousFailing() throws Exception {
30+
String screenShot = "1";
31+
32+
Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(true)
33+
.setExecutionTime(100)
34+
.setRecoverableError(false)
35+
.setErrorMessage("Previous failed")
36+
.setStackTrace("Previous stacktrace")
37+
.setFailureScreenshotFile(screenShot).build();
38+
Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(1100).build();
39+
Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current);
40+
41+
assertTrue(result.getFailed());
42+
assertEquals(1200, result.getExecutionTime());
43+
assertEquals("Previous failed", result.getErrorMessage());
44+
assertEquals("Previous stacktrace", result.getStackTrace());
45+
assertFalse(result.getRecoverableError());
46+
assertEquals(screenShot, result.getFailureScreenshotFile());
47+
}
3648

37-
assertTrue(result.getFailed());
38-
assertEquals(1200, result.getExecutionTime());
39-
assertEquals("Previous failed", result.getErrorMessage());
40-
assertEquals("Previous stacktrace", result.getStackTrace());
41-
assertFalse(result.getRecoverableError());
42-
assertEquals(screenShot, result.getFailureScreenshotFile());
43-
}
49+
@Test
50+
public void testMergingResultsCurrentFailing() throws Exception {
51+
String screenShot = "2";
52+
53+
Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(100).build();
54+
Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(true)
55+
.setExecutionTime(100)
56+
.setRecoverableError(false)
57+
.setErrorMessage("current failed")
58+
.setStackTrace("current stacktrace")
59+
.setFailureScreenshotFile(screenShot).build();
60+
Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current);
61+
62+
assertTrue(result.getFailed());
63+
assertEquals(200, result.getExecutionTime());
64+
assertEquals("current failed", result.getErrorMessage());
65+
assertEquals("current stacktrace", result.getStackTrace());
66+
assertFalse(result.getRecoverableError());
67+
assertEquals(screenShot, result.getFailureScreenshotFile());
68+
}
4469

45-
@Test
46-
public void testMergingResultsCurrentFailing() throws Exception {
47-
String screenShot = "2";
48-
49-
Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(100).build();
50-
Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(true).
51-
setExecutionTime(100).
52-
setRecoverableError(false).
53-
setErrorMessage("current failed").
54-
setStackTrace("current stacktrace").
55-
setFailureScreenshotFile(screenShot).build();
56-
Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current);
70+
@Test
71+
public void testMergingResultsBothFailing() throws Exception {
72+
String screenShotPrevious = "2";
73+
String screenShotCurrent = "hello";
74+
75+
Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(true)
76+
.setExecutionTime(1001)
77+
.setRecoverableError(true)
78+
.setErrorMessage("previous failed")
79+
.setStackTrace("previous stacktrace")
80+
.setFailureScreenshotFile(screenShotPrevious).build();
81+
Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(true)
82+
.setExecutionTime(1002)
83+
.setRecoverableError(false)
84+
.setErrorMessage("current failed")
85+
.setStackTrace("current stacktrace")
86+
.setFailureScreenshotFile(screenShotCurrent).build();
87+
Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current);
88+
89+
assertTrue(result.getFailed());
90+
assertEquals(2003, result.getExecutionTime());
91+
assertEquals("previous failed", result.getErrorMessage());
92+
assertEquals("previous stacktrace", result.getStackTrace());
93+
assertFalse(result.getRecoverableError());
94+
assertEquals(screenShotPrevious, result.getFailureScreenshotFile());
95+
}
5796

58-
assertTrue(result.getFailed());
59-
assertEquals(200, result.getExecutionTime());
60-
assertEquals("current failed", result.getErrorMessage());
61-
assertEquals("current stacktrace", result.getStackTrace());
62-
assertFalse(result.getRecoverableError());
63-
assertEquals(screenShot, result.getFailureScreenshotFile());
97+
@Test
98+
public void testMergingResultsCurrentFailingAndIsRecoverable() throws Exception {
99+
String screenShotCurrent = "screenShotCurrent.png";
100+
101+
Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(1001).build();
102+
Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(true)
103+
.setExecutionTime(1002)
104+
.setRecoverableError(true)
105+
.setErrorMessage("current failed")
106+
.setStackTrace("current stacktrace")
107+
.setFailureScreenshotFile(screenShotCurrent).build();
108+
Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current);
109+
110+
assertTrue(result.getFailed());
111+
assertEquals(2003, result.getExecutionTime());
112+
assertEquals("current failed", result.getErrorMessage());
113+
assertEquals("current stacktrace", result.getStackTrace());
114+
assertTrue(result.getRecoverableError());
115+
assertEquals(screenShotCurrent, result.getFailureScreenshotFile());
116+
}
64117
}
65118

66-
@Test
67-
public void testMergingResultsBothFailing() throws Exception {
68-
String screenShotPrevious = "2";
69-
String screenShotCurrent = "hello";
70-
71-
Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(true).
72-
setExecutionTime(1001).
73-
setRecoverableError(true).
74-
setErrorMessage("previous failed").
75-
setStackTrace("previous stacktrace").
76-
setFailureScreenshotFile(screenShotPrevious).build();
77-
Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(true).
78-
setExecutionTime(1002).
79-
setRecoverableError(false).
80-
setErrorMessage("current failed").
81-
setStackTrace("current stacktrace").
82-
setFailureScreenshotFile(screenShotCurrent).build();
83-
Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current);
119+
@Nested
120+
public class Skipped {
84121

85-
assertTrue(result.getFailed());
86-
assertEquals(2003, result.getExecutionTime());
87-
assertEquals("previous failed", result.getErrorMessage());
88-
assertEquals("previous stacktrace", result.getStackTrace());
89-
assertFalse(result.getRecoverableError());
90-
assertEquals(screenShotPrevious, result.getFailureScreenshotFile());
91-
}
122+
@Test
123+
public void testMergingResultsPreviousSkipped() throws Exception {
124+
Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setSkipScenario(true)
125+
.setExecutionTime(100)
126+
.build();
127+
Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setSkipScenario(false).setExecutionTime(1100).build();
128+
Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current);
92129

93-
@Test
94-
public void testMergingResultsCurrentFailingAndIsRecoverable() throws Exception {
95-
String screenShotCurrent = "screenShotCurrent.png";
96-
97-
Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(1001).build();
98-
Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setFailed(true).
99-
setExecutionTime(1002).
100-
setRecoverableError(true).
101-
setErrorMessage("current failed").
102-
setStackTrace("current stacktrace").
103-
setFailureScreenshotFile(screenShotCurrent).build();
104-
Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current);
130+
assertTrue(result.getSkipScenario());
131+
assertEquals(1200, result.getExecutionTime());
132+
}
133+
134+
@Test
135+
public void testMergingResultsCurrentSkipped() throws Exception {
136+
Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setSkipScenario(false).setExecutionTime(100).build();
137+
Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setSkipScenario(true)
138+
.setExecutionTime(100)
139+
.build();
140+
Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current);
141+
142+
assertTrue(result.getSkipScenario());
143+
assertEquals(200, result.getExecutionTime());
144+
}
145+
146+
@Test
147+
public void testMergingResultsBothSkipped() throws Exception {
148+
Spec.ProtoExecutionResult previous = Spec.ProtoExecutionResult.newBuilder().setSkipScenario(true)
149+
.setExecutionTime(1001)
150+
.build();
151+
Spec.ProtoExecutionResult current = Spec.ProtoExecutionResult.newBuilder().setSkipScenario(true)
152+
.setExecutionTime(1002)
153+
.build();
154+
Spec.ProtoExecutionResult result = new TestExecutionStage().mergeExecResults(previous, current);
155+
156+
assertTrue(result.getSkipScenario());
157+
assertEquals(2003, result.getExecutionTime());
158+
}
105159

106-
assertTrue(result.getFailed());
107-
assertEquals(2003, result.getExecutionTime());
108-
assertEquals("current failed", result.getErrorMessage());
109-
assertEquals("current stacktrace", result.getStackTrace());
110-
assertTrue(result.getRecoverableError());
111-
assertEquals(screenShotCurrent, result.getFailureScreenshotFile());
112160
}
113161

114162
private static class TestExecutionStage extends AbstractExecutionStage {

0 commit comments

Comments
 (0)