use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method continueWithErrorDep.
@Test
public void continueWithErrorDep() throws Exception {
initializeTester();
SkyKey errorKey = GraphTester.toSkyKey("my_error_value");
tester.getOrCreate(errorKey).setHasError(true);
tester.set("after", new StringValue("after"));
SkyKey parentKey = GraphTester.toSkyKey("parent");
tester.getOrCreate(parentKey).addErrorDependency(errorKey, new StringValue("recovered")).setComputedValue(CONCATENATE).addDependency("after");
EvaluationResult<StringValue> result = tester.eval(/*keepGoing=*/
true, parentKey);
assertThat(result.errorMap()).isEmpty();
assertEquals("recoveredafter", result.get(parentKey).getValue());
tester.set("after", new StringValue("before"));
tester.invalidate();
result = tester.eval(/*keepGoing=*/
true, parentKey);
assertThat(result.errorMap()).isEmpty();
assertEquals("recoveredbefore", result.get(parentKey).getValue());
}
use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method errorInDependencyGroup.
/**
* "top" requests a dependency group in which the first value, called "error", throws an
* exception, so "mid" and "mid2", which depend on "slow", never get built.
*/
@Test
public void errorInDependencyGroup() throws Exception {
initializeTester();
SkyKey topKey = GraphTester.toSkyKey("top");
CountDownLatch slowStart = new CountDownLatch(1);
CountDownLatch errorFinish = new CountDownLatch(1);
final SkyKey errorKey = GraphTester.toSkyKey("error");
tester.getOrCreate(errorKey).setBuilder(new ChainedFunction(/*notifyStart=*/
null, /*waitToFinish=*/
slowStart, /*notifyFinish=*/
errorFinish, /*waitForException=*/
false, /*value=*/
null, /*deps=*/
ImmutableList.<SkyKey>of()));
SkyKey slowKey = GraphTester.toSkyKey("slow");
tester.getOrCreate(slowKey).setBuilder(new ChainedFunction(/*notifyStart=*/
slowStart, /*waitToFinish=*/
errorFinish, /*notifyFinish=*/
null, /*waitForException=*/
true, new StringValue("slow"), /*deps=*/
ImmutableList.<SkyKey>of()));
final SkyKey midKey = GraphTester.toSkyKey("mid");
tester.getOrCreate(midKey).addDependency(slowKey).setComputedValue(COPY);
final SkyKey mid2Key = GraphTester.toSkyKey("mid2");
tester.getOrCreate(mid2Key).addDependency(slowKey).setComputedValue(COPY);
tester.set(topKey, null);
tester.getOrCreate(topKey).setBuilder(new SkyFunction() {
@Override
public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException, InterruptedException {
env.getValues(ImmutableList.of(errorKey, midKey, mid2Key));
if (env.valuesMissing()) {
return null;
}
return new StringValue("top");
}
@Override
public String extractTag(SkyKey skyKey) {
return null;
}
});
// Assert that build fails and "error" really is in error.
EvaluationResult<StringValue> result = tester.eval(/*keepGoing=*/
false, topKey);
assertTrue(result.hasError());
assertThat(result.getError(topKey).getRootCauses()).containsExactly(errorKey);
// Ensure that evaluation succeeds if errorKey does not throw an error.
tester.getOrCreate(errorKey).setBuilder(null);
tester.set(errorKey, new StringValue("ok"));
tester.invalidate();
assertEquals(new StringValue("top"), tester.evalAndGet("top"));
}
use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method manyDirtyValuesClearChildrenOnFail.
/**
* Regression test: enqueue so many values that some of them won't have started processing, and
* then either interrupt processing or have a child throw an error. In the latter case, this also
* tests that a value that hasn't started processing can still have a child error bubble up to it.
* In both cases, it tests that the graph is properly cleaned of the dirty values and references
* to them.
*/
private void manyDirtyValuesClearChildrenOnFail(boolean interrupt) throws Exception {
SkyKey leafKey = GraphTester.toSkyKey("leaf");
tester.set(leafKey, new StringValue("leafy"));
SkyKey lastKey = GraphTester.toSkyKey("last");
tester.set(lastKey, new StringValue("last"));
final List<SkyKey> tops = new ArrayList<>();
// leaf child is enqueued for processing.
for (int i = 0; i < 10000; i++) {
SkyKey topKey = GraphTester.toSkyKey("top" + i);
tester.getOrCreate(topKey).addDependency(leafKey).addDependency(lastKey).setComputedValue(CONCATENATE);
tops.add(topKey);
}
tester.eval(/*keepGoing=*/
false, tops.toArray(new SkyKey[0]));
final CountDownLatch notifyStart = new CountDownLatch(1);
tester.set(leafKey, null);
if (interrupt) {
// leaf will wait for an interrupt if desired. We cannot use the usual ChainedFunction
// because we need to actually throw the interrupt.
final AtomicBoolean shouldSleep = new AtomicBoolean(true);
tester.getOrCreate(leafKey, /*markAsModified=*/
true).setBuilder(new NoExtractorFunction() {
@Override
public SkyValue compute(SkyKey skyKey, Environment env) throws InterruptedException {
notifyStart.countDown();
if (shouldSleep.get()) {
// Should be interrupted within 5 seconds.
Thread.sleep(5000);
throw new AssertionError("leaf was not interrupted");
}
return new StringValue("crunchy");
}
});
tester.invalidate();
TestThread evalThread = new TestThread() {
@Override
public void runTest() {
try {
tester.eval(/*keepGoing=*/
false, tops.toArray(new SkyKey[0]));
Assert.fail();
} catch (InterruptedException e) {
// Expected.
}
}
};
evalThread.start();
assertTrue(notifyStart.await(TestUtils.WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS));
evalThread.interrupt();
evalThread.joinAndAssertState(TestUtils.WAIT_TIMEOUT_MILLISECONDS);
// Free leafKey to compute next time.
shouldSleep.set(false);
} else {
// Non-interrupt case. Just throw an error in the child.
tester.getOrCreate(leafKey, /*markAsModified=*/
true).setHasError(true);
tester.invalidate();
// The error thrown may non-deterministically bubble up to a parent that has not yet started
// processing, but has been enqueued for processing.
tester.eval(/*keepGoing=*/
false, tops.toArray(new SkyKey[0]));
tester.getOrCreate(leafKey, /*markAsModified=*/
true).setHasError(false);
tester.set(leafKey, new StringValue("crunchy"));
}
// lastKey was not touched during the previous build, but its reverse deps on its parents should
// still be accurate.
tester.set(lastKey, new StringValue("new last"));
tester.invalidate();
EvaluationResult<StringValue> result = tester.eval(/*keepGoing=*/
false, tops.toArray(new SkyKey[0]));
for (SkyKey topKey : tops) {
assertEquals(topKey.toString(), "crunchynew last", result.get(topKey).getValue());
}
}
use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method dirtyDependsOnErrorTurningGood.
@Test
public void dirtyDependsOnErrorTurningGood() throws Exception {
initializeTester();
SkyKey error = GraphTester.toSkyKey("error");
tester.getOrCreate(error).setHasError(true);
SkyKey topKey = GraphTester.toSkyKey("top");
tester.getOrCreate(topKey).addDependency(error).setComputedValue(COPY);
EvaluationResult<StringValue> result = tester.eval(/*keepGoing=*/
false, topKey);
assertThat(result.getError(topKey).getRootCauses()).containsExactly(error);
tester.getOrCreate(error).setHasError(false);
StringValue val = new StringValue("reformed");
tester.set(error, val);
tester.invalidate();
result = tester.eval(/*keepGoing=*/
false, topKey);
assertEquals(val, result.get(topKey));
assertFalse(result.hasError());
}
use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method transientPruning.
@Test
public void transientPruning() throws Exception {
SkyKey leaf = GraphTester.toSkyKey("leaf");
tester.getOrCreate("top").setHasTransientError(true).addDependency(leaf);
tester.set(leaf, new StringValue("leafy"));
tester.evalAndGetError("top");
tester.getOrCreate(leaf, /*markAsModified=*/
true);
tester.invalidate();
tester.evalAndGetError("top");
}
Aggregations