Skip to content

Commit

Permalink
Add timestamp attribute
Browse files Browse the repository at this point in the history
While the timestamp attribute is not part of the JUnit or Surefire XSD
in practice it seems to be a common enough property[1] that we can add
it without expecting any of the popular tools to break.

Closes: #44

 1. https://github.com/testmoapp/junitxml
  • Loading branch information
mpkorstanje committed Nov 15, 2024
1 parent 4b5ddd5 commit 52909ab
Show file tree
Hide file tree
Showing 19 changed files with 45 additions and 26 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added
- Update dependency io.cucumber:messages up to v26 ((#38)[https://github.com/cucumber/query/pull/38])
- Add `timestamp` attribute ((#45)[https://github.com/cucumber/junit-xml-formatter/pull/45])

## [0.5.0] - 2024-06-22
### Added
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package io.cucumber.junitxmlformatter;

import io.cucumber.messages.Convertor;
import io.cucumber.messages.types.Envelope;
import io.cucumber.messages.types.Feature;
import io.cucumber.messages.types.Pickle;
import io.cucumber.messages.types.PickleStep;
import io.cucumber.messages.types.Step;
import io.cucumber.messages.types.TestCaseStarted;
import io.cucumber.messages.types.TestRunStarted;
import io.cucumber.messages.types.TestStep;
import io.cucumber.messages.types.TestStepFinished;
import io.cucumber.messages.types.TestStepResult;
Expand All @@ -22,6 +24,7 @@
import java.util.Optional;

import static io.cucumber.messages.types.TestStepResultStatus.PASSED;
import static java.time.format.DateTimeFormatter.ISO_INSTANT;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.stream.Collectors.toList;

Expand Down Expand Up @@ -123,4 +126,11 @@ TestStepResult getTestCaseStatus(TestCaseStarted testCaseStarted) {
.orElse(SCENARIO_WITH_NO_STEPS);
}

public String getTestRunStartedTimeStamp() {
return query.findTestRunStarted()
.map(TestRunStarted::getTimestamp)
.map(Convertor::toInstant)
.map(ISO_INSTANT::format)
.orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ private void writeSuiteAttributes(EscapingXmlStreamWriter writer) throws XMLStre
writer.writeAttribute("skipped", counts.getOrDefault(SKIPPED, 0L).toString());
writer.writeAttribute("failures", String.valueOf(countFailures(counts)));
writer.writeAttribute("errors", "0");
writer.writeAttribute("timestamp", data.getTestRunStartedTimeStamp());
}

private static long countFailures(Map<TestStepResultStatus, Long> counts) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.xmlunit.assertj.XmlAssert;
import org.xmlunit.builder.Input;
import org.xmlunit.validation.JAXPValidator;
import org.xmlunit.validation.Languages;
Expand All @@ -20,6 +21,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
Expand All @@ -28,6 +30,7 @@
import java.util.stream.Stream;

import static io.cucumber.junitxmlformatter.Jackson.OBJECT_MAPPER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.xmlunit.assertj.XmlAssert.assertThat;

class MessagesToJunitXmlWriterAcceptanceTest {
Expand All @@ -49,7 +52,7 @@ void test(TestCase testCase) throws IOException {
ByteArrayOutputStream bytes = writeJunitXmlReport(testCase, new ByteArrayOutputStream());
Source expected = Input.fromPath(testCase.expected).build();
Source actual = Input.fromByteArray(bytes.toByteArray()).build();
assertThat(actual).and(expected).ignoreWhitespace().areIdentical();
XmlAssert.assertThat(actual).and(expected).ignoreWhitespace().areIdentical();
}

@ParameterizedTest
Expand All @@ -58,7 +61,7 @@ void validateAgainstJenkins(TestCase testCase) throws IOException {
ByteArrayOutputStream bytes = writeJunitXmlReport(testCase, new ByteArrayOutputStream());
Source actual = Input.fromByteArray(bytes.toByteArray()).build();
Source jenkinsSchema = Input.fromPath(Paths.get("../jenkins-junit.xsd")).build();
assertThat(actual).isValidAgainst(jenkinsSchema);
XmlAssert.assertThat(actual).isValidAgainst(jenkinsSchema);
}

static final List<String> testCasesWithMissingException = Arrays.asList(
Expand All @@ -76,11 +79,16 @@ void validateAgainstSurefire(TestCase testCase) throws IOException {
ByteArrayOutputStream bytes = writeJunitXmlReport(testCase, new ByteArrayOutputStream());
Source actual = Input.fromByteArray(bytes.toByteArray()).build();
Source surefireSchema = Input.fromPath(Paths.get("../surefire-test-report-3.0.xsd")).build();
if (!testCasesWithMissingException.contains(testCase.name)) {
assertThat(actual).isValidAgainst(surefireSchema);
return;
}

JAXPValidator validator = new JAXPValidator(Languages.W3C_XML_SCHEMA_NS_URI);
validator.setSchemaSource(surefireSchema);
ValidationResult validationResult = validator.validateInstance(actual);

List<String> expectedProblems = new ArrayList<>();
/*
* We add the timestamp attribute to all reports.
*/
expectedProblems.add("cvc-complex-type.3.2.2: Attribute 'timestamp' is not allowed to appear in element 'testsuite'.");
/*
This report tries to be compatible with the Jenkins XSD. The Surefire
XSD is a bit stricter and generally assumes tests fail with an
Expand All @@ -94,12 +102,11 @@ void validateAgainstSurefire(TestCase testCase) throws IOException {
Since the Surefire XSD is also relatively popular we do check it and
exclude the cases that don't pass selectively.
*/
JAXPValidator validator = new JAXPValidator(Languages.W3C_XML_SCHEMA_NS_URI);
validator.setSchemaSource(surefireSchema);
ValidationResult validationResult = validator.validateInstance(actual);
if (testCasesWithMissingException.contains(testCase.name)) {
expectedProblems.add("cvc-complex-type.4: Attribute 'type' must appear on element 'failure'.");
}
Iterable<ValidationProblem> problems = validationResult.getProblems();
Assertions.assertThat(problems).extracting(ValidationProblem::getMessage)
.containsOnly("cvc-complex-type.4: Attribute 'type' must appear on element 'failure'.");
assertThat(problems).extracting(ValidationProblem::getMessage).containsAll(expectedProblems);
}

@ParameterizedTest
Expand Down
2 changes: 1 addition & 1 deletion testdata/attachments.feature.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.045" tests="11" skipped="0" failures="0" errors="0">
<testsuite name="Cucumber" time="0.045" tests="11" skipped="0" failures="0" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="Attachments" name="Strings can be attached with a media type" time="0.003">
<system-out><![CDATA[
When the string "hello" is attached as "application/octet-stream"...........passed
Expand Down
2 changes: 1 addition & 1 deletion testdata/cdata.feature.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.005" tests="1" skipped="0" failures="0" errors="0">
<testsuite name="Cucumber" time="0.005" tests="1" skipped="0" failures="0" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="cdata" name="cdata" time="0.003">
<system-out><![CDATA[
Given I have 42 <![CDATA[cukes]]]]><![CDATA[> in my belly...............................passed
Expand Down
2 changes: 1 addition & 1 deletion testdata/data-tables.feature.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.007" tests="1" skipped="0" failures="0" errors="0">
<testsuite name="Cucumber" time="0.007" tests="1" skipped="0" failures="0" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="Data Tables" name="transposed table" time="0.005">
<system-out><![CDATA[
When the following table is transposed:.....................................passed
Expand Down
2 changes: 1 addition & 1 deletion testdata/examples-tables.feature.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.073" tests="9" skipped="0" failures="4" errors="0">
<testsuite name="Cucumber" time="0.073" tests="9" skipped="0" failures="4" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="Examples Tables" name="Eating cucumbers - These are passing - #1.1" time="0.007">
<system-out><![CDATA[
Given there are 12 cucumbers................................................passed
Expand Down
2 changes: 1 addition & 1 deletion testdata/hooks.feature.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.055" tests="5" skipped="0" failures="3" errors="0">
<testsuite name="Cucumber" time="0.055" tests="5" skipped="0" failures="3" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="Hooks" name="No tags and a passed step" time="0.009">
<system-out><![CDATA[
When a step passes..........................................................passed
Expand Down
2 changes: 1 addition & 1 deletion testdata/markdown.feature.md.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.021" tests="2" skipped="0" failures="1" errors="0">
<testsuite name="Cucumber" time="0.021" tests="2" skipped="0" failures="1" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="Cheese" name="Nom nom nom - Ylajali! - because we need more tables - #1.1" time="0.009">
<failure type="Error" message="You asked me to fail">
<![CDATA[You asked me to fail
Expand Down
2 changes: 1 addition & 1 deletion testdata/minimal.feature.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.005" tests="1" skipped="0" failures="0" errors="0">
<testsuite name="Cucumber" time="0.005" tests="1" skipped="0" failures="0" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="minimal" name="cukes" time="0.003">
<system-out><![CDATA[
Given I have 42 cukes in my belly...........................................passed
Expand Down
2 changes: 1 addition & 1 deletion testdata/parameter-types.feature.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.005" tests="1" skipped="0" failures="0" errors="0">
<testsuite name="Cucumber" time="0.005" tests="1" skipped="0" failures="0" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="Parameter Types" name="Flight transformer" time="0.003">
<system-out><![CDATA[
Given LHR-CDG has been delayed..............................................passed
Expand Down
2 changes: 1 addition & 1 deletion testdata/pending.feature.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.017" tests="3" skipped="0" failures="3" errors="0">
<testsuite name="Cucumber" time="0.017" tests="3" skipped="0" failures="3" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="Pending steps" name="Unimplemented step signals pending status" time="0.003">
<failure>
<![CDATA[TODO]]>
Expand Down
2 changes: 1 addition & 1 deletion testdata/retry.feature.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.041" tests="10" skipped="0" failures="7" errors="0">
<testsuite name="Cucumber" time="0.041" tests="10" skipped="0" failures="7" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="Retry" name="Test cases that pass aren't retried" time="0.003">
<system-out><![CDATA[
Given a step that always passes.............................................passed
Expand Down
2 changes: 1 addition & 1 deletion testdata/rules.feature.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.031" tests="3" skipped="0" failures="0" errors="0">
<testsuite name="Cucumber" time="0.031" tests="3" skipped="0" failures="0" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="Usage of a `Rule`" name="A sale cannot happen if the customer does not have enough money - Not enough money" time="0.009">
<system-out><![CDATA[
Given the customer has 100 cents............................................passed
Expand Down
2 changes: 1 addition & 1 deletion testdata/skipped.feature.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.019" tests="3" skipped="3" failures="0" errors="0">
<testsuite name="Cucumber" time="0.019" tests="3" skipped="3" failures="0" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="Skipping scenarios" name="Skipping from a Before hook" time="0.005">
<skipped/>
<system-out><![CDATA[
Expand Down
2 changes: 1 addition & 1 deletion testdata/stack-traces.feature.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.005" tests="1" skipped="0" failures="1" errors="0">
<testsuite name="Cucumber" time="0.005" tests="1" skipped="0" failures="1" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="Stack traces" name="A failing step" time="0.003">
<failure type="Error" message="BOOM">
<![CDATA[BOOM
Expand Down
2 changes: 1 addition & 1 deletion testdata/undefined.feature.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.017" tests="3" skipped="0" failures="3" errors="0">
<testsuite name="Cucumber" time="0.017" tests="3" skipped="0" failures="3" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="Undefined steps" name="An undefined step causes a failure" time="0.003">
<failure/>
<system-out><![CDATA[
Expand Down
2 changes: 1 addition & 1 deletion testdata/unknown-parameter-type.feature.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Cucumber" time="0.005" tests="1" skipped="0" failures="1" errors="0">
<testsuite name="Cucumber" time="0.005" tests="1" skipped="0" failures="1" errors="0" timestamp="1970-01-01T00:00:00Z">
<testcase classname="Parameter Types" name="undefined parameter type" time="0.003">
<failure/>
<system-out><![CDATA[
Expand Down

0 comments on commit 52909ab

Please sign in to comment.