@Test public void testIsTestRunRequiredForTestBuiltFromCacheIfHasTestResultFiles() throws IOException, ExecutionException, InterruptedException { ExecutionContext executionContext = createMock(ExecutionContext.class); expect(executionContext.isDebugEnabled()).andReturn(false); FakeTestRule testRule = new FakeTestRule( ImmutableSet.<Label>of(Label.of("windows")), BuildTargetFactory.newInstance("//:lulz"), new SourcePathResolver(new BuildRuleResolver()), ImmutableSortedSet.<BuildRule>of()); CachingBuildEngine cachingBuildEngine = createMock(CachingBuildEngine.class); BuildResult result = new BuildResult(testRule, FETCHED_FROM_CACHE, CacheResult.hit("dir")); expect(cachingBuildEngine.getBuildRuleResult(BuildTargetFactory.newInstance("//:lulz"))) .andReturn(result); replay(executionContext, cachingBuildEngine); assertTrue( "A cache hit updates the build artifact but not the test results. " + "Therefore, the test should be re-run to ensure the test results are up to date.", TestRunning.isTestRunRequiredForTest( testRule, cachingBuildEngine, executionContext, createMock(TestRuleKeyFileHelper.class), /* results cache enabled */ true, /* running with test selectors */ false)); verify(executionContext, cachingBuildEngine); }
public void shouldSetBuildTargetParameters() throws ConstructorArgMarshalException, NoSuchBuildTargetException { class Dto { public BuildTarget single; public BuildTarget sameBuildFileTarget; public List<BuildTarget> targets; } Dto dto = new Dto(); marshaller.populate( createCellRoots(filesystem), filesystem, buildRuleFactoryParams(), dto, ImmutableSet.<BuildTarget>builder(), ImmutableSet.<BuildTargetPattern>builder(), ImmutableMap.<String, Object>of( "single", "//com/example:cheese", "sameBuildFileTarget", ":cake", "targets", ImmutableList.of(":cake", "//com/example:cheese"))); BuildTarget cheese = BuildTargetFactory.newInstance("//com/example:cheese"); BuildTarget cake = BuildTargetFactory.newInstance("//example/path:cake"); assertEquals(cheese, dto.single); assertEquals(cake, dto.sameBuildFileTarget); assertEquals(ImmutableList.of(cake, cheese), dto.targets); }
@Test public void testCreateWorkerTool() throws NoSuchBuildTargetException { BuildRuleResolver resolver = new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()); BuildRule shBinaryRule = new ShBinaryBuilder(BuildTargetFactory.newInstance("//:my_exe")) .setMain(new FakeSourcePath("bin/exe")) .build(resolver); BuildRule workerRule = WorkerToolBuilder.newWorkerToolBuilder(BuildTargetFactory.newInstance("//:worker_rule")) .setExe(shBinaryRule.getBuildTarget()) .setArgs("arg1 arg2") .build(resolver); assertThat( "getBinaryBuildRule should return the build rule supplied in the definition.", shBinaryRule, Matchers.equalToObject(((WorkerTool) workerRule).getBinaryBuildRule())); assertThat( "getArgs should return the args string supplied in the definition.", "arg1 arg2", Matchers.is(((WorkerTool) workerRule).getArgs())); }
@Test public void testThatOriginalBuildParamsDepsDoNotPropagateToArchive() { SourcePathResolver pathResolver = new SourcePathResolver(new BuildRuleResolver()); // Create an `Archive` rule using build params with an existing dependency, // as if coming from a `TargetNode` which had declared deps. These should *not* // propagate to the `Archive` rule, since it only cares about dependencies generating // it's immediate inputs. BuildRule dep = new FakeBuildRule( BuildRuleParamsFactory.createTrivialBuildRuleParams( BuildTargetFactory.newInstance("//:fake")), pathResolver); BuildTarget target = BuildTargetFactory.newInstance("//:archive"); BuildRuleParams params = new FakeBuildRuleParamsBuilder(BuildTargetFactory.newInstance("//:dummy")) .setDeps(ImmutableSortedSet.of(dep)) .build(); Archive archive = Archives.createArchiveRule( pathResolver, target, params, DEFAULT_ARCHIVER, DEFAULT_OUTPUT, DEFAULT_INPUTS); // Verify that the archive rules dependencies are empty. assertEquals(archive.getDeps(), ImmutableSortedSet.<BuildRule>of()); }
@Test public void testThatBuildTargetSourcePathDepsAndPathsArePropagated() { BuildRuleResolver resolver = new BuildRuleResolver(); BuildTarget target = BuildTargetFactory.newInstance("//foo:bar"); BuildRuleParams params = BuildRuleParamsFactory.createTrivialBuildRuleParams(target); // Create a couple of genrules to generate inputs for an archive rule. Genrule genrule1 = (Genrule) GenruleBuilder.newGenruleBuilder(BuildTargetFactory.newInstance("//:genrule")) .setOut("foo/bar.o") .build(resolver); Genrule genrule2 = (Genrule) GenruleBuilder.newGenruleBuilder(BuildTargetFactory.newInstance("//:genrule2")) .setOut("foo/test.o") .build(resolver); // Build the archive using a normal input the outputs of the genrules above. Archive archive = Archives.createArchiveRule( new SourcePathResolver(resolver), target, params, DEFAULT_ARCHIVER, DEFAULT_OUTPUT, ImmutableList.<SourcePath>of( new TestSourcePath("simple.o"), new BuildTargetSourcePath(genrule1.getBuildTarget()), new BuildTargetSourcePath(genrule2.getBuildTarget()))); // Verify that the archive dependencies include the genrules providing the // SourcePath inputs. assertEquals(ImmutableSortedSet.<BuildRule>of(genrule1, genrule2), archive.getDeps()); }
@Test public void testGetCandidateRulesByIncludedLabels() throws CmdLineException { TestRule rule1 = new FakeTestRule( BuildRuleType.JAVA_TEST, ImmutableSet.of("windows", "linux"), BuildTargetFactory.newInstance("//:for"), ImmutableSortedSet.<BuildRule>of(), ImmutableSet.<BuildTargetPattern>of()); TestRule rule2 = new FakeTestRule( BuildRuleType.JAVA_TEST, ImmutableSet.of("android"), BuildTargetFactory.newInstance("//:teh"), ImmutableSortedSet.<BuildRule>of(rule1), ImmutableSet.<BuildTargetPattern>of()); TestRule rule3 = new FakeTestRule( BuildRuleType.JAVA_TEST, ImmutableSet.of("windows"), BuildTargetFactory.newInstance("//:lulz"), ImmutableSortedSet.<BuildRule>of(rule2), ImmutableSet.<BuildTargetPattern>of()); Iterable<TestRule> rules = Lists.newArrayList(rule1, rule2, rule3); DependencyGraph graph = createDependencyGraphFromBuildRules(rules); TestCommandOptions options = getOptions("--include", "linux", "windows"); Iterable<TestRule> result = TestCommand.getCandidateRulesByIncludedLabels(graph, options.getIncludedLabels()); assertThat(result, IsIterableContainingInAnyOrder.containsInAnyOrder(rule1, rule3)); }
@Test public void testFilterBuilds() throws CmdLineException { TestCommandOptions options = getOptions("--exclude", "linux", "windows"); TestRule rule1 = new FakeTestRule( BuildRuleType.JAVA_TEST, ImmutableSet.of("windows", "linux"), BuildTargetFactory.newInstance("//:for"), ImmutableSortedSet.<BuildRule>of(), ImmutableSet.<BuildTargetPattern>of()); TestRule rule2 = new FakeTestRule( BuildRuleType.JAVA_TEST, ImmutableSet.of("android"), BuildTargetFactory.newInstance("//:teh"), ImmutableSortedSet.<BuildRule>of(), ImmutableSet.<BuildTargetPattern>of()); TestRule rule3 = new FakeTestRule( BuildRuleType.JAVA_TEST, ImmutableSet.of("windows"), BuildTargetFactory.newInstance("//:lulz"), ImmutableSortedSet.<BuildRule>of(), ImmutableSet.<BuildTargetPattern>of()); List<TestRule> testRules = ImmutableList.of(rule1, rule2, rule3); Iterable<TestRule> result = TestCommand.filterTestRules(options, testRules); assertThat(result, IsIterableContainingInOrder.contains(rule2)); }
@Test public void testReferentialAliases() throws IOException, NoSuchBuildTargetException { BuildTargetParser parser = EasyMock.createMock(BuildTargetParser.class); EasyMock.expect(parser.parse("//java/com/example:foo", ParseContext.fullyQualified())) .andReturn(BuildTargetFactory.newInstance("//java/com/example:foo")); EasyMock.expect(parser.parse("//java/com/example:bar", ParseContext.fullyQualified())) .andReturn(BuildTargetFactory.newInstance("//java/com/example:bar")); EasyMock.replay(parser); Reader reader = new StringReader( Joiner.on('\n') .join( "[alias]", "foo = //java/com/example:foo", "bar = //java/com/example:bar", "foo_codename = foo", "", "# Do not delete these: automation builds require these aliases to exist!", "automation_foo = foo_codename", "automation_bar = bar")); BuckConfig config = createWithDefaultFilesystem(reader, parser); assertEquals("//java/com/example:foo", config.getBuildTargetForAlias("foo")); assertEquals("//java/com/example:bar", config.getBuildTargetForAlias("bar")); assertEquals("//java/com/example:foo", config.getBuildTargetForAlias("foo_codename")); assertEquals("//java/com/example:foo", config.getBuildTargetForAlias("automation_foo")); assertEquals("//java/com/example:bar", config.getBuildTargetForAlias("automation_bar")); assertNull(config.getBuildTargetForAlias("baz")); EasyMock.verify(parser); }
@Test public void testGetBuildTargetForAlias() throws IOException, NoSuchBuildTargetException { BuildTargetParser parser = EasyMock.createMock(BuildTargetParser.class); EasyMock.expect(parser.parse("//java/com/example:foo", ParseContext.fullyQualified())) .andReturn(BuildTargetFactory.newInstance("//java/com/example:foo")); EasyMock.expect(parser.parse("//java/com/example:bar", ParseContext.fullyQualified())) .andReturn(BuildTargetFactory.newInstance("//java/com/example:bar")); EasyMock.replay(parser); Reader reader = new StringReader( Joiner.on('\n') .join("[alias]", "foo = //java/com/example:foo", "bar = //java/com/example:bar")); BuckConfig config = createWithDefaultFilesystem(reader, parser); assertEquals("//java/com/example:foo", config.getBuildTargetForAlias("foo")); assertEquals("//java/com/example:bar", config.getBuildTargetForAlias("bar")); assertNull( "Invalid alias names, such as build targets, should be tolerated by this method.", config.getBuildTargetForAlias("//java/com/example:foo")); assertNull(config.getBuildTargetForAlias("baz")); Reader noAliasesReader = new StringReader(""); BuckConfig noAliasesConfig = createWithDefaultFilesystem(noAliasesReader, parser); assertNull(noAliasesConfig.getBuildTargetForAlias("foo")); assertNull(noAliasesConfig.getBuildTargetForAlias("bar")); assertNull(noAliasesConfig.getBuildTargetForAlias("baz")); EasyMock.verify(parser); }
@Test public void changingRuleKeyFieldOfDepChangesKeyWhenClassImplementsAppendToRuleKey() { BuildTarget target = BuildTargetFactory.newInstance("//cheese:peas"); BuildRuleParams params = new FakeBuildRuleParamsBuilder(target).build(); SourcePathResolver pathResolver = new SourcePathResolver( new BuildRuleResolver(TargetGraph.EMPTY, new BuildTargetNodeToBuildRuleTransformer())); DefaultFileHashCache hashCache = new DefaultFileHashCache(new FakeProjectFilesystem()); BuildRule buildRule1 = new TestRuleKeyAppendableBuildRule(params, pathResolver, "foo", "bar"); BuildRule buildRule2 = new TestRuleKeyAppendableBuildRule(params, pathResolver, "foo", "xyzzy"); BuildTarget parentTarget = BuildTargetFactory.newInstance("//cheese:milk"); BuildRuleParams parentParams1 = new FakeBuildRuleParamsBuilder(parentTarget) .setDeclaredDeps(ImmutableSortedSet.of(buildRule1)) .build(); BuildRule parentRule1 = new NoopBuildRule(parentParams1, pathResolver); BuildRuleParams parentParams2 = new FakeBuildRuleParamsBuilder(parentTarget) .setDeclaredDeps(ImmutableSortedSet.of(buildRule2)) .build(); BuildRule parentRule2 = new NoopBuildRule(parentParams2, pathResolver); RuleKey ruleKey1 = new DefaultRuleKeyBuilderFactory(hashCache, pathResolver).build(parentRule1); RuleKey ruleKey2 = new DefaultRuleKeyBuilderFactory(hashCache, pathResolver).build(parentRule2); assertNotEquals(ruleKey1, ruleKey2); }
@Test public void getOutputDoesNotAccessWrappedJavaLibrary() throws IOException { BuildRuleResolver ruleResolver = new BuildRuleResolver(); SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver); JavaLibrary javaLibrary = (JavaLibrary) JavaLibraryBuilder.createBuilder(BuildTargetFactory.newInstance("//:lib")) .build(ruleResolver); BuildRuleParams params = new FakeBuildRuleParamsBuilder(BuildTargetFactory.newInstance("//:target")).build(); DexProducedFromJavaLibrary dexProducedFromJavaLibrary = new DexProducedFromJavaLibrary(params, pathResolver, javaLibrary); ObjectMapper mapper = new ObjectMapper(); FakeOnDiskBuildInfo onDiskBuildInfo = new FakeOnDiskBuildInfo() .putMetadata(DexProducedFromJavaLibrary.LINEAR_ALLOC_KEY_ON_DISK_METADATA, "0") .putMetadata( DexProducedFromJavaLibrary.CLASSNAMES_TO_HASHES, mapper.writeValueAsString(ImmutableMap.<String, String>of())); initialize(dexProducedFromJavaLibrary, onDiskBuildInfo); assertFalse(dexProducedFromJavaLibrary.hasOutput()); }
@Test public void testIsHalideCompilerTarget() { BuildTarget target = BuildTargetFactory.newInstance("//:foo"); assertFalse(HalideLibraryDescription.isHalideCompilerTarget(target)); target = BuildTargetFactory.newInstance("//:foo#halide-compiler"); assertTrue(HalideLibraryDescription.isHalideCompilerTarget(target)); }
@Test public void testIsTestRunRequiredForTestBuiltLocally() throws IOException, ExecutionException, InterruptedException { ExecutionContext executionContext = createMock(ExecutionContext.class); expect(executionContext.isDebugEnabled()).andReturn(false); FakeTestRule testRule = new FakeTestRule( ImmutableSet.<Label>of(Label.of("windows")), BuildTargetFactory.newInstance("//:lulz"), new SourcePathResolver(new BuildRuleResolver()), ImmutableSortedSet.<BuildRule>of()); CachingBuildEngine cachingBuildEngine = createMock(CachingBuildEngine.class); BuildResult result = new BuildResult(testRule, BUILT_LOCALLY, CacheResult.skip()); expect(cachingBuildEngine.getBuildRuleResult(BuildTargetFactory.newInstance("//:lulz"))) .andReturn(result); replay(executionContext, cachingBuildEngine); assertTrue( "A test built locally should always run regardless of any cached result. ", TestRunning.isTestRunRequiredForTest( testRule, cachingBuildEngine, executionContext, createMock(TestRuleKeyFileHelper.class), /* results cache enabled */ true, /* running with test selectors */ false)); verify(executionContext, cachingBuildEngine); }
@Test public void ruleKeyDoesNotChangeWhenOnlyDependencyRuleKeyChanges() throws Exception { ProjectFilesystem filesystem = new FakeProjectFilesystem(); BuildRuleResolver resolver = new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathResolver pathResolver = new SourcePathResolver(resolver); Path depOutput = Paths.get("output"); FakeBuildRule dep = resolver.addToIndex( new FakeBuildRule(BuildTargetFactory.newInstance("//:dep"), filesystem, pathResolver)); dep.setOutputFile(depOutput.toString()); filesystem.writeContentsToPath("hello", dep.getPathToOutput()); FakeFileHashCache hashCache = new FakeFileHashCache(ImmutableMap.of(filesystem.resolve(depOutput), HashCode.fromInt(0))); BuildRule rule = GenruleBuilder.newGenruleBuilder(BuildTargetFactory.newInstance("//:rule")) .setOut("out") .setSrcs(ImmutableList.<SourcePath>of(new BuildTargetSourcePath(dep.getBuildTarget()))) .build(resolver, filesystem); RuleKey inputKey1 = new InputBasedRuleKeyBuilderFactory(0, hashCache, pathResolver).build(rule); RuleKey inputKey2 = new InputBasedRuleKeyBuilderFactory(0, hashCache, pathResolver).build(rule); assertThat(inputKey1, Matchers.equalTo(inputKey2)); }
@Test public void testArgsWithLocationMacroAffectDependenciesAndExpands() throws Exception { BuildRuleResolver resolver = new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathResolver pathResolver = new SourcePathResolver(resolver); BuildRule shBinaryRule = new ShBinaryBuilder(BuildTargetFactory.newInstance("//:my_exe")) .setMain(new FakeSourcePath("bin/exe")) .build(resolver); BuildRule exportFileRule = ExportFileBuilder.newExportFileBuilder(BuildTargetFactory.newInstance("//:file")) .setSrc(new FakeSourcePath("file.txt")) .build(resolver); WorkerToolBuilder workerToolBuilder = WorkerToolBuilder.newWorkerToolBuilder(BuildTargetFactory.newInstance("//:worker_rule")) .setExe(shBinaryRule.getBuildTarget()) .setArgs("--input $(location //:file)"); WorkerTool workerTool = (WorkerTool) workerToolBuilder.build(resolver); assertThat( workerToolBuilder.findImplicitDeps(), Matchers.hasItem(exportFileRule.getBuildTarget())); assertThat(workerTool.getDeps(), Matchers.hasItems(shBinaryRule, exportFileRule)); assertThat(workerTool.getRuntimeDeps(), Matchers.hasItems(shBinaryRule, exportFileRule)); assertThat( workerTool.getArgs(), Matchers.containsString( pathResolver .getAbsolutePath(new BuildTargetSourcePath(exportFileRule.getBuildTarget())) .toString())); }
@Test public void testGetShellCommand() { String bash = "rm -rf /usr"; String cmdExe = "rmdir /s /q C:\\Windows"; String cmd = "echo \"Hello\""; String genruleName = "//example:genrule"; ExecutionContext linuxExecutionContext = newEmptyExecutionContext(Platform.LINUX); ExecutionContext windowsExecutionContext = newEmptyExecutionContext(Platform.WINDOWS); // Test platform-specific Genrule rule = Genrule.newGenruleBuilder(new FakeAbstractBuildRuleBuilderParams()) .setBuildTarget(BuildTargetFactory.newInstance(genruleName)) .setBash(Optional.of(bash)) .setCmdExe(Optional.of(cmdExe)) .setOut("out.txt") .build(new BuildRuleResolver()); ImmutableList<String> command = rule.createGenruleStep().getShellCommand(linuxExecutionContext); assertEquals(ImmutableList.of("/bin/bash", "-e", "-c", bash), command); command = rule.createGenruleStep().getShellCommand(windowsExecutionContext); assertEquals(ImmutableList.of("cmd.exe", "/c", cmdExe), command); // Test fallback rule = Genrule.newGenruleBuilder(new FakeAbstractBuildRuleBuilderParams()) .setBuildTarget(BuildTargetFactory.newInstance("//example:genrule")) .setCmd(Optional.of(cmd)) .setOut("out.txt") .build(new BuildRuleResolver()); command = rule.createGenruleStep().getShellCommand(linuxExecutionContext); assertEquals(ImmutableList.of("/bin/bash", "-e", "-c", cmd), command); command = rule.createGenruleStep().getShellCommand(windowsExecutionContext); assertEquals(ImmutableList.of("cmd.exe", "/c", cmd), command); // Test command absent rule = Genrule.newGenruleBuilder(new FakeAbstractBuildRuleBuilderParams()) .setBuildTarget(BuildTargetFactory.newInstance("//example:genrule")) .setOut("out.txt") .build(new BuildRuleResolver()); try { rule.createGenruleStep().getShellCommand(linuxExecutionContext); } catch (HumanReadableException e) { assertEquals( String.format("You must specify either bash or cmd for genrule %s.", genruleName), e.getHumanReadableErrorMessage()); } try { rule.createGenruleStep().getShellCommand(windowsExecutionContext); } catch (HumanReadableException e) { assertEquals( String.format("You must specify either cmd_exe or cmd for genrule %s.", genruleName), e.getHumanReadableErrorMessage()); } }
@Test public void testGetExecutableCommand() { BuildRuleResolver ruleResolver = new BuildRuleResolver(); SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver); // prebuilt_jar //third_party/generator:generator PrebuiltJarBuilder.createBuilder( BuildTargetFactory.newInstance("//third_party/generator:generator")) .setBinaryJar(PATH_TO_GENERATOR_JAR) .build(ruleResolver); // prebuilt_jar //third_party/guava:guava BuildRule guava = PrebuiltJarBuilder.createBuilder( BuildTargetFactory.newInstance("//third_party/guava:guava")) .setBinaryJar(PATH_TO_GUAVA_JAR) .build(ruleResolver); // java_library //java/com/facebook/base:base BuildRule libraryRule = JavaLibraryBuilder.createBuilder( BuildTargetFactory.newInstance("//java/com/facebook/base:base")) .addSrc(Paths.get("java/com/facebook/base/Base.java")) .addDep(guava.getBuildTarget()) .build(ruleResolver); BuildRuleParams params = new FakeBuildRuleParamsBuilder( BuildTargetFactory.newInstance("//java/com/facebook/base:Main")) .setDeps(ImmutableSortedSet.of(libraryRule)) .build(); // java_binary //java/com/facebook/base:Main JavaBinary javaBinary = ruleResolver.addToIndex( new JavaBinary( params, new SourcePathResolver(ruleResolver), "com.facebook.base.Main", null, /* merge manifests */ true, null, /* blacklist */ ImmutableSet.<String>of(), new DefaultDirectoryTraverser(), ImmutableSetMultimap.<JavaLibrary, Path>of())); // Strip the trailing "." from the absolute path to the current directory. final String basePath = new File(".").getAbsolutePath().replaceFirst("\\.$", ""); // Each classpath entry is specified via its absolute path so that the executable command can be // run from a /tmp directory, if necessary. String expectedClasspath = basePath + javaBinary.getPathToOutput(); List<String> expectedCommand = ImmutableList.of("java", "-jar", expectedClasspath); assertEquals(expectedCommand, javaBinary.getExecutableCommand().getCommandPrefix(pathResolver)); assertFalse( "Library rules that are used exclusively by genrules should not be part of the classpath.", expectedClasspath.contains(PATH_TO_GENERATOR_JAR.toString())); }
@Test public void testAmendBuilder() throws NoSuchBuildTargetException { Map<BuildTarget, BuildRule> buildRuleIndex = Maps.newHashMap(); BuildRuleResolver ruleResolver = new BuildRuleResolver(buildRuleIndex); // Set up mocks. ProjectFilesystem projectFilesystem = EasyMock.createMock(ProjectFilesystem.class); EasyMock.expect(projectFilesystem.getAbsolutifier()) .andReturn(IdentityPathAbsolutifier.getIdentityAbsolutifier()); BuildTargetParser buildTargetParser = new BuildTargetParser(projectFilesystem) { @Override public BuildTarget parse(String buildTargetName, ParseContext parseContext) throws NoSuchBuildTargetException { return BuildTargetFactory.newInstance(buildTargetName); } }; Map<String, ?> instance = ImmutableMap.of( "vm_args", ImmutableList.of("-Dbuck.robolectric_dir=javatests/com/facebook/base"), "source_under_test", ImmutableList.of("//java/com/facebook/base:base")); BuildTarget buildTarget = BuildTargetFactory.newInstance("//javatests/com/facebook/base:base"); BuildFileTree buildFileTree = EasyMock.createMock(BuildFileTree.class); EasyMock.replay(projectFilesystem, buildFileTree); BuildRuleFactoryParams params = new BuildRuleFactoryParams( instance, projectFilesystem, buildFileTree, buildTargetParser, buildTarget, new FakeRuleKeyBuilderFactory()); // Create a builder using the factory. RobolectricTestBuildRuleFactory factory = new RobolectricTestBuildRuleFactory(); RobolectricTestRule.Builder builder = factory.newBuilder(new FakeAbstractBuildRuleBuilderParams()).setBuildTarget(buildTarget); // Invoke the method under test. factory.amendBuilder(builder, params); // Create a build rule using the builder. BuildRule base = new FakeJavaLibraryRule( BuildRuleType.ANDROID_LIBRARY, buildTarget, ImmutableSortedSet.<BuildRule>of(), ImmutableSet.<BuildTargetPattern>of()); buildRuleIndex.put(BuildTargetFactory.newInstance("//java/com/facebook/base:base"), base); RobolectricTestRule robolectricRule = (RobolectricTestRule) ruleResolver.buildAndAddToIndex(builder); // Verify the build rule built from the builder. assertEquals( ImmutableList.of("-Dbuck.robolectric_dir=javatests/com/facebook/base"), robolectricRule.getVmArgs()); assertEquals(ImmutableSet.of(base), robolectricRule.getSourceUnderTest()); EasyMock.verify(projectFilesystem, buildFileTree); }
@Test public void testPathsUnderDirectories() throws CmdLineException, IOException { ProjectFilesystem projectFilesystem = new FakeProjectFilesystem(); Path resDir = Paths.get("some/resources/dir"); BuildTarget androidResourceTarget = BuildTargetFactory.newInstance("//:res"); TargetNode<?> androidResourceNode = AndroidResourceBuilder.createBuilder(androidResourceTarget).setRes(resDir).build(); Path genSrc = resDir.resolve("foo.txt"); BuildTarget genTarget = BuildTargetFactory.newInstance("//:res"); TargetNode<?> genNode = GenruleBuilder.newGenruleBuilder(genTarget) .setSrcs(ImmutableList.<SourcePath>of(new PathSourcePath(projectFilesystem, genSrc))) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(androidResourceNode, genNode); SortedMap<String, TargetNode<?>> matchingBuildRules; // Specifying a resource under the resource directory causes a match. matchingBuildRules = targetsCommand.getMatchingNodes( targetGraph, Optional.of(ImmutableSet.of(resDir.resolve("some_resource.txt"))), Optional.<ImmutableSet<BuildTarget>>absent(), Optional.<ImmutableSet<BuildRuleType>>absent(), false, "BUCK"); assertEquals(ImmutableSet.of(androidResourceTarget.toString()), matchingBuildRules.keySet()); // Specifying a resource with the same string-like common prefix, but not under the above // resource dir, should not trigger a match. matchingBuildRules = targetsCommand.getMatchingNodes( targetGraph, Optional.of( ImmutableSet.of( Paths.get(resDir.toString() + "_extra").resolve("some_resource.txt"))), Optional.<ImmutableSet<BuildTarget>>absent(), Optional.<ImmutableSet<BuildRuleType>>absent(), false, "BUCK"); assertTrue(matchingBuildRules.isEmpty()); // Specifying a resource with the same string-like common prefix, but not under the above // resource dir, should not trigger a match. matchingBuildRules = targetsCommand.getMatchingNodes( targetGraph, Optional.of(ImmutableSet.of(genSrc)), Optional.<ImmutableSet<BuildTarget>>absent(), Optional.<ImmutableSet<BuildRuleType>>absent(), false, "BUCK"); assertEquals( ImmutableSet.of(androidResourceTarget.toString(), genTarget.toString()), matchingBuildRules.keySet()); }
@Test public void testCreateBuildRule() throws Exception { // Set up a #halide-compiler rule, then set up a halide_library rule, and // check that the library rule depends on the compiler rule. BuildTarget compilerTarget = BuildTargetFactory.newInstance("//:rule") .withFlavors(HalideLibraryDescription.HALIDE_COMPILER_FLAVOR); BuildTarget libTarget = BuildTargetFactory.newInstance("//:rule"); ProjectFilesystem filesystem = new FakeProjectFilesystem(); HalideLibraryBuilder compilerBuilder = new HalideLibraryBuilder(compilerTarget); compilerBuilder.setSrcs( ImmutableSortedSet.of(SourceWithFlags.of(new FakeSourcePath("main.cpp")))); HalideLibraryBuilder libBuilder = new HalideLibraryBuilder(libTarget); TargetGraph targetGraph = TargetGraphFactory.newInstance(compilerBuilder.build(), libBuilder.build()); BuildRuleResolver resolver = new BuildRuleResolver(targetGraph, new BuildTargetNodeToBuildRuleTransformer()); CxxBinary compiler = (CxxBinary) compilerBuilder.build(resolver, filesystem, targetGraph); HalideLibrary lib = (HalideLibrary) libBuilder.build(resolver, filesystem, targetGraph); // Check that we picked up the implicit dependency on the #halide-compiler // version of the rule. assertEquals(lib.getDeps(), ImmutableSortedSet.<BuildRule>of(compiler)); // Check that the library rule has the correct preprocessor input. CxxPlatform cxxPlatform = CxxLibraryBuilder.createDefaultPlatform(); String headerName = "rule.h"; Path headerPath = BuildTargets.getGenPath(libTarget, "%s/" + headerName); Path headerRoot = CxxDescriptionEnhancer.getHeaderSymlinkTreePath( libTarget, cxxPlatform.getFlavor(), HeaderVisibility.PUBLIC); assertEquals( CxxPreprocessorInput.builder() .addRules( CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( libTarget, cxxPlatform.getFlavor(), HeaderVisibility.PUBLIC)) .setIncludes( CxxHeaders.builder() .putNameToPathMap( Paths.get(headerName), new BuildTargetSourcePath(libTarget, headerPath)) .putFullNameToPathMap( headerRoot.resolve(headerName), new BuildTargetSourcePath(libTarget, headerPath)) .build()) .addSystemIncludeRoots(headerRoot) .build(), lib.getCxxPreprocessorInput(cxxPlatform, HeaderVisibility.PUBLIC)); // Check that the library rule has the correct native linkable input. NativeLinkableInput input = lib.getNativeLinkableInput(cxxPlatform, Linker.LinkableDepType.STATIC); BuildRule buildRule = FluentIterable.from(input.getArgs()) .transformAndConcat(Arg.getDepsFunction(new SourcePathResolver(resolver))) .get(0); assertTrue(buildRule instanceof HalideLibrary); }
@Test public void testGetMatchingAppleTestBuildTarget() throws CmdLineException, IOException { BuildTarget libraryTarget = BuildTargetFactory.newInstance("//foo:lib"); TargetNode<?> libraryNode = AppleLibraryBuilder.createBuilder(libraryTarget) .setSrcs( Optional.of( ImmutableSortedSet.of(SourceWithFlags.of(new FakeSourcePath("foo/foo.m"))))) .build(); BuildTarget testTarget = BuildTargetFactory.newInstance("//foo:xctest"); TargetNode<?> testNode = AppleTestBuilder.createBuilder(testTarget) .setExtension(Either.<AppleBundleExtension, String>ofLeft(AppleBundleExtension.XCTEST)) .setSrcs( Optional.of( ImmutableSortedSet.of(SourceWithFlags.of(new FakeSourcePath("foo/testfoo.m"))))) .setDeps(Optional.of(ImmutableSortedSet.of(libraryTarget))) .build(); ImmutableSet<TargetNode<?>> nodes = ImmutableSet.of(libraryNode, testNode); TargetGraph targetGraph = TargetGraphFactory.newInstance(nodes); // No target depends on the referenced file. SortedMap<String, TargetNode<?>> matchingBuildRules = targetsCommand.getMatchingNodes( targetGraph, Optional.of(ImmutableSet.of(Paths.get("foo/bar.m"))), Optional.<ImmutableSet<BuildTarget>>absent(), Optional.<ImmutableSet<BuildRuleType>>absent(), false, "BUCK"); assertTrue(matchingBuildRules.isEmpty()); // Both AppleLibrary nodes, AppleBundle, and AppleTest match the referenced file. matchingBuildRules = targetsCommand.getMatchingNodes( targetGraph, Optional.of(ImmutableSet.of(Paths.get("foo/foo.m"))), Optional.<ImmutableSet<BuildTarget>>absent(), Optional.<ImmutableSet<BuildRuleType>>absent(), false, "BUCK"); assertEquals(ImmutableSet.of("//foo:lib", "//foo:xctest"), matchingBuildRules.keySet()); // The test AppleLibrary, AppleBundle and AppleTest match the referenced file. matchingBuildRules = targetsCommand.getMatchingNodes( targetGraph, Optional.of(ImmutableSet.of(Paths.get("foo/testfoo.m"))), Optional.<ImmutableSet<BuildTarget>>absent(), Optional.<ImmutableSet<BuildRuleType>>absent(), false, "BUCK"); assertEquals(ImmutableSet.of("//foo:xctest"), matchingBuildRules.keySet()); }
private JavaLibraryRule createAndroidLibraryRule( String buildTarget, BuildRuleResolver ruleResolver, String resDirectory, String assetDirectory, String nativeLibsDirectory) { BuildTarget libraryOnebuildTarget = BuildTargetFactory.newInstance(buildTarget); AndroidLibraryRule.Builder androidLibraryRuleBuilder = AndroidLibraryRule.newAndroidLibraryRuleBuilder(new FakeAbstractBuildRuleBuilderParams()) .addSrc(buildTarget.split(":")[1] + ".java") .setBuildTarget(libraryOnebuildTarget); if (!Strings.isNullOrEmpty(resDirectory) || !Strings.isNullOrEmpty(assetDirectory)) { BuildTarget resourceOnebuildTarget = BuildTargetFactory.newInstance(buildTarget); AndroidResourceRule androidResourceRule = ruleResolver.buildAndAddToIndex( AndroidResourceRule.newAndroidResourceRuleBuilder( new FakeAbstractBuildRuleBuilderParams()) .setAssetsDirectory(assetDirectory) .setRes(resDirectory) .setBuildTarget(resourceOnebuildTarget)); androidLibraryRuleBuilder.addDep(androidResourceRule.getBuildTarget()); } if (!Strings.isNullOrEmpty(resDirectory) || !Strings.isNullOrEmpty(assetDirectory)) { BuildTarget resourceOnebuildTarget = BuildTargetFactory.newInstance(buildTarget + "_resources"); AndroidResourceRule androidResourceRule = ruleResolver.buildAndAddToIndex( AndroidResourceRule.newAndroidResourceRuleBuilder( new FakeAbstractBuildRuleBuilderParams()) .setAssetsDirectory(assetDirectory) .setRes(resDirectory) .setBuildTarget(resourceOnebuildTarget)); androidLibraryRuleBuilder.addDep(androidResourceRule.getBuildTarget()); } if (!Strings.isNullOrEmpty(nativeLibsDirectory)) { BuildTarget nativeLibOnebuildTarget = BuildTargetFactory.newInstance(buildTarget + "_native_libs"); BuildRule nativeLibsRule = ruleResolver.buildAndAddToIndex( PrebuiltNativeLibrary.newPrebuiltNativeLibrary( new FakeAbstractBuildRuleBuilderParams()) .setBuildTarget(nativeLibOnebuildTarget) .setNativeLibsDirectory(nativeLibsDirectory)); androidLibraryRuleBuilder.addDep(nativeLibsRule.getBuildTarget()); } JavaLibraryRule androidLibraryRule = ruleResolver.buildAndAddToIndex(androidLibraryRuleBuilder); return androidLibraryRule; }
@Test public void buildTargetsWithDifferentFlavorsProduceDifferentDefaultSonames() { BuildTarget target1 = BuildTargetFactory.newInstance("//:rule#one"); BuildTarget target2 = BuildTargetFactory.newInstance("//:rule#two"); assertNotEquals( CxxDescriptionEnhancer.getDefaultSharedLibrarySoname( target1, CxxPlatformUtils.DEFAULT_PLATFORM), CxxDescriptionEnhancer.getDefaultSharedLibrarySoname( target2, CxxPlatformUtils.DEFAULT_PLATFORM)); }
@Test public void extractRuleKeyAppendable() throws MacroException { BuildTarget target = BuildTargetFactory.newInstance("//:rule"); BuildRuleResolver resolver = new BuildRuleResolver(); LocationMacroExpander macroExpander = new LocationMacroExpander(); assertThat( macroExpander.extractRuleKeyAppendables( target, createCellRoots(new FakeProjectFilesystem()), resolver, "//some/other:rule"), Matchers.<Object>equalTo( new BuildTargetSourcePath(BuildTargetFactory.newInstance("//some/other:rule")))); }
/** Verify that owners are correctly detected: - inputs that belong to multiple targets */ @Test public void verifyInputsWithMultipleOwnersAreCorrectlyReported() throws CmdLineException { // All files will be directories now FakeProjectFilesystem filesystem = new FakeProjectFilesystem() { @Override public File getFileForRelativePath(String pathRelativeToProjectRoot) { return new ExistingFile(getProjectRoot(), pathRelativeToProjectRoot); } }; // Create inputs String[] args = new String[] { "java/somefolder/badfolder/somefile.java", "java/somefolder/perfect.java", "com/test/subtest/random.java" }; ImmutableSortedSet<InputRule> inputs = InputRule.inputPathsAsInputRules(ImmutableSortedSet.copyOf(args)); // Build rule that owns all inputs BuildTarget target1 = BuildTargetFactory.newInstance("//base/name1", "name1"); BuildTarget target2 = BuildTargetFactory.newInstance("//base/name2", "name2"); BuildRule owner1Rule = new StubBuildRule(target1, inputs); BuildRule owner2Rule = new StubBuildRule(target2, inputs); // Create graph MutableDirectedGraph<BuildRule> mutableGraph = new MutableDirectedGraph<BuildRule>(); mutableGraph.addNode(owner1Rule); mutableGraph.addNode(owner2Rule); DependencyGraph graph = new DependencyGraph(mutableGraph); // Create options AuditOwnerOptions options = getOptions(args); // Create command under test AuditOwnerCommand command = createAuditOwnerCommand(filesystem); // Generate report and verify nonFileInputs are filled in as expected. AuditOwnerCommand.OwnersReport report = command.generateOwnersReport(graph, options); assertTrue(report.nonFileInputs.isEmpty()); assertTrue(report.nonExistentInputs.isEmpty()); assertTrue(report.inputsWithNoOwners.isEmpty()); assertTrue(report.owners.containsKey(owner1Rule)); assertTrue(report.owners.containsKey(owner2Rule)); assertEquals(owner1Rule.getInputs(), report.owners.get(owner1Rule)); assertEquals(owner2Rule.getInputs(), report.owners.get(owner2Rule)); }
@Test public void createBuildRuleForUnflavoredTargetCreateThriftLibrary() { BuildRuleResolver resolver = new BuildRuleResolver(); SourcePathResolver pathResolver = new SourcePathResolver(resolver); BuildTarget unflavoredTarget = BuildTargetFactory.newInstance("//:thrift"); BuildRuleParams unflavoredParams = BuildRuleParamsFactory.createTrivialBuildRuleParams(unflavoredTarget); // Setup an empty thrift buck config, missing the compiler. FakeBuckConfig buckConfig = new FakeBuckConfig( ImmutableMap.<String, ImmutableMap<String, String>>of(), ImmutableMap.<String, String>of()); ThriftBuckConfig thriftBuckConfig = new ThriftBuckConfig(buckConfig); ThriftLibraryDescription desc = new ThriftLibraryDescription( thriftBuckConfig, ImmutableList.<ThriftLanguageSpecificEnhancer>of()); // Setup the thrift source. String sourceName = "test.thrift"; SourcePath source = new TestSourcePath(sourceName); // Create a dep and verify it gets attached. BuildTarget depTarget = BuildTargetFactory.newInstance("//:dep"); Path depIncludeRoot = desc.getIncludeRoot(depTarget); HeaderSymlinkTree depIncludeSymlinkTree = createFakeSymlinkTree(depTarget, pathResolver, depIncludeRoot); ThriftLibrary dep = new ThriftLibrary( BuildRuleParamsFactory.createTrivialBuildRuleParams(depTarget), pathResolver, ImmutableSortedSet.<ThriftLibrary>of(), depIncludeSymlinkTree, ImmutableMap.<Path, SourcePath>of()); resolver.addToIndex(dep); // Build up the constructor arg. ThriftConstructorArg arg = desc.createUnpopulatedConstructorArg(); arg.name = "thrift"; arg.srcs = ImmutableMap.of(source, ImmutableList.<String>of()); arg.deps = Optional.of(ImmutableSortedSet.of(dep.getBuildTarget())); arg.flags = Optional.absent(); // Build the thrift library rule and verify that it's setup correctly. BuildRule rule = desc.createBuildRule(TargetGraph.EMPTY, unflavoredParams, resolver, arg); assertTrue(rule instanceof ThriftLibrary); ThriftLibrary me = (ThriftLibrary) rule; assertEquals(ImmutableSortedSet.of(dep), me.getThriftDeps()); assertEquals(desc.getIncludeRoot(unflavoredTarget), me.getIncludeTreeRule().getIncludePath()); }
@Test public void inputBasedRuleKeyAvoidsRerunningIfGeneratedSourceDoesNotChange() throws Exception { CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(FakeBuckConfig.builder().build())); BuildTarget target = BuildTargetFactory.newInstance(workspace.getDestPath(), "//:binary_using_generated_source"); String unusedGenruleInput = "unused.dat"; BuildTarget genrule = BuildTargetFactory.newInstance("//:gensource"); String sourceName = "bar.cpp"; CxxSourceRuleFactory cxxSourceRuleFactory = CxxSourceRuleFactoryHelper.of(workspace.getDestPath(), target, cxxPlatform); BuildTarget preprocessTarget = cxxSourceRuleFactory.createPreprocessBuildTarget( sourceName, AbstractCxxSource.Type.CXX, CxxSourceRuleFactory.PicType.PDC); BuildTarget compileTarget = cxxSourceRuleFactory.createCompileBuildTarget(sourceName, CxxSourceRuleFactory.PicType.PDC); // Run the build and verify that the C++ source was (preprocessed and) compiled. workspace.runBuckBuild(target.toString()).assertSuccess(); if (mode == CxxPreprocessMode.SEPARATE) { assertThat( workspace.getBuildLog().getLogEntry(preprocessTarget).getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.BUILT_LOCALLY))); } assertThat( workspace.getBuildLog().getLogEntry(compileTarget).getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.BUILT_LOCALLY))); // Now modify the unused genrule input. workspace.writeContentsToPath("SOMETHING ELSE", unusedGenruleInput); // Run the build again and verify that got a matching input-based rule key, and therefore // didn't recompile. workspace.runBuckBuild(target.toString()).assertSuccess(); // Verify that the genrule actually re-ran. assertThat( workspace.getBuildLog().getLogEntry(genrule).getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.BUILT_LOCALLY))); // Verify that the (preprocess and) compile rules aren't re-run. if (mode == CxxPreprocessMode.SEPARATE) { assertThat( workspace.getBuildLog().getLogEntry(preprocessTarget).getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.MATCHING_INPUT_BASED_RULE_KEY))); } assertThat( workspace.getBuildLog().getLogEntry(compileTarget).getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.MATCHING_INPUT_BASED_RULE_KEY))); }
@Test public void annotatedAppendableBuildRulesIncludeTheirRuleKey() { BuildTarget target = BuildTargetFactory.newInstance("//cheese:peas"); BuildTarget depTarget = BuildTargetFactory.newInstance("//cheese:more-peas"); SourcePathResolver pathResolver = new SourcePathResolver(new BuildRuleResolver()); BuildRule rule = new EmptyRule(target); FileHashCache fileHashCache = new NullFileHashCache(); DefaultRuleKeyBuilderFactory factory = new DefaultRuleKeyBuilderFactory(fileHashCache, pathResolver); class AppendableRule extends EmptyRule implements RuleKeyAppendable { public AppendableRule(BuildTarget target) { super(target); } @Override public RuleKeyBuilder appendToRuleKey(RuleKeyBuilder builder) { return builder.setReflectively("cheese", "brie"); } @Override public RuleKey getRuleKey() { return new RuleKey("abcd"); } } AppendableRule appendableRule = new AppendableRule(depTarget); RuleKey subKey = new RuleKeyBuilder(pathResolver, fileHashCache).setReflectively("cheese", "brie").build(); RuleKeyBuilder builder = factory.newInstance(rule); builder.setReflectively("field.appendableSubKey", subKey); builder.setReflectively("field", appendableRule.getRuleKey()); RuleKey expected = builder.build(); class RuleContainingAppendableRule extends EmptyRule { @AddToRuleKey private final AppendableRule field; public RuleContainingAppendableRule(BuildTarget target, AppendableRule appendableRule) { super(target); this.field = appendableRule; } } RuleKey seen = factory.build(new RuleContainingAppendableRule(target, appendableRule)); assertEquals(expected, seen); }
@Test @SuppressWarnings("unchecked") public void testWriteModule() throws Exception { TargetNode<?> guavaTargetNode = JavaLibraryBuilder.createBuilder( BuildTargetFactory.newInstance("//third_party/guava:guava")) .addSrc(Paths.get("third_party/guava/src/Collections.java")) .build(); TargetNode<?> baseTargetNode = JavaLibraryBuilder.createBuilder( BuildTargetFactory.newInstance("//java/com/example/base:base")) .addDep(guavaTargetNode.getBuildTarget()) .addSrc(Paths.get("java/com/example/base/Base.java")) .build(); IjModuleGraph moduleGraph = IjModuleGraphTest.createModuleGraph(ImmutableSet.of(guavaTargetNode, baseTargetNode)); IjModule baseModule = IjModuleGraphTest.getModuleForTarget(moduleGraph, baseTargetNode); IjProjectTemplateDataPreparer dataPreparer = new IjProjectTemplateDataPreparer(javaPackageFinder, moduleGraph, filesystem); ContentRoot contentRoot = dataPreparer.getContentRoot(baseModule); assertEquals("file://$MODULE_DIR$/../../java/com/example/base", contentRoot.getUrl()); IjSourceFolder baseSourceFolder = contentRoot.getFolders().first(); assertEquals("sourceFolder", baseSourceFolder.getType()); assertFalse(baseSourceFolder.getIsTestSource()); assertEquals("com.example.base", baseSourceFolder.getPackagePrefix()); assertEquals("file://$MODULE_DIR$/../../java/com/example/base", baseSourceFolder.getUrl()); assertThat( dataPreparer.getDependencies(baseModule), contains( allOf( hasProperty("type", equalTo(IjDependencyListBuilder.Type.MODULE)), hasProperty( "data", equalTo( Optional.of( DependencyEntryData.builder() .setName("third_party_guava") .setScope(IjDependencyListBuilder.Scope.COMPILE) .setExported(false) .build())))), allOf(hasProperty("type", equalTo(IjDependencyListBuilder.Type.SOURCE_FOLDER))))); }
@Test public void modifyingTheContentsOfTheFileChangesTheRuleKey() throws IOException { Path root = Files.createTempDirectory("root"); FakeProjectFilesystem filesystem = new FakeProjectFilesystem(root.toFile()); Path temp = Paths.get("example_file"); FileHashCache hashCache = new DefaultFileHashCache(filesystem); SourcePathResolver resolver = new SourcePathResolver(new BuildRuleResolver()); RuleKeyBuilderFactory ruleKeyFactory = new DefaultRuleKeyBuilderFactory(hashCache, resolver); filesystem.writeContentsToPath("I like cheese", temp); ExportFileBuilder builder = ExportFileBuilder.newExportFileBuilder(BuildTargetFactory.newInstance("//some:file")) .setSrc(new PathSourcePath(filesystem, temp)); ExportFile rule = (ExportFile) builder.build(new BuildRuleResolver(), filesystem); RuleKey original = ruleKeyFactory.newInstance(rule).build(); filesystem.writeContentsToPath("I really like cheese", temp); // Create a new rule. The FileHashCache held by the existing rule will retain a reference to the // previous content of the file, so we need to create an identical rule. rule = (ExportFile) builder.build(new BuildRuleResolver(), filesystem); hashCache = new DefaultFileHashCache(filesystem); resolver = new SourcePathResolver(new BuildRuleResolver()); ruleKeyFactory = new DefaultRuleKeyBuilderFactory(hashCache, resolver); RuleKey refreshed = ruleKeyFactory.newInstance(rule).build(); assertNotEquals(original, refreshed); }