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

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 typeMatcher() {
    return named("org.junit.runners.BlockJUnit4ClassRunner");
  }

  @Override
  protected ElementMatcher classLoaderMatcher() {
    return hasClassesNamed("org.junit.runners.BlockJUnit4ClassRunner");
  }

  @Override
  protected Map, 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