Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Core] Mark pending steps as failed in teamcity plugin #2264

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Removed

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

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

Expand Down
40 changes: 26 additions & 14 deletions core/src/main/java/io/cucumber/core/plugin/TeamCityPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.joining;

/**
* Outputs Teamcity services messages to std out.
*
* @see <a
* href=https://www.jetbrains.com/help/teamcity/service-messages.html>TeamCity
* - Service Messages</a>
*/
public class TeamCityPlugin implements EventListener {

private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ss.SSSZ");
Expand Down Expand Up @@ -230,7 +237,7 @@ private String extractSourceLocation(TestStep testStep) {
if (java8Matcher.matches()) {
String fqDeclaringClassName = java8Matcher.group(1);
String declaringClassName;
int indexOfPackageSeparator = fqDeclaringClassName.indexOf(".");
int indexOfPackageSeparator = fqDeclaringClassName.lastIndexOf(".");
if (indexOfPackageSeparator != -1) {
declaringClassName = fqDeclaringClassName.substring(indexOfPackageSeparator + 1);
} else {
Expand All @@ -250,22 +257,27 @@ private void printTestStepFinished(TestStepFinished event) {
Throwable error = event.getResult().getError();
Status status = event.getResult().getStatus();
switch (status) {
case SKIPPED:
print(TEMPLATE_TEST_IGNORED, timeStamp, duration, error == null ? "Step skipped" : error.getMessage(),
name);
case SKIPPED: {
String message = error == null ? "Step skipped" : error.getMessage();
print(TEMPLATE_TEST_IGNORED, timeStamp, duration, message, name);
break;
case PENDING:
print(TEMPLATE_TEST_IGNORED, timeStamp, duration, error == null ? "Step pending" : error.getMessage(),
name);
}
case PENDING: {
String details = error == null ? "" : error.getMessage();
print(TEMPLATE_TEST_FAILED, timeStamp, duration, "Step pending", details, name);
break;
case UNDEFINED:
print(TEMPLATE_TEST_FAILED, timeStamp, duration, "Step undefined", getSnippets(currentTestCase), name);
}
case UNDEFINED: {
String snippets = getSnippets(currentTestCase);
print(TEMPLATE_TEST_FAILED, timeStamp, duration, "Step undefined", snippets, name);
break;
}
case AMBIGUOUS:
case FAILED:
case FAILED: {
String details = extractStackTrace(error);
print(TEMPLATE_TEST_FAILED, timeStamp, duration, "Step failed", details, name);
break;
}
default:
break;
}
Expand Down Expand Up @@ -307,8 +319,8 @@ private String getSnippets(TestCase testCase) {
URI uri = testCase.getUri();
Location location = testCase.getLocation();
List<Suggestion> suggestionForTestCase = suggestions.stream()
.filter(suggestions -> suggestions.getUri().equals(uri) &&
suggestions.getTestCaseLocation().equals(location))
.filter(suggestion -> suggestion.getUri().equals(uri) &&
suggestion.getTestCaseLocation().equals(location))
.map(SnippetsSuggestedEvent::getSuggestion)
.collect(Collectors.toList());
return createMessage(suggestionForTestCase);
Expand All @@ -322,7 +334,7 @@ private static String createMessage(Collection<Suggestion> suggestions) {
if (suggestions.size() > 1) {
sb.append(" and ").append(suggestions.size() - 1).append(" other step(s)");
}
sb.append("using the snippet(s) below:\n\n");
sb.append(" using the snippet(s) below:\n\n");
String snippets = suggestions
.stream()
.map(Suggestion::getSnippets)
Expand Down Expand Up @@ -379,7 +391,7 @@ private String formatCommand(String command, Object... parameters) {
escapedParameters[i] = escape(parameters[i].toString());
}

return String.format(command, escapedParameters);
return String.format(command, (Object[]) escapedParameters);
}

private String escape(String source) {
Expand Down
50 changes: 48 additions & 2 deletions core/src/test/java/io/cucumber/core/plugin/TeamCityPluginTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.cucumber.core.plugin;

import io.cucumber.core.backend.StubHookDefinition;
import io.cucumber.core.backend.StubPendingException;
import io.cucumber.core.backend.StubStepDefinition;
import io.cucumber.core.backend.TestCaseState;
import io.cucumber.core.feature.TestFeatureParser;
Expand Down Expand Up @@ -212,7 +213,29 @@ void should_print_error_message_for_undefined_steps() {
.run();

assertThat(out, bytesContainsString("" +
"##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']"));
"##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']"));
}

@Test
void should_print_error_message_for_pending_steps() {
Feature feature = TestFeatureParser.parse("path/test.feature", "" +
"Feature: feature name\n" +
" Scenario: scenario name\n" +
" Given first step\n" +
" Given second step\n");

ByteArrayOutputStream out = new ByteArrayOutputStream();
Runtime.builder()
.withFeatureSupplier(new StubFeatureSupplier(feature))
.withAdditionalPlugins(new TeamCityPlugin(new PrintStream(out)))
.withEventBus(new TimeServiceEventBus(fixed(EPOCH, of("UTC")), UUID::randomUUID))
.withBackendSupplier(
new StubBackendSupplier(new StubStepDefinition("first step", new StubPendingException())))
.build()
.run();

assertThat(out, bytesContainsString("" +
"##teamcity[testFailed timestamp = '1970-01-01T12:00:00.000+0000' duration = '0' message = 'Step pending' details = 'TODO: implement me' name = 'first step']"));
}

@Test
Expand Down Expand Up @@ -241,7 +264,7 @@ void should_print_error_message_for_before_hooks() {
}

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

@Test
void should_print_location_hint_for_lambda_hooks() {
Feature feature = TestFeatureParser.parse("path/test.feature", "" +
"Feature: feature name\n" +
" Scenario: scenario name\n" +
" Given first step\n");

ByteArrayOutputStream out = new ByteArrayOutputStream();
Runtime.builder()
.withFeatureSupplier(new StubFeatureSupplier(feature))
.withAdditionalPlugins(new TeamCityPlugin(new PrintStream(out)))
.withEventBus(new TimeServiceEventBus(fixed(EPOCH, of("UTC")), UUID::randomUUID))
.withBackendSupplier(new StubBackendSupplier(
singletonList(new StubHookDefinition("com.example.HookDefinition.<init>(HookDefinition.java:12)")),
singletonList(new StubStepDefinition("first step")),
emptyList()))
.build()
.run();

assertThat(out, bytesContainsString("" +
"##teamcity[testStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = 'java:test://com.example.HookDefinition/HookDefinition' captureStandardOutput = 'true' name = 'Before']\n"));
}

}