@Test public void testInferCxxBinaryDepsCaching() throws IOException { assumeTrue(Platform.detect() != Platform.WINDOWS); ProjectWorkspace workspace = InferHelper.setupCxxInferWorkspace(this, tmp); workspace.enableDirCache(); // enable the cache CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(new FakeBuckConfig())); BuildTarget inputBuildTarget = BuildTargetFactory.newInstance("//foo:binary_with_deps"); String inputBuildTargetName = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER).getFullyQualifiedName(); /* * Build the given target and check that it succeeds. */ workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); /* * Check that building after clean will use the cache */ workspace.runBuckCommand("clean").assertSuccess(); workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); BuckBuildLog buildLog = workspace.getBuildLog(); for (BuildTarget buildTarget : buildLog.getAllTargets()) { buildLog.assertTargetWasFetchedFromCache(buildTarget.toString()); } /* * Check that if the file in the binary target changes, then all the deps will be fetched * from the cache */ String sourceName = "src_with_deps.c"; workspace.replaceFileContents("foo/" + sourceName, "10", "30"); workspace.runBuckCommand("clean").assertSuccess(); workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); buildLog = workspace.getBuildLog(); CxxSourceRuleFactory cxxSourceRuleFactory = CxxSourceRuleFactoryHelper.of(inputBuildTarget, cxxPlatform); BuildTarget captureBuildTarget = cxxSourceRuleFactory.createInferCaptureBuildTarget(sourceName); // this is flavored, and denotes the analysis step (generates a local report) BuildTarget inferAnalysisTarget = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER_ANALYZE); // this is the flavored version of the top level target (the one give in input to buck) BuildTarget inferReportTarget = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER); String bt; for (BuildTarget buildTarget : buildLog.getAllTargets()) { bt = buildTarget.toString(); if (bt.equals(inferAnalysisTarget.toString()) || bt.equals(captureBuildTarget.toString()) || bt.equals(inferReportTarget.toString())) { buildLog.assertTargetBuiltLocally(bt); } else { buildLog.assertTargetWasFetchedFromCache(buildTarget.toString()); } } }
@Test public void compilationDatabaseFetchedFromCacheAlsoFetchesSymlinkTreeOrHeaderMap() throws IOException { ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "compilation_database", tmp); workspace.setUp(); ProjectFilesystem filesystem = new FakeProjectFilesystem(); // This test only fails if the directory cache is enabled and we don't update // the header map/symlink tree correctly when fetching from the cache. workspace.enableDirCache(); addLibraryHeaderFiles(workspace); BuildTarget target = BuildTargetFactory.newInstance("//:library_with_header#default,compilation-database"); // Populate the cache with the built rule workspace.buildAndReturnOutput(target.getFullyQualifiedName()); Path headerSymlinkTreeFolder = BuildTargets.getGenPath( filesystem, target.withFlavors( ImmutableFlavor.of("default"), CxxDescriptionEnhancer.HEADER_SYMLINK_TREE_FLAVOR), "%s"); Path exportedHeaderSymlinkTreeFolder = BuildTargets.getGenPath( filesystem, target.withFlavors( ImmutableFlavor.of("default"), CxxDescriptionEnhancer.EXPORTED_HEADER_SYMLINK_TREE_FLAVOR), "%s"); // Validate the symlink tree/header maps verifyHeaders(workspace, headerSymlinkTreeFolder, "bar.h", "baz.h", "blech_private.h"); verifyHeaders(workspace, exportedHeaderSymlinkTreeFolder, "bar.h", "baz.h"); // Delete the newly-added files and build again Files.delete(workspace.getPath("baz.h")); Files.delete(workspace.getPath("blech_private.h")); workspace.buildAndReturnOutput(target.getFullyQualifiedName()); verifyHeaders(workspace, headerSymlinkTreeFolder, "bar.h"); verifyHeaders(workspace, exportedHeaderSymlinkTreeFolder, "bar.h"); // Restore the headers, build again, and check the symlink tree/header maps addLibraryHeaderFiles(workspace); workspace.buildAndReturnOutput(target.getFullyQualifiedName()); verifyHeaders(workspace, headerSymlinkTreeFolder, "bar.h", "baz.h", "blech_private.h"); verifyHeaders(workspace, exportedHeaderSymlinkTreeFolder, "bar.h", "baz.h"); }
@Test public void testInferCxxBinaryWithCachedDepsGetsAllItsTransitiveDeps() throws IOException { assumeTrue(Platform.detect() != Platform.WINDOWS); ProjectWorkspace workspace = InferHelper.setupCxxInferWorkspace(this, tmp); workspace.enableDirCache(); // enable the cache BuildTarget inputBuildTarget = BuildTargetFactory.newInstance("//foo:binary_with_chain_deps"); String inputBuildTargetName = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER).getFullyQualifiedName(); /* * Build the given target and check that it succeeds. */ workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); /* * Check that building after clean will use the cache */ workspace.runBuckCommand("clean").assertSuccess(); workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); BuckBuildLog buildLog = workspace.getBuildLog(); for (BuildTarget buildTarget : buildLog.getAllTargets()) { buildLog.assertTargetWasFetchedFromCache(buildTarget.toString()); } /* * Check that if the file in the top target changes, then all the transitive deps will be * fetched from the cache (even those that are not direct dependencies). * Make sure there's the specs file of the dependency that has distance 2 from * the binary target. */ String sourceName = "top_chain.c"; workspace.replaceFileContents("foo/" + sourceName, "*p += 1", "*p += 10"); workspace.runBuckCommand("clean").assertSuccess(); workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); // Check all the buildrules were fetched from the cache (and there's the specs file) assertTrue( "Expected specs file for func_ret_null() in chain_dep_two.c not found", workspace .getPath( "buck-out/gen/foo/infer-analysis-chain_dep_two#default,infer-analyze/specs/" + "mockedSpec.specs") .toFile() .exists()); }
@Test public void compilationDatabaseWithDepsFetchedFromCacheAlsoFetchesSymlinkTreeOrHeaderMapOfDeps() throws IOException { ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "compilation_database_with_deps", tmp); workspace.setUp(); ProjectFilesystem filesystem = new FakeProjectFilesystem(); // This test only fails if the directory cache is enabled and we don't update // the header map/symlink tree correctly when fetching from the cache. workspace.enableDirCache(); addDepLibraryHeaderFiles(workspace); BuildTarget target = BuildTargetFactory.newInstance("//:library_with_header#default,compilation-database"); // Populate the cache with the built rule workspace.buildAndReturnOutput(target.getFullyQualifiedName()); Path dep1ExportedSymlinkTreeFolder = BuildTargets.getGenPath( filesystem, BuildTargetFactory.newInstance("//dep1:dep1#default,headers"), "%s"); Path dep2ExportedSymlinkTreeFolder = BuildTargets.getGenPath( filesystem, BuildTargetFactory.newInstance("//dep2:dep2#default,headers"), "%s"); // Validate the deps' symlink tree/header maps verifyHeaders(workspace, dep1ExportedSymlinkTreeFolder, "dep1/dep1.h", "dep1/dep1_new.h"); verifyHeaders(workspace, dep2ExportedSymlinkTreeFolder, "dep2/dep2.h", "dep2/dep2_new.h"); // Delete the newly-added files and build again Files.delete(workspace.getPath("dep1/dep1_new.h")); Files.delete(workspace.getPath("dep2/dep2_new.h")); workspace.buildAndReturnOutput(target.getFullyQualifiedName()); verifyHeaders(workspace, dep1ExportedSymlinkTreeFolder, "dep1/dep1.h"); verifyHeaders(workspace, dep2ExportedSymlinkTreeFolder, "dep2/dep2.h"); // Restore the headers, build again, and check the deps' symlink tree/header maps addDepLibraryHeaderFiles(workspace); workspace.buildAndReturnOutput(target.getFullyQualifiedName()); verifyHeaders(workspace, dep1ExportedSymlinkTreeFolder, "dep1/dep1.h", "dep1/dep1_new.h"); verifyHeaders(workspace, dep2ExportedSymlinkTreeFolder, "dep2/dep2.h", "dep2/dep2_new.h"); }