Skip to content

Commit ad227f2

Browse files
authored
fix invocation of listeners after method (fixes allure-framework#177, via allure-framework#269)
1 parent 5cb4290 commit ad227f2

3 files changed

Lines changed: 201 additions & 37 deletions

File tree

allure-java-commons/src/main/java/io/qameta/allure/AllureLifecycle.java

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,17 @@ public AllureLifecycle() {
6161
* @param writer the results writer.
6262
*/
6363
public AllureLifecycle(final AllureResultsWriter writer) {
64-
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
65-
this.notifier = new LifecycleNotifier(
66-
load(ContainerLifecycleListener.class, classLoader),
67-
load(TestLifecycleListener.class, classLoader),
68-
load(FixtureLifecycleListener.class, classLoader),
69-
load(StepLifecycleListener.class, classLoader)
70-
);
64+
this(writer, getDefaultNotifier());
65+
}
66+
67+
/**
68+
* Creates a new lifecycle instance with specified {@link AllureResultsWriter}
69+
* and {@link LifecycleNotifier}.
70+
*
71+
* @param writer the results writer.
72+
*/
73+
AllureLifecycle(final AllureResultsWriter writer, final LifecycleNotifier lifecycleNotifier) {
74+
this.notifier = lifecycleNotifier;
7175
this.writer = writer;
7276
this.storage = new AllureStorage();
7377
this.threadContext = new AllureThreadContext();
@@ -141,14 +145,16 @@ public void stopTestContainer(final String uuid) {
141145
* @param uuid the uuid of container.
142146
*/
143147
public void writeTestContainer(final String uuid) {
144-
final Optional<TestResultContainer> found = storage.removeContainer(uuid);
148+
final Optional<TestResultContainer> found = storage.getContainer(uuid);
145149
if (!found.isPresent()) {
146150
LOGGER.error("Could not write test container: container with uuid {} not found", uuid);
147151
return;
148152
}
149153
final TestResultContainer container = found.get();
150154
notifier.beforeContainerWrite(container);
151155
writer.write(container);
156+
157+
storage.remove(uuid);
152158
notifier.afterContainerWrite(container);
153159
}
154160

@@ -243,7 +249,7 @@ public void updateFixture(final String uuid, final Consumer<FixtureResult> updat
243249
* @param uuid the uuid of fixture.
244250
*/
245251
public void stopFixture(final String uuid) {
246-
final Optional<FixtureResult> found = storage.removeFixture(uuid);
252+
final Optional<FixtureResult> found = storage.getFixture(uuid);
247253
if (!found.isPresent()) {
248254
LOGGER.error("Could not stop test fixture: test fixture with uuid {} not found", uuid);
249255
return;
@@ -253,7 +259,10 @@ public void stopFixture(final String uuid) {
253259
notifier.beforeFixtureStop(fixture);
254260
fixture.setStage(Stage.FINISHED);
255261
fixture.setStop(System.currentTimeMillis());
262+
263+
storage.remove(uuid);
256264
threadContext.clear();
265+
257266
notifier.afterFixtureStop(fixture);
258267
}
259268

@@ -298,7 +307,7 @@ public void scheduleTestCase(final String containerUuid, final TestResult result
298307
public void scheduleTestCase(final TestResult result) {
299308
notifier.beforeTestSchedule(result);
300309
result.setStage(Stage.SCHEDULED);
301-
storage.addTestResult(result);
310+
storage.put(result.getUuid(), result);
302311
notifier.afterTestSchedule(result);
303312
}
304313

@@ -389,7 +398,7 @@ public void stopTestCase(final String uuid) {
389398
* @param uuid the uuid of test case to write.
390399
*/
391400
public void writeTestCase(final String uuid) {
392-
final Optional<TestResult> found = storage.removeTestResult(uuid);
401+
final Optional<TestResult> found = storage.getTestResult(uuid);
393402
if (!found.isPresent()) {
394403
LOGGER.error("Could not write test case: test case with uuid {} not found", uuid);
395404
return;
@@ -398,6 +407,7 @@ public void writeTestCase(final String uuid) {
398407
final TestResult testResult = found.get();
399408
notifier.beforeTestWrite(testResult);
400409
writer.write(testResult);
410+
storage.remove(uuid);
401411
notifier.afterTestWrite(testResult);
402412
}
403413

@@ -499,18 +509,21 @@ public void stopStep() {
499509
* @param uuid the uuid of step to stop.
500510
*/
501511
public void stopStep(final String uuid) {
502-
final Optional<StepResult> found = storage.removeStep(uuid);
512+
final Optional<StepResult> found = storage.getStep(uuid);
503513
if (!found.isPresent()) {
504514
LOGGER.error("Could not stop step: step with uuid {} not found", uuid);
505515
return;
506516
}
507517

508518
final StepResult step = found.get();
509-
510519
notifier.beforeStepStop(step);
520+
511521
step.setStage(Stage.FINISHED);
512522
step.setStop(System.currentTimeMillis());
523+
524+
storage.remove(uuid);
513525
threadContext.stop();
526+
514527
notifier.afterStepStop(step);
515528
}
516529

@@ -597,4 +610,14 @@ private static FileSystemResultsWriter getDefaultWriter() {
597610
final String path = properties.getProperty("allure.results.directory", "allure-results");
598611
return new FileSystemResultsWriter(Paths.get(path));
599612
}
613+
614+
private static LifecycleNotifier getDefaultNotifier() {
615+
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
616+
return new LifecycleNotifier(
617+
load(ContainerLifecycleListener.class, classLoader),
618+
load(TestLifecycleListener.class, classLoader),
619+
load(FixtureLifecycleListener.class, classLoader),
620+
load(StepLifecycleListener.class, classLoader)
621+
);
622+
}
600623
}

allure-java-commons/src/main/java/io/qameta/allure/internal/AllureStorage.java

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,38 +27,18 @@ public Optional<TestResultContainer> getContainer(final String uuid) {
2727
return get(uuid, TestResultContainer.class);
2828
}
2929

30-
public Optional<TestResultContainer> removeContainer(final String uuid) {
31-
return remove(uuid, TestResultContainer.class);
32-
}
33-
34-
public void addTestResult(final TestResult testResult) {
35-
put(testResult.getUuid(), testResult);
36-
}
37-
3830
public Optional<TestResult> getTestResult(final String uuid) {
3931
return get(uuid, TestResult.class);
4032
}
4133

42-
public Optional<TestResult> removeTestResult(final String uuid) {
43-
return remove(uuid, TestResult.class);
44-
}
45-
4634
public Optional<FixtureResult> getFixture(final String uuid) {
4735
return get(uuid, FixtureResult.class);
4836
}
4937

50-
public Optional<FixtureResult> removeFixture(final String uuid) {
51-
return remove(uuid, FixtureResult.class);
52-
}
53-
5438
public Optional<StepResult> getStep(final String uuid) {
5539
return get(uuid, StepResult.class);
5640
}
5741

58-
public Optional<StepResult> removeStep(final String uuid) {
59-
return remove(uuid, StepResult.class);
60-
}
61-
6242
public <T> Optional<T> get(final String uuid, final Class<T> clazz) {
6343
lock.readLock().lock();
6444
try {
@@ -82,13 +62,11 @@ public <T> T put(final String uuid, final T item) {
8262
}
8363
}
8464

85-
public <T> Optional<T> remove(final String uuid, final Class<T> clazz) {
65+
public void remove(final String uuid) {
8666
lock.writeLock().lock();
8767
try {
8868
Objects.requireNonNull(uuid, "Can't remove item from storage: uuid can't be null");
89-
return Optional.ofNullable(storage.remove(uuid))
90-
.filter(clazz::isInstance)
91-
.map(clazz::cast);
69+
storage.remove(uuid);
9270
} finally {
9371
lock.writeLock().unlock();
9472
}
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package io.qameta.allure;
2+
3+
import io.qameta.allure.aspects.StepsAspects;
4+
import io.qameta.allure.listener.LifecycleNotifier;
5+
import io.qameta.allure.listener.StepLifecycleListener;
6+
import io.qameta.allure.model.Attachment;
7+
import io.qameta.allure.model.ExecutableItem;
8+
import io.qameta.allure.model.Status;
9+
import io.qameta.allure.model.StepResult;
10+
import io.qameta.allure.model.TestResult;
11+
import io.qameta.allure.test.AllureResults;
12+
import io.qameta.allure.test.AllureResultsWriterStub;
13+
import org.junit.jupiter.api.Test;
14+
15+
import java.util.UUID;
16+
import java.util.concurrent.atomic.AtomicInteger;
17+
import java.util.stream.Stream;
18+
19+
import static io.qameta.allure.util.ResultsUtils.getStatus;
20+
import static io.qameta.allure.util.ResultsUtils.getStatusDetails;
21+
import static java.util.Collections.emptyList;
22+
import static java.util.Collections.singletonList;
23+
import static org.assertj.core.api.Assertions.assertThat;
24+
25+
/**
26+
* @author charlie (Dmitry Baev).
27+
*/
28+
class StepLifecycleListenerTest {
29+
30+
@Test
31+
void shouldExecuteBeforeStepStart() {
32+
final AtomicInteger executionCount = new AtomicInteger();
33+
final StepLifecycleListener listener = new StepLifecycleListener() {
34+
@Override
35+
public void beforeStepStart(final StepResult result) {
36+
executionCount.incrementAndGet();
37+
}
38+
};
39+
final AllureResults run = run(listener, "first", "second");
40+
41+
assertThat(run.getTestResults())
42+
.flatExtracting(TestResult::getSteps)
43+
.extracting(StepResult::getName)
44+
.containsExactly("first", "second");
45+
46+
assertThat(executionCount.get())
47+
.isEqualTo(2);
48+
}
49+
50+
@Test
51+
void shouldExecuteAfterStepStart() {
52+
final AtomicInteger executionCount = new AtomicInteger();
53+
final StepLifecycleListener listener = new StepLifecycleListener() {
54+
@Override
55+
public void afterStepStart(final StepResult result) {
56+
executionCount.incrementAndGet();
57+
Allure.addAttachment("inner " + result.getName(), "some");
58+
}
59+
};
60+
final AllureResults run = run(listener, "first", "second");
61+
62+
assertThat(run.getTestResults())
63+
.flatExtracting(TestResult::getSteps)
64+
.extracting(StepResult::getName)
65+
.containsExactly("first", "second");
66+
67+
assertThat(run.getTestResults())
68+
.flatExtracting(TestResult::getSteps)
69+
.filteredOn("name", "first")
70+
.flatExtracting(StepResult::getAttachments)
71+
.extracting(Attachment::getName)
72+
.containsExactly("inner first");
73+
74+
assertThat(run.getTestResults())
75+
.flatExtracting(TestResult::getSteps)
76+
.filteredOn("name", "second")
77+
.flatExtracting(StepResult::getAttachments)
78+
.extracting(Attachment::getName)
79+
.containsExactly("inner second");
80+
81+
assertThat(executionCount.get())
82+
.isEqualTo(2);
83+
}
84+
85+
@Issue("177")
86+
@Test
87+
void shouldExecuteBeforeStepStop() {
88+
final AtomicInteger executionCount = new AtomicInteger();
89+
final StepLifecycleListener listener = new StepLifecycleListener() {
90+
@Override
91+
public void beforeStepStop(final StepResult result) {
92+
executionCount.incrementAndGet();
93+
Allure.addAttachment("inner " + result.getName(), "some");
94+
}
95+
};
96+
final AllureResults run = run(listener, "first", "second");
97+
98+
assertThat(run.getTestResults())
99+
.flatExtracting(TestResult::getSteps)
100+
.extracting(StepResult::getName)
101+
.containsExactly("first", "second");
102+
103+
assertThat(run.getTestResults())
104+
.flatExtracting(TestResult::getSteps)
105+
.filteredOn("name", "first")
106+
.flatExtracting(StepResult::getAttachments)
107+
.extracting(Attachment::getName)
108+
.containsExactly("inner first");
109+
110+
assertThat(run.getTestResults())
111+
.flatExtracting(TestResult::getSteps)
112+
.filteredOn("name", "second")
113+
.flatExtracting(StepResult::getAttachments)
114+
.extracting(Attachment::getName)
115+
.containsExactly("inner second");
116+
117+
assertThat(executionCount.get())
118+
.isEqualTo(2);
119+
}
120+
121+
protected AllureResults run(final StepLifecycleListener listener, final String... steps) {
122+
final AllureResultsWriterStub writer = new AllureResultsWriterStub();
123+
final LifecycleNotifier notifier = new LifecycleNotifier(
124+
emptyList(),
125+
emptyList(),
126+
emptyList(),
127+
singletonList(listener)
128+
);
129+
final AllureLifecycle lifecycle = new AllureLifecycle(writer, notifier);
130+
131+
final String uuid = UUID.randomUUID().toString();
132+
final TestResult result = new TestResult().setUuid(uuid);
133+
134+
final AllureLifecycle cached = Allure.getLifecycle();
135+
try {
136+
Allure.setLifecycle(lifecycle);
137+
StepsAspects.setLifecycle(lifecycle);
138+
139+
lifecycle.scheduleTestCase(result);
140+
lifecycle.startTestCase(uuid);
141+
142+
Stream.of(steps).forEach(step -> {
143+
final String stepUuid = UUID.randomUUID().toString();
144+
lifecycle.startStep(stepUuid, new StepResult().setName(step).setStatus(Status.PASSED));
145+
lifecycle.stopStep(stepUuid);
146+
});
147+
} catch (Throwable e) {
148+
lifecycle.updateTestCase(uuid, testResult -> {
149+
getStatus(e).ifPresent(testResult::setStatus);
150+
getStatusDetails(e).ifPresent(testResult::setStatusDetails);
151+
152+
});
153+
} finally {
154+
lifecycle.stopTestCase(uuid);
155+
lifecycle.writeTestCase(uuid);
156+
157+
Allure.setLifecycle(cached);
158+
StepsAspects.setLifecycle(cached);
159+
}
160+
161+
return writer;
162+
}
163+
}

0 commit comments

Comments
 (0)