Skip to content

Commit 7554d9e

Browse files
authored
Merge pull request #114 from testomatio/Issue-103_Karate
Issue-103-hot-fix
2 parents 7f9ac6d + 7e3ced7 commit 7554d9e

10 files changed

Lines changed: 153 additions & 40 deletions

File tree

java-reporter-core/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
<groupId>io.testomat</groupId>
99
<artifactId>java-reporter-core</artifactId>
10-
<version>0.9.2</version>
10+
<version>0.9.3</version>
1111
<packaging>jar</packaging>
1212

1313
<name>Testomat.io Reporter Core</name>

java-reporter-core/src/main/java/io/testomat/core/constants/CommonConstants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package io.testomat.core.constants;
22

33
public class CommonConstants {
4-
public static final String REPORTER_VERSION = "0.9.2";
4+
public static final String REPORTER_VERSION = "0.9.3";
55

66
public static final String TESTS_STRING = "tests";
77
public static final String API_KEY_STRING = "api_key";

java-reporter-core/src/main/java/io/testomat/core/facade/methods/artifact/ReportedTestStorage.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,25 @@ public class ReportedTestStorage {
2121
/**
2222
* Stores test execution metadata in the internal storage.
2323
* <p>
24-
* The method adds a new entry containing {@code test_id} and {@code rid}
25-
* only if an entry with the same values does not already exist.
26-
* The check and insertion are performed atomically using synchronization
27-
* to prevent duplicates in concurrent environments.
24+
* The method extracts {@code test_id} and {@code rid} from the provided body
25+
* and stores them as a new entry if an identical pair does not already exist.
26+
* If {@code rid} is {@code null}, the entry is ignored and nothing is stored.
27+
* <p>
28+
* The existence check and insertion are performed inside a synchronized block
29+
* to guarantee atomicity and prevent duplicate entries in concurrent environments.
2830
*
29-
* @param body a map containing test execution data; expected to include
30-
* {@code "test_id"} and {@code "rid"} keys
31+
* @param body a map containing test execution data. Expected to contain
32+
* {@code "rid"} and optionally {@code "test_id"}.
3133
*/
3234
public static void store(Map<String, Object> body) {
3335

3436
Object testId = body.get("test_id");
3537
Object rid = body.get("rid");
3638

39+
if (rid == null) {
40+
return;
41+
}
42+
3743
synchronized (STORAGE) {
3844

3945
boolean exists = STORAGE.stream().anyMatch(m ->

java-reporter-core/src/test/java/io/testomat/core/artifact/ReportedTestStorageTest.java

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import static org.junit.jupiter.api.Assertions.assertEquals;
44
import static org.junit.jupiter.api.Assertions.assertFalse;
55
import static org.junit.jupiter.api.Assertions.assertNotNull;
6-
import static org.junit.jupiter.api.Assertions.assertNull;
76
import static org.junit.jupiter.api.Assertions.assertTrue;
87

98
import java.util.Arrays;
@@ -177,20 +176,33 @@ void testEmptyArtifactLinkList() {
177176
}
178177

179178
@Test
180-
@DisplayName("Should handle null values in test data")
181-
void testNullValuesInTestData() {
179+
@DisplayName("Should not store duplicate entries with same test_id and rid")
180+
void testNoDuplicateEntries() {
182181
Map<String, Object> body = new HashMap<>();
183-
body.put("test_id", null);
184-
body.put("rid", null);
182+
body.put("test_id", "test-1");
183+
body.put("rid", "rid-1");
185184

185+
ReportedTestStorage.store(body);
186186
ReportedTestStorage.store(body);
187187

188188
List<Map<String, Object>> storage = ReportedTestStorage.getStorage();
189-
Map<String, Object> stored = storage.get(storage.size() - 1);
190189

191-
assertTrue(stored.containsKey("test_id"));
192-
assertTrue(stored.containsKey("rid"));
193-
assertNull(stored.get("test_id"));
194-
assertNull(stored.get("rid"));
190+
assertEquals(1, storage.size());
191+
}
192+
193+
@Test
194+
@DisplayName("Should not store entry with null rid")
195+
void testRidNullNotStored() {
196+
197+
Map<String, Object> body = new HashMap<>();
198+
body.put("test_id", "test-1");
199+
body.put("rid", null);
200+
201+
ReportedTestStorage.store(body);
202+
203+
List<Map<String, Object>> storage =
204+
ReportedTestStorage.getStorage();
205+
206+
assertEquals(0, storage.size());
195207
}
196208
}

java-reporter-cucumber/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
<dependency>
5252
<groupId>io.testomat</groupId>
5353
<artifactId>java-reporter-core</artifactId>
54-
<version>0.9.2</version>
54+
<version>0.9.3</version>
5555
</dependency>
5656
<dependency>
5757
<groupId>org.slf4j</groupId>

java-reporter-junit/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
<dependency>
5252
<groupId>io.testomat</groupId>
5353
<artifactId>java-reporter-core</artifactId>
54-
<version>0.9.2</version>
54+
<version>0.9.3</version>
5555
</dependency>
5656
<dependency>
5757
<groupId>org.slf4j</groupId>

java-reporter-karate/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>io.testomat</groupId>
88
<artifactId>java-reporter-karate</artifactId>
9-
<version>0.2.4</version>
9+
<version>0.2.5</version>
1010
<packaging>jar</packaging>
1111

1212
<name>Testomat.io Java Reporter Karate</name>
@@ -52,7 +52,7 @@
5252
<dependency>
5353
<groupId>io.testomat</groupId>
5454
<artifactId>java-reporter-core</artifactId>
55-
<version>0.9.2</version>
55+
<version>0.9.3</version>
5656
</dependency>
5757
<dependency>
5858
<groupId>io.karatelabs</groupId>

java-reporter-karate/src/main/java/io/testomat/karate/extractor/TestDataExtractor.java

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.testomat.core.model.ExceptionDetails;
1111
import java.io.PrintWriter;
1212
import java.io.StringWriter;
13+
import java.nio.charset.StandardCharsets;
1314
import java.util.Arrays;
1415
import java.util.Objects;
1516
import java.util.UUID;
@@ -135,27 +136,25 @@ public String getNormalizedStatus(ScenarioRuntime sr) {
135136
}
136137

137138
/**
138-
* Generates a stable runtime identifier (rId) for a Karate test scenario execution.
139-
* <p>
140-
* The identifier is deterministically derived from the scenario location
141-
* (feature file path and scenario line number). This ensures that the same
142-
* scenario always produces the same rId across multiple test runs.
143-
* <p>
144-
* The rId is generated using a name-based UUID calculated from the string:
145-
* <pre>
146-
* &lt;feature-relative-path&gt;:&lt;scenario-line-number&gt;
147-
* </pre>
139+
* Generates a report identifier (rId) for a Karate scenario.
140+
* The identifier is based on the feature path, scenario line, and example index
141+
* (if the scenario is a Scenario Outline).
148142
*
149-
* @param sr the {@link ScenarioRuntime} representing the executed Karate test scenario
150-
* @return a deterministic UUID string uniquely identifying the scenario execution
143+
* @param sr scenario runtime
144+
* @return stable UUID identifying this scenario execution
151145
*/
152146
public String getRid(ScenarioRuntime sr) {
153-
String raw = String.format("%s:%s",
154-
sr.scenario.getFeature().getResource().getRelativePath(),
155-
sr.scenario.getLine()
156-
);
147+
StringBuilder raw = new StringBuilder()
148+
.append(sr.scenario.getFeature().getResource().getRelativePath())
149+
.append(":")
150+
.append(sr.scenario.getLine());
151+
152+
int exampleIndex = sr.scenario.getExampleIndex();
153+
if (exampleIndex >= 0) {
154+
raw.append(":").append(exampleIndex);
155+
}
157156

158-
return UUID.nameUUIDFromBytes(raw.getBytes()).toString();
157+
return UUID.nameUUIDFromBytes(raw.toString().getBytes(StandardCharsets.UTF_8)).toString();
159158
}
160159

161160
private ExceptionDetails createExceptionDetails(Throwable throwable) {

java-reporter-karate/src/test/java/io/testomat/karate/extractor/TestDataExtractorTest.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
import com.intuit.karate.core.Tags;
1010
import com.intuit.karate.resource.Resource;
1111
import io.testomat.core.model.ExceptionDetails;
12+
import java.nio.charset.StandardCharsets;
1213
import java.util.ArrayList;
1314
import java.util.Arrays;
1415
import java.util.Collection;
16+
import java.util.UUID;
1517
import java.util.stream.Collectors;
1618
import org.junit.jupiter.api.Test;
1719

@@ -143,13 +145,107 @@ void getRidGeneratesStableUuid() {
143145
ScenarioRuntime sr = mockScenarioRuntime();
144146

145147
when(sr.scenario.getLine()).thenReturn(4);
148+
when(sr.scenario.getExampleIndex()).thenReturn(-1);
146149

147150
String rid1 = extractor.getRid(sr);
148151
String rid2 = extractor.getRid(sr);
149152

153+
assertThat(rid1)
154+
.isNotNull()
155+
.isEqualTo(rid2);
156+
}
157+
158+
@Test
159+
void getRidSameWithoutExampleIndex() {
160+
ScenarioRuntime sr1 = mockScenarioRuntime();
161+
ScenarioRuntime sr2 = mockScenarioRuntime();
162+
163+
when(sr1.scenario.getLine()).thenReturn(5);
164+
when(sr2.scenario.getLine()).thenReturn(5);
165+
166+
when(sr1.scenario.getExampleIndex()).thenReturn(-1);
167+
when(sr2.scenario.getExampleIndex()).thenReturn(-1);
168+
169+
String rid1 = extractor.getRid(sr1);
170+
String rid2 = extractor.getRid(sr2);
171+
150172
assertThat(rid1).isEqualTo(rid2);
151173
}
152174

175+
@Test
176+
void getRidDifferentLinesProduceDifferentRid() {
177+
ScenarioRuntime sr1 = mockScenarioRuntime();
178+
ScenarioRuntime sr2 = mockScenarioRuntime();
179+
180+
when(sr1.scenario.getLine()).thenReturn(1);
181+
when(sr2.scenario.getLine()).thenReturn(2);
182+
183+
when(sr1.scenario.getExampleIndex()).thenReturn(-1);
184+
when(sr2.scenario.getExampleIndex()).thenReturn(-1);
185+
186+
String rid1 = extractor.getRid(sr1);
187+
String rid2 = extractor.getRid(sr2);
188+
189+
assertThat(rid1).isNotEqualTo(rid2);
190+
}
191+
192+
@Test
193+
void getRidIncludesExampleIndex() {
194+
ScenarioRuntime sr1 = mockScenarioRuntime();
195+
ScenarioRuntime sr2 = mockScenarioRuntime();
196+
197+
when(sr1.scenario.getLine()).thenReturn(10);
198+
when(sr2.scenario.getLine()).thenReturn(10);
199+
200+
when(sr1.scenario.getExampleIndex()).thenReturn(0);
201+
when(sr2.scenario.getExampleIndex()).thenReturn(1);
202+
203+
String rid1 = extractor.getRid(sr1);
204+
String rid2 = extractor.getRid(sr2);
205+
206+
assertThat(rid1).isNotEqualTo(rid2);
207+
}
208+
209+
@Test
210+
void getRidDifferentFeatureFilesProduceDifferentRid() {
211+
ScenarioRuntime sr1 = mockScenarioRuntime();
212+
ScenarioRuntime sr2 = mockScenarioRuntime();
213+
214+
when(sr1.scenario.getLine()).thenReturn(1);
215+
when(sr2.scenario.getLine()).thenReturn(1);
216+
217+
when(sr1.scenario.getExampleIndex()).thenReturn(-1);
218+
when(sr2.scenario.getExampleIndex()).thenReturn(-1);
219+
220+
when(sr2.scenario.getFeature()
221+
.getResource()
222+
.getRelativePath())
223+
.thenReturn("features/Other.feature");
224+
225+
String rid1 = extractor.getRid(sr1);
226+
String rid2 = extractor.getRid(sr2);
227+
228+
assertThat(rid1).isNotEqualTo(rid2);
229+
}
230+
231+
@Test
232+
void getRidMatchesExpectedUuid() {
233+
ScenarioRuntime sr = mockScenarioRuntime();
234+
235+
when(sr.scenario.getLine()).thenReturn(4);
236+
when(sr.scenario.getExampleIndex()).thenReturn(-1);
237+
238+
String expected =
239+
UUID.nameUUIDFromBytes(
240+
"features/KarateTest.feature:4"
241+
.getBytes(StandardCharsets.UTF_8)
242+
).toString();
243+
244+
String rid = extractor.getRid(sr);
245+
246+
assertThat(rid).isEqualTo(expected);
247+
}
248+
153249
private ScenarioRuntime mockScenarioRuntime() {
154250
ScenarioRuntime sr = mock(ScenarioRuntime.class);
155251

java-reporter-testng/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
<dependency>
4848
<groupId>io.testomat</groupId>
4949
<artifactId>java-reporter-core</artifactId>
50-
<version>0.9.2</version>
50+
<version>0.9.3</version>
5151
</dependency>
5252
<dependency>
5353
<groupId>org.slf4j</groupId>

0 commit comments

Comments
 (0)