-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Core] Implement TeamCity output format plugin (#1842)
This plugin inserts markers that can be picked up by IDEA and Teamcity. These in turn can then use this information to display a test tree and show the output grouped by scenario. This is plugin is nessesary because Intelij uses reflection to extract more information from the plugin system then what would normally be available. By substituting the `CucumberJvm[1-5]SMFormatter` with this plugin we avoid runtime errors when our internals inevitably change. Unfortunately the teamcity format is poorly documented[1]. Reverse engingeering[2][3] the format from the plugin yields some information but the exact function is rather opaque. 1. https://confluence.jetbrains.com/display/TCD9/Build+Script+Interaction+with+TeamCity 2. https://github.com/JetBrains/intellij-community/tree/master/plugins/cucumber-jvm-formatter5/src/org/jetbrains/plugins/cucumber/java/run 3. https://github.com/JetBrains/intellij-community/tree/master/plugins/cucumber-jvm-formatter/src/org/jetbrains/plugins/cucumber/java/run
- Loading branch information
1 parent
de3f234
commit e78e495
Showing
20 changed files
with
643 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
379 changes: 379 additions & 0 deletions
379
core/src/main/java/io/cucumber/core/plugin/TeamCityPlugin.java
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
140 changes: 140 additions & 0 deletions
140
core/src/test/java/io/cucumber/core/plugin/TeamCityPluginTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package io.cucumber.core.plugin; | ||
|
||
import io.cucumber.core.feature.TestFeatureParser; | ||
import io.cucumber.core.gherkin.Feature; | ||
import io.cucumber.core.runner.TestHelper; | ||
import io.cucumber.plugin.event.Result; | ||
import org.junit.jupiter.api.Test; | ||
import org.mockito.stubbing.Answer; | ||
|
||
import java.io.ByteArrayOutputStream; | ||
import java.io.File; | ||
import java.io.PrintStream; | ||
import java.util.AbstractMap.SimpleEntry; | ||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import static io.cucumber.core.runner.TestHelper.createWriteHookAction; | ||
import static io.cucumber.core.runner.TestHelper.result; | ||
import static java.nio.charset.StandardCharsets.UTF_8; | ||
import static org.hamcrest.CoreMatchers.containsString; | ||
import static org.hamcrest.MatcherAssert.assertThat; | ||
|
||
class TeamCityPluginTest { | ||
|
||
private final List<Feature> features = new ArrayList<>(); | ||
private final Map<String, Result> stepsToResult = new HashMap<>(); | ||
private final Map<String, String> stepsToLocation = new HashMap<>(); | ||
private final List<SimpleEntry<String, Result>> hooks = new ArrayList<>(); | ||
private final List<String> hookLocations = new ArrayList<>(); | ||
private final List<Answer<Object>> hookActions = new ArrayList<>(); | ||
private final String location = new File("").toURI().toString(); | ||
|
||
@Test | ||
void should_handle_scenario_outline() { | ||
Feature feature = TestFeatureParser.parse("path/test.feature", "" + | ||
"Feature: feature name\n" + | ||
" Scenario Outline: <name>\n" + | ||
" Given first step\n" + | ||
" Then <arg> step\n" + | ||
" Examples: examples name\n" + | ||
" | name | arg |\n" + | ||
" | name 1 | second |\n" + | ||
" | name 2 | third |\n"); | ||
features.add(feature); | ||
stepsToLocation.put("first step", "path/step_definitions.java:3"); | ||
stepsToLocation.put("second step", "path/step_definitions.java:7"); | ||
stepsToLocation.put("third step", "path/step_definitions.java:11"); | ||
|
||
String formatterOutput = runFeaturesWithFormatter(); | ||
|
||
assertThat(formatterOutput, containsString("" + | ||
"##teamcity[enteredTheMatrix timestamp = '1970-01-01T12:00:00.000+0000']\n" + | ||
"##teamcity[testSuiteStarted timestamp = '1970-01-01T12:00:00.000+0000' name = 'Cucumber']\n" + | ||
"##teamcity[customProgressStatus testsCategory = 'Scenarios' count = '0' timestamp = '1970-01-01T12:00:00.000+0000']\n" + | ||
"##teamcity[testSuiteStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = '" + location + "path/test.feature:1' name = 'feature name']\n" + | ||
"##teamcity[testSuiteStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = '" + location + "path/test.feature:2' name = '<name>']\n" + | ||
"##teamcity[testSuiteStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = '" + location + "path/test.feature:5' name = 'examples name']\n" + | ||
"##teamcity[testSuiteStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = '" + location + "path/test.feature:7' name = 'Example #1']\n" + | ||
"##teamcity[customProgressStatus type = 'testStarted' timestamp = '1970-01-01T12:00:00.000+0000']\n" + | ||
"##teamcity[testStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = '" + location + "path/test.feature:3' captureStandardOutput = 'true' name = 'first step']\n" + | ||
"##teamcity[testFinished timestamp = '1970-01-01T12:00:00.000+0000' duration = '0' name = 'first step']\n" + | ||
"##teamcity[testStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = '" + location + "path/test.feature:4' captureStandardOutput = 'true' name = 'second step']\n" + | ||
"##teamcity[testFinished timestamp = '1970-01-01T12:00:00.000+0000' duration = '0' name = 'second step']\n" + | ||
"##teamcity[customProgressStatus type = 'testFinished' timestamp = '1970-01-01T12:00:00.000+0000']\n" + | ||
"##teamcity[testSuiteFinished timestamp = '1970-01-01T12:00:00.000+0000' name = 'Example #1']\n" + | ||
"##teamcity[testSuiteStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = '" + location + "path/test.feature:8' name = 'Example #2']\n" + | ||
"##teamcity[customProgressStatus type = 'testStarted' timestamp = '1970-01-01T12:00:00.000+0000']\n" + | ||
"##teamcity[testStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = '" + location + "path/test.feature:3' captureStandardOutput = 'true' name = 'first step']\n" + | ||
"##teamcity[testFinished timestamp = '1970-01-01T12:00:00.000+0000' duration = '0' name = 'first step']\n" + | ||
"##teamcity[testStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = '" + location + "path/test.feature:4' captureStandardOutput = 'true' name = 'third step']\n" + | ||
"##teamcity[testFinished timestamp = '1970-01-01T12:00:00.000+0000' duration = '0' name = 'third step']\n" + | ||
"##teamcity[customProgressStatus type = 'testFinished' timestamp = '1970-01-01T12:00:00.000+0000']\n" + | ||
"##teamcity[testSuiteFinished timestamp = '1970-01-01T12:00:00.000+0000' name = 'Example #2']\n" + | ||
"##teamcity[customProgressStatus testsCategory = '' count = '0' timestamp = '1970-01-01T12:00:00.000+0000']\n" + | ||
"##teamcity[testSuiteFinished timestamp = '1970-01-01T12:00:00.000+0000' name = 'examples name']\n" + | ||
"##teamcity[testSuiteFinished timestamp = '1970-01-01T12:00:00.000+0000' name = '<name>']\n" + | ||
"##teamcity[testSuiteFinished timestamp = '1970-01-01T12:00:00.000+0000' name = 'feature name']\n" + | ||
"##teamcity[testSuiteFinished timestamp = '1970-01-01T12:00:00.000+0000' name = 'Cucumber']\n" | ||
)); | ||
} | ||
|
||
@Test | ||
void should_print_error_message_for_failed_steps() { | ||
Feature feature = TestFeatureParser.parse("path/test.feature", "" + | ||
"Feature: feature name\n" + | ||
" Scenario: scenario name\n" + | ||
" Given first step\n"); | ||
features.add(feature); | ||
stepsToLocation.put("first step", "path/step_definitions.java:3"); | ||
stepsToResult.put("first step", result("failed")); | ||
|
||
String formatterOutput = runFeaturesWithFormatter(); | ||
|
||
assertThat(formatterOutput, containsString("" + | ||
"##teamcity[testFailed timestamp = '1970-01-01T12:00:00.000+0000' duration = '0' message = 'Step failed' details = 'the stack trace' name = 'first step']\n" | ||
)); | ||
} | ||
|
||
@Test | ||
void should_print_error_message_for_before_hooks() { | ||
Feature feature = TestFeatureParser.parse("path/test.feature", "" + | ||
"Feature: feature name\n" + | ||
" Scenario: scenario name\n" + | ||
" Given first step\n"); | ||
features.add(feature); | ||
stepsToLocation.put("first step", "path/step_definitions.java:3"); | ||
stepsToResult.put("first step", result("passed")); | ||
hooks.add(TestHelper.hookEntry("before", result("failed"))); | ||
hookLocations.add("HookDefinition.java:3"); | ||
|
||
String formatterOutput = runFeaturesWithFormatter(); | ||
|
||
assertThat(formatterOutput, containsString("" + | ||
"##teamcity[testStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = 'java:test://HookDefinition.java:3' captureStandardOutput = 'true' name = 'Before']\n" + | ||
"##teamcity[testFailed timestamp = '1970-01-01T12:00:00.000+0000' duration = '0' message = 'Step failed' details = 'the stack trace' name = 'Before']\n" | ||
)); | ||
} | ||
|
||
private String runFeaturesWithFormatter() { | ||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); | ||
PrintStream printStream = new PrintStream(byteArrayOutputStream); | ||
final TeamCityPlugin formatter = new TeamCityPlugin(printStream); | ||
|
||
TestHelper.builder() | ||
.withFormatterUnderTest(formatter) | ||
.withFeatures(features) | ||
.withStepsToResult(stepsToResult) | ||
.withStepsToLocation(stepsToLocation) | ||
.withHooks(hooks) | ||
.withHookLocations(hookLocations) | ||
.withHookActions(hookActions) | ||
.build() | ||
.run(); | ||
|
||
return new String(byteArrayOutputStream.toByteArray(), UTF_8); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.