1 /* 2 * Copyright (C) 2013 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.caliper.runner; 16 17 import static com.google.common.base.Preconditions.checkState; 18 19 import com.google.caliper.config.InvalidConfigurationException; 20 import com.google.caliper.model.Trial; 21 import com.google.caliper.util.InvalidCommandException; 22 import com.google.common.collect.ImmutableList; 23 import com.google.common.collect.Lists; 24 import com.google.common.io.Files; 25 26 import org.junit.rules.TestWatcher; 27 import org.junit.runner.Description; 28 29 import java.io.File; 30 import java.io.PrintWriter; 31 import java.io.StringWriter; 32 import java.util.Arrays; 33 import java.util.List; 34 35 /** 36 * A {@link TestWatcher} that can be used to configure a run of caliper. 37 * 38 * <p>Provides common test configuration utilities and redirects output to a buffer and only dumps 39 * it during a failure. 40 * 41 * <p>TODO(lukes,gak): This is a bad name since it isn't just watching the tests, it is helping you 42 * run the tests. 43 */ 44 public final class CaliperTestWatcher extends TestWatcher { 45 // N.B. StringWriter is internally synchronized and is safe to write to from multiple threads. 46 private StringWriter stdout; 47 private final StringWriter stderr = new StringWriter(); 48 private File workerOutput; 49 50 private String instrument; 51 private Class<?> benchmarkClass; 52 private List<String> extraOptions = Lists.newArrayList(); 53 forBenchmark(Class<?> benchmarkClass)54 CaliperTestWatcher forBenchmark(Class<?> benchmarkClass) { 55 this.benchmarkClass = benchmarkClass; 56 return this; 57 } 58 instrument(String instrument)59 CaliperTestWatcher instrument(String instrument) { 60 this.instrument = instrument; 61 return this; 62 } 63 options(String... extraOptions)64 CaliperTestWatcher options(String... extraOptions) { 65 this.extraOptions = Arrays.asList(extraOptions); 66 return this; 67 } 68 run()69 void run() throws InvalidCommandException, InvalidBenchmarkException, 70 InvalidConfigurationException { 71 checkState(benchmarkClass != null, "You must configure a benchmark!"); 72 workerOutput = Files.createTempDir(); 73 // configure a custom dir so the files aren't deleted when CaliperMain returns 74 List<String> options = Lists.newArrayList( 75 "-Cworker.output=" + workerOutput.getPath(), 76 "-Cresults.file.class=", 77 "-Cresults.upload.class=" + InMemoryResultsUploader.class.getName()); 78 if (instrument != null) { 79 options.add("-i"); 80 options.add(instrument); 81 } 82 options.addAll(extraOptions); 83 options.add(benchmarkClass.getName()); 84 this.stdout = new StringWriter(); 85 CaliperMain.exitlessMain( 86 options.toArray(new String[0]), 87 new PrintWriter(stdout, true), 88 new PrintWriter(stderr, true)); 89 } 90 finished(Description description)91 @Override protected void finished(Description description) { 92 if (workerOutput != null) { 93 for (File f : workerOutput.listFiles()) { 94 f.delete(); 95 } 96 workerOutput.delete(); 97 } 98 } 99 failed(Throwable e, Description description)100 @Override protected void failed(Throwable e, Description description) { 101 // don't log if run was never called. 102 if (stdout != null) { 103 System.err.println("Caliper failed with the following output (stdout):\n" 104 + stdout.toString() + "stderr:\n" + stderr.toString()); 105 } 106 } 107 trials()108 ImmutableList<Trial> trials() { 109 return InMemoryResultsUploader.trials(); 110 } 111 getStderr()112 public StringWriter getStderr() { 113 return stderr; 114 } 115 getStdout()116 public StringWriter getStdout() { 117 return stdout; 118 } 119 workerOutputDirectory()120 File workerOutputDirectory() { 121 return workerOutput; 122 } 123 } 124