private int runTestsExternal( final CommandRunnerParams params, Build build, Iterable<String> command, Iterable<TestRule> testRules) throws InterruptedException, IOException { TestRunningOptions options = getTestRunningOptions(params); // Walk the test rules, collecting all the specs. List<ExternalTestRunnerTestSpec> specs = Lists.newArrayList(); for (TestRule testRule : testRules) { if (!(testRule instanceof ExternalTestRunnerRule)) { params .getBuckEventBus() .post( ConsoleEvent.severe( String.format( "Test %s does not support external test running", testRule.getBuildTarget()))); return 1; } ExternalTestRunnerRule rule = (ExternalTestRunnerRule) testRule; specs.add(rule.getExternalTestRunnerSpec(build.getExecutionContext(), options)); } // Serialize the specs to a file to pass into the test runner. Path infoFile = params .getCell() .getFilesystem() .resolve(BuckConstant.SCRATCH_PATH.resolve("external_runner_specs.json")); Files.createDirectories(infoFile.getParent()); Files.deleteIfExists(infoFile); params.getObjectMapper().writerWithDefaultPrettyPrinter().writeValue(infoFile.toFile(), specs); // Launch and run the external test runner, forwarding it's stdout/stderr to the console. // We wait for it to complete then returns its error code. ListeningProcessExecutor processExecutor = new ListeningProcessExecutor(); ProcessExecutorParams processExecutorParams = ProcessExecutorParams.builder() .addAllCommand(command) .addAllCommand(withDashArguments) .addCommand("--buck-test-info", infoFile.toString()) .setDirectory(params.getCell().getFilesystem().getRootPath().toFile()) .build(); ForwardingProcessListener processListener = new ForwardingProcessListener( Channels.newChannel(params.getConsole().getStdOut()), Channels.newChannel(params.getConsole().getStdErr())); ListeningProcessExecutor.LaunchedProcess process = processExecutor.launchProcess(processExecutorParams, processListener); try { return processExecutor.waitForProcess(process, Long.MAX_VALUE, TimeUnit.DAYS); } finally { processExecutor.destroyProcess(process, /* force */ false); processExecutor.waitForProcess(process, Long.MAX_VALUE, TimeUnit.DAYS); } }
static int executeBuildAndPrintAnyFailuresToConsole(Build build, Console console) { Set<BuildRule> rulesToBuild = build.getDependencyGraph().getNodesWithNoIncomingEdges(); int exitCode; try { // Get the Future representing the build and then block until everything is built. build.executeBuild(rulesToBuild).get(); exitCode = 0; } catch (IOException e) { console.printBuildFailureWithoutStacktrace(e); exitCode = 1; } catch (StepFailedException e) { console.printBuildFailureWithoutStacktrace(e); exitCode = e.getExitCode(); } catch (ExecutionException e) { // This is likely a checked exception that was caught while building a build rule. Throwable cause = e.getCause(); if (cause instanceof HumanReadableException) { throw ((HumanReadableException) cause); } else if (cause instanceof ExceptionWithHumanReadableMessage) { throw new HumanReadableException((ExceptionWithHumanReadableMessage) cause); } else { if (cause instanceof RuntimeException) { console.printBuildFailureWithStacktrace(e); } else { console.printBuildFailureWithoutStacktrace(e); } exitCode = 1; } } catch (InterruptedException e) { // This suggests an error in Buck rather than a user error. // Print the entire stack trace so we can debug it. console.printBuildFailureWithStacktrace(e); exitCode = 1; } return exitCode; }
private int runTestsInternal( CommandRunnerParams params, BuildEngine buildEngine, Build build, Iterable<TestRule> testRules) throws InterruptedException, IOException { if (!withDashArguments.isEmpty()) { params .getBuckEventBus() .post( ConsoleEvent.severe("Unexpected arguments after \"--\" when using internal runner")); return 1; } ConcurrencyLimit concurrencyLimit = new ConcurrencyLimit( getNumTestThreads(params.getBuckConfig()), params.getBuckConfig().getLoadLimit()); try (CommandThreadManager testPool = new CommandThreadManager( "Test-Run", params.getBuckConfig().getWorkQueueExecutionOrder(), concurrencyLimit)) { return TestRunning.runTests( params, testRules, Preconditions.checkNotNull(build.getBuildContext()), build.getExecutionContext(), getTestRunningOptions(params), testPool.getExecutor(), buildEngine, new DefaultStepRunner(build.getExecutionContext())); } catch (ExecutionException e) { params .getBuckEventBus() .post(ConsoleEvent.severe(MoreExceptions.getHumanReadableOrLocalizedMessage(e))); return 1; } }
@Override @SuppressWarnings("PMD.PrematureDeclaration") int runCommandWithOptionsInternal(BuildCommandOptions options) throws IOException { // Set the logger level based on the verbosity option. Verbosity verbosity = console.getVerbosity(); Logging.setLoggingLevelForVerbosity(verbosity); // Create artifact cache to initialize Cassandra connection, if appropriate. ArtifactCache artifactCache = getArtifactCache(); try { buildTargets = getBuildTargets(options.getArgumentsFormattedAsBuildTargets()); } catch (NoSuchBuildTargetException e) { console.printBuildFailureWithoutStacktrace(e); return 1; } if (buildTargets.isEmpty()) { console.printBuildFailure("Must specify at least one build target."); // If there are aliases defined in .buckconfig, suggest that the user // build one of them. We show the user only the first 10 aliases. ImmutableSet<String> aliases = options.getBuckConfig().getAliases(); if (!aliases.isEmpty()) { console .getStdErr() .println( String.format( "Try building one of the following targets:\n%s", Joiner.on(' ').join(Iterators.limit(aliases.iterator(), 10)))); } return 1; } getBuckEventBus().post(BuildEvent.started(buildTargets)); // Parse the build files to create a DependencyGraph. DependencyGraph dependencyGraph; try { dependencyGraph = getParser() .parseBuildFilesForTargets( buildTargets, options.getDefaultIncludes(), getBuckEventBus()); } catch (BuildTargetException | BuildFileParseException e) { console.printBuildFailureWithoutStacktrace(e); return 1; } // Create and execute the build. build = options.createBuild( options.getBuckConfig(), dependencyGraph, getProjectFilesystem(), getAndroidDirectoryResolver(), artifactCache, console, getBuckEventBus(), Optional.<TargetDevice>absent(), getCommandRunnerParams().getPlatform()); int exitCode = 0; try { exitCode = executeBuildAndPrintAnyFailuresToConsole(build, console); } finally { // Shutdown the Executor Service once the build completes. // Note: we need to use shutdown() instead of shutdownNow() to ensure that tasks submitted to // the Execution Service are completed. build.getStepRunner().getListeningExecutorService().shutdown(); } getBuckEventBus().post(BuildEvent.finished(buildTargets, exitCode)); if (exitCode != 0) { return exitCode; } return 0; }
@Override public int runWithoutHelp(CommandRunnerParams params) throws IOException, InterruptedException { LOG.debug("Running with arguments %s", getArguments()); try (CommandThreadManager pool = new CommandThreadManager( "Test", params.getBuckConfig().getWorkQueueExecutionOrder(), getConcurrencyLimit(params.getBuckConfig()))) { // Post the build started event, setting it to the Parser recorded start time if appropriate. BuildEvent.Started started = BuildEvent.started(getArguments()); if (params.getParser().getParseStartTime().isPresent()) { params.getBuckEventBus().post(started, params.getParser().getParseStartTime().get()); } else { params.getBuckEventBus().post(started); } // The first step is to parse all of the build files. This will populate the parser and find // all of the test rules. TargetGraph targetGraph; ImmutableSet<BuildTarget> explicitBuildTargets; try { // If the user asked to run all of the tests, parse all of the build files looking for any // test rules. if (isRunAllTests()) { targetGraph = params .getParser() .buildTargetGraphForTargetNodeSpecs( params.getBuckEventBus(), params.getCell(), getEnableProfiling(), pool.getExecutor(), ImmutableList.of( TargetNodePredicateSpec.of( new Predicate<TargetNode<?>>() { @Override public boolean apply(TargetNode<?> input) { return input.getType().isTestRule(); } }, BuildFileSpec.fromRecursivePath(Paths.get(""))))) .getSecond(); explicitBuildTargets = ImmutableSet.of(); // Otherwise, the user specified specific test targets to build and run, so build a graph // around these. } else { LOG.debug("Parsing graph for arguments %s", getArguments()); Pair<ImmutableSet<BuildTarget>, TargetGraph> result = params .getParser() .buildTargetGraphForTargetNodeSpecs( params.getBuckEventBus(), params.getCell(), getEnableProfiling(), pool.getExecutor(), parseArgumentsAsTargetNodeSpecs(params.getBuckConfig(), getArguments())); targetGraph = result.getSecond(); explicitBuildTargets = result.getFirst(); LOG.debug("Got explicit build targets %s", explicitBuildTargets); ImmutableSet.Builder<BuildTarget> testTargetsBuilder = ImmutableSet.builder(); for (TargetNode<?> node : targetGraph.getAll(explicitBuildTargets)) { ImmutableSortedSet<BuildTarget> nodeTests = TargetNodes.getTestTargetsForNode(node); if (!nodeTests.isEmpty()) { LOG.debug("Got tests for target %s: %s", node.getBuildTarget(), nodeTests); testTargetsBuilder.addAll(nodeTests); } } ImmutableSet<BuildTarget> testTargets = testTargetsBuilder.build(); if (!testTargets.isEmpty()) { LOG.debug("Got related test targets %s, building new target graph...", testTargets); targetGraph = params .getParser() .buildTargetGraph( params.getBuckEventBus(), params.getCell(), getEnableProfiling(), pool.getExecutor(), Iterables.concat(explicitBuildTargets, testTargets)); LOG.debug("Finished building new target graph with tests."); } } } catch (BuildTargetException | BuildFileParseException e) { params .getBuckEventBus() .post(ConsoleEvent.severe(MoreExceptions.getHumanReadableOrLocalizedMessage(e))); return 1; } TargetGraphToActionGraph targetGraphToActionGraph = new TargetGraphToActionGraph( params.getBuckEventBus(), new BuildTargetNodeToBuildRuleTransformer()); Pair<ActionGraph, BuildRuleResolver> actionGraphAndResolver = Preconditions.checkNotNull(targetGraphToActionGraph.apply(targetGraph)); // Look up all of the test rules in the action graph. Iterable<TestRule> testRules = Iterables.filter(actionGraphAndResolver.getFirst().getNodes(), TestRule.class); // Unless the user requests that we build filtered tests, filter them out here, before // the build. if (!isBuildFiltered(params.getBuckConfig())) { testRules = filterTestRules(params.getBuckConfig(), explicitBuildTargets, testRules); } if (isDryRun()) { printMatchingTestRules(params.getConsole(), testRules); } CachingBuildEngine cachingBuildEngine = new CachingBuildEngine( pool.getExecutor(), params.getFileHashCache(), getBuildEngineMode().or(params.getBuckConfig().getBuildEngineMode()), params.getBuckConfig().getDependencySchedulingOrder(), params.getBuckConfig().getBuildDepFiles(), params.getBuckConfig().getBuildMaxDepFileCacheEntries(), actionGraphAndResolver.getSecond()); try (Build build = createBuild( params.getBuckConfig(), actionGraphAndResolver.getFirst(), actionGraphAndResolver.getSecond(), params.getAndroidPlatformTargetSupplier(), cachingBuildEngine, params.getArtifactCache(), params.getConsole(), params.getBuckEventBus(), getTargetDeviceOptional(), params.getPlatform(), params.getEnvironment(), params.getObjectMapper(), params.getClock(), Optional.of(getAdbOptions(params.getBuckConfig())), Optional.of(getTargetDeviceOptions()))) { // Build all of the test rules. int exitCode = build.executeAndPrintFailuresToEventBus( testRules, isKeepGoing(), params.getBuckEventBus(), params.getConsole(), getPathToBuildReport(params.getBuckConfig())); params.getBuckEventBus().post(BuildEvent.finished(started, exitCode)); if (exitCode != 0) { return exitCode; } // If the user requests that we build tests that we filter out, then we perform // the filtering here, after we've done the build but before we run the tests. if (isBuildFiltered(params.getBuckConfig())) { testRules = filterTestRules(params.getBuckConfig(), explicitBuildTargets, testRules); } // Once all of the rules are built, then run the tests. Optional<ImmutableList<String>> externalTestRunner = params.getBuckConfig().getExternalTestRunner(); if (externalTestRunner.isPresent()) { return runTestsExternal(params, build, externalTestRunner.get(), testRules); } return runTestsInternal(params, cachingBuildEngine, build, testRules); } } }
@Override public int runWithoutHelp(CommandRunnerParams params) throws IOException, InterruptedException { if (getArguments().isEmpty()) { params.getConsole().printBuildFailure("Must specify at least one build target to fetch."); return 1; } // Post the build started event, setting it to the Parser recorded start time if appropriate. BuildEvent.Started started = BuildEvent.started(getArguments()); if (params.getParser().getParseStartTime().isPresent()) { params.getBuckEventBus().post(started, params.getParser().getParseStartTime().get()); } else { params.getBuckEventBus().post(started); } FetchTargetNodeToBuildRuleTransformer ruleGenerator = createFetchTransformer(params); TargetGraphToActionGraph transformer = new TargetGraphToActionGraph( params.getBuckEventBus(), ruleGenerator, params.getFileHashCache()); ActionGraph actionGraph; ImmutableSet<BuildTarget> buildTargets; try { Pair<ImmutableSet<BuildTarget>, TargetGraph> result = params .getParser() .buildTargetGraphForTargetNodeSpecs( parseArgumentsAsTargetNodeSpecs( params.getBuckConfig(), params.getRepository().getFilesystem().getIgnorePaths(), getArguments()), new ParserConfig(params.getBuckConfig()), params.getBuckEventBus(), params.getConsole(), params.getEnvironment(), getEnableProfiling()); actionGraph = transformer.apply(result.getSecond()); buildTargets = ruleGenerator.getDownloadableTargets(); } catch (BuildTargetException | BuildFileParseException e) { params.getConsole().printBuildFailureWithoutStacktrace(e); return 1; } int exitCode; SourcePathResolver pathResolver = new SourcePathResolver(transformer.getRuleResolver()); try (CommandThreadManager pool = new CommandThreadManager("Fetch", getConcurrencyLimit(params.getBuckConfig())); Build build = createBuild( params.getBuckConfig(), actionGraph, params.getAndroidPlatformTargetSupplier(), new CachingBuildEngine( pool.getExecutor(), params.getFileHashCache(), getBuildEngineMode().or(params.getBuckConfig().getBuildEngineMode()), params.getBuckConfig().getBuildDepFiles(), new InputBasedRuleKeyBuilderFactory(params.getFileHashCache(), pathResolver), new AbiRuleKeyBuilderFactory(params.getFileHashCache(), pathResolver), new DependencyFileRuleKeyBuilderFactory( params.getFileHashCache(), pathResolver)), getArtifactCache(params), params.getConsole(), params.getBuckEventBus(), Optional.<TargetDevice>absent(), params.getPlatform(), params.getEnvironment(), params.getObjectMapper(), params.getClock(), Optional.<AdbOptions>absent(), Optional.<TargetDeviceOptions>absent())) { exitCode = build.executeAndPrintFailuresToEventBus( buildTargets, isKeepGoing(), params.getBuckEventBus(), params.getConsole().getAnsi(), getPathToBuildReport(params.getBuckConfig())); } params.getBuckEventBus().post(BuildEvent.finished(started, exitCode)); return exitCode; }