
com.undefinedlabs.scope.rules.JUnit4RunChildScopeRunnerAgentRule Maven / Gradle / Ivy
package com.undefinedlabs.scope.rules;
import static com.undefinedlabs.scope.agent.ScopeClassLoaderMatcher.hasClassesNamed;
import static net.bytebuddy.matcher.ElementMatchers.named;
import com.undefinedlabs.scope.ScopeGlobalTracer;
import com.undefinedlabs.scope.logger.ScopeLoggerResolver;
import com.undefinedlabs.scope.rules.model.JUnit4ScopeDescription;
import com.undefinedlabs.scope.runner.ScopeGlobalRunner;
import com.undefinedlabs.scope.runner.ScopeRunner;
import com.undefinedlabs.scope.runner.TestStatus;
import com.undefinedlabs.scope.runner.rules.AbstractScopeRunnerAgentRule;
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.tag.TagKeys;
import com.undefinedlabs.scope.utils.tag.TagValues;
import io.opentracing.Span;
import io.opentracing.Tracer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.junit.runner.Description;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
public class JUnit4RunChildScopeRunnerAgentRule extends AbstractScopeRunnerAgentRule {
@Override
protected ElementMatcher super TypeDescription> typeMatcher() {
return named("org.junit.runners.BlockJUnit4ClassRunner");
}
@Override
protected ElementMatcher classLoaderMatcher() {
return hasClassesNamed("org.junit.runners.BlockJUnit4ClassRunner");
}
@Override
protected Map extends ElementMatcher super MethodDescription>, String> transformers() {
final Map, String> transformers = new HashMap<>();
transformers.put(
named("runChild"),
JUnit4RunChildScopeRunnerAgentRule.class.getName() + "$JUnit4RunChildAdvice");
return transformers;
}
public static JUnit4ScopeDescription extractDescription(
final BlockJUnit4ClassRunner runner, final FrameworkMethod frameworkMethod) {
try {
Method describeChild = null;
if (runner
.getClass()
.getName()
.equalsIgnoreCase("org.junit.runners.BlockJUnit4ClassRunner")) {
describeChild = runner.getClass().getDeclaredMethod("describeChild", FrameworkMethod.class);
} else {
describeChild =
runner
.getClass()
.getSuperclass()
.getDeclaredMethod("describeChild", FrameworkMethod.class);
}
describeChild.setAccessible(true);
final Description description = (Description) describeChild.invoke(runner, frameworkMethod);
return new JUnit4ScopeDescription(description);
} catch (final Exception e) {
ScopeLoggerResolver.INSTANCE.get().error("Could not extract JUnit4 Description: " + e);
return null;
}
}
public static class JUnit4RunChildAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static Object enter(
@Advice.This final Object thiz, @Advice.AllArguments final Object[] args) {
final FrameworkMethod fwkMethod = (FrameworkMethod) args[0];
final BlockJUnit4ClassRunner runner = (BlockJUnit4ClassRunner) thiz;
try {
final JUnit4ScopeDescription desc = extractDescription(runner, fwkMethod);
if (desc == null) {
return null;
}
final String testSuite = desc.getClassName();
String testName = desc.getMethodName();
final String runnerClassName = thiz.getClass().getName();
Object[] parameters = null;
switch (runnerClassName) {
// Parameterized tests.
case "org.junit.runners.Parameterized$TestClassRunnerForParameters":
boolean isJunit411 = false;
// JUnit 4.11
try {
final Field paramsField = runner.getClass().getDeclaredField("fParameters");
paramsField.setAccessible(true);
parameters = (Object[]) paramsField.get(runner);
isJunit411 = true;
} catch (final NoSuchFieldException e) {
isJunit411 = false;
}
// JUnit 4.10 or less
if (!isJunit411) {
final Method computeParams = runner.getClass().getDeclaredMethod("computeParams");
computeParams.setAccessible(true);
parameters = (Object[]) computeParams.invoke(runner);
}
break;
case "org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParameters":
final Field paramsField = runner.getClass().getDeclaredField("parameters");
paramsField.setAccessible(true);
parameters = (Object[]) paramsField.get(runner);
break;
}
if (parameters != null) {
final Map parametersMap = new HashMap<>();
for (int i = 0; i < parameters.length; i++) {
parametersMap.put(String.valueOf(i), String.valueOf(parameters[i]));
}
final String hashedParams = SpanUtils.INSTANCE.hashParameters(parametersMap);
testName = desc.getMethodNameNoSpecialChars() + " (" + hashedParams + ")";
}
final ScopeRunner scopeRunner = ScopeGlobalRunner.get();
final List testStatuses = scopeRunner.getTestStatuses(testSuite, testName);
if (!testStatuses.contains(TestStatus.CACHED)) {
return null;
}
final Tracer tracer = ScopeGlobalTracer.get();
final Span span =
tracer
.buildSpan(testName)
.ignoreActiveSpan()
.withTag(TagKeys.COMPONENT, TagValues.Test.Framework.JUNIT_4)
.withTag(TagKeys.SPAN_KIND, TagValues.SPAN_KIND_TEST)
.withTag(TagKeys.Test.TEST_NAME, testName)
.withTag(TagKeys.Test.TEST_SUITE, testSuite)
.withTag(TagKeys.Test.TEST_FRAMEWORK, TagValues.Test.Framework.JUNIT_4)
.withTag(TagKeys.Test.TEST_LANGUAGE, TagValues.Test.Language.JAVA)
.withTag(TagKeys.Test.TEST_STATUS, TagValues.Test.TEST_CACHE)
.withTag(TagKeys.ERROR, false)
.start();
span.setBaggageItem(BaggageKeys.TRACE_KIND, BaggageValues.TRACE_KIND_TEST);
span.finish(SpanUtils.INSTANCE.getStartTimestampMicros(span));
Statistics.INSTANCE.registerRunnerCachedTest(
TagValues.Test.Framework.JUNIT_4, testSuite, testName);
return new Object();
} catch (final Exception e) {
ScopeLoggerResolver.INSTANCE.get().error("Error on ITR JUnit4: " + e);
return null;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy