All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.undefinedlabs.scope.rules.TestNGScopeAgentRule Maven / Gradle / Ivy

package com.undefinedlabs.scope.rules;

import com.undefinedlabs.scope.ScopeGlobalTracer;
import com.undefinedlabs.scope.ScopeSpanContainer;
import com.undefinedlabs.scope.coverage.*;
import com.undefinedlabs.scope.coverage.extractor.model.ScopeCoverageData;
import com.undefinedlabs.scope.events.EventFieldsFactory;
import com.undefinedlabs.scope.events.exception.ThrowableEvent;
import com.undefinedlabs.scope.rules.model.TestNGScopeDescription;
import com.undefinedlabs.scope.rules.transformer.ScopeAgentAdvicedTransformer;
import com.undefinedlabs.scope.settings.ScopeSettings;
import com.undefinedlabs.scope.settings.ScopeSettingsResolver;
import com.undefinedlabs.scope.statistics.Statistics;
import com.undefinedlabs.scope.utils.SpanUtils;
import com.undefinedlabs.scope.utils.baggage.BaggageKeys;
import com.undefinedlabs.scope.utils.baggage.BaggageValues;
import com.undefinedlabs.scope.utils.event.EventValues;
import com.undefinedlabs.scope.utils.sourcecode.ExceptionSourceCodeFactory;
import com.undefinedlabs.scope.utils.sourcecode.ExceptionSourceCodeFrame;
import com.undefinedlabs.scope.utils.sourcecode.SourceCodeFrame;
import com.undefinedlabs.scope.utils.sourcecode.SourceCodeFrameFactory;
import com.undefinedlabs.scope.utils.tag.TagKeys;
import com.undefinedlabs.scope.utils.tag.TagValues;
import io.opentracing.Span;
import io.opentracing.Tracer;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import org.apache.commons.lang3.StringUtils;
import org.testng.ITestResult;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static net.bytebuddy.matcher.ElementMatchers.*;

public class TestNGScopeAgentRule extends AbstractScopeAgentRule {

    public static final Map TEST_WAS_STARTED = new HashMap<>();
    public static final Map TEST_WAS_SUCCEED = new HashMap<>();
    public static final Map TEST_WAS_FAILED = new HashMap<>();
    public static final Map TEST_WAS_SKIPPED = new HashMap<>();
    public static final Map SCOPE_SPAN_CONTAINER_BY_TEST_METHOD_MAP = new ConcurrentHashMap<>();

    @Override
    protected Iterable transformers() {
        final Class instrumentedClass = lookUp("org.testng.ITestListener");
        return (instrumentedClass != null) ? Collections.singleton(newAgentBuilder()
            .type(isSubTypeOf(instrumentedClass), isSystemClassLoader()).transform(new ScopeAgentAdvicedTransformer(TestNGStartedTestAdvice.class, named("onTestStart")))
            .type(isSubTypeOf(instrumentedClass), isSystemClassLoader()).transform(new ScopeAgentAdvicedTransformer(TestNGSucceedTestAdvice.class, named("onTestSuccess")))
            .type(isSubTypeOf(instrumentedClass), isSystemClassLoader()).transform(new ScopeAgentAdvicedTransformer(TestNGFailedTestAdvice.class, named("onTestFailure")))
            .type(isSubTypeOf(instrumentedClass), isSystemClassLoader()).transform(new ScopeAgentAdvicedTransformer(TestNGSkippedTestAdvice.class, named("onTestSkipped"))))
                : emptyCollection();
    }

    public static class TestNGStartedTestAdvice {

