diff options
Diffstat (limited to 'src/test/java/com/google/devtools/build/skyframe/ParallelEvaluatorTest.java')
-rw-r--r-- | src/test/java/com/google/devtools/build/skyframe/ParallelEvaluatorTest.java | 413 |
1 files changed, 224 insertions, 189 deletions
diff --git a/src/test/java/com/google/devtools/build/skyframe/ParallelEvaluatorTest.java b/src/test/java/com/google/devtools/build/skyframe/ParallelEvaluatorTest.java index 9c87572818..c8464b4291 100644 --- a/src/test/java/com/google/devtools/build/skyframe/ParallelEvaluatorTest.java +++ b/src/test/java/com/google/devtools/build/skyframe/ParallelEvaluatorTest.java @@ -48,14 +48,6 @@ import com.google.devtools.build.skyframe.NotifyingHelper.Listener; import com.google.devtools.build.skyframe.NotifyingHelper.Order; import com.google.devtools.build.skyframe.ParallelEvaluator.EventFilter; import com.google.devtools.build.skyframe.SkyFunctionException.Transience; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -67,8 +59,13 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; - import javax.annotation.Nullable; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; /** * Tests for {@link ParallelEvaluator}. @@ -202,36 +199,38 @@ public class ParallelEvaluatorTest { */ @Test public void interruptedEvaluatorThread() throws Exception { - runInterruptionTest(new SkyFunctionFactory() { - @Override - public SkyFunction create(final Semaphore threadStarted, final String[] errorMessage) { - return new SkyFunction() { - // No need to synchronize access to this field; we always request just one more - // dependency, so it's only one SkyFunction running at any time. - private int valueIdCounter = 0; - + runInterruptionTest( + new SkyFunctionFactory() { @Override - public SkyValue compute(SkyKey key, Environment env) { - // Signal the waiting test thread that the Evaluator thread has really started. - threadStarted.release(); + public SkyFunction create(final Semaphore threadStarted, final String[] errorMessage) { + return new SkyFunction() { + // No need to synchronize access to this field; we always request just one more + // dependency, so it's only one SkyFunction running at any time. + private int valueIdCounter = 0; - // Keep the evaluator busy until the test's thread gets scheduled and can - // interrupt the Evaluator's thread. - env.getValue(GraphTester.toSkyKey("a" + valueIdCounter++)); + @Override + public SkyValue compute(SkyKey key, Environment env) throws InterruptedException { + // Signal the waiting test thread that the Evaluator thread has really started. + threadStarted.release(); - // This method never throws InterruptedException, therefore it's the responsibility - // of the Evaluator to detect the interrupt and avoid calling subsequent SkyFunctions. - return null; - } + // Keep the evaluator busy until the test's thread gets scheduled and can + // interrupt the Evaluator's thread. + env.getValue(GraphTester.toSkyKey("a" + valueIdCounter++)); - @Nullable - @Override - public String extractTag(SkyKey skyKey) { - return null; + // This method never throws InterruptedException, therefore it's the responsibility + // of the Evaluator to detect the interrupt and avoid calling subsequent + // SkyFunctions. + return null; + } + + @Nullable + @Override + public String extractTag(SkyKey skyKey) { + return null; + } + }; } - }; - } - }); + }); } private void runPartialResultOnInterruption(boolean buildFastFirst) throws Exception { @@ -1263,7 +1262,8 @@ public class ParallelEvaluatorTest { new SkyFunction() { @Nullable @Override - public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException { + public SkyValue compute(SkyKey skyKey, Environment env) + throws SkyFunctionException, InterruptedException { Map<SkyKey, ValueOrException<SomeErrorException>> values = env.getValuesOrThrow( ImmutableList.of(errorKey, otherKey), SomeErrorException.class); @@ -1488,7 +1488,7 @@ public class ParallelEvaluatorTest { class ParentFunction implements SkyFunction { @Override - public SkyValue compute(SkyKey skyKey, Environment env) { + public SkyValue compute(SkyKey skyKey, Environment env) throws InterruptedException { SkyValue dep = env.getValue(SkyKey.create(childType, "billy the kid")); if (dep == null) { return null; @@ -1579,27 +1579,32 @@ public class ParallelEvaluatorTest { SkyKey topKey = GraphTester.toSkyKey("top"); final SkyKey parentKey = GraphTester.toSkyKey("parent"); tester.getOrCreate(parentKey).addDependency(errorKey).setComputedValue(CONCATENATE); - tester.getOrCreate(topKey).setBuilder(new SkyFunction() { - @Override - public SkyValue compute(SkyKey skyKey, Environment env) throws GenericFunctionException { - try { - if (env.getValueOrThrow(parentKey, SomeErrorException.class) == null) { - return null; - } - } catch (SomeErrorException e) { - assertEquals(e.toString(), exception, e); - } - if (keepGoing) { - return topValue; - } else { - throw new GenericFunctionException(topException, Transience.PERSISTENT); - } - } - @Override - public String extractTag(SkyKey skyKey) { - throw new UnsupportedOperationException(); - } - }); + tester + .getOrCreate(topKey) + .setBuilder( + new SkyFunction() { + @Override + public SkyValue compute(SkyKey skyKey, Environment env) + throws GenericFunctionException, InterruptedException { + try { + if (env.getValueOrThrow(parentKey, SomeErrorException.class) == null) { + return null; + } + } catch (SomeErrorException e) { + assertEquals(e.toString(), exception, e); + } + if (keepGoing) { + return topValue; + } else { + throw new GenericFunctionException(topException, Transience.PERSISTENT); + } + } + + @Override + public String extractTag(SkyKey skyKey) { + throw new UnsupportedOperationException(); + } + }); tester.getOrCreate(topKey).addErrorDependency(errorKey, new StringValue("recovered")) .setComputedValue(CONCATENATE); EvaluationResult<StringValue> result = eval(keepGoing, ImmutableList.of(topKey)); @@ -1742,29 +1747,33 @@ public class ParallelEvaluatorTest { tester.set(dep, new StringValue("child" + i)); } final SomeErrorException parentExn = new SomeErrorException("parent error"); - tester.getOrCreate(parentKey).setBuilder(new SkyFunction() { - @Override - public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException { - try { - SkyValue value = env.getValueOrThrow(errorDep, SomeErrorException.class); - if (value == null) { - return null; - } - } catch (SomeErrorException e) { - // Recover from the child error. - } - env.getValues(deps); - if (env.valuesMissing()) { - return null; - } - throw new GenericFunctionException(parentExn, Transience.PERSISTENT); - } + tester + .getOrCreate(parentKey) + .setBuilder( + new SkyFunction() { + @Override + public SkyValue compute(SkyKey skyKey, Environment env) + throws SkyFunctionException, InterruptedException { + try { + SkyValue value = env.getValueOrThrow(errorDep, SomeErrorException.class); + if (value == null) { + return null; + } + } catch (SomeErrorException e) { + // Recover from the child error. + } + env.getValues(deps); + if (env.valuesMissing()) { + return null; + } + throw new GenericFunctionException(parentExn, Transience.PERSISTENT); + } - @Override - public String extractTag(SkyKey skyKey) { - return null; - } - }); + @Override + public String extractTag(SkyKey skyKey) { + return null; + } + }); EvaluationResult<StringValue> evaluationResult = eval(keepGoing, ImmutableList.of(parentKey)); assertTrue(evaluationResult.hasError()); assertEquals(keepGoing ? parentExn : childExn, evaluationResult.getError().getException()); @@ -1891,46 +1900,55 @@ public class ParallelEvaluatorTest { // The parent should be built exactly twice: once during normal evaluation and once // during error bubbling. final AtomicInteger numParentInvocations = new AtomicInteger(0); - tester.getOrCreate(parentKey).setBuilder(new SkyFunction() { - @Override - public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException { - int invocations = numParentInvocations.incrementAndGet(); - if (handleChildError) { - try { - SkyValue value = env.getValueOrThrow(childKey, SomeErrorException.class); - // On the first invocation, either the child error should already be cached and not - // propagated, or it should be computed freshly and not propagated. On the second build - // (error bubbling), the child error should be propagated. - assertTrue("bogus non-null value " + value, value == null); - assertEquals("parent incorrectly re-computed during normal evaluation", 1, invocations); - assertFalse("child error not propagated during error bubbling", - env.inErrorBubblingForTesting()); - return value; - } catch (SomeErrorException e) { - assertTrue("child error propagated during normal evaluation", - env.inErrorBubblingForTesting()); - assertEquals(2, invocations); - return null; - } - } else { - if (invocations == 1) { - assertFalse("parent's first computation should be during normal evaluation", - env.inErrorBubblingForTesting()); - return env.getValue(childKey); - } else { - assertEquals(2, invocations); - assertTrue("parent incorrectly re-computed during normal evaluation", - env.inErrorBubblingForTesting()); - return env.getValue(childKey); - } - } - } + tester + .getOrCreate(parentKey) + .setBuilder( + new SkyFunction() { + @Override + public SkyValue compute(SkyKey skyKey, Environment env) + throws SkyFunctionException, InterruptedException { + int invocations = numParentInvocations.incrementAndGet(); + if (handleChildError) { + try { + SkyValue value = env.getValueOrThrow(childKey, SomeErrorException.class); + // On the first invocation, either the child error should already be cached and + // not propagated, or it should be computed freshly and not propagated. On the + // second build (error bubbling), the child error should be propagated. + assertTrue("bogus non-null value " + value, value == null); + assertEquals( + "parent incorrectly re-computed during normal evaluation", 1, invocations); + assertFalse( + "child error not propagated during error bubbling", + env.inErrorBubblingForTesting()); + return value; + } catch (SomeErrorException e) { + assertTrue( + "child error propagated during normal evaluation", + env.inErrorBubblingForTesting()); + assertEquals(2, invocations); + return null; + } + } else { + if (invocations == 1) { + assertFalse( + "parent's first computation should be during normal evaluation", + env.inErrorBubblingForTesting()); + return env.getValue(childKey); + } else { + assertEquals(2, invocations); + assertTrue( + "parent incorrectly re-computed during normal evaluation", + env.inErrorBubblingForTesting()); + return env.getValue(childKey); + } + } + } - @Override - public String extractTag(SkyKey skyKey) { - return null; - } - }); + @Override + public String extractTag(SkyKey skyKey) { + return null; + } + }); if (childErrorCached) { // Ensure that the child is already in the graph. evalValueInError(childKey); @@ -1979,19 +1997,23 @@ public class ParallelEvaluatorTest { final SkyKey otherKey = GraphTester.toSkyKey("otherKey"); final AtomicInteger numOtherParentInvocations = new AtomicInteger(0); final AtomicInteger numErrorParentInvocations = new AtomicInteger(0); - tester.getOrCreate(otherParentKey).setBuilder(new SkyFunction() { - @Override - public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException { - int invocations = numOtherParentInvocations.incrementAndGet(); - assertEquals("otherParentKey should not be restarted", 1, invocations); - return env.getValue(otherKey); - } + tester + .getOrCreate(otherParentKey) + .setBuilder( + new SkyFunction() { + @Override + public SkyValue compute(SkyKey skyKey, Environment env) + throws SkyFunctionException, InterruptedException { + int invocations = numOtherParentInvocations.incrementAndGet(); + assertEquals("otherParentKey should not be restarted", 1, invocations); + return env.getValue(otherKey); + } - @Override - public String extractTag(SkyKey skyKey) { - return null; - } - }); + @Override + public String extractTag(SkyKey skyKey) { + return null; + } + }); tester .getOrCreate(otherKey) .setBuilder( @@ -2026,33 +2048,38 @@ public class ParallelEvaluatorTest { return null; } }); - tester.getOrCreate(errorParentKey).setBuilder(new SkyFunction() { - @Override - public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException { - int invocations = numErrorParentInvocations.incrementAndGet(); - try { - SkyValue value = env.getValueOrThrow(errorKey, SomeErrorException.class); - assertTrue("bogus non-null value " + value, value == null); - if (invocations == 1) { - return null; - } else { - assertFalse(env.inErrorBubblingForTesting()); - fail("RACE CONDITION: errorParentKey was restarted!"); - return null; - } - } catch (SomeErrorException e) { - assertTrue("child error propagated during normal evaluation", - env.inErrorBubblingForTesting()); - assertEquals(2, invocations); - return null; - } - } + tester + .getOrCreate(errorParentKey) + .setBuilder( + new SkyFunction() { + @Override + public SkyValue compute(SkyKey skyKey, Environment env) + throws SkyFunctionException, InterruptedException { + int invocations = numErrorParentInvocations.incrementAndGet(); + try { + SkyValue value = env.getValueOrThrow(errorKey, SomeErrorException.class); + assertTrue("bogus non-null value " + value, value == null); + if (invocations == 1) { + return null; + } else { + assertFalse(env.inErrorBubblingForTesting()); + fail("RACE CONDITION: errorParentKey was restarted!"); + return null; + } + } catch (SomeErrorException e) { + assertTrue( + "child error propagated during normal evaluation", + env.inErrorBubblingForTesting()); + assertEquals(2, invocations); + return null; + } + } - @Override - public String extractTag(SkyKey skyKey) { - return null; - } - }); + @Override + public String extractTag(SkyKey skyKey) { + return null; + } + }); graph = new NotifyingHelper.NotifyingProcessableGraph( new InMemoryGraphImpl(), @@ -2143,41 +2170,49 @@ public class ParallelEvaluatorTest { final SkyKey parentKey = GraphTester.toSkyKey("parent"); final SkyKey childKey = GraphTester.toSkyKey("child"); final AtomicBoolean errorPropagated = new AtomicBoolean(false); - tester.getOrCreate(grandparentKey).setBuilder(new SkyFunction() { - @Override - public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException { - try { - return env.getValueOrThrow(parentKey, SomeErrorException.class); - } catch (SomeErrorException e) { - errorPropagated.set(true); - throw new GenericFunctionException(e, Transience.PERSISTENT); - } - } + tester + .getOrCreate(grandparentKey) + .setBuilder( + new SkyFunction() { + @Override + public SkyValue compute(SkyKey skyKey, Environment env) + throws SkyFunctionException, InterruptedException { + try { + return env.getValueOrThrow(parentKey, SomeErrorException.class); + } catch (SomeErrorException e) { + errorPropagated.set(true); + throw new GenericFunctionException(e, Transience.PERSISTENT); + } + } - @Override - public String extractTag(SkyKey skyKey) { - return null; - } - }); - tester.getOrCreate(parentKey).setBuilder(new SkyFunction() { - @Override - public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException { - if (explicitlyPropagateError) { - try { - return env.getValueOrThrow(childKey, SomeErrorException.class); - } catch (SomeErrorException e) { - throw new GenericFunctionException(e, childKey); - } - } else { - return env.getValue(childKey); - } - } + @Override + public String extractTag(SkyKey skyKey) { + return null; + } + }); + tester + .getOrCreate(parentKey) + .setBuilder( + new SkyFunction() { + @Override + public SkyValue compute(SkyKey skyKey, Environment env) + throws SkyFunctionException, InterruptedException { + if (explicitlyPropagateError) { + try { + return env.getValueOrThrow(childKey, SomeErrorException.class); + } catch (SomeErrorException e) { + throw new GenericFunctionException(e, childKey); + } + } else { + return env.getValue(childKey); + } + } - @Override - public String extractTag(SkyKey skyKey) { - return null; - } - }); + @Override + public String extractTag(SkyKey skyKey) { + return null; + } + }); tester.getOrCreate(childKey).setHasError(/*hasError=*/true); EvaluationResult<StringValue> result = eval(keepGoing, ImmutableList.of(grandparentKey)); assertTrue(result.hasError()); |