Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import org.testng.IAttributes;
import org.testng.IClass;
import org.testng.IConfigurationListener;
import org.testng.IDataProviderListener;
import org.testng.IDataProviderMethod;
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.IMethodInstance;
Expand Down Expand Up @@ -110,7 +112,8 @@ public class AllureTestNg implements
ITestListener,
IInvokedMethodListener,
IConfigurationListener,
IMethodInterceptor {
IMethodInterceptor,
IDataProviderListener {

private static final Logger LOGGER = LoggerFactory.getLogger(AllureTestNg.class);

Expand Down Expand Up @@ -150,6 +153,10 @@ public class AllureTestNg implements
* Store uuid for class test containers.
*/
private final Map<ITestClass, String> classContainerUuidStorage = new ConcurrentHashMap<>();
/**
* Store uuid for data provider containers.
*/
private final Map<ITestNGMethod, String> dataProviderContainerUuidStorage = new ConcurrentHashMap<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final AllureLifecycle lifecycle;
private final AllureTestNgTestFilter testFilter;
Expand Down Expand Up @@ -280,6 +287,14 @@ public void onAfterClass(final ITestClass testClass) {
getLifecycle().stopTestContainer(uuid);
getLifecycle().writeTestContainer(uuid);
});
dataProviderContainerUuidStorage.entrySet().removeIf(entry -> {
if (entry.getKey().getTestClass().equals(testClass)) {
getLifecycle().stopTestContainer(entry.getValue());
getLifecycle().writeTestContainer(entry.getValue());
return true;
}
return false;
});
}

@Override
Expand All @@ -302,6 +317,10 @@ public void onTestStart(final ITestResult testResult) {
.map(ITestResult::getMethod)
.map(ITestNGMethod::getTestClass)
.ifPresent(clazz -> addClassContainerChild(clazz, uuid));

Optional.of(testResult)
.map(ITestResult::getMethod)
.ifPresent(method -> addDataProviderContainerChild(method, uuid));
}

@SuppressWarnings("BooleanExpressionComplexity")
Expand Down Expand Up @@ -626,6 +645,65 @@ public void onConfigurationSkip(final ITestResult itr) {
//do nothing
}

@Override
public void beforeDataProviderExecution(final IDataProviderMethod dataProviderMethod,
final ITestNGMethod method,
final ITestContext iTestContext) {
currentExecutable.remove();
final String containerUuid = dataProviderContainerUuidStorage.computeIfAbsent(
method,
key -> {
final String uuid = UUID.randomUUID().toString();
getLifecycle().startTestContainer(
new TestResultContainer()
.setUuid(uuid)
.setName(method.getMethodName())
);
return uuid;
}
);

final String uuid = currentExecutable.get();
final FixtureResult result = new FixtureResult()
.setName(dataProviderMethod.getMethod().getName())
.setStage(Stage.RUNNING);

processDescription(
getClass().getClassLoader(),
dataProviderMethod.getMethod(),
result::setDescription,
result::setDescriptionHtml
);

getLifecycle().startPrepareFixture(containerUuid, uuid, result);
}

@Override
public void afterDataProviderExecution(final IDataProviderMethod dataProviderMethod,
final ITestNGMethod method,
final ITestContext iTestContext) {
final String uuid = currentExecutable.get();
getLifecycle().updateFixture(uuid, result -> {
if (result.getStatus() == null) {
result.setStatus(Status.PASSED);
}
});
getLifecycle().stopFixture(uuid);
currentExecutable.remove();
}

@Override
public void onDataProviderFailure(final ITestNGMethod method,
final ITestContext ctx,
final RuntimeException t) {
final String uuid = currentExecutable.get();
getLifecycle().updateFixture(uuid, result -> result
.setStatus(getStatus(t))
.setStatusDetails(getStatusDetails(t).orElse(null)));
getLifecycle().stopFixture(uuid);
currentExecutable.remove();
}

protected String getHistoryId(final ITestNGMethod method, final List<Parameter> parameters) {
final MessageDigest digest = getMd5Digest();
final String testClassName = method.getTestClass().getName();
Expand Down Expand Up @@ -827,6 +905,10 @@ private Consumer<TestResult> setStatus(final Status status, final StatusDetails
};
}

private void addDataProviderContainerChild(final ITestNGMethod method, final String childUuid) {
this.addChildToContainer(dataProviderContainerUuidStorage.get(method), childUuid);
}

