
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 extends AgentBuilder> 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