From e77f1c20a5b13ed66969b9b04500555bc4831301 Mon Sep 17 00:00:00 2001 From: Krishnan Mahadevan Date: Mon, 12 Feb 2024 22:47:48 +0530 Subject: [PATCH] Copy test result attributes when unexpected failures Closes #3064 --- CHANGES.txt | 1 + .../testng/internal/invokers/TestInvoker.java | 2 ++ .../java/test/listeners/ListenersTest.java | 10 +++++++ .../listeners/issue3064/EvidenceListener.java | 19 +++++++++++++ .../issue3064/EvidenceRetryAnalyzer.java | 16 +++++++++++ .../listeners/issue3064/SampleTestCase.java | 28 +++++++++++++++++++ 6 files changed, 76 insertions(+) create mode 100644 testng-core/src/test/java/test/listeners/issue3064/EvidenceListener.java create mode 100644 testng-core/src/test/java/test/listeners/issue3064/EvidenceRetryAnalyzer.java create mode 100644 testng-core/src/test/java/test/listeners/issue3064/SampleTestCase.java diff --git a/CHANGES.txt b/CHANGES.txt index 11a9b7aff..79ce07f3d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,6 @@ Current 7.10.0 +Fixed: GITHUB-3064: TestResult lost if failure creating RetryAnalyzer (Krishnan Mahadevan) Fixed: GITHUB-3048: ConcurrentModificationException when injecting values (Krishnan Mahadevan) Fixed: GITHUB-3050: Race condition when creating Guice Modules (Krishnan Mahadevan) Fixed: GITHUB-3059: Support the ability to inject custom listener factory (Krishnan Mahadevan) diff --git a/testng-core/src/main/java/org/testng/internal/invokers/TestInvoker.java b/testng-core/src/main/java/org/testng/internal/invokers/TestInvoker.java index d9f02cee9..ee12e5b51 100644 --- a/testng-core/src/main/java/org/testng/internal/invokers/TestInvoker.java +++ b/testng-core/src/main/java/org/testng/internal/invokers/TestInvoker.java @@ -972,6 +972,8 @@ public int invoke(int invCount) { ITestResult r = TestResult.newEndTimeAwareTestResult( arguments.getTestMethod(), m_testContext, cause, start); + Optional.ofNullable(Reporter.getCurrentTestResult()) + .ifPresent(it -> TestResult.copyAttributes(it, r)); r.setStatus(TestResult.FAILURE); result.add(r); runTestResultListener(r); diff --git a/testng-core/src/test/java/test/listeners/ListenersTest.java b/testng-core/src/test/java/test/listeners/ListenersTest.java index 8d1f6e27d..45eb9f955 100644 --- a/testng-core/src/test/java/test/listeners/ListenersTest.java +++ b/testng-core/src/test/java/test/listeners/ListenersTest.java @@ -28,6 +28,8 @@ import test.listeners.issue2880.ListenerForIssue2880; import test.listeners.issue2880.TestClassWithFailingConfigsSample; import test.listeners.issue2880.TestClassWithPassingConfigsSample; +import test.listeners.issue3064.EvidenceListener; +import test.listeners.issue3064.SampleTestCase; public class ListenersTest extends SimpleBaseTest { @@ -37,6 +39,14 @@ public class ListenersTest extends SimpleBaseTest { "test.listeners.issue2638.TestClassBSample.testMethod" }; + @Test(description = "GITHUB-3064") + public void ensureTestResultAttributesAreCarriedForward() { + TestNG testng = create(SampleTestCase.class); + testng.run(); + assertThat(EvidenceListener.failureTestResult.getAttribute(EvidenceListener.ATTRIBUTE_KEY)) + .isEqualTo("attributeValue"); + } + @Test(description = "GITHUB-2638", dataProvider = "suiteProvider") public void ensureDuplicateListenersAreNotWiredInAcrossSuites( XmlSuite xmlSuite, Map expected) { diff --git a/testng-core/src/test/java/test/listeners/issue3064/EvidenceListener.java b/testng-core/src/test/java/test/listeners/issue3064/EvidenceListener.java new file mode 100644 index 000000000..40397b32f --- /dev/null +++ b/testng-core/src/test/java/test/listeners/issue3064/EvidenceListener.java @@ -0,0 +1,19 @@ +package test.listeners.issue3064; + +import org.testng.ITestListener; +import org.testng.ITestResult; + +public class EvidenceListener implements ITestListener { + public static final String ATTRIBUTE_KEY = "attributeKey"; + public static ITestResult failureTestResult; + + @Override + public void onTestStart(ITestResult result) { + result.setAttribute(ATTRIBUTE_KEY, "attributeValue"); + } + + @Override + public void onTestFailure(ITestResult result) { + failureTestResult = result; + } +} diff --git a/testng-core/src/test/java/test/listeners/issue3064/EvidenceRetryAnalyzer.java b/testng-core/src/test/java/test/listeners/issue3064/EvidenceRetryAnalyzer.java new file mode 100644 index 000000000..4d51f8b64 --- /dev/null +++ b/testng-core/src/test/java/test/listeners/issue3064/EvidenceRetryAnalyzer.java @@ -0,0 +1,16 @@ +package test.listeners.issue3064; + +import org.testng.IRetryAnalyzer; +import org.testng.ITestResult; + +public class EvidenceRetryAnalyzer implements IRetryAnalyzer { + + public EvidenceRetryAnalyzer() { + throw new RuntimeException("Failed on purpose"); + } + + @Override + public boolean retry(ITestResult result) { + return false; + } +} diff --git a/testng-core/src/test/java/test/listeners/issue3064/SampleTestCase.java b/testng-core/src/test/java/test/listeners/issue3064/SampleTestCase.java new file mode 100644 index 000000000..2a8c190c1 --- /dev/null +++ b/testng-core/src/test/java/test/listeners/issue3064/SampleTestCase.java @@ -0,0 +1,28 @@ +package test.listeners.issue3064; + +import static org.testng.Assert.fail; + +import org.testng.ITestContext; +import org.testng.ITestNGMethod; +import org.testng.Reporter; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +@Test +@Listeners(EvidenceListener.class) +public class SampleTestCase { + + @BeforeSuite(alwaysRun = true) + public void suiteSetup() { + ITestContext context = Reporter.getCurrentTestResult().getTestContext(); + for (ITestNGMethod method : context.getAllTestMethods()) { + method.setRetryAnalyzerClass(EvidenceRetryAnalyzer.class); + } + } + + @Test + public void testOne() { + fail(); + } +}