aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java/com/google/devtools')
-rw-r--r--src/test/java/com/google/devtools/build/lib/concurrent/AbstractQueueVisitorTest.java78
-rw-r--r--src/test/java/com/google/devtools/build/lib/concurrent/ErrorClassifierTest.java38
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();
+ }
+}
+