use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method parentOfCycleAndTransientInternal.
/**
* {@link ParallelEvaluator} can be configured to not store errors alongside recovered values.
* In that case, transient errors that are recovered from do not make the parent transient.
*/
protected void parentOfCycleAndTransientInternal(boolean errorsStoredAlongsideValues) throws Exception {
initializeTester();
SkyKey cycleKey1 = GraphTester.toSkyKey("cycleKey1");
SkyKey cycleKey2 = GraphTester.toSkyKey("cycleKey2");
SkyKey mid = GraphTester.toSkyKey("mid");
SkyKey errorKey = GraphTester.toSkyKey("errorKey");
tester.getOrCreate(cycleKey1).addDependency(cycleKey2).setComputedValue(COPY);
tester.getOrCreate(cycleKey2).addDependency(cycleKey1).setComputedValue(COPY);
tester.getOrCreate(errorKey).setHasTransientError(true);
tester.getOrCreate(mid).addErrorDependency(errorKey, new StringValue("recovered")).setComputedValue(COPY);
SkyKey top = GraphTester.toSkyKey("top");
CountDownLatch topEvaluated = new CountDownLatch(2);
tester.getOrCreate(top).setBuilder(new ChainedFunction(topEvaluated, null, null, false, new StringValue("unused"), ImmutableList.of(mid, cycleKey1)));
EvaluationResult<StringValue> evalResult = tester.eval(true, top);
assertThatEvaluationResult(evalResult).hasError();
ErrorInfo errorInfo = evalResult.getError(top);
assertThat(topEvaluated.getCount()).isEqualTo(1);
if (errorsStoredAlongsideValues) {
// The parent should be transitively transient, since it transitively depends on a transient
// error.
assertThat(errorInfo.isTransient()).isTrue();
assertThat(errorInfo.getException()).hasMessage(NODE_TYPE.getName() + ":errorKey");
assertThat(errorInfo.getRootCauseOfException()).isEqualTo(errorKey);
} else {
assertThatErrorInfo(errorInfo).isNotTransient();
assertThatErrorInfo(errorInfo).hasExceptionThat().isNull();
}
if (cyclesDetected()) {
assertThatErrorInfo(errorInfo).hasCycleInfoThat().containsExactly(new CycleInfo(ImmutableList.of(top), ImmutableList.of(cycleKey1, cycleKey2)));
} else {
assertThatErrorInfo(errorInfo).hasCycleInfoThat().hasSize(1);
}
// But the parent itself shouldn't have a direct dep on the special error transience node.
assertThatEvaluationResult(evalResult).hasDirectDepsInGraphThat(top).doesNotContain(ErrorTransienceValue.KEY);
}
use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method changePruningWithDoneValue.
@Test
public void changePruningWithDoneValue() throws Exception {
initializeTester();
SkyKey leaf = GraphTester.toSkyKey("leaf");
SkyKey mid = GraphTester.toSkyKey("mid");
SkyKey top = GraphTester.toSkyKey("top");
SkyKey suffix = GraphTester.toSkyKey("suffix");
StringValue suffixValue = new StringValue("suffix");
tester.set(suffix, suffixValue);
tester.getOrCreate(top).addDependency(mid).addDependency(suffix).setComputedValue(CONCATENATE);
tester.getOrCreate(mid).addDependency(leaf).addDependency(suffix).setComputedValue(CONCATENATE);
SkyValue leafyValue = new StringValue("leafy");
tester.set(leaf, leafyValue);
StringValue value = (StringValue) tester.evalAndGet("top");
assertEquals("leafysuffixsuffix", value.getValue());
// Mark leaf changed, but don't actually change it.
tester.getOrCreate(leaf, /*markAsModified=*/
true);
// mid will give an error if re-evaluated, but it shouldn't be because it is not marked changed,
// and its dirty child will evaluate to the same element.
tester.getOrCreate(mid, /*markAsModified=*/
false).setHasError(true);
tester.invalidate();
value = (StringValue) tester.evalAndGet("leaf");
assertEquals("leafy", value.getValue());
assertThat(tester.getDirtyKeys()).containsExactly(mid, top);
assertThat(tester.getDeletedKeys()).isEmpty();
EvaluationResult<StringValue> result = tester.eval(/*keepGoing=*/
false, top);
assertWithMessage(result.toString()).that(result.hasError()).isFalse();
value = result.get(top);
assertEquals("leafysuffixsuffix", value.getValue());
assertThat(tester.getDirtyKeys()).isEmpty();
assertThat(tester.getDeletedKeys()).isEmpty();
}
use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method singleValueDependsOnManyDirtyValues.
@Test
public void singleValueDependsOnManyDirtyValues() throws Exception {
initializeTester();
SkyKey[] values = new SkyKey[TEST_NODE_COUNT];
StringBuilder expected = new StringBuilder();
for (int i = 0; i < values.length; i++) {
String valueName = Integer.toString(i);
values[i] = GraphTester.toSkyKey(valueName);
tester.set(values[i], new StringValue(valueName));
expected.append(valueName);
}
SkyKey topKey = toSkyKey("top");
TestFunction value = tester.getOrCreate(topKey).setComputedValue(CONCATENATE);
for (int i = 0; i < values.length; i++) {
value.addDependency(values[i]);
}
EvaluationResult<StringValue> result = tester.eval(/*keepGoing=*/
false, topKey);
assertEquals(new StringValue(expected.toString()), result.get(topKey));
for (int j = 0; j < RUNS; j++) {
for (int i = 0; i < values.length; i++) {
tester.getOrCreate(values[i], /*markAsModified=*/
true);
}
// This value has an error, but we should never discover it because it is not marked changed
// and all of its dependencies re-evaluate to the same thing.
tester.getOrCreate(topKey, /*markAsModified=*/
false).setHasError(true);
tester.invalidate();
result = tester.eval(/*keep_going=*/
false, topKey);
assertEquals(new StringValue(expected.toString()), result.get(topKey));
}
}
use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method dirtyValueChildrenProperlyRemovedOnEarlyBuildAbort.
/**
* Tests scenario where we have dirty values in the graph, and then one of them is deleted since
* its evaluation did not complete before an error was thrown. Can either test the graph via an
* evaluation of that deleted value, or an invalidation of a child, and can either remove the
* thrown error or throw it again on that evaluation.
*/
private void dirtyValueChildrenProperlyRemovedOnEarlyBuildAbort(boolean reevaluateMissingValue, boolean removeError) throws Exception {
initializeTester();
SkyKey errorKey = GraphTester.toSkyKey("error");
tester.set(errorKey, new StringValue("biding time"));
SkyKey slowKey = GraphTester.toSkyKey("slow");
tester.set(slowKey, new StringValue("slow"));
SkyKey midKey = GraphTester.toSkyKey("mid");
tester.getOrCreate(midKey).addDependency(slowKey).setComputedValue(COPY);
SkyKey lastKey = GraphTester.toSkyKey("last");
tester.set(lastKey, new StringValue("last"));
SkyKey motherKey = GraphTester.toSkyKey("mother");
tester.getOrCreate(motherKey).addDependency(errorKey).addDependency(midKey).addDependency(lastKey).setComputedValue(CONCATENATE);
SkyKey fatherKey = GraphTester.toSkyKey("father");
tester.getOrCreate(fatherKey).addDependency(errorKey).addDependency(midKey).addDependency(lastKey).setComputedValue(CONCATENATE);
EvaluationResult<StringValue> result = tester.eval(/*keepGoing=*/
false, motherKey, fatherKey);
assertEquals("biding timeslowlast", result.get(motherKey).getValue());
assertEquals("biding timeslowlast", result.get(fatherKey).getValue());
tester.set(slowKey, null);
// Each parent depends on errorKey, midKey, lastKey. We keep slowKey waiting until errorKey is
// finished. So there is no way lastKey can be enqueued by either parent. Thus, the parent that
// is cleaned has not interacted with lastKey this build. Still, lastKey's reverse dep on that
// parent should be removed.
CountDownLatch errorFinish = new CountDownLatch(1);
tester.set(errorKey, null);
tester.getOrCreate(errorKey).setBuilder(new ChainedFunction(/*notifyStart=*/
null, /*waitToFinish=*/
null, /*notifyFinish=*/
errorFinish, /*waitForException=*/
false, /*value=*/
null, /*deps=*/
ImmutableList.<SkyKey>of()));
tester.getOrCreate(slowKey).setBuilder(new ChainedFunction(/*notifyStart=*/
null, /*waitToFinish=*/
errorFinish, /*notifyFinish=*/
null, /*waitForException=*/
true, new StringValue("leaf2"), /*deps=*/
ImmutableList.<SkyKey>of()));
tester.invalidate();
// errorKey finishes, written to graph -> leafKey maybe starts+finishes & (Visitor aborts)
// -> one of mother or father builds. The other one should be cleaned, and no references to it
// left in the graph.
result = tester.eval(/*keepGoing=*/
false, motherKey, fatherKey);
assertTrue(result.hasError());
// Only one of mother or father should be in the graph.
assertTrue(result.getError(motherKey) + ", " + result.getError(fatherKey), (result.getError(motherKey) == null) != (result.getError(fatherKey) == null));
SkyKey parentKey = (reevaluateMissingValue == (result.getError(motherKey) == null)) ? motherKey : fatherKey;
// Give slowKey a nice ordinary builder.
tester.getOrCreate(slowKey, /*markAsModified=*/
false).setBuilder(null).setConstantValue(new StringValue("leaf2"));
if (removeError) {
tester.getOrCreate(errorKey, /*markAsModified=*/
true).setBuilder(null).setConstantValue(new StringValue("reformed"));
}
String lastString = "last";
if (!reevaluateMissingValue) {
// Mark the last key modified if we're not trying the absent value again. This invalidation
// will test if lastKey still has a reference to the absent value.
lastString = "last2";
tester.set(lastKey, new StringValue(lastString));
}
tester.invalidate();
result = tester.eval(/*keepGoing=*/
false, parentKey);
if (removeError) {
assertThat(result.get(parentKey).getValue()).isEqualTo("reformedleaf2" + lastString);
} else {
assertNotNull(result.getError(parentKey));
}
}
use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method valueInjectionOverExistingEntryMarkedForInvalidation.
@Test
public void valueInjectionOverExistingEntryMarkedForInvalidation() throws Exception {
SkyKey key = GraphTester.toSkyKey("value");
SkyValue val = new StringValue("val");
tester.getOrCreate(key).setConstantValue(new StringValue("old_val"));
tester.differencer.invalidate(ImmutableList.of(key));
tester.differencer.inject(ImmutableMap.of(key, val));
assertEquals(val, tester.evalAndGet("value"));
}
Aggregations