11package io .qameta .allure .testng ;
22
33import io .qameta .allure .Allure ;
4+ import io .qameta .allure .Flaky ;
5+ import io .qameta .allure .Muted ;
46import io .qameta .allure .model .FixtureResult ;
57import io .qameta .allure .model .Label ;
68import io .qameta .allure .model .Parameter ;
1214import org .slf4j .Logger ;
1315import org .slf4j .LoggerFactory ;
1416import org .testng .IAttributes ;
17+ import org .testng .IClass ;
1518import org .testng .IInvokedMethod ;
1619import org .testng .IInvokedMethodListener2 ;
1720import org .testng .ISuite ;
2124import org .testng .ITestListener ;
2225import org .testng .ITestNGMethod ;
2326import org .testng .ITestResult ;
27+ import org .testng .internal .ConstructorOrMethod ;
2428import org .testng .xml .XmlSuite ;
2529import org .testng .xml .XmlTest ;
2630
31+ import java .lang .annotation .Annotation ;
2732import java .lang .management .ManagementFactory ;
2833import java .math .BigInteger ;
2934import java .net .InetAddress ;
@@ -155,6 +160,9 @@ public void onTestStart(ITestResult testResult) {
155160 .withName (testResult .getName ())
156161 .withFullName (testResult .getMethod ().getQualifiedName ())
157162 .withDescription (method .getDescription ())
163+ .withStatusDetails (new StatusDetails ()
164+ .withFlaky (isFlaky (testResult ))
165+ .withMuted (isMuted (testResult )))
158166 .withParameters (getParameters (testResult ))
159167 .withLabels (labels );
160168 getLifecycle ().scheduleTestCase (parentUuid , result );
@@ -182,7 +190,7 @@ public void onTestFailure(ITestResult result) {
182190
183191 //if test has failed without any setup
184192 if (!current .isStarted ()) {
185- createTestResutForUnexecutedTest (result );
193+ createTestResultForTestWithoutSetup (result );
186194 }
187195
188196 current .after ();
@@ -206,7 +214,7 @@ public void onTestSkipped(ITestResult result) {
206214
207215 //if test was skipped without any setup
208216 if (!current .isStarted ()) {
209- createTestResutForUnexecutedTest (result );
217+ createTestResultForTestWithoutSetup (result );
210218 }
211219 current .after ();
212220 StatusDetails details = getStatusDetails (result .getThrowable ()).orElse (null );
@@ -215,7 +223,7 @@ public void onTestSkipped(ITestResult result) {
215223 getLifecycle ().writeTestCase (current .getUuid ());
216224 }
217225
218- private void createTestResutForUnexecutedTest (ITestResult result ) {
226+ private void createTestResultForTestWithoutSetup (ITestResult result ) {
219227 onTestStart (result );
220228 currentTestResult .remove ();
221229 }
@@ -345,6 +353,35 @@ public void afterInvocation(IInvokedMethod method, ITestResult testResult) {
345353 //do nothing
346354 }
347355
356+ private boolean isFlaky (ITestResult result ) {
357+ return hasAnnotation (result , Flaky .class );
358+ }
359+
360+ private boolean isMuted (ITestResult result ) {
361+ return hasAnnotation (result , Muted .class );
362+ }
363+
364+ private boolean hasAnnotation (ITestResult result , Class <? extends Annotation > clazz ) {
365+ return hasAnnotationOnMethod (result , clazz ) || hasAnnotationOnClass (result , clazz );
366+ }
367+
368+ private boolean hasAnnotationOnClass (ITestResult result , Class <? extends Annotation > clazz ) {
369+ return Optional .of (result )
370+ .map (ITestResult ::getTestClass )
371+ .map (IClass ::getRealClass )
372+ .map (aClass -> aClass .isAnnotationPresent (clazz ))
373+ .orElse (false );
374+ }
375+
376+ private boolean hasAnnotationOnMethod (ITestResult result , Class <? extends Annotation > clazz ) {
377+ return Optional .of (result )
378+ .map (ITestResult ::getMethod )
379+ .map (ITestNGMethod ::getConstructorOrMethod )
380+ .map (ConstructorOrMethod ::getMethod )
381+ .map (method -> method .isAnnotationPresent (clazz ))
382+ .orElse (false );
383+ }
384+
348385 /**
349386 * Returns the unique id for given results item.
350387 */
0 commit comments