diff options
Diffstat (limited to 'src/test/java/com')
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/concurrent/AbstractQueueVisitorTest.java | 78 | ||||
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/concurrent/ErrorClassifierTest.java | 38 |
2 files changed, 115 insertions, 1 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/concurrent/AbstractQueueVisitorTest.java b/src/test/java/com/google/devtools/build/lib/concurrent/AbstractQueueVisitorTest.java index 7a3982ed12..8f6d389b98 100644 --- a/src/test/java/com/google/devtools/build/lib/concurrent/AbstractQueueVisitorTest.java +++ b/src/test/java/com/google/devtools/build/lib/concurrent/AbstractQueueVisitorTest.java @@ -34,6 +34,7 @@ import org.junit.runners.JUnit4; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -408,7 +409,7 @@ public class AbstractQueueVisitorTest { @Override public void handle(Throwable t, ErrorClassification classification) { if (t == error) { - assertThat(classification).isEqualTo(ErrorClassification.CRITICAL_AND_LOG); + assertThat(classification).isEqualTo(ErrorClassification.AS_CRITICAL_AS_POSSIBLE); criticalErrorSeen.compareAndSet(false, true); } else { fail(); @@ -459,6 +460,81 @@ public class AbstractQueueVisitorTest { assertTrue(criticalErrorSeen.get()); } + private static class ClassifiedException extends RuntimeException { + private final ErrorClassification classification; + + private ClassifiedException(ErrorClassification classification) { + this.classification = classification; + } + } + + @Test + public void mostSevereErrorPropagated() throws Exception { + ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 0, TimeUnit.SECONDS, + new LinkedBlockingQueue<Runnable>()); + final Set<Throwable> seenErrors = Sets.newConcurrentHashSet(); + final ClassifiedException criticalException = + new ClassifiedException(ErrorClassification.CRITICAL); + final ClassifiedException criticalAndLogException = + new ClassifiedException(ErrorClassification.CRITICAL_AND_LOG); + final ErrorClassifier errorClassifier = new ErrorClassifier() { + @Override + protected ErrorClassification classifyException(Exception e) { + return (e instanceof ClassifiedException) + ? ((ClassifiedException) e).classification + : ErrorClassification.NOT_CRITICAL; + } + }; + ErrorHandler errorHandler = new ErrorHandler() { + @Override + public void handle(Throwable t, ErrorClassification classification) { + assertThat(classification).isEqualTo(errorClassifier.classify(t)); + seenErrors.add(t); + } + }; + AbstractQueueVisitor visitor = + new AbstractQueueVisitor( + /*concurrent=*/ true, + executor, + /*shutdownOnCompletion=*/ true, + /*failFastOnException=*/ false, + errorClassifier, + errorHandler); + final CountDownLatch exnLatch = visitor.getExceptionLatchForTestingOnly(); + Runnable criticalExceptionRunnable = new Runnable() { + @Override + public void run() { + throw criticalException; + } + }; + Runnable criticalAndLogExceptionRunnable = new Runnable() { + @Override + public void run() { + // Wait for the critical exception to be thrown. There's a benign race between our 'await' + // call completing because the exception latch was counted down, and our thread being + // interrupted by AbstractQueueVisitor because the critical error was encountered. This is + // completely fine; all that matters is that we have a chance to throw our error _after_ + // the previous one was thrown by the other Runnable. + try { + exnLatch.await(); + } catch (InterruptedException e) { + // Ignored. + } + throw criticalAndLogException; + } + }; + visitor.execute(criticalExceptionRunnable); + visitor.execute(criticalAndLogExceptionRunnable); + ClassifiedException exn = null; + try { + visitor.awaitQuiescence(/*interruptWorkers=*/ true); + } catch (ClassifiedException e) { + exn = e; + } + assertEquals(criticalAndLogException, exn); + assertThat(seenErrors).containsExactly(criticalException, criticalAndLogException); + } + private static Runnable throwingRunnable() { return new Runnable() { @Override diff --git a/src/test/java/com/google/devtools/build/lib/concurrent/ErrorClassifierTest.java b/src/test/java/com/google/devtools/build/lib/concurrent/ErrorClassifierTest.java new file mode 100644 index 0000000000..7c06270731 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/concurrent/ErrorClassifierTest.java @@ -0,0 +1,38 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.lib.concurrent; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.devtools.build.lib.concurrent.ErrorClassifier.ErrorClassification; +import java.util.Arrays; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link ErrorClassifier}. */ +@RunWith(JUnit4.class) +public class ErrorClassifierTest { + @Test + public void testErrorClassificationNaturalOrder() { + ErrorClassification[] values = ErrorClassification.values(); + Arrays.sort(values); + assertThat(values).asList().containsExactly( + ErrorClassification.NOT_CRITICAL, + ErrorClassification.CRITICAL, + ErrorClassification.CRITICAL_AND_LOG, + ErrorClassification.AS_CRITICAL_AS_POSSIBLE).inOrder(); + } +} + |