/* * 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 java.io.File; import java.lang.management.ManagementFactory; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.security.CodeSource; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.aether.resolution.ArtifactResolutionException; import org.eclipse.aether.resolution.DependencyResolutionException; import org.junit.internal.runners.statements.RunAfters; import org.junit.internal.runners.statements.RunBefores; import org.junit.runner.Runner; import org.junit.runners.Suite; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; import org.junit.runners.model.Statement; import com.navercorp.pinpoint.common.Version; import com.navercorp.pinpoint.common.util.SystemProperty; import com.navercorp.pinpoint.exception.PinpointException; public abstract class AbstractPinpointPluginTestSuite extends Suite { private static final int NO_JVM_VERSION = -1; private static final String[] REQUIRED_CLASS_PATHS = new String[] { "junit", // JUnit "hamcrest-core", // for JUnit "pinpoint-test", // pinpoint-test-{VERSION}.jar "/test/target/classes" // pinpoint-test build output directory }; private final List<String> requiredLibraries; private final String testClassLocation; private final String agentJar; private final String configFile; private final String[] jvmArguments; private final int[] jvmVersions; private final boolean debug; public AbstractPinpointPluginTestSuite(Class<?> testClass) throws InitializationError, ArtifactResolutionException, DependencyResolutionException { super(testClass, Collections.<Runner> emptyList()); PinpointAgent agent = testClass.getAnnotation(PinpointAgent.class); this.agentJar = resolveAgentPath(agent); PinpointConfig config = testClass.getAnnotation(PinpointConfig.class); this.configFile = config == null ? null : resolveConfigFileLocation(config.value()); JvmArgument jvmArgument = testClass.getAnnotation(JvmArgument.class); this.jvmArguments = jvmArgument == null ? new String[0] : jvmArgument.value(); JvmVersion jvmVersion = testClass.getAnnotation(JvmVersion.class); this.jvmVersions = jvmVersion == null ? new int[] { NO_JVM_VERSION } : jvmVersion.value(); this.requiredLibraries = resolveRequiredLibraries(); this.testClassLocation = resolveTestClassLocation(testClass); this.debug = isDebugMode(); } protected String getJavaExecutable(int version) { StringBuilder builder = new StringBuilder(); String javaHome; if (version == NO_JVM_VERSION) { javaHome = SystemProperty.INSTANCE.getProperty("java.home"); } else { String envName = "JAVA_" + version + "_HOME"; javaHome = SystemProperty.INSTANCE.getEnv(envName); } if (javaHome == null) { return null; } builder.append(javaHome); builder.append(File.separatorChar); builder.append("bin"); builder.append(File.separatorChar); builder.append("java"); if (SystemProperty.INSTANCE.getProperty("os.name").contains("indows")) { builder.append(".exe"); } return builder.toString(); } private String resolveTestClassLocation(Class<?> testClass) { CodeSource codeSource = testClass.getProtectionDomain().getCodeSource(); URL testClassLocation = codeSource.getLocation(); return toPathString(testClassLocation); } private List<String> resolveRequiredLibraries() { List<String> result = new ArrayList<String>(); ClassLoader cl = getClass().getClassLoader(); while (true) { if (cl instanceof URLClassLoader) { findRequiredLibraries(result, (URLClassLoader)cl); } cl = cl.getParent(); if (cl == null) { break; } } return result; } private void findRequiredLibraries(List<String> result, URLClassLoader cl) { outer: for (URL url : cl.getURLs()) { for (String required : REQUIRED_CLASS_PATHS) { if (url.getFile().contains(required)) { result.add(toPathString(url)); continue outer; } } } } private String toPathString(URL url) { try { return new File(url.toURI()).getAbsolutePath(); } catch (URISyntaxException e) { throw new RuntimeException("???", e); } } private String resolveAgentPath(PinpointAgent agent) { String path = agent == null ? "agent/target/pinpoint-agent-" + Version.VERSION : agent.value(); String version = agent == null ? Version.VERSION : agent.version(); String relativePath = path + (!path.endsWith("/") ? "/" : "") + "pinpoint-bootstrap-" + version + ".jar"; File parent = new File(".").getAbsoluteFile(); while (true) { File candidate = new File(parent, relativePath); if (candidate.exists()) { return candidate.getAbsolutePath(); } parent = parent.getParentFile(); if (parent == null) { throw new IllegalArgumentException("Cannot find agent path: " + relativePath); } } } private String resolveConfigFileLocation(String configFile) { URL url = getClass().getResource(configFile.startsWith("/") ? configFile : "/" + configFile); if (url != null) { return toPathString(url); } File config = new File(configFile); if (config.exists()) { return config.getAbsolutePath(); } throw new PinpointException("Cannot find pinpoint configuration file: " + configFile); } private boolean isDebugMode() { return ManagementFactory.getRuntimeMXBean().getInputArguments().toString().contains("jdwp"); } @Override protected Statement withBeforeClasses(Statement statement) { List<FrameworkMethod> befores= getTestClass().getAnnotatedMethods(BeforePinpointPluginTest.class); return befores.isEmpty() ? statement : new RunBefores(statement, befores, null); } @Override protected Statement withAfterClasses(Statement statement) { List<FrameworkMethod> afters= getTestClass().getAnnotatedMethods(AfterPinpointPluginTest.class); return afters.isEmpty() ? statement : new RunAfters(statement, afters, null); } @Override protected List<Runner> getChildren() { List<Runner> runners = new ArrayList<Runner>(); try { for (int ver : jvmVersions) { String javaExe = getJavaExecutable(ver); // TODO for now, java 8 is not mandatory to build pinpoint. // so failing to find java installation should not cause build failure. if (javaExe == null) { System.out.println("Cannot find Java version " + ver + ". Skip test with Java " + ver); continue; } PinpointPluginTestContext context = new PinpointPluginTestContext(agentJar, configFile, requiredLibraries, getTestClass().getJavaClass(), testClassLocation, jvmArguments, debug, ver, javaExe); List<PinpointPluginTestInstance> cases = createTestCases(context); for (PinpointPluginTestInstance c : cases) { runners.add(new PinpointPluginTestRunner(context, c)); } } } catch (Exception e) { System.out.println(e.getMessage()); throw new RuntimeException("Fail to create test runners", e); } if (runners.isEmpty()) { throw new RuntimeException("No test"); } return runners; } protected abstract List<PinpointPluginTestInstance> createTestCases(PinpointPluginTestContext context) throws Exception; }