private void addClassContainerChild(final ITestClass clazz, final String childUuid) {
this.addChildToContainer(classContainerUuidStorage.get(clazz), childUuid);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
import io.qameta.allure.testng.samples.TestsWithIdForFilter;
import org.assertj.core.api.Condition;
import org.assertj.core.groups.Tuple;
import org.testng.ITestNGListener;
import org.testng.TestNG;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
Expand Down Expand Up @@ -130,7 +129,7 @@ public void shouldNotDisplayConfigurationFailsAsTests() {
public void shouldSetConfigurationProperty() {
AllureTestNgConfig allureTestNgConfig = AllureTestNgConfig.loadConfigProperties();
allureTestNgConfig.setHideDisabledTests(true);
assertThat(allureTestNgConfig.isHideDisabledTests()).isEqualTo(true);
assertThat(allureTestNgConfig.isHideDisabledTests()).isTrue();
}

@AllureFeatures.Parallel
Expand Down Expand Up @@ -507,7 +506,7 @@ public void multipleSuites() {
.hasSize(3);
List<String> uids = testResults.stream().map(TestResult::getUuid).collect(Collectors.toList());
assertThat(testContainers).as("Unexpected quantity of testng containers has been written")
.hasSize(8).extracting(TestResultContainer::getName)
.hasSize(9).extracting(TestResultContainer::getName)
.contains(beforeMethodName, beforeMethodName, firstTagName, firstSuiteName, secondTagName,
secondSuiteName);

Expand Down Expand Up @@ -553,7 +552,7 @@ public void parallelMethods() {
assertThat(testResults).as("Unexpected quantity of testng case results has been written")
.hasSize(2001);
assertThat(testContainers).as("Unexpected quantity of testng containers has been written")
.hasSize(6006);
.hasSize(6007);

assertContainersPerMethod(before1, testContainers, uids);
assertContainersPerMethod(before2, testContainers, uids);
Expand Down Expand Up @@ -1218,7 +1217,7 @@ public void shouldAddBeforeFixtureToFakeTestResult(final String suite, final Str
.findAny();
assertThat(result).as("Before failed fake test result").isNotEmpty();
final Optional<TestResultContainer> befores = results.getTestResultContainers().stream()
.filter(c -> Objects.nonNull(c.getBefores()) && c.getBefores().size() > 0)
.filter(c -> Objects.nonNull(c.getBefores()) && !c.getBefores().isEmpty())
.findAny();
assertThat(result).as("Before failed configuration container").isNotEmpty();
assertThat(befores.get().getChildren())
Expand Down Expand Up @@ -1252,7 +1251,6 @@ private AllureResults runTestNgSuites(AllureTestNgConfig config, final String...

private AllureResults runTestNgSuites(final Consumer<TestNG> configurer,
final String... suites) {
;
return runTestNgSuites(configurer, AllureTestNgConfig.loadConfigProperties(), suites);
}

Expand All @@ -1276,7 +1274,7 @@ private AllureResults runTestNgSuites(final Consumer<TestNG> configurer,
new AllureTestNgTestFilter(),
config);
final TestNG testNg = new TestNG(false);
testNg.addListener((ITestNGListener) adapter);
testNg.addListener(adapter);
testNg.setTestSuites(suiteFiles);

configurer.accept(testNg);
Expand Down Expand Up @@ -1461,7 +1459,7 @@ public void onlyId() {
@Test
@AllureFeatures.Filtration
public void idAssignToOtherTest() {
TestPlanV1_0 plan = new TestPlanV1_0().setTests(Arrays.asList(otherId));
TestPlanV1_0 plan = new TestPlanV1_0().setTests(singletonList(otherId));
List<TestResult> testResults = runTestPlan(plan, TestsWithIdForFilter.class).getTestResults();

assertThat(testResults)
Expand All @@ -1476,7 +1474,7 @@ public void idAssignToOtherTest() {
@Test
@AllureFeatures.Filtration
public void skippedTest() {
TestPlanV1_0 plan = new TestPlanV1_0().setTests(Arrays.asList(skipped));
TestPlanV1_0 plan = new TestPlanV1_0().setTests(singletonList(skipped));
List<TestResult> testResults = runTestPlan(plan, TestsWithIdForFilter.class).getTestResults();
assertThat(testResults)
.hasSize(1)
Expand Down Expand Up @@ -1508,13 +1506,140 @@ public AllureResults runTestPlan(final TestPlan plan, final Class<?>... testClas
return RunUtils.runTests(lifecycle -> {
final AllureTestNg adapter = new AllureTestNg(lifecycle, new AllureTestNgTestFilter(plan));
final TestNG testNG = new TestNG(false);
testNG.addListener((ITestNGListener) adapter);
testNG.addListener(adapter);
testNG.setTestClasses(testClasses);
testNG.setOutputDirectory("build/test-output");
testNG.run();
});
}

@AllureFeatures.Fixtures
@Test(description = "Should process data provider in setup")
public void shouldProcessDataProviderInSetup() {
final AllureResults results = runTestNgSuites("suites/data-provider-with-attachment.xml");

assertThat(results.getTestResultContainers())
.flatExtracting(TestResultContainer::getBefores)
.extracting(FixtureResult::getName, FixtureResult::getStatus)
.contains(Tuple.tuple("dataProvider", Status.PASSED));

assertThat(results.getTestResultContainers())
.flatExtracting(TestResultContainer::getBefores)
.filteredOn("name", "dataProvider")
.flatExtracting(FixtureResult::getAttachments)
.hasSize(1)
.extracting(Attachment::getName)
.contains("attachment");
}

@AllureFeatures.Fixtures
@Test(description = "Should process failed data provider in setup")
public void shouldProcessFailedDataProviderInSetup() {
final AllureResults results = runTestNgSuites("suites/failed-data-provider.xml");

assertThat(results.getTestResultContainers())
.flatExtracting(TestResultContainer::getBefores)
.extracting(FixtureResult::getName, FixtureResult::getStatus)
.contains(Tuple.tuple("dataProvider", Status.BROKEN));
}

@AllureFeatures.Fixtures
@Test(description = "Should process flaky data provider in setup")
public void shouldProcessFlakyDataProvider() {
final AllureResults results = runTestNgSuites("suites/flaky-data-provider.xml");

assertThat(results.getTestResultContainers())
.flatExtracting(TestResultContainer::getBefores)
.extracting(FixtureResult::getName, FixtureResult::getStatus)
.containsSubsequence(
Tuple.tuple("provide", Status.BROKEN),
Tuple.tuple("provide", Status.PASSED)
);
}

@AllureFeatures.Fixtures
@Test(description = "Should properly link data provider container to test result")
public void shouldProperlyLinkDataProviderContainerToTestResult() {
final AllureResults results = runTestNgSuites("suites/data-provider-with-attachment.xml");

final TestResult tr = findTestResultByName(results, "test");
final TestResultContainer dpContainer = results.getTestResultContainers().stream()
.filter(c -> c.getName().equals("test"))
.findFirst()
.orElseThrow(() -> new IllegalStateException("DP container not found"));

assertThat(dpContainer.getChildren())
.contains(tr.getUuid());
}

@AllureFeatures.Fixtures
@Test(description = "Should link multiple tests to data provider container")
public void shouldLinkMultipleTestsToDataProviderContainer() {
final AllureResults results = runTestNgSuites("suites/data-provider-multiple-tests.xml");

final List<TestResult> test1Results = results.getTestResults().stream()
.filter(tr -> tr.getName().equals("test1"))
.collect(Collectors.toList());
final List<TestResult> test2Results = results.getTestResults().stream()
.filter(tr -> tr.getName().equals("test2"))
.collect(Collectors.toList());

assertThat(test1Results).hasSize(2);
assertThat(test2Results).hasSize(2);

final TestResultContainer dpContainer1 = findTestContainerByName(results, "test1");
final TestResultContainer dpContainer2 = findTestContainerByName(results, "test2");

assertThat(dpContainer1.getChildren())
.containsAll(test1Results.stream().map(TestResult::getUuid).collect(Collectors.toList()));
assertThat(dpContainer2.getChildren())
.containsAll(test2Results.stream().map(TestResult::getUuid).collect(Collectors.toList()));
}

@AllureFeatures.Fixtures
@Test(description = "Should link inherited data provider")
public void shouldLinkInheritedDataProvider() {
final AllureResults results = runTestNgSuites("suites/data-provider-inheritance.xml");

final TestResult testBase = findTestResultByName(results, "testBase");
final TestResult testChild = findTestResultByName(results, "testChild");

final TestResultContainer dpContainerBase = findTestContainerByName(results, "testBase");
final TestResultContainer dpContainerChild = findTestContainerByName(results, "testChild");

assertThat(dpContainerBase.getChildren()).contains(testBase.getUuid());
assertThat(dpContainerChild.getChildren()).contains(testChild.getUuid());
}

@AllureFeatures.Fixtures
@Test(description = "Should link correct data provider in multiple classes")
public void shouldLinkCorrectDataProviderInMultipleClasses() {
final AllureResults results = runTestNgSuites("suites/data-provider-multiple-classes.xml");

final TestResult test1 = findTestResultByName(results, "test1");
final TestResult test2 = findTestResultByName(results, "test2");

final TestResultContainer dpContainer1 = findTestContainerByName(results, "test1");
final TestResultContainer dpContainer2 = findTestContainerByName(results, "test2");

assertThat(dpContainer1.getChildren())
.contains(test1.getUuid())
.doesNotContain(test2.getUuid());
assertThat(dpContainer2.getChildren())
.contains(test2.getUuid())
.doesNotContain(test1.getUuid());
}

@AllureFeatures.Fixtures
@Test(description = "Should process parallel data provider")
public void shouldProcessParallelDataProvider() {
final AllureResults results = runTestNgSuites("suites/data-provider-parallel.xml");

assertThat(results.getTestResults()).hasSize(4);
final TestResultContainer dpContainer = findTestContainerByName(results, "test");
assertThat(dpContainer.getChildren()).hasSize(4);
}

private Integer getOrderParameter(final TestResult result) {
return result.getParameters().stream()
.filter(p -> p.getName().equals("order"))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2016-2024 Qameta Software Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.qameta.allure.testng.samples;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class DataProviderInheritanceBase {

@DataProvider
public Object[][] dp() {
return new Object[][]{{"data"}};
}

@Test(dataProvider = "dp")
public void testBase(String s) {
}
}
Loading
Loading