use of com.google.devtools.build.lib.actions.ActionExecutionContext in project bazel by bazelbuild.
the class TreeArtifactBuildTest method testAbsoluteSymlinkAccepted.
@Test
public void testAbsoluteSymlinkAccepted() throws Exception {
scratch.overwriteFile("/random/pointer");
final Artifact out = createTreeArtifact("output");
TreeArtifactTestAction action = new TreeArtifactTestAction(out) {
@Override
public void execute(ActionExecutionContext actionExecutionContext) {
try {
writeFile(out.getPath().getChild("one"), "one");
writeFile(out.getPath().getChild("two"), "two");
FileSystemUtils.ensureSymbolicLink(out.getPath().getChild("links").getChild("link"), "/random/pointer");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
registerAction(action);
buildArtifact(action.getSoleOutput());
}
use of com.google.devtools.build.lib.actions.ActionExecutionContext in project bazel by bazelbuild.
the class TreeArtifactBuildTest method testInvalidOutputRegistrations.
@Test
public void testInvalidOutputRegistrations() throws Exception {
// Failure expected
StoredEventHandler storingEventHandler = new StoredEventHandler();
reporter.removeHandler(failFastHandler);
reporter.addHandler(storingEventHandler);
TreeArtifactTestAction failureOne = new TreeArtifactTestAction(Runnables.doNothing(), outOneFileOne, outOneFileTwo) {
@Override
public void executeTestBehavior(ActionExecutionContext actionExecutionContext) {
try {
writeFile(outOneFileOne, "one");
writeFile(outOneFileTwo, "two");
// In this test case, we only register one output. This will fail.
registerOutput(actionExecutionContext, "one");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
registerAction(failureOne);
try {
buildArtifact(outOne);
// Should have thrown
fail();
} catch (BuildFailedException e) {
//not all outputs were created
List<Event> errors = ImmutableList.copyOf(Iterables.filter(storingEventHandler.getEvents(), IS_ERROR_EVENT));
assertThat(errors).hasSize(2);
assertThat(errors.get(0).getMessage()).contains("not present on disk");
assertThat(errors.get(1).getMessage()).contains("not all outputs were created or valid");
}
TreeArtifactTestAction failureTwo = new TreeArtifactTestAction(Runnables.doNothing(), outTwoFileOne, outTwoFileTwo) {
@Override
public void executeTestBehavior(ActionExecutionContext actionExecutionContext) {
try {
writeFile(outTwoFileOne, "one");
writeFile(outTwoFileTwo, "two");
// In this test case, register too many outputs. This will fail.
registerOutput(actionExecutionContext, "one");
registerOutput(actionExecutionContext, "two");
registerOutput(actionExecutionContext, "three");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
registerAction(failureTwo);
storingEventHandler.clear();
try {
buildArtifact(outTwo);
// Should have thrown
fail();
} catch (BuildFailedException e) {
List<Event> errors = ImmutableList.copyOf(Iterables.filter(storingEventHandler.getEvents(), IS_ERROR_EVENT));
assertThat(errors).hasSize(2);
assertThat(errors.get(0).getMessage()).contains("not present on disk");
assertThat(errors.get(1).getMessage()).contains("not all outputs were created or valid");
}
}
use of com.google.devtools.build.lib.actions.ActionExecutionContext in project bazel by bazelbuild.
the class TreeArtifactBuildTest method testValidRelativeSymlinkAccepted.
@Test
public void testValidRelativeSymlinkAccepted() throws Exception {
final Artifact out = createTreeArtifact("output");
TreeArtifactTestAction action = new TreeArtifactTestAction(out) {
@Override
public void execute(ActionExecutionContext actionExecutionContext) {
try {
writeFile(out.getPath().getChild("one"), "one");
writeFile(out.getPath().getChild("two"), "two");
FileSystemUtils.ensureSymbolicLink(out.getPath().getChild("links").getChild("link"), "../one");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
registerAction(action);
buildArtifact(action.getSoleOutput());
}
use of com.google.devtools.build.lib.actions.ActionExecutionContext in project bazel by bazelbuild.
the class TreeArtifactBuildTest method testAbsoluteSymlinkBadTargetRejected.
@Test
public void testAbsoluteSymlinkBadTargetRejected() throws Exception {
// Failure expected
StoredEventHandler storingEventHandler = new StoredEventHandler();
reporter.removeHandler(failFastHandler);
reporter.addHandler(storingEventHandler);
final Artifact out = createTreeArtifact("output");
TreeArtifactTestAction action = new TreeArtifactTestAction(out) {
@Override
public void execute(ActionExecutionContext actionExecutionContext) {
try {
writeFile(out.getPath().getChild("one"), "one");
writeFile(out.getPath().getChild("two"), "two");
FileSystemUtils.ensureSymbolicLink(out.getPath().getChild("links").getChild("link"), "/random/pointer");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
registerAction(action);
try {
buildArtifact(action.getSoleOutput());
// Should have thrown
fail();
} catch (BuildFailedException e) {
List<Event> errors = ImmutableList.copyOf(Iterables.filter(storingEventHandler.getEvents(), IS_ERROR_EVENT));
assertThat(errors).hasSize(2);
assertThat(errors.get(0).getMessage()).contains("Failed to resolve relative path links/link");
assertThat(errors.get(1).getMessage()).contains("not all outputs were created or valid");
}
}
use of com.google.devtools.build.lib.actions.ActionExecutionContext in project bazel by bazelbuild.
the class SkyframeAwareActionTest method testRaceConditionBetweenInputAcquisitionAndSkyframeDeps.
/**
* Regression test to avoid a potential race condition in {@link ActionExecutionFunction}.
*
* <p>The test ensures that when ActionExecutionFunction executes a Skyframe-aware action
* (implementor of {@link SkyframeAwareAction}), ActionExecutionFunction first requests the inputs
* of the action and ensures they are built before requesting any of its Skyframe dependencies.
*
* <p>This strict ordering is very important to avoid the race condition, which could arise if the
* compute method were too eager to request all dependencies: request input files but even if some
* are missing, request also the skyframe-dependencies. The race is described in this method's
* body.
*/
@Test
public void testRaceConditionBetweenInputAcquisitionAndSkyframeDeps() throws Exception {
// Sequence of events on threads A and B, showing SkyFunctions and requested SkyKeys, leading
// to an InconsistentFilesystemException:
//
// _______________[Thread A]_________________|_______________[Thread B]_________________
// ActionExecutionFunction(gen2_action: | idle
// genfiles/gen1 -> genfiles/foo/bar/gen2) |
// ARTIFACT:genfiles/gen1 |
// MOCK_VALUE:dummy_argument |
// env.valuesMissing():yes ==> return |
// |
// ArtifactFunction(genfiles/gen1) | MockFunction()
// CONFIGURED_TARGET://foo:gen1 | FILE:genfiles/foo
// ACTION_EXECUTION:gen1_action | env.valuesMissing():yes ==> return
// env.valuesMissing():yes ==> return |
// | FileFunction(genfiles/foo)
// ActionExecutionFunction(gen1_action) | FILE:genfiles
// ARTIFACT:genfiles/gen0 | env.valuesMissing():yes ==> return
// env.valuesMissing():yes ==> return |
// | FileFunction(genfiles)
// ArtifactFunction(genfiles/gen0) | FILE_STATE:genfiles
// CONFIGURED_TARGET://foo:gen0 | env.valuesMissing():yes ==> return
// ACTION_EXECUTION:gen0_action |
// env.valuesMissing():yes ==> return | FileStateFunction(genfiles)
// | stat genfiles
// ActionExecutionFunction(gen0_action) | return FileStateValue:non-existent
// create output directory: genfiles |
// working | FileFunction(genfiles/foo)
// | FILE:genfiles
// | FILE_STATE:genfiles/foo
// | env.valuesMissing():yes ==> return
// |
// | FileStateFunction(genfiles/foo)
// | stat genfiles/foo
// | return FileStateValue:non-existent
// |
// done, created genfiles/gen0 | FileFunction(genfiles/foo)
// return ActionExecutionValue(gen0_action) | FILE:genfiles
// | FILE_STATE:genfiles/foo
// ArtifactFunction(genfiles/gen0) | return FileValue(genfiles/foo:non-existent)
// CONFIGURED_TARGET://foo:gen0 |
// ACTION_EXECUTION:gen0_action | MockFunction()
// return ArtifactSkyKey(genfiles/gen0) | FILE:genfiles/foo
// | FILE:genfiles/foo/bar/gen1
// ActionExecutionFunction(gen1_action) | env.valuesMissing():yes ==> return
// ARTIFACT:genfiles/gen0 |
// create output directory: genfiles/foo/bar | FileFunction(genfiles/foo/bar/gen1)
// done, created genfiles/foo/bar/gen1 | FILE:genfiles/foo/bar
// return ActionExecutionValue(gen1_action) | env.valuesMissing():yes ==> return
// |
// idle | FileFunction(genfiles/foo/bar)
// | FILE:genfiles/foo
// | FILE_STATE:genfiles/foo/bar
// | env.valuesMissing():yes ==> return
// |
// | FileStateFunction(genfiles/foo/bar)
// | stat genfiles/foo/bar
// | return FileStateValue:directory
// |
// | FileFunction(genfiles/foo/bar)
// | FILE:genfiles/foo
// | FILE_STATE:genfiles/foo/bar
// | throw InconsistentFilesystemException:
// | genfiles/foo doesn't exist but
// | genfiles/foo/bar does!
Artifact genFile1 = createDerivedArtifact("foo/bar/gen1.txt");
Artifact genFile2 = createDerivedArtifact("gen2.txt");
registerAction(new SingleOutputAction(null, genFile1) {
@Override
public void execute(ActionExecutionContext actionExecutionContext) throws ActionExecutionException, InterruptedException {
writeOutput(null, "gen1");
}
});
registerAction(new SingleOutputSkyframeAwareAction(genFile1, genFile2) {
@Override
public void establishSkyframeDependencies(Environment env) throws ExceptionBase {
assertThat(env.valuesMissing()).isFalse();
}
@Override
public void execute(ActionExecutionContext actionExecutionContext) throws ActionExecutionException, InterruptedException {
writeOutput(readInput(), "gen2");
}
});
builder.buildArtifacts(reporter, ImmutableSet.of(genFile2), null, null, null, null, executor, null, false, null, null);
}
Aggregations