From 8190086414a885dd9b22e3247936b904f193c5b4 Mon Sep 17 00:00:00 2001 From: Benjamin Bischoff <5775857+bischoffdev@users.noreply.github.com> Date: Thu, 12 Sep 2024 10:15:54 +0200 Subject: [PATCH] 3.8.1 (#356) * tdd tests * simplified unique scenario detection code * more tdd * multi run hash detection * updated jobs --- .github/workflows/example-report.yml | 4 +- .github/workflows/release.yml | 8 +- .github/workflows/unit-tests.yml | 8 +- CHANGELOG.md | 6 + .../ElementMultipleRunsPreProcessor.java | 88 ++++-- .../ElementMultipleRunsPreProcessorTest.java | 271 +++++++++++++++++- examples/core-example/pom.xml | 2 +- examples/maven-example/pom.xml | 2 +- pom.xml | 2 +- 9 files changed, 350 insertions(+), 41 deletions(-) diff --git a/.github/workflows/example-report.yml b/.github/workflows/example-report.yml index f2392371..ed30fa22 100644 --- a/.github/workflows/example-report.yml +++ b/.github/workflows/example-report.yml @@ -8,9 +8,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4.1.7 - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v3.13.0 with: java-version: '17' distribution: 'temurin' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f4e85c29..2c47ad71 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,12 +11,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Set up JDK 11 - uses: actions/setup-java@v3 + - uses: actions/checkout@v4.1.7 + - name: Set up JDK + uses: actions/setup-java@v3.13.0 with: distribution: 'temurin' - java-version: '11' + java-version: '17' cache: maven - name: Set up Apache Maven Central diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 2954389d..b30ffc7a 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -12,11 +12,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Set up JDK 11 - uses: actions/setup-java@v3 + - uses: actions/checkout@v4.1.7 + - name: Set up JDK + uses: actions/setup-java@v3.13.0 with: - java-version: '11' + java-version: '17' distribution: 'temurin' cache: maven - name: Test with Maven diff --git a/CHANGELOG.md b/CHANGELOG.md index 261eec5c..549aefda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. Back to [Readme](README.md). +## [3.8.1] - 2024-09-12 + +### Changed + +* Much safer detection of multi-run scenarios when using `groupPreviousScenarioRuns` + ## [3.8.0] - 2024-09-06 ### Fixed diff --git a/engine/src/main/java/com/trivago/cluecumber/engine/json/processors/ElementMultipleRunsPreProcessor.java b/engine/src/main/java/com/trivago/cluecumber/engine/json/processors/ElementMultipleRunsPreProcessor.java index fc35981b..ffea0549 100644 --- a/engine/src/main/java/com/trivago/cluecumber/engine/json/processors/ElementMultipleRunsPreProcessor.java +++ b/engine/src/main/java/com/trivago/cluecumber/engine/json/processors/ElementMultipleRunsPreProcessor.java @@ -15,13 +15,18 @@ */ package com.trivago.cluecumber.engine.json.processors; +import com.trivago.cluecumber.engine.json.pojo.Argument; import com.trivago.cluecumber.engine.json.pojo.Element; import com.trivago.cluecumber.engine.json.pojo.Report; +import com.trivago.cluecumber.engine.json.pojo.Row; +import com.trivago.cluecumber.engine.json.pojo.Step; +import com.trivago.cluecumber.engine.json.pojo.Tag; import javax.inject.Inject; import javax.inject.Singleton; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -46,40 +51,71 @@ public ElementMultipleRunsPreProcessor() { * @param reports The list of reports to cycle through. */ public void addMultipleRunsInformationToScenarios(final List reports) { + Map> elementsByUniqueId = new HashMap<>(); - List elements = new ArrayList<>(); + // Group elements by unique ID for (Report report : reports) { - elements.addAll(report.getElements()); + for (Element element : report.getElements()) { + String combinedId = generateCombinedId(element); + elementsByUniqueId.computeIfAbsent(combinedId, k -> new ArrayList<>()).add(element); + } } - // Group elements by id (that should combine feature and scenario names) and line, to also ensure that scenario outlines are properly handled - Map>> groupedElements = elements.stream() - .collect(Collectors.groupingBy( - Element::getId, - Collectors.groupingBy(Element::getLine) - )); + // Process each group of elements + for (List group : elementsByUniqueId.values()) { + if (group.size() < 2) continue; - // set flags based on start time and add children element to last run element - groupedElements.values().forEach(idGroup -> idGroup.values().forEach(group -> { - if (group.size() < 2) { - return; - } - group.sort(Comparator.comparing( - Element::getStartDateTime, Comparator.nullsLast(Comparator.naturalOrder())).reversed()); - Element lastRunElement = group.get(0); - lastRunElement.setMultiRunChildren(group); - lastRunElement.setMultiRunParent(true); - // remove first of line group as it is the last run element - group.remove(0); - for (Element element : group) { - element.isMultiRunChild(true); - } - lastRunElement.setMultiRunChildren(group); - })); + group.sort(Comparator.comparing(Element::getStartDateTime, Comparator.nullsLast(Comparator.naturalOrder())).reversed()); + Element parentElement = group.remove(0); + parentElement.setMultiRunParent(true); + group.forEach(element -> element.isMultiRunChild(true)); + parentElement.setMultiRunChildren(group); + } - // Remove elements marked as isMultiRunChild from each report + // Remove child elements from reports for (Report report : reports) { report.getElements().removeIf(Element::isMultiRunChild); } } + + private String generateCombinedId(Element element) { + List argumentValues = new ArrayList<>(); + List docStrings = new ArrayList<>(); + List> outputs = new ArrayList<>(); + List rows = new ArrayList<>(); + + for (Step step : element.getSteps()) { + step.getMatch().getArguments().stream() + .map(argument -> argument.getOffset() + ": " + argument.getVal()) + .forEach(argumentValues::add); + + if (step.getDocString() != null) { + docStrings.add(step.getDocString().getLine() + ": " + step.getDocString().getValue()); + } + + if (step.getOutput() != null) { + outputs.add(step.getOutput()); + } + + if (step.getRows() != null) { + step.getRows().forEach(row -> rows.add(String.join(", ", row.getCells()))); + } + } + + return String.valueOf((element.getFeatureIndex() + + element.getDescription() + + element.getLine() + + element.getFeatureName() + + element.getName() + + element.getId() + + element.getTags().stream().map(Tag::getName).collect(Collectors.joining(",")) + + element.getTotalNumberOfSteps() + + element.getSteps().stream().map(Step::getKeyword).collect(Collectors.joining(", ")) + + element.getSteps().stream().map(Step::getName).collect(Collectors.joining(", ")) + + String.join(", ", docStrings) + + String.join(", ", argumentValues) + + String.join(", ", rows) + + outputs.stream().map(output -> String.join(", ", output)).collect(Collectors.joining(", "))) + .hashCode()); + } } diff --git a/engine/src/test/java/com/trivago/cluecumber/engine/json/processors/ElementMultipleRunsPreProcessorTest.java b/engine/src/test/java/com/trivago/cluecumber/engine/json/processors/ElementMultipleRunsPreProcessorTest.java index 5d261d86..e2e629d3 100644 --- a/engine/src/test/java/com/trivago/cluecumber/engine/json/processors/ElementMultipleRunsPreProcessorTest.java +++ b/engine/src/test/java/com/trivago/cluecumber/engine/json/processors/ElementMultipleRunsPreProcessorTest.java @@ -1,7 +1,13 @@ package com.trivago.cluecumber.engine.json.processors; +import com.trivago.cluecumber.engine.json.pojo.Argument; +import com.trivago.cluecumber.engine.json.pojo.DocString; import com.trivago.cluecumber.engine.json.pojo.Element; +import com.trivago.cluecumber.engine.json.pojo.Match; import com.trivago.cluecumber.engine.json.pojo.Report; +import com.trivago.cluecumber.engine.json.pojo.Row; +import com.trivago.cluecumber.engine.json.pojo.Step; +import com.trivago.cluecumber.engine.json.pojo.Tag; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -16,12 +22,12 @@ public class ElementMultipleRunsPreProcessorTest { private ElementMultipleRunsPreProcessor elementMultipleRunsPreProcessor; @BeforeEach -public void setup() { + public void setup() { elementMultipleRunsPreProcessor = new ElementMultipleRunsPreProcessor(); } @Test - public void addMultipleRunsInformationToScenariosTest() { + public void addMultipleRunsInformationToGroupableScenariosTest() { List reports = new ArrayList<>(); Report report = new Report(); List elements = new ArrayList<>(); @@ -71,4 +77,265 @@ public void addMultipleRunsInformationToScenariosTest() { assertFalse(e.get(1).isMultiRunChild()); assertEquals(e.get(1).getMultiRunChildren().size(), 1); } + + @Test + public void addMultipleRunsInformationToSameScenariosWithDifferentKeywords() { + List reports = new ArrayList<>(); + Report report = new Report(); + List elements = new ArrayList<>(); + + Step step = new Step(); + step.setKeyword("Given"); + Element element = createNewElement(List.of(step)); + elements.add(element); + + step = new Step(); + step.setKeyword("And"); + element = createNewElement(List.of(step)); + elements.add(element); + + report.setElements(elements); + reports.add(report); + + elementMultipleRunsPreProcessor.addMultipleRunsInformationToScenarios(reports); + + List newElements = reports.get(0).getElements(); + assertEquals(2, newElements.size()); + } + + @Test + public void addMultipleRunsInformationToSameScenariosWithDifferentParameterValues() { + List reports = new ArrayList<>(); + Report report = new Report(); + List elements = new ArrayList<>(); + + Step step = new Step(); + Argument argument = new Argument(); + argument.setOffset(1); + argument.setVal("abc"); + Match match = new Match(); + match.setArguments(List.of(argument)); + step.setMatch(match); + Element element = createNewElement(List.of(step)); + elements.add(element); + + step = new Step(); + argument = new Argument(); + argument.setOffset(1); + argument.setVal("def"); + match = new Match(); + match.setArguments(List.of(argument)); + step.setMatch(match); element = createNewElement(List.of(step)); + elements.add(element); + + report.setElements(elements); + reports.add(report); + + elementMultipleRunsPreProcessor.addMultipleRunsInformationToScenarios(reports); + + List newElements = reports.get(0).getElements(); + assertEquals(2, newElements.size()); + } + + @Test + public void addMultipleRunsInformationToSameScenariosWithDifferentNames() { + List reports = new ArrayList<>(); + Report report = new Report(); + List elements = new ArrayList<>(); + + Step step = new Step(); + step.setName("Given I have 4 apples"); + Element element = createNewElement(List.of(step)); + elements.add(element); + + step = new Step(); + step.setName("Given I have 5 apples"); + element = createNewElement(List.of(step)); + elements.add(element); + + report.setElements(elements); + reports.add(report); + + elementMultipleRunsPreProcessor.addMultipleRunsInformationToScenarios(reports); + + List newElements = reports.get(0).getElements(); + assertEquals(2, newElements.size()); + } + + @Test + public void addMultipleRunsInformationToSameScenariosWithDifferentDocStrings() { + List reports = new ArrayList<>(); + Report report = new Report(); + List elements = new ArrayList<>(); + + Step step = new Step(); + DocString docString = new DocString(); + docString.setValue("abc"); + step.setDocString(docString); + Element element = createNewElement(List.of(step)); + elements.add(element); + + step = new Step(); + docString = new DocString(); + docString.setValue("def"); + step.setDocString(docString); + element = createNewElement(List.of(step)); + elements.add(element); + + report.setElements(elements); + reports.add(report); + + elementMultipleRunsPreProcessor.addMultipleRunsInformationToScenarios(reports); + + List newElements = reports.get(0).getElements(); + assertEquals(2, newElements.size()); + } + + @Test + public void addMultipleRunsInformationToSameScenariosWithDifferentOutputs() { + List reports = new ArrayList<>(); + Report report = new Report(); + List elements = new ArrayList<>(); + + Step step = new Step(); + step.setOutput(List.of("abc")); + Element element = createNewElement(List.of(step)); + elements.add(element); + + step = new Step(); + step.setOutput(List.of("def")); + element = createNewElement(List.of(step)); + elements.add(element); + + report.setElements(elements); + reports.add(report); + + elementMultipleRunsPreProcessor.addMultipleRunsInformationToScenarios(reports); + + List newElements = reports.get(0).getElements(); + assertEquals(2, newElements.size()); + } + + @Test + public void addMultipleRunsInformationToSameScenariosWithDifferentDataTableRows() { + List reports = new ArrayList<>(); + Report report = new Report(); + List elements = new ArrayList<>(); + + Step step = new Step(); + List rows = new ArrayList<>(); + Row row = new Row(); + row.setCells(List.of("aaa", "bbb")); + rows.add(row); + step.setRows(rows); + Element element = createNewElement(List.of(step)); + elements.add(element); + + step = new Step(); + rows = new ArrayList<>(); + row = new Row(); + row.setCells(List.of("aaa", "ddd")); + rows.add(row); + step.setRows(rows); + element = createNewElement(List.of(step)); + elements.add(element); + + report.setElements(elements); + reports.add(report); + + elementMultipleRunsPreProcessor.addMultipleRunsInformationToScenarios(reports); + + List newElements = reports.get(0). getElements(); + assertEquals(2, newElements.size()); + } + + @Test + public void addMultipleRunsInformationToSameScenariosWithDifferentTags() { + List reports = new ArrayList<>(); + Report report = new Report(); + List elements = new ArrayList<>(); + + Step step = new Step(); + Element element = createNewElement(List.of(step)); + Tag tag = new Tag(); + tag.setName("tag1"); + element.setTags(List.of(tag)); + elements.add(element); + + step = new Step(); + element = createNewElement(List.of(step)); + tag = new Tag(); + tag.setName("tag2"); + element.setTags(List.of(tag)); + elements.add(element); + + report.setElements(elements); + reports.add(report); + + elementMultipleRunsPreProcessor.addMultipleRunsInformationToScenarios(reports); + + List newElements = reports.get(0).getElements(); + assertEquals(2, newElements.size()); + } + + @Test + public void addMultipleRunsInformationToSameScenariosWithDifferentDescription() { + List reports = new ArrayList<>(); + Report report = new Report(); + List elements = new ArrayList<>(); + + Step step = new Step(); + Element element = createNewElement(List.of(step)); + element.setDescription("description1"); + elements.add(element); + + step = new Step(); + element = createNewElement(List.of(step)); + element.setDescription("description2"); + elements.add(element); + + report.setElements(elements); + reports.add(report); + + elementMultipleRunsPreProcessor.addMultipleRunsInformationToScenarios(reports); + + List newElements = reports.get(0).getElements(); + assertEquals(2, newElements.size()); + } + + @Test + public void addMultipleRunsInformationToSameScenariosWithDifferentFeatureNames() { + List reports = new ArrayList<>(); + Report report = new Report(); + List elements = new ArrayList<>(); + + Step step = new Step(); + Element element = createNewElement(List.of(step)); + element.setFeatureName("feature1"); + elements.add(element); + + step = new Step(); + element = createNewElement(List.of(step)); + element.setFeatureName("feature2"); + elements.add(element); + + report.setElements(elements); + reports.add(report); + + elementMultipleRunsPreProcessor.addMultipleRunsInformationToScenarios(reports); + + List newElements = reports.get(0).getElements(); + assertEquals(2, newElements.size()); + } + + private Element createNewElement(final List steps) { + Element element = new Element(); + element.setName("Scenario 1"); + element.setType("scenario"); + element.setId("feature1-scenario1"); + element.setSteps(steps); + element.setLine(3); + element.setStartTimestamp("2019-04-11T08:00:21.123Z"); + return element; + } } diff --git a/examples/core-example/pom.xml b/examples/core-example/pom.xml index b3b00696..afd0bc85 100644 --- a/examples/core-example/pom.xml +++ b/examples/core-example/pom.xml @@ -6,7 +6,7 @@ blog.softwaretester core-example - 3.8.0 + 3.8.1 jar diff --git a/examples/maven-example/pom.xml b/examples/maven-example/pom.xml index b553ac7e..f889deb5 100644 --- a/examples/maven-example/pom.xml +++ b/examples/maven-example/pom.xml @@ -6,7 +6,7 @@ blog.softwaretester maven-example - 3.8.0 + 3.8.1 pom diff --git a/pom.xml b/pom.xml index 817c8663..187349b7 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ - 3.8.0 + 3.8.1 11 11 11