Skip to content

Commit a7d88f2

Browse files
clicmanbaev
authored andcommitted
add cucumber jvm integration (via #35)
1 parent 7217661 commit a7d88f2

20 files changed

Lines changed: 984 additions & 3 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
.gradle
22
schema
33
build
4+
/*/allure-results/
45

56
#IDEA Files
67
.idea
@@ -15,3 +16,6 @@ build
1516

1617
#Mac OS stuff
1718
.DS_Store
19+
20+
#Netbeans files
21+
/.nb-gradle/

allure-cucumber-jvm/build.gradle

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
description = 'Allure CucumberJVM'
2+
3+
configurations {
4+
agent
5+
}
6+
7+
dependencies {
8+
agent 'org.aspectj:aspectjweaver'
9+
10+
compile project(':allure-java-commons')
11+
compile 'info.cukes:gherkin:2.12.2'
12+
compile 'info.cukes:cucumber-core:1.2.5'
13+
compile 'info.cukes:cucumber-java:1.2.5'
14+
compile 'info.cukes:cucumber-junit:1.2.5'
15+
16+
testCompile 'junit:junit:4.12'
17+
18+
19+
}
20+
21+
test.doFirst {
22+
jvmArgs "-javaagent:${configurations.agent.singleFile}"
23+
}
24+
25+
test {
26+
systemProperty 'allure.model.indentOutput', true
27+
systemProperty 'allure.results.directory', 'build/allure-results'
28+
}
29+
30+
31+
task spiOffJar(type: Jar, dependsOn: classes) {
32+
classifier = 'spi-off'
33+
from sourceSets.main.allJava
34+
}
35+
36+
artifacts {
37+
archives spiOffJar
38+
}
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
package io.qameta.allure.cucumberjvm;
2+
3+
import cucumber.runtime.StepDefinitionMatch;
4+
import gherkin.I18n;
5+
import gherkin.formatter.Formatter;
6+
import gherkin.formatter.Reporter;
7+
import gherkin.formatter.model.Background;
8+
import gherkin.formatter.model.Examples;
9+
import gherkin.formatter.model.Feature;
10+
import gherkin.formatter.model.Match;
11+
import gherkin.formatter.model.Result;
12+
import gherkin.formatter.model.Scenario;
13+
import gherkin.formatter.model.ScenarioOutline;
14+
import gherkin.formatter.model.Step;
15+
import gherkin.formatter.model.Tag;
16+
import io.qameta.allure.Allure;
17+
import io.qameta.allure.AllureLifecycle;
18+
import io.qameta.allure.ResultsUtils;
19+
import io.qameta.allure.model.Status;
20+
import io.qameta.allure.model.StatusDetails;
21+
import io.qameta.allure.model.StepResult;
22+
import io.qameta.allure.model.TestResult;
23+
24+
import java.util.ArrayList;
25+
import java.util.Collections;
26+
import java.util.Deque;
27+
import java.util.LinkedList;
28+
import java.util.List;
29+
30+
31+
/**
32+
* Allure plugin for Cucumber-JVM.
33+
*/
34+
public class AllureCucumberJvm implements Reporter, Formatter {
35+
36+
private static final List<String> SCENARIO_OUTLINE_KEYWORDS = Collections.synchronizedList(new ArrayList<String>());
37+
38+
private static final String FAILED = "failed";
39+
private static final String PASSED = "passed";
40+
private static final String SKIPPED = "skipped";
41+
42+
43+
private final Deque<Step> gherkinSteps = new LinkedList<>();
44+
private final AllureLifecycle lifecycle;
45+
private Feature currentFeature;
46+
private boolean isNullMatch = true;
47+
private Scenario currentScenario;
48+
49+
50+
public AllureCucumberJvm() {
51+
this.lifecycle = Allure.getLifecycle();
52+
final List<I18n> i18nList = I18n.getAll();
53+
54+
i18nList.forEach(i18n -> SCENARIO_OUTLINE_KEYWORDS.addAll(i18n.keywords("scenario_outline")));
55+
}
56+
57+
@Override
58+
public void feature(final Feature feature) {
59+
this.currentFeature = feature;
60+
}
61+
62+
@Override
63+
public void before(final Match match, final Result result) {
64+
new StepUtils(currentFeature, currentScenario).fireFixtureStep(match, result, true);
65+
}
66+
67+
@Override
68+
public void after(final Match match, final Result result) {
69+
new StepUtils(currentFeature, currentScenario).fireFixtureStep(match, result, false);
70+
}
71+
72+
@Override
73+
public void startOfScenarioLifeCycle(final Scenario scenario) {
74+
this.currentScenario = scenario;
75+
76+
final Deque<Tag> tags = new LinkedList<>();
77+
tags.addAll(scenario.getTags());
78+
79+
if (SCENARIO_OUTLINE_KEYWORDS.contains(scenario.getKeyword())) {
80+
synchronized (gherkinSteps) {
81+
gherkinSteps.clear();
82+
}
83+
} else {
84+
tags.addAll(currentFeature.getTags());
85+
}
86+
87+
final LabelBuilder labelBuilder = new LabelBuilder(currentFeature, scenario, tags);
88+
89+
90+
final TestResult result = new TestResult()
91+
.withUuid(scenario.getId())
92+
.withHistoryId(StepUtils.getHistoryId(scenario.getId()))
93+
.withName(scenario.getName())
94+
.withLabels(labelBuilder.getScenarioLabels())
95+
.withLinks(labelBuilder.getScenarioLinks());
96+
97+
if (!currentFeature.getDescription().isEmpty()) {
98+
result.withDescription(currentFeature.getDescription());
99+
}
100+
101+
lifecycle.scheduleTestCase(result);
102+
lifecycle.startTestCase(scenario.getId());
103+
104+
}
105+
106+
@Override
107+
public void step(final Step step) {
108+
synchronized (gherkinSteps) {
109+
gherkinSteps.add(step);
110+
}
111+
}
112+
113+
@Override
114+
public void match(final Match match) {
115+
final StepUtils stepUtils = new StepUtils(currentFeature, currentScenario);
116+
if (match instanceof StepDefinitionMatch) {
117+
isNullMatch = false;
118+
final Step step = stepUtils.extractStep((StepDefinitionMatch) match);
119+
synchronized (gherkinSteps) {
120+
while (gherkinSteps.peek() != null && !stepUtils.isEqualSteps(step, gherkinSteps.peek())) {
121+
stepUtils.fireCanceledStep(gherkinSteps.remove());
122+
}
123+
if (stepUtils.isEqualSteps(step, gherkinSteps.peek())) {
124+
gherkinSteps.remove();
125+
}
126+
}
127+
final StepResult stepResult = new StepResult();
128+
stepResult.withName(String.format("%s %s", step.getKeyword(), step.getName()))
129+
.withStart(System.currentTimeMillis());
130+
lifecycle.startStep(currentScenario.getId(), stepUtils.getStepUuid(step), stepResult);
131+
}
132+
}
133+
134+
@Override
135+
public void result(final Result result) {
136+
if (!isNullMatch) {
137+
final StatusDetails statusDetails = new StatusDetails();
138+
final TagParser tagParser = new TagParser(currentFeature, currentScenario);
139+
statusDetails
140+
.withFlaky(tagParser.isFlaky())
141+
.withMuted(tagParser.isMuted())
142+
.withKnown(tagParser.isKnown());
143+
144+
switch (result.getStatus()) {
145+
case FAILED:
146+
lifecycle.updateStep(stepResult -> stepResult.withStatus(Status.FAILED));
147+
lifecycle.updateTestCase(currentScenario.getId(), scenarioResult ->
148+
scenarioResult.withStatus(Status.FAILED)
149+
.withStatusDetails(ResultsUtils.getStatusDetails(result.getError()).get()));
150+
lifecycle.stopStep();
151+
break;
152+
case SKIPPED:
153+
lifecycle.updateStep(stepResult -> stepResult.withStatus(Status.SKIPPED));
154+
lifecycle.stopStep();
155+
break;
156+
case PASSED:
157+
lifecycle.updateStep(stepResult -> stepResult.withStatus(Status.PASSED));
158+
lifecycle.stopStep();
159+
lifecycle.updateTestCase(currentScenario.getId(), scenarioResult ->
160+
scenarioResult.withStatus(Status.PASSED)
161+
.withStatusDetails(statusDetails));
162+
break;
163+
default:
164+
break;
165+
}
166+
isNullMatch = true;
167+
}
168+
}
169+
170+
@Override
171+
public void endOfScenarioLifeCycle(final Scenario scenario) {
172+
final StepUtils stepUtils = new StepUtils(currentFeature, currentScenario);
173+
synchronized (gherkinSteps) {
174+
while (gherkinSteps.peek() != null) {
175+
stepUtils.fireCanceledStep(gherkinSteps.remove());
176+
}
177+
}
178+
lifecycle.stopTestCase(scenario.getId());
179+
lifecycle.writeTestCase(scenario.getId());
180+
}
181+
182+
@Override
183+
public void embedding(final String string, final byte[] bytes) {
184+
//Nothing to do with Allure
185+
}
186+
187+
@Override
188+
public void write(final String string) {
189+
//Nothing to do with Allure
190+
}
191+
192+
@Override
193+
public void syntaxError(final String state, final String event,
194+
final List<String> legalEvents, final String uri, final Integer line) {
195+
//Nothing to do with Allure
196+
}
197+
198+
@Override
199+
public void uri(final String uri) {
200+
//Nothing to do with Allure
201+
}
202+
203+
@Override
204+
public void scenarioOutline(final ScenarioOutline so) {
205+
//Nothing to do with Allure
206+
}
207+
208+
@Override
209+
public void examples(final Examples exmpls) {
210+
//Nothing to do with Allure
211+
}
212+
213+
214+
@Override
215+
public void background(final Background b) {
216+
//Nothing to do with Allure
217+
}
218+
219+
@Override
220+
public void scenario(final Scenario scnr) {
221+
//Nothing to do with Allure
222+
}
223+
224+
@Override
225+
public void done() {
226+
//Nothing to do with Allure
227+
}
228+
229+
@Override
230+
public void close() {
231+
//Nothing to do with Allure
232+
}
233+
234+
@Override
235+
public void eof() {
236+
//Nothing to do with Allure
237+
238+
}
239+
240+
}

0 commit comments

Comments
 (0)