use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method checkNotComparableNotPruned.
private void checkNotComparableNotPruned(boolean hasEvent) throws Exception {
initializeTester();
SkyKey parent = GraphTester.toSkyKey("parent");
SkyKey child = GraphTester.toSkyKey("child");
NotComparableStringValue notComparableString = new NotComparableStringValue("not comparable");
if (hasEvent) {
tester.getOrCreate(child).setConstantValue(notComparableString).setWarning("shmoop");
} else {
tester.getOrCreate(child).setConstantValue(notComparableString);
}
final AtomicInteger parentEvaluated = new AtomicInteger();
final String val = "some val";
tester.getOrCreate(parent).addDependency(child).setComputedValue(new ValueComputer() {
@Override
public SkyValue compute(Map<SkyKey, SkyValue> deps, Environment env) throws InterruptedException {
parentEvaluated.incrementAndGet();
return new StringValue(val);
}
});
assertStringValue(val, tester.evalAndGet(/*keepGoing=*/
false, parent));
assertThat(parentEvaluated.get()).isEqualTo(1);
if (hasEvent) {
assertContainsEvent(eventCollector, "shmoop");
} else {
assertEventCount(0, eventCollector);
}
tester.resetPlayedEvents();
tester.getOrCreate(child, /*markAsModified=*/
true);
tester.invalidate();
assertStringValue(val, tester.evalAndGet(/*keepGoing=*/
false, parent));
assertThat(parentEvaluated.get()).isEqualTo(2);
if (hasEvent) {
assertContainsEvent(eventCollector, "shmoop");
} else {
assertEventCount(0, eventCollector);
}
}
use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method cachedErrorCausesRestart.
/**
* Tests that a race between a node being marked clean and another node requesting it is benign.
* Here, we first evaluate errorKey, depending on invalidatedKey. Then we invalidate
* invalidatedKey (without actually changing it) and evaluate errorKey and topKey together.
* Through forced synchronization, we make sure that the following sequence of events happens:
*
* <ol>
* <li>topKey requests errorKey;
* <li>errorKey is marked clean;
* <li>topKey finishes its first evaluation and registers its deps;
* <li>topKey restarts, since it sees that its only dep, errorKey, is done;
* <li>topKey sees the error thrown by errorKey and throws the error, shutting down the
* threadpool;
* </ol>
*/
@Test
public void cachedErrorCausesRestart() throws Exception {
// TrackingProgressReceiver does unnecessary examination of node values.
initializeTester(new TrackingProgressReceiver() {
@Override
public void evaluated(SkyKey skyKey, Supplier<SkyValue> skyValueSupplier, EvaluationState state) {
evaluated.add(skyKey);
}
});
final SkyKey errorKey = GraphTester.toSkyKey("error");
SkyKey invalidatedKey = GraphTester.toSkyKey("invalidated");
final SkyKey topKey = GraphTester.toSkyKey("top");
tester.getOrCreate(errorKey).addDependency(invalidatedKey).setHasError(true);
tester.getOrCreate(invalidatedKey).setConstantValue(new StringValue("constant"));
final CountDownLatch topSecondEval = new CountDownLatch(2);
final CountDownLatch topRequestedError = new CountDownLatch(1);
final CountDownLatch errorMarkedClean = new CountDownLatch(1);
injectGraphListenerForTesting(new Listener() {
@Override
public void accept(SkyKey key, EventType type, Order order, Object context) {
if (errorKey.equals(key) && type == EventType.MARK_CLEAN) {
if (order == Order.BEFORE) {
TrackingAwaiter.INSTANCE.awaitLatchAndTrackExceptions(topRequestedError, "top didn't request");
} else {
errorMarkedClean.countDown();
TrackingAwaiter.INSTANCE.awaitLatchAndTrackExceptions(topSecondEval, "top didn't restart");
// Make sure that the other thread notices the error and interrupts this thread.
try {
Thread.sleep(TestUtils.WAIT_TIMEOUT_MILLISECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
}, /*deterministic=*/
false);
EvaluationResult<StringValue> result = tester.eval(/*keepGoing=*/
false, errorKey);
assertThatEvaluationResult(result).hasError();
assertThatEvaluationResult(result).hasErrorEntryForKeyThat(errorKey).hasExceptionThat().isNotNull();
tester.getOrCreate(topKey).setBuilder(new SkyFunction() {
@Nullable
@Override
public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException, InterruptedException {
topSecondEval.countDown();
env.getValue(errorKey);
topRequestedError.countDown();
assertThat(env.valuesMissing()).isTrue();
TrackingAwaiter.INSTANCE.awaitLatchAndTrackExceptions(errorMarkedClean, "error not marked clean");
return null;
}
@Nullable
@Override
public String extractTag(SkyKey skyKey) {
return null;
}
});
tester.getOrCreate(invalidatedKey, /*markAsModified=*/
true);
tester.invalidate();
EvaluationResult<StringValue> result2 = tester.eval(/*keepGoing=*/
false, errorKey, topKey);
assertThatEvaluationResult(result2).hasError();
assertThatEvaluationResult(result2).hasErrorEntryForKeyThat(errorKey).hasExceptionThat().isNotNull();
assertThatEvaluationResult(result2).hasErrorEntryForKeyThat(topKey).hasExceptionThat().isNotNull();
assertThatEvaluationResult(result2).hasErrorEntryForKeyThat(topKey).rootCauseOfExceptionIs(errorKey);
}
use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method failedDirtyBuildInBuilder.
@Test
public void failedDirtyBuildInBuilder() throws Exception {
initializeTester();
SkyKey leaf = GraphTester.toSkyKey("leaf");
SkyKey secondError = GraphTester.toSkyKey("secondError");
SkyKey top = GraphTester.toSkyKey("top");
tester.getOrCreate(top).addDependency(leaf).addErrorDependency(secondError, new StringValue("recover")).setComputedValue(CONCATENATE);
tester.set(secondError, new StringValue("secondError")).addDependency(leaf);
tester.set(leaf, new StringValue("leafy"));
StringValue topValue = (StringValue) tester.evalAndGet("top");
assertEquals("leafysecondError", topValue.getValue());
assertThat(tester.getDirtyKeys()).isEmpty();
assertThat(tester.getDeletedKeys()).isEmpty();
// Invalidate leaf.
tester.getOrCreate(leaf, /*markAsModified=*/
true);
tester.set(leaf, new StringValue("crunchy"));
tester.getOrCreate(secondError, /*markAsModified=*/
true).setHasError(true);
tester.getOrCreate(top, /*markAsModified=*/
false).setHasError(true);
tester.invalidate();
EvaluationResult<StringValue> result = tester.eval(/*keepGoing=*/
false, top);
assertNull("value should not have completed evaluation", result.get(top));
assertWithMessage("The error thrown by leaf should have been swallowed by the error thrown by top").that(result.getError().getRootCauses()).containsExactly(top);
}
use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method twoRailLeftRightDependenciesWithFailure.
/**
* General stress/fuzz test of the evaluator with failure. Construct a large graph, and then throw
* exceptions during building at various points.
*/
@Test
public void twoRailLeftRightDependenciesWithFailure() throws Exception {
initializeTester();
SkyKey[] leftValues = new SkyKey[TEST_NODE_COUNT];
SkyKey[] rightValues = new SkyKey[TEST_NODE_COUNT];
for (int i = 0; i < TEST_NODE_COUNT; i++) {
leftValues[i] = GraphTester.toSkyKey("left-" + i);
rightValues[i] = GraphTester.toSkyKey("right-" + i);
if (i == 0) {
tester.getOrCreate(leftValues[i]).addDependency("leaf").setComputedValue(COPY);
tester.getOrCreate(rightValues[i]).addDependency("leaf").setComputedValue(COPY);
} else {
tester.getOrCreate(leftValues[i]).addDependency(leftValues[i - 1]).addDependency(rightValues[i - 1]).setComputedValue(new PassThroughSelected(leftValues[i - 1]));
tester.getOrCreate(rightValues[i]).addDependency(leftValues[i - 1]).addDependency(rightValues[i - 1]).setComputedValue(new PassThroughSelected(rightValues[i - 1]));
}
}
tester.set("leaf", new StringValue("leaf"));
String lastLeft = "left-" + (TEST_NODE_COUNT - 1);
String lastRight = "right-" + (TEST_NODE_COUNT - 1);
for (int i = 0; i < TESTED_NODES; i++) {
try {
tester.getOrCreate(leftValues[i], /*markAsModified=*/
true).setHasError(true);
tester.invalidate();
EvaluationResult<StringValue> result = tester.eval(/*keep_going=*/
false, lastLeft, lastRight);
assertTrue(result.hasError());
tester.differencer.invalidate(ImmutableList.of(leftValues[i]));
tester.invalidate();
result = tester.eval(/*keep_going=*/
false, lastLeft, lastRight);
assertTrue(result.hasError());
tester.getOrCreate(leftValues[i], /*markAsModified=*/
true).setHasError(false);
tester.invalidate();
result = tester.eval(/*keep_going=*/
false, lastLeft, lastRight);
assertEquals(new StringValue("leaf"), result.get(toSkyKey(lastLeft)));
assertEquals(new StringValue("leaf"), result.get(toSkyKey(lastRight)));
} catch (Exception e) {
System.err.println("twoRailLeftRightDependenciesWithFailure exception on run " + i);
throw e;
}
}
}
use of com.google.devtools.build.skyframe.GraphTester.StringValue in project bazel by bazelbuild.
the class MemoizingEvaluatorTest method nodeInvalidatedThenDoubleCycle.
@Test
public void nodeInvalidatedThenDoubleCycle() throws InterruptedException {
makeGraphDeterministic();
// When topKey depends on depKey, and both are top-level nodes in the graph,
final SkyKey topKey = skyKey("bKey");
final SkyKey depKey = skyKey("aKey");
tester.getOrCreate(topKey).addDependency(depKey).setConstantValue(new StringValue("a"));
tester.getOrCreate(depKey).setConstantValue(new StringValue("b"));
// Then evaluation is as expected.
EvaluationResult<StringValue> result1 = tester.eval(/*keepGoing=*/
true, topKey, depKey);
assertThatEvaluationResult(result1).hasEntryThat(topKey).isEqualTo(new StringValue("a"));
assertThatEvaluationResult(result1).hasEntryThat(depKey).isEqualTo(new StringValue("b"));
assertThatEvaluationResult(result1).hasNoError();
// When both nodes acquire self-edges, with topKey still also depending on depKey, in the same
// group,
tester.getOrCreate(depKey, /*markAsModified=*/
true).addDependency(depKey);
tester.getOrCreate(topKey, /*markAsModified=*/
true).setConstantValue(null).removeDependency(depKey).setBuilder(new SkyFunction() {
@Nullable
@Override
public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException, InterruptedException {
env.getValues(ImmutableList.of(topKey, depKey));
assertThat(env.valuesMissing()).isTrue();
return null;
}
@Nullable
@Override
public String extractTag(SkyKey skyKey) {
return null;
}
});
tester.invalidate();
// Then evaluation is as expected -- topKey has removed its dep on depKey (since depKey was not
// done when topKey found its cycle), and both topKey and depKey have cycles.
EvaluationResult<StringValue> result2 = tester.eval(/*keepGoing=*/
true, topKey, depKey);
if (cyclesDetected()) {
assertThatEvaluationResult(result2).hasErrorEntryForKeyThat(topKey).hasCycleInfoThat().containsExactly(new CycleInfo(ImmutableList.of(topKey)));
assertThatEvaluationResult(result2).hasDirectDepsInGraphThat(topKey).containsExactly(topKey);
assertThatEvaluationResult(result2).hasErrorEntryForKeyThat(depKey).hasCycleInfoThat().containsExactly(new CycleInfo(ImmutableList.of(depKey)));
} else {
assertThatEvaluationResult(result2).hasErrorEntryForKeyThat(topKey).hasCycleInfoThat().hasSize(1);
assertThatEvaluationResult(result2).hasErrorEntryForKeyThat(depKey).hasCycleInfoThat().hasSize(1);
}
// When the nodes return to their original, error-free state,
tester.getOrCreate(topKey, /*markAsModified=*/
true).setBuilder(null).addDependency(depKey).setConstantValue(new StringValue("a"));
tester.getOrCreate(depKey, /*markAsModified=*/
true).removeDependency(depKey);
tester.invalidate();
// Then evaluation is as expected.
EvaluationResult<StringValue> result3 = tester.eval(/*keepGoing=*/
true, topKey, depKey);
assertThatEvaluationResult(result3).hasEntryThat(topKey).isEqualTo(new StringValue("a"));
assertThatEvaluationResult(result3).hasEntryThat(depKey).isEqualTo(new StringValue("b"));
assertThatEvaluationResult(result3).hasNoError();
}
Aggregations