/* * Copyright 2014 NAVER Corp. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.navercorp.pinpoint.test.plugin; import org.junit.runner.Description; import org.junit.runner.manipulation.Filter; import org.junit.runner.manipulation.NoTestsRemainException; import org.junit.runner.manipulation.Sorter; import org.junit.runner.notification.RunNotifier; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; import org.junit.runners.model.RunnerScheduler; import org.junit.runners.model.Statement; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; /** * * We have referred OrderedThreadPoolExecutor ParentRunner of JUnit. * * @author Jongho Moon * @author Taejin Koo * */ public class PinpointPluginTestRunner extends BlockJUnit4ClassRunner { private final PinpointPluginTestContext context; private final PinpointPluginTestInstance testCase; private final Object childrenLock = new Object(); private volatile Collection<FrameworkMethod> filteredChildren = null; private volatile RunnerScheduler scheduler = new RunnerScheduler() { public void schedule(Runnable childStatement) { childStatement.run(); } public void finished() { // do nothing } }; PinpointPluginTestRunner(PinpointPluginTestContext context, PinpointPluginTestInstance testCase) throws InitializationError { super(context.getTestClass()); this.context = context; this.testCase = testCase; } @Override protected String getName() { return String.format("[%s]", testCase.getTestId()); } @Override protected String testName(final FrameworkMethod method) { return String.format("%s[%s]", method.getName(), testCase.getTestId()); } @Override protected Statement classBlock(RunNotifier notifier) { return new PinpointPluginTestStatement(this, notifier, context, testCase); } @Override public void filter(Filter filter) throws NoTestsRemainException { synchronized (childrenLock) { List<FrameworkMethod> children = new ArrayList<FrameworkMethod>(getFilteredChildren()); for (Iterator<FrameworkMethod> iter = children.iterator(); iter.hasNext(); ) { FrameworkMethod each = iter.next(); if (shouldRun(filter, each)) { try { filter.apply(each); } catch (NoTestsRemainException e) { iter.remove(); } } else { iter.remove(); } } filteredChildren = Collections.unmodifiableCollection(children); if (filteredChildren.isEmpty()) { throw new NoTestsRemainException(); } } } private Collection<FrameworkMethod> getFilteredChildren() { if (filteredChildren == null) { synchronized (childrenLock) { if (filteredChildren == null) { filteredChildren = Collections.unmodifiableCollection(getChildren()); } } } return filteredChildren; } public void sort(Sorter sorter) { synchronized (childrenLock) { for (FrameworkMethod each : getFilteredChildren()) { sorter.apply(each); } List<FrameworkMethod> sortedChildren = new ArrayList<FrameworkMethod>(getFilteredChildren()); Collections.sort(sortedChildren, comparator(sorter)); filteredChildren = Collections.unmodifiableCollection(sortedChildren); } } private Comparator<? super FrameworkMethod> comparator(final Sorter sorter) { return new Comparator<FrameworkMethod>() { public int compare(FrameworkMethod o1, FrameworkMethod o2) { return sorter.compare(describeChild(o1), describeChild(o2)); } }; } private void runChildren(final RunNotifier notifier) { final RunnerScheduler currentScheduler = scheduler; try { for (final FrameworkMethod each : getFilteredChildren()) { currentScheduler.schedule(new Runnable() { public void run() { runChild(each, notifier); } }); } } finally { currentScheduler.finished(); } } protected Statement childrenInvoker(final RunNotifier notifier) { return new Statement() { @Override public void evaluate() { runChildren(notifier); } }; } boolean isAvaiable(Filter filter) { synchronized (childrenLock) { List<FrameworkMethod> children = new ArrayList<FrameworkMethod>(getFilteredChildren()); for (FrameworkMethod method : children) { if (shouldRun(filter, method)) { return true; } } } return false; } private boolean shouldRun(Filter filter, FrameworkMethod each) { if (filter.shouldRun(describeChild(each))) { return true; } String testDescribe = PinpointPluginTestUtils.getTestDescribe(each.getMethod()); return testDescribe.equals(filter.describe()); } @Override public Description getDescription() { Description description = Description.createSuiteDescription(getName(), getRunnerAnnotations()); for (FrameworkMethod child : getFilteredChildren()) { description.addChild(describeChild(child)); } return description; } }