Skip to content

Commit f1023ce

Browse files
committed
init
1 parent d4b8c68 commit f1023ce

8 files changed

Lines changed: 455 additions & 0 deletions

File tree

allure-karate/build.gradle.kts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
description = "Allure Karate Integration"
2+
3+
val agent: Configuration by configurations.creating
4+
5+
val karateVersion = "1.0.0"
6+
7+
configurations {
8+
testImplementation {
9+
exclude(group="ch.qos.logback", module = "logback-classic")
10+
}
11+
}
12+
13+
dependencies {
14+
agent("org.aspectj:aspectjweaver")
15+
api(project(":allure-java-commons"))
16+
implementation("com.intuit.karate:karate-core:${karateVersion}")
17+
implementation(project(":allure-test-filter"))
18+
testAnnotationProcessor("org.slf4j:slf4j-simple")
19+
testAnnotationProcessor(project(":allure-descriptions-javadoc"))
20+
testImplementation("io.github.glytching:junit-extensions")
21+
testImplementation("org.assertj:assertj-core")
22+
testImplementation("org.junit.jupiter:junit-jupiter-api")
23+
testImplementation("org.junit.jupiter:junit-jupiter-params")
24+
testImplementation("org.slf4j:slf4j-simple")
25+
testImplementation(project(":allure-java-commons-test"))
26+
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
27+
}
28+
29+
tasks.jar {
30+
manifest {
31+
attributes(mapOf(
32+
"Automatic-Module-Name" to "io.qameta.allure.karate"
33+
))
34+
}
35+
from("src/main/services") {
36+
into("META-INF/services")
37+
}
38+
}
39+
40+
tasks.test {
41+
systemProperty("junit.jupiter.execution.parallel.enabled", "false")
42+
useJUnitPlatform()
43+
exclude("**/features/*")
44+
doFirst {
45+
jvmArgs("-javaagent:${agent.singleFile}")
46+
}
47+
}
48+
49+
val spiOffJar by tasks.creating(Jar::class) {
50+
from(sourceSets.getByName("main").output)
51+
classifier = "spi-off"
52+
}
53+
54+
val spiOff by configurations.creating {
55+
extendsFrom(configurations.getByName("compile"))
56+
}
57+
58+
artifacts.add("archives", spiOffJar)
59+
artifacts.add("spiOff", spiOffJar)
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/*
2+
* Copyright 2021 Qameta Software OÜ
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.qameta.allure.karate;
17+
18+
import com.intuit.karate.RuntimeHook;
19+
import com.intuit.karate.core.Feature;
20+
import com.intuit.karate.core.Result;
21+
import com.intuit.karate.core.Scenario;
22+
import com.intuit.karate.core.ScenarioResult;
23+
import com.intuit.karate.core.ScenarioRuntime;
24+
import com.intuit.karate.core.Step;
25+
import com.intuit.karate.core.StepResult;
26+
import io.qameta.allure.Allure;
27+
import io.qameta.allure.AllureLifecycle;
28+
import io.qameta.allure.model.Stage;
29+
import io.qameta.allure.model.Status;
30+
import io.qameta.allure.model.StatusDetails;
31+
import io.qameta.allure.model.TestResult;
32+
import io.qameta.allure.util.ResultsUtils;
33+
import org.slf4j.Logger;
34+
import org.slf4j.LoggerFactory;
35+
36+
import java.io.BufferedInputStream;
37+
import java.io.FileInputStream;
38+
import java.io.IOException;
39+
import java.io.InputStream;
40+
import java.util.List;
41+
import java.util.Objects;
42+
import java.util.Optional;
43+
import java.util.UUID;
44+
45+
/**
46+
* @author charlie (Dmitry Baev).
47+
*/
48+
public class AllureKarate implements RuntimeHook {
49+
50+
private static final Logger LOGGER = LoggerFactory.getLogger(AllureKarate.class);
51+
52+
private static final String ALLURE_UUID = "ALLURE_UUID";
53+
54+
private AllureLifecycle lifecycle;
55+
56+
public AllureKarate() {
57+
this(Allure.getLifecycle());
58+
}
59+
60+
public AllureKarate(final AllureLifecycle lifecycle) {
61+
this.lifecycle = lifecycle;
62+
}
63+
64+
@Override
65+
public boolean beforeScenario(final ScenarioRuntime sr) {
66+
final Feature feature = sr.featureRuntime.feature;
67+
final String featureName = feature.getName();
68+
final String featureNameQualified = feature.getPackageQualifiedName();
69+
final Scenario scenario = sr.scenario;
70+
final String scenarioName = scenario.getName();
71+
LOGGER.info("tags: {}", sr.tags.getTagValues());
72+
73+
final String uuid = UUID.randomUUID().toString();
74+
sr.magicVariables.put(ALLURE_UUID, uuid);
75+
76+
final TestResult result = new TestResult()
77+
.setUuid(uuid)
78+
.setFullName(String.format("%s | %s", featureNameQualified, scenarioName))
79+
.setName(scenarioName)
80+
.setDescription(scenario.getDescription())
81+
.setTestCaseId(scenario.getUniqueId())
82+
.setStage(Stage.RUNNING)
83+
.setLabels(List.of(
84+
ResultsUtils.createFeatureLabel(featureName)
85+
));
86+
87+
lifecycle.scheduleTestCase(result);
88+
lifecycle.startTestCase(uuid);
89+
return true;
90+
}
91+
92+
@Override
93+
public void afterScenario(final ScenarioRuntime sr) {
94+
final String uuid = (String) sr.magicVariables.get(ALLURE_UUID);
95+
if (Objects.isNull(uuid)) {
96+
return;
97+
}
98+
final Optional<ScenarioResult> maybeResult = Optional.of(sr)
99+
.map(s -> s.result);
100+
101+
final Status status = !sr.isFailed()
102+
? Status.PASSED
103+
: maybeResult
104+
.map(ScenarioResult::getError)
105+
.flatMap(ResultsUtils::getStatus)
106+
.orElse(null);
107+
108+
final StatusDetails statusDetails = maybeResult
109+
.map(ScenarioResult::getError)
110+
.flatMap(ResultsUtils::getStatusDetails)
111+
.orElse(null);
112+
113+
lifecycle.updateTestCase(uuid, tr -> {
114+
tr.setStage(Stage.FINISHED);
115+
tr.setStatus(status);
116+
tr.setStatusDetails(statusDetails);
117+
});
118+
119+
lifecycle.stopTestCase(uuid);
120+
lifecycle.writeTestCase(uuid);
121+
}
122+
123+
@Override
124+
public boolean beforeStep(final Step step,
125+
final ScenarioRuntime sr) {
126+
final String parentUuid = (String) sr.magicVariables.get(ALLURE_UUID);
127+
if (Objects.isNull(parentUuid)) {
128+
return true;
129+
}
130+
131+
final String uuid = parentUuid + "-" + step.getIndex();
132+
final io.qameta.allure.model.StepResult stepResult = new io.qameta.allure.model.StepResult()
133+
.setName(step.getText());
134+
135+
lifecycle.startStep(parentUuid, uuid, stepResult);
136+
137+
return true;
138+
}
139+
140+
@Override
141+
public void afterStep(final StepResult result,
142+
final ScenarioRuntime sr) {
143+
final String parentUuid = (String) sr.magicVariables.get(ALLURE_UUID);
144+
if (Objects.isNull(parentUuid)) {
145+
return;
146+
}
147+
148+
final Step step = result.getStep();
149+
final String uuid = parentUuid + "-" + step.getIndex();
150+
151+
152+
final Result stepResult = result.getResult();
153+
154+
final Status status = !stepResult.isFailed()
155+
? Status.PASSED
156+
: Optional.of(stepResult)
157+
.map(Result::getError)
158+
.flatMap(ResultsUtils::getStatus)
159+
.orElse(null);
160+
161+
final StatusDetails statusDetails = Optional.of(stepResult)
162+
.map(Result::getError)
163+
.flatMap(ResultsUtils::getStatusDetails)
164+
.orElse(null);
165+
166+
result.getEmbeds().forEach(embed -> {
167+
try (InputStream is = new BufferedInputStream(new FileInputStream(embed.getFile()))) {
168+
lifecycle.addAttachment(
169+
embed.getFile().getName(),
170+
embed.getResourceType().contentType,
171+
embed.getResourceType().getExtension(),
172+
is
173+
);
174+
} catch (IOException e) {
175+
LOGGER.warn("could not save embedding", e);
176+
}
177+
});
178+
179+
lifecycle.updateStep(uuid, s -> {
180+
s.setStatus(status);
181+
s.setStatusDetails(statusDetails);
182+
});
183+
lifecycle.stopStep(uuid);
184+
185+
}
186+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright 2021 Qameta Software OÜ
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.qameta.allure.karate;
17+
18+
import com.intuit.karate.Runner;
19+
import io.qameta.allure.Allure;
20+
import io.qameta.allure.AllureLifecycle;
21+
import io.qameta.allure.aspects.AttachmentsAspects;
22+
import io.qameta.allure.aspects.StepsAspects;
23+
import io.qameta.allure.model.Status;
24+
import io.qameta.allure.model.StepResult;
25+
import io.qameta.allure.model.TestResult;
26+
import io.qameta.allure.test.AllureResults;
27+
import io.qameta.allure.test.AllureResultsWriterStub;
28+
import org.junit.jupiter.api.Test;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.assertj.core.api.Assertions.tuple;
32+
33+
/**
34+
* @author charlie (Dmitry Baev).
35+
*/
36+
class AllureKarateTest {
37+
38+
@Test
39+
void shouldCreateAllureResults() {
40+
final AllureResults results = run("classpath:testdata/first.feature");
41+
42+
assertThat(results.getTestResults())
43+
.extracting(TestResult::getName, TestResult::getStatus)
44+
.containsExactlyInAnyOrder(
45+
tuple("f1 - s1", Status.PASSED),
46+
tuple("f1 - s2", Status.PASSED)
47+
);
48+
49+
}
50+
51+
@SuppressWarnings("unchecked")
52+
@Test
53+
void shouldCreateSteps() {
54+
final AllureResults results = run("classpath:testdata/first.feature");
55+
56+
assertThat(results.getTestResults())
57+
.filteredOn("name", "f1 - s1")
58+
.flatExtracting(TestResult::getSteps)
59+
.extracting(StepResult::getName, StepResult::getStatus)
60+
.containsExactlyInAnyOrder(
61+
tuple("print 'first feature:@smoke, first scenario'", Status.PASSED)
62+
);
63+
64+
}
65+
66+
@SuppressWarnings("unchecked")
67+
@Test
68+
void shouldCreateAttachments() {
69+
final AllureResults results = run("classpath:testdata/first.feature");
70+
71+
assertThat(results.getTestResults())
72+
.filteredOn("name", "f1 - s1")
73+
.flatExtracting(TestResult::getSteps)
74+
.extracting(StepResult::getName, StepResult::getStatus)
75+
.containsExactlyInAnyOrder(
76+
tuple("print 'first feature:@smoke, first scenario'", Status.PASSED)
77+
);
78+
79+
}
80+
81+
@Test
82+
void testTest() {
83+
Runner.builder()
84+
.path("classpath:testdata/demo-01.feature")
85+
.hook(new AllureKarate())
86+
.backupReportDir(false)
87+
.outputJunitXml(false)
88+
.outputCucumberJson(false)
89+
.outputHtmlReport(false)
90+
.parallel(1);
91+
}
92+
93+
AllureResults run(final String... path) {
94+
final AllureResultsWriterStub writerStub = new AllureResultsWriterStub();
95+
final AllureLifecycle lifecycle = new AllureLifecycle(writerStub);
96+
final AllureKarate allureKarate = new AllureKarate(lifecycle);
97+
98+
final AllureLifecycle defaultLifecycle = Allure.getLifecycle();
99+
try {
100+
Allure.setLifecycle(lifecycle);
101+
StepsAspects.setLifecycle(lifecycle);
102+
AttachmentsAspects.setLifecycle(lifecycle);
103+
104+
Runner.builder()
105+
.path(path)
106+
.hook(allureKarate)
107+
.backupReportDir(false)
108+
.outputJunitXml(false)
109+
.outputCucumberJson(false)
110+
.outputHtmlReport(false)
111+
.parallel(1);
112+
113+
return writerStub;
114+
} finally {
115+
Allure.setLifecycle(defaultLifecycle);
116+
StepsAspects.setLifecycle(defaultLifecycle);
117+
AttachmentsAspects.setLifecycle(defaultLifecycle);
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)