        @Advice.OnMethodExit
        public static void exit(@Advice.Argument(0) ITestResult testResult) {
            synchronized (TEST_WAS_STARTED) {

                final TestNGScopeDescription testNGScopeDescription = new TestNGScopeDescription(testResult);
                if(Boolean.TRUE.equals(TEST_WAS_STARTED.get(testNGScopeDescription))){
                    return;
                }

                final Tracer tracer = ScopeGlobalTracer.get();
                final SourceCodeFrame sourceCodeFrame = SourceCodeFrameFactory.INSTANCE.createFrame(testNGScopeDescription.getClassName(), testNGScopeDescription.getMethodName());

                final Span span = tracer.buildSpan(testNGScopeDescription.getMethodName() + (StringUtils.isNotEmpty(testNGScopeDescription.getHashedParameterValues()) ? " ("+testNGScopeDescription.getHashedParameterValues()+ ")" : ""))
                        .ignoreActiveSpan()
                        .withTag(TagKeys.COMPONENT, TagValues.Test.Framework.TEST_NG)
                        .withTag(TagKeys.SPAN_KIND, TagValues.SPAN_KIND_TEST)
                        .withTag(TagKeys.Test.TEST_NAME, StringUtils.isNotEmpty(testNGScopeDescription.getMethodName()) ? testNGScopeDescription.getMethodName() + (StringUtils.isNotEmpty(testNGScopeDescription.getHashedParameterValues()) ? " ("+testNGScopeDescription.getHashedParameterValues()+ ")" : "") : "")
                        .withTag(TagKeys.Test.TEST_SUITE, testNGScopeDescription.getClassName())
                        .withTag(TagKeys.Test.TEST_FRAMEWORK, TagValues.Test.Framework.TEST_NG)
                        .withTag(TagKeys.Test.TEST_LANGUAGE, TagValues.Test.Language.JAVA)
                        .withTag(StringUtils.isNotEmpty(sourceCodeFrame.getLinkPathWithMethodBoundaries()) ? TagKeys.Test.TEST_CODE : TagKeys.SOURCE,
                                StringUtils.isNotEmpty(sourceCodeFrame.getLinkPathWithMethodBoundaries()) ? sourceCodeFrame.getLinkPathWithMethodBoundaries() : sourceCodeFrame.getLinkPathWithMethodLine())
                        .start();

                SpanUtils.INSTANCE.setTagObject(span, TagKeys.Test.TEST_ARGUMENTS, !testNGScopeDescription.getParameters().isEmpty() ? testNGScopeDescription.getParameters() : null);

                Statistics.INSTANCE.registerStartedTestSpan(span);
                span.setBaggageItem(BaggageKeys.TRACE_KIND, BaggageValues.TRACE_KIND_TEST);
                SCOPE_SPAN_CONTAINER_BY_TEST_METHOD_MAP.put(testNGScopeDescription, new ScopeSpanContainer(span, tracer.activateSpan(span)));
                TEST_WAS_STARTED.put(testNGScopeDescription, Boolean.TRUE);
            }

        }
    }

    public static class TestNGSucceedTestAdvice {
        @Advice.OnMethodExit
        public static void exit(@Advice.Argument(0) ITestResult testResult) {
            synchronized (TEST_WAS_SUCCEED) {
                final TestNGScopeDescription testNGScopeDescription = new TestNGScopeDescription(testResult);
                if(Boolean.TRUE.equals(TEST_WAS_SUCCEED.get(testNGScopeDescription))){
                    return;
                }

                final ScopeSpanContainer scopeSpanContainer = SCOPE_SPAN_CONTAINER_BY_TEST_METHOD_MAP.get(testNGScopeDescription);
                if( scopeSpanContainer == null ){
                    return;
                }

                final Span span = scopeSpanContainer.getSpan();

                span.setTag(TagKeys.ERROR, false);
                span.setTag(TagKeys.Test.TEST_STATUS, TagValues.Test.TEST_PASS);

                if((boolean) ScopeSettingsResolver.INSTANCE.get().getSetting(ScopeSettings.SCOPE_CODE_COVERAGE)){
                    final CoverageSessionInfo coverageSessionInfo = GlobalCoverageReporter.get().activeSession().close();
                    final CoverageSessionReport coverageReport = CoverageSessionAnalyzer.INSTANCE.analyze(coverageSessionInfo);
                    final ScopeCoverageData coverageData = ScopeCoverageExtractor.INSTANCE.analyze(coverageReport);
                    SpanUtils.INSTANCE.setTagObject(span, TagKeys.Test.TEST_COVERAGE, coverageData);
                }

                span.finish();
                Statistics.INSTANCE.registerFinishedTestSpan(span);

                scopeSpanContainer.getScope().close();
                SCOPE_SPAN_CONTAINER_BY_TEST_METHOD_MAP.remove(testNGScopeDescription);
                TEST_WAS_SUCCEED.put(testNGScopeDescription, Boolean.TRUE);
            }
        }
    }

