Skip to content

Commit 1b42c4c

Browse files
authored
[Core] Mark pending steps as failed in teamcity plugin (#2264)
* [Core] Mark pending steps as failed in teamcity plugin The teamcity plugin communicates test results to IntelliJ IDEA using teamcity service messages[1]. Currently the teamcity plugin marks pending steps as skipped rather then failed. This is inconsistent with the changes from #1960 in which pending steps are considered a test failure. 1: https://www.jetbrains.com/help/teamcity/service-messages.html * [Core] Fix teamcity link for cucumber-java8 hooks The teamcity plugin communicates test results to IntelliJ IDEA using teamcity service messages[1]. These messages can link to files using a url-like protocol. The code use to convert code locations from cucumber-java8 step definitions did not correctly extract the method from this string representation.
1 parent 19efceb commit 1b42c4c

File tree

3 files changed

+75
-16
lines changed

3 files changed

+75
-16
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1616
### Removed
1717

1818
### Fixed
19+
* [Core] Mark pending steps as failed in teamcity plugin ([#2264](https://github.com/cucumber/cucumber-jvm/pull/2264)) M.P. Korstanje)
1920

2021
## [6.10.1] (2021-03-08)
2122

core/src/main/java/io/cucumber/core/plugin/TeamCityPlugin.java

+26-14
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@
4848
import static java.util.Collections.emptyList;
4949
import static java.util.stream.Collectors.joining;
5050

51+
/**
52+
* Outputs Teamcity services messages to std out.
53+
*
54+
* @see <a
55+
* href=https://www.jetbrains.com/help/teamcity/service-messages.html>TeamCity
56+
* - Service Messages</a>
57+
*/
5158
public class TeamCityPlugin implements EventListener {
5259

5360
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ss.SSSZ");
@@ -230,7 +237,7 @@ private String extractSourceLocation(TestStep testStep) {
230237
if (java8Matcher.matches()) {
231238
String fqDeclaringClassName = java8Matcher.group(1);
232239
String declaringClassName;
233-
int indexOfPackageSeparator = fqDeclaringClassName.indexOf(".");
240+
int indexOfPackageSeparator = fqDeclaringClassName.lastIndexOf(".");
234241
if (indexOfPackageSeparator != -1) {
235242
declaringClassName = fqDeclaringClassName.substring(indexOfPackageSeparator + 1);
236243
} else {
@@ -250,22 +257,27 @@ private void printTestStepFinished(TestStepFinished event) {
250257
Throwable error = event.getResult().getError();
251258
Status status = event.getResult().getStatus();
252259
switch (status) {
253-
case SKIPPED:
254-
print(TEMPLATE_TEST_IGNORED, timeStamp, duration, error == null ? "Step skipped" : error.getMessage(),
255-
name);
260+
case SKIPPED: {
261+
String message = error == null ? "Step skipped" : error.getMessage();
262+
print(TEMPLATE_TEST_IGNORED, timeStamp, duration, message, name);
256263
break;
257-
case PENDING:
258-
print(TEMPLATE_TEST_IGNORED, timeStamp, duration, error == null ? "Step pending" : error.getMessage(),
259-
name);
264+
}
265+
case PENDING: {
266+
String details = error == null ? "" : error.getMessage();
267+
print(TEMPLATE_TEST_FAILED, timeStamp, duration, "Step pending", details, name);
260268
break;
261-
case UNDEFINED:
262-
print(TEMPLATE_TEST_FAILED, timeStamp, duration, "Step undefined", getSnippets(currentTestCase), name);
269+
}
270+
case UNDEFINED: {
271+
String snippets = getSnippets(currentTestCase);
272+
print(TEMPLATE_TEST_FAILED, timeStamp, duration, "Step undefined", snippets, name);
263273
break;
274+
}
264275
case AMBIGUOUS:
265-
case FAILED:
276+
case FAILED: {
266277
String details = extractStackTrace(error);
267278
print(TEMPLATE_TEST_FAILED, timeStamp, duration, "Step failed", details, name);
268279
break;
280+
}
269281
default:
270282
break;
271283
}
@@ -307,8 +319,8 @@ private String getSnippets(TestCase testCase) {
307319
URI uri = testCase.getUri();
308320
Location location = testCase.getLocation();
309321
List<Suggestion> suggestionForTestCase = suggestions.stream()
310-
.filter(suggestions -> suggestions.getUri().equals(uri) &&
311-
suggestions.getTestCaseLocation().equals(location))
322+
.filter(suggestion -> suggestion.getUri().equals(uri) &&
323+
suggestion.getTestCaseLocation().equals(location))
312324
.map(SnippetsSuggestedEvent::getSuggestion)
313325
.collect(Collectors.toList());
314326
return createMessage(suggestionForTestCase);
@@ -322,7 +334,7 @@ private static String createMessage(Collection<Suggestion> suggestions) {
322334
if (suggestions.size() > 1) {
323335
sb.append(" and ").append(suggestions.size() - 1).append(" other step(s)");
324336
}
325-
sb.append("using the snippet(s) below:\n\n");
337+
sb.append(" using the snippet(s) below:\n\n");
326338
String snippets = suggestions
327339
.stream()
328340
.map(Suggestion::getSnippets)
@@ -379,7 +391,7 @@ private String formatCommand(String command, Object... parameters) {
379391
escapedParameters[i] = escape(parameters[i].toString());
380392
}
381393

382-
return String.format(command, escapedParameters);
394+
return String.format(command, (Object[]) escapedParameters);
383395
}
384396

385397
private String escape(String source) {

core/src/test/java/io/cucumber/core/plugin/TeamCityPluginTest.java

+48-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.cucumber.core.plugin;
22

33
import io.cucumber.core.backend.StubHookDefinition;
4+
import io.cucumber.core.backend.StubPendingException;
45
import io.cucumber.core.backend.StubStepDefinition;
56
import io.cucumber.core.backend.TestCaseState;
67
import io.cucumber.core.feature.TestFeatureParser;
@@ -212,7 +213,29 @@ void should_print_error_message_for_undefined_steps() {
212213
.run();
213214

214215
assertThat(out, bytesContainsString("" +
215-
"##teamcity[testFailed timestamp = '1970-01-01T12:00:00.000+0000' duration = '0' message = 'Step undefined' details = 'You can implement this step and 1 other step(s)using the snippet(s) below:|n|ntest snippet 0|ntest snippet 1|n' name = 'first step']"));
216+
"##teamcity[testFailed timestamp = '1970-01-01T12:00:00.000+0000' duration = '0' message = 'Step undefined' details = 'You can implement this step and 1 other step(s) using the snippet(s) below:|n|ntest snippet 0|ntest snippet 1|n' name = 'first step']"));
217+
}
218+
219+
@Test
220+
void should_print_error_message_for_pending_steps() {
221+
Feature feature = TestFeatureParser.parse("path/test.feature", "" +
222+
"Feature: feature name\n" +
223+
" Scenario: scenario name\n" +
224+
" Given first step\n" +
225+
" Given second step\n");
226+
227+
ByteArrayOutputStream out = new ByteArrayOutputStream();
228+
Runtime.builder()
229+
.withFeatureSupplier(new StubFeatureSupplier(feature))
230+
.withAdditionalPlugins(new TeamCityPlugin(new PrintStream(out)))
231+
.withEventBus(new TimeServiceEventBus(fixed(EPOCH, of("UTC")), UUID::randomUUID))
232+
.withBackendSupplier(
233+
new StubBackendSupplier(new StubStepDefinition("first step", new StubPendingException())))
234+
.build()
235+
.run();
236+
237+
assertThat(out, bytesContainsString("" +
238+
"##teamcity[testFailed timestamp = '1970-01-01T12:00:00.000+0000' duration = '0' message = 'Step pending' details = 'TODO: implement me' name = 'first step']"));
216239
}
217240

218241
@Test
@@ -241,7 +264,7 @@ void should_print_error_message_for_before_hooks() {
241264
}
242265

243266
@Test
244-
void should_print_location_hint_for_hooks() {
267+
void should_print_location_hint_for_java_hooks() {
245268
Feature feature = TestFeatureParser.parse("path/test.feature", "" +
246269
"Feature: feature name\n" +
247270
" Scenario: scenario name\n" +
@@ -263,4 +286,27 @@ void should_print_location_hint_for_hooks() {
263286
"##teamcity[testStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = 'java:test://com.example.HookDefinition/beforeHook' captureStandardOutput = 'true' name = 'Before']\n"));
264287
}
265288

289+
@Test
290+
void should_print_location_hint_for_lambda_hooks() {
291+
Feature feature = TestFeatureParser.parse("path/test.feature", "" +
292+
"Feature: feature name\n" +
293+
" Scenario: scenario name\n" +
294+
" Given first step\n");
295+
296+
ByteArrayOutputStream out = new ByteArrayOutputStream();
297+
Runtime.builder()
298+
.withFeatureSupplier(new StubFeatureSupplier(feature))
299+
.withAdditionalPlugins(new TeamCityPlugin(new PrintStream(out)))
300+
.withEventBus(new TimeServiceEventBus(fixed(EPOCH, of("UTC")), UUID::randomUUID))
301+
.withBackendSupplier(new StubBackendSupplier(
302+
singletonList(new StubHookDefinition("com.example.HookDefinition.<init>(HookDefinition.java:12)")),
303+
singletonList(new StubStepDefinition("first step")),
304+
emptyList()))
305+
.build()
306+
.run();
307+
308+
assertThat(out, bytesContainsString("" +
309+
"##teamcity[testStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = 'java:test://com.example.HookDefinition/HookDefinition' captureStandardOutput = 'true' name = 'Before']\n"));
310+
}
311+
266312
}

0 commit comments

Comments
 (0)