Skip to content

Commit 4e59632

Browse files
prevent spock2 uuid reuse (#1251)
1 parent bf6d32a commit 4e59632

File tree

2 files changed

+88
-15
lines changed

2 files changed

+88
-15
lines changed

allure-spock2/src/main/java/io/qameta/allure/spock2/AllureSpock2.java

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,7 @@
8282
*/
8383
public class AllureSpock2 extends AbstractRunListener implements IGlobalExtension {
8484

85-
private final ThreadLocal<String> testResults = new InheritableThreadLocal<String>() {
86-
@Override
87-
protected String initialValue() {
88-
return UUID.randomUUID().toString();
89-
}
90-
};
85+
private final ThreadLocal<String> testResults = new ThreadLocal<>();
9186

9287
private final AllureLifecycle lifecycle;
9388

@@ -142,7 +137,7 @@ public void visitSpec(final SpecInfo spec) {
142137

143138
@Override
144139
public void beforeIteration(final IterationInfo iteration) {
145-
final String uuid = testResults.get();
140+
final String uuid = UUID.randomUUID().toString();
146141

147142
final FeatureInfo feature = iteration.getFeature();
148143
final MethodInfo methodInfo = feature.getFeatureMethod();
@@ -222,6 +217,7 @@ public void beforeIteration(final IterationInfo iteration) {
222217
result::setDescriptionHtml
223218
);
224219

220+
testResults.set(uuid);
225221
getLifecycle().scheduleTestCase(result);
226222
getLifecycle().startTestCase(uuid);
227223

@@ -285,6 +281,9 @@ private boolean match(final TestPlanV1_0.TestCase tc, final String allureId, fin
285281
@Override
286282
public void error(final ErrorInfo error) {
287283
final String uuid = testResults.get();
284+
if (Objects.isNull(uuid)) {
285+
return;
286+
}
288287
getLifecycle().updateTestCase(uuid, testResult -> testResult
289288
.setStatus(getStatus(error.getException()).orElse(null))
290289
.setStatusDetails(getStatusDetails(error.getException()).orElse(null))
@@ -294,15 +293,22 @@ public void error(final ErrorInfo error) {
294293
@Override
295294
public void afterIteration(final IterationInfo iteration) {
296295
final String uuid = testResults.get();
297-
testResults.remove();
296+
if (Objects.isNull(uuid)) {
297+
testResults.remove();
298+
return;
299+
}
298300

299-
getLifecycle().updateTestCase(uuid, testResult -> {
300-
if (Objects.isNull(testResult.getStatus())) {
301-
testResult.setStatus(Status.PASSED);
302-
}
303-
});
304-
getLifecycle().stopTestCase(uuid);
305-
getLifecycle().writeTestCase(uuid);
301+
try {
302+
getLifecycle().updateTestCase(uuid, testResult -> {
303+
if (Objects.isNull(testResult.getStatus())) {
304+
testResult.setStatus(Status.PASSED);
305+
}
306+
});
307+
getLifecycle().stopTestCase(uuid);
308+
getLifecycle().writeTestCase(uuid);
309+
} finally {
310+
testResults.remove();
311+
}
306312
}
307313

308314
private List<Parameter> getParameters(final List<String> names, final Object... values) {

allure-spock2/src/test/groovy/io/qameta/allure/spock2/AllureSpock2Test.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@
6161
import org.spockframework.runtime.GlobalExtensionRegistry;
6262
import org.spockframework.runtime.RunContext;
6363
import org.spockframework.runtime.SpockEngine;
64+
import org.mockito.ArgumentCaptor;
6465

66+
import java.lang.reflect.Method;
6567
import java.time.Instant;
6668
import java.util.Arrays;
6769
import java.util.Collection;
@@ -73,12 +75,77 @@
7375

7476
import static org.assertj.core.api.Assertions.assertThat;
7577
import static org.assertj.core.api.Assertions.tuple;
78+
import static org.mockito.Mockito.mock;
79+
import static org.mockito.Mockito.times;
80+
import static org.mockito.Mockito.verify;
81+
import static org.mockito.Mockito.verifyNoInteractions;
82+
import static org.mockito.Mockito.when;
7683

7784
/**
7885
* @author charlie (Dmitry Baev).
7986
*/
8087
class AllureSpock2Test {
8188

89+
@Test
90+
void shouldCreateNewUuidForEachIteration() throws Exception {
91+
final io.qameta.allure.AllureLifecycle lifecycle = mock(io.qameta.allure.AllureLifecycle.class);
92+
final AllureSpock2 allureSpock2 = new AllureSpock2(lifecycle);
93+
94+
final org.spockframework.runtime.model.SpecInfo specInfo = mock(org.spockframework.runtime.model.SpecInfo.class);
95+
final org.spockframework.runtime.model.FeatureInfo featureInfo = mock(org.spockframework.runtime.model.FeatureInfo.class);
96+
final org.spockframework.runtime.model.MethodInfo methodInfo = mock(org.spockframework.runtime.model.MethodInfo.class);
97+
final org.spockframework.runtime.model.IterationInfo iterationInfo = mock(org.spockframework.runtime.model.IterationInfo.class);
98+
99+
final Method method = DummySpec.class.getMethod("dummy");
100+
when(methodInfo.getReflection()).thenReturn(method);
101+
102+
when(specInfo.getReflection()).thenReturn((Class) DummySpec.class);
103+
when(specInfo.getPackage()).thenReturn(DummySpec.class.getPackage().getName());
104+
when(specInfo.getName()).thenReturn(DummySpec.class.getSimpleName());
105+
when(specInfo.getSubSpec()).thenReturn(null);
106+
when(specInfo.getSuperSpec()).thenReturn(null);
107+
108+
when(featureInfo.getFeatureMethod()).thenReturn(methodInfo);
109+
when(featureInfo.getSpec()).thenReturn(specInfo);
110+
when(featureInfo.getDataVariables()).thenReturn(Collections.emptyList());
111+
when(featureInfo.getTestTags()).thenReturn(Collections.emptySet());
112+
113+
when(iterationInfo.getFeature()).thenReturn(featureInfo);
114+
when(iterationInfo.getDataValues()).thenReturn(new Object[0]);
115+
when(iterationInfo.getDisplayName()).thenReturn("dummy");
116+
when(iterationInfo.getName()).thenReturn("dummy");
117+
118+
final ArgumentCaptor<TestResult> scheduled = ArgumentCaptor.forClass(TestResult.class);
119+
120+
allureSpock2.beforeIteration(iterationInfo);
121+
allureSpock2.beforeIteration(iterationInfo);
122+
123+
verify(lifecycle, times(2)).scheduleTestCase(scheduled.capture());
124+
final List<TestResult> captured = scheduled.getAllValues();
125+
assertThat(captured)
126+
.hasSize(2)
127+
.extracting(TestResult::getUuid)
128+
.doesNotContainNull();
129+
assertThat(captured.get(0).getUuid()).isNotEqualTo(captured.get(1).getUuid());
130+
}
131+
132+
@Test
133+
void shouldIgnoreErrorAndAfterIterationWhenUuidMissing() {
134+
final io.qameta.allure.AllureLifecycle lifecycle = mock(io.qameta.allure.AllureLifecycle.class);
135+
final AllureSpock2 allureSpock2 = new AllureSpock2(lifecycle);
136+
137+
allureSpock2.error(mock(org.spockframework.runtime.model.ErrorInfo.class));
138+
allureSpock2.afterIteration(mock(org.spockframework.runtime.model.IterationInfo.class));
139+
140+
verifyNoInteractions(lifecycle);
141+
}
142+
143+
private static final class DummySpec {
144+
public void dummy() {
145+
// noop
146+
}
147+
}
148+
82149
@Test
83150
void shouldStoreTestsInformation() {
84151
final AllureResults results = runClasses(OneTest.class);

0 commit comments

Comments
 (0)