    public static class TestNGFailedTestAdvice {
        @Advice.OnMethodExit
        public static void exit(@Advice.Argument(0) ITestResult testResult) {
            synchronized (TEST_WAS_FAILED) {
                final TestNGScopeDescription testNGScopeDescription = new TestNGScopeDescription(testResult);
                if(Boolean.TRUE.equals(TEST_WAS_FAILED.get(testNGScopeDescription))){
                    return;
                }

                final ScopeSpanContainer scopeSpanContainer = SCOPE_SPAN_CONTAINER_BY_TEST_METHOD_MAP.get(testNGScopeDescription);
                if ( scopeSpanContainer == null ) {
                    return;
                }

                final Span span = scopeSpanContainer.getSpan();
                final Throwable throwable = testResult.getThrowable();

                final ExceptionSourceCodeFrame exceptionSourceCodeFrame = ExceptionSourceCodeFactory.INSTANCE.createFrame(throwable);
                final ThrowableEvent.Builder throwableEventBuilder = ThrowableEvent.newBuilder();
                throwableEventBuilder
                        .withEventType((exceptionSourceCodeFrame.getUserThrowable() instanceof AssertionError) ? EventValues.Test.TEST_FAILURE : EventValues.Test.TEST_ERROR)
                        .withThrowable(exceptionSourceCodeFrame.getUserThrowable())
                        .withSource(exceptionSourceCodeFrame.getSourceCodeFrame().getLinkPathWithMethodLine());

                span.setTag(TagKeys.ERROR, true);
                span.setTag(TagKeys.Test.TEST_STATUS, (throwable instanceof AssertionError) ? TagValues.Test.TEST_FAIL : TagValues.Test.TEST_ERROR);
                span.log(EventFieldsFactory.INSTANCE.createFields(throwableEventBuilder.build()));

                if((boolean) ScopeSettingsResolver.INSTANCE.get().getSetting(ScopeSettings.SCOPE_CODE_COVERAGE)){
                    final CoverageSessionInfo coverageSessionInfo = GlobalCoverageReporter.get().activeSession().close();
                    final CoverageSessionReport coverageReport = CoverageSessionAnalyzer.INSTANCE.analyze(coverageSessionInfo);
                    final ScopeCoverageData coverageData = ScopeCoverageExtractor.INSTANCE.analyze(coverageReport);
                    SpanUtils.INSTANCE.setTagObject(span, TagKeys.Test.TEST_COVERAGE, coverageData);
                }

                span.finish();
                Statistics.INSTANCE.registerFinishedTestSpan(span);

                scopeSpanContainer.getScope().close();
                SCOPE_SPAN_CONTAINER_BY_TEST_METHOD_MAP.remove(testNGScopeDescription);
                TEST_WAS_FAILED.put(testNGScopeDescription, Boolean.TRUE);
            }
        }
    }

    public static class TestNGSkippedTestAdvice {

        @Advice.OnMethodExit
        public static void exit(@Advice.Argument(0) ITestResult testResult) {
            synchronized (TEST_WAS_SKIPPED) {
                final TestNGScopeDescription testNGScopeDescription = new TestNGScopeDescription(testResult);
                if(Boolean.TRUE.equals(TEST_WAS_SKIPPED.get(testNGScopeDescription))){
                    return;
                }

                final ScopeSpanContainer scopeSpanContainer = SCOPE_SPAN_CONTAINER_BY_TEST_METHOD_MAP.get(testNGScopeDescription);
                if (scopeSpanContainer == null ){
                    return;
                }

                final Span span = scopeSpanContainer.getSpan();

                span.setTag(TagKeys.ERROR, false);
                span.setTag(TagKeys.Test.TEST_STATUS, TagValues.Test.TEST_SKIP);
                span.finish();

                Statistics.INSTANCE.registerFinishedTestSpan(span);
                scopeSpanContainer.getScope().close();
                SCOPE_SPAN_CONTAINER_BY_TEST_METHOD_MAP.remove(testNGScopeDescription);
                TEST_WAS_SKIPPED.put(testNGScopeDescription, Boolean.TRUE);
            }
        }

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy