/* * Copyright 2010 Henry Coles * * 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 org.pitest.coverage.execute; import static org.pitest.util.Unchecked.translateCheckedException; import java.io.BufferedOutputStream; import java.io.IOException; import java.net.Socket; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.pitest.boot.HotSwapAgent; import org.pitest.classinfo.ClassName; import org.pitest.classpath.ClassPathByteArraySource; import org.pitest.coverage.CoverageTransformer; import org.pitest.dependency.DependencyExtractor; import org.pitest.functional.FCollection; import org.pitest.functional.predicate.Predicate; import org.pitest.functional.prelude.Prelude; import org.pitest.help.PitHelpError; import org.pitest.mutationtest.mocksupport.BendJavassistToMyWillTransformer; import org.pitest.mutationtest.mocksupport.JavassistInputStreamInterceptorAdapater; import org.pitest.testapi.TestUnit; import org.pitest.testapi.execute.FindTestUnits; import org.pitest.util.ExitCode; import org.pitest.util.Glob; import org.pitest.util.Log; import org.pitest.util.SafeDataInputStream; import sun.pitest.CodeCoverageStore; public class CoverageMinion { private static final Logger LOG = Log.getLogger(); public static void main(final String[] args) { enablePowerMockSupport(); ExitCode exitCode = ExitCode.OK; Socket s = null; CoveragePipe invokeQueue = null; try { final int port = Integer.parseInt(args[0]); s = new Socket("localhost", port); final SafeDataInputStream dis = new SafeDataInputStream( s.getInputStream()); final CoverageOptions paramsFromParent = dis.read(CoverageOptions.class); Log.setVerbose(paramsFromParent.isVerbose()); invokeQueue = new CoveragePipe(new BufferedOutputStream( s.getOutputStream())); CodeCoverageStore.init(invokeQueue); LOG.info("Checking environment"); if (paramsFromParent.getPitConfig().verifyEnvironment().hasSome()) { throw paramsFromParent.getPitConfig().verifyEnvironment().value(); } HotSwapAgent.addTransformer(new CoverageTransformer( convertToJVMClassFilter(paramsFromParent.getFilter()))); final List<TestUnit> tus = getTestsFromParent(dis, paramsFromParent); LOG.info(tus.size() + " tests received"); final CoverageWorker worker = new CoverageWorker(invokeQueue, tus); worker.run(); } catch (final PitHelpError phe) { LOG.log(Level.SEVERE, phe.getMessage()); exitCode = ExitCode.JUNIT_ISSUE; } catch (final Throwable ex) { ex.printStackTrace(System.out); LOG.log(Level.SEVERE, "Error calculating coverage. Process will exit.", ex); exitCode = ExitCode.UNKNOWN_ERROR; } finally { if (invokeQueue != null) { invokeQueue.end(exitCode); } try { if (s != null) { s.close(); } } catch (final IOException e) { throw translateCheckedException(e); } } System.exit(exitCode.getCode()); } @SuppressWarnings("unchecked") private static void enablePowerMockSupport() { // Bwahahahahahahaha HotSwapAgent.addTransformer(new BendJavassistToMyWillTransformer(Prelude .or(new Glob("javassist/*")), JavassistInputStreamInterceptorAdapater.inputStreamAdapterSupplier(JavassistCoverageInterceptor.class))); } private static Predicate<String> convertToJVMClassFilter( final Predicate<String> child) { return new Predicate<String>() { @Override public Boolean apply(final String a) { return child.apply(a.replace("/", ".")); } }; } private static List<TestUnit> getTestsFromParent( final SafeDataInputStream dis, final CoverageOptions paramsFromParent) throws IOException { final List<ClassName> classes = receiveTestClassesFromParent(dis); Collections.sort(classes); // ensure classes loaded in a consistent order final List<TestUnit> tus = discoverTests(paramsFromParent, classes); final DependencyFilter filter = new DependencyFilter( new DependencyExtractor(new ClassPathByteArraySource(), paramsFromParent.getDependencyAnalysisMaxDistance()), paramsFromParent.getFilter()); final List<TestUnit> filteredTus = filter .filterTestsByDependencyAnalysis(tus); LOG.info("Dependency analysis reduced number of potential tests by " + (tus.size() - filteredTus.size())); return filteredTus; } private static List<TestUnit> discoverTests( final CoverageOptions paramsFromParent, final List<ClassName> classes) { final FindTestUnits finder = new FindTestUnits( paramsFromParent.getPitConfig()); final List<TestUnit> tus = finder .findTestUnitsForAllSuppliedClasses(FCollection.flatMap(classes, ClassName.nameToClass())); LOG.info("Found " + tus.size() + " tests"); return tus; } private static List<ClassName> receiveTestClassesFromParent( final SafeDataInputStream dis) { final int count = dis.readInt(); LOG.fine("Expecting " + count + " tests classes from parent"); final List<ClassName> classes = new ArrayList<ClassName>(count); for (int i = 0; i != count; i++) { classes.add(new ClassName(dis.readString())); } LOG.fine("Tests classes received"); return classes; } }