1 /* 2 * Copyright (C) 2017 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.util.concurrent; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.truth.Truth.assertWithMessage; 21 import static com.google.common.util.concurrent.MoreExecutors.shutdownAndAwaitTermination; 22 import static com.google.common.util.concurrent.Uninterruptibles.awaitUninterruptibly; 23 import static java.util.concurrent.Executors.newSingleThreadExecutor; 24 import static java.util.concurrent.TimeUnit.SECONDS; 25 import static org.junit.Assert.assertThrows; 26 27 import com.google.common.util.concurrent.ClosingFuture.ClosingCallable; 28 import com.google.common.util.concurrent.ClosingFuture.DeferredCloser; 29 import com.google.common.util.concurrent.ClosingFuture.ValueAndCloser; 30 import com.google.common.util.concurrent.ClosingFuture.ValueAndCloserConsumer; 31 import java.io.Closeable; 32 import java.util.concurrent.CountDownLatch; 33 import java.util.concurrent.ExecutionException; 34 import java.util.concurrent.Executor; 35 import java.util.concurrent.ExecutorService; 36 37 /** 38 * Tests for {@link ClosingFuture} that exercise {@link 39 * ClosingFuture#finishToValueAndCloser(ValueAndCloserConsumer, Executor)}. 40 */ 41 public class ClosingFutureFinishToValueAndCloserTest extends AbstractClosingFutureTest { 42 private final ExecutorService finishToValueAndCloserExecutor = newSingleThreadExecutor(); 43 private volatile ValueAndCloser<?> valueAndCloser; 44 45 @Override tearDown()46 protected void tearDown() throws Exception { 47 super.tearDown(); 48 assertWithMessage("finishToValueAndCloserExecutor was shut down") 49 .that(shutdownAndAwaitTermination(finishToValueAndCloserExecutor, 10, SECONDS)) 50 .isTrue(); 51 } 52 testFinishToValueAndCloser_throwsIfCalledTwice()53 public void testFinishToValueAndCloser_throwsIfCalledTwice() throws Exception { 54 ClosingFuture<Closeable> closingFuture = 55 ClosingFuture.submit( 56 new ClosingCallable<Closeable>() { 57 @Override 58 public Closeable call(DeferredCloser closer) throws Exception { 59 return closer.eventuallyClose(mockCloseable, executor); 60 } 61 }, 62 executor); 63 closingFuture.finishToValueAndCloser( 64 new NoOpValueAndCloserConsumer<>(), finishToValueAndCloserExecutor); 65 assertThrows( 66 IllegalStateException.class, 67 () -> 68 closingFuture.finishToValueAndCloser( 69 new NoOpValueAndCloserConsumer<>(), finishToValueAndCloserExecutor)); 70 } 71 testFinishToValueAndCloser_throwsAfterCallingFinishToFuture()72 public void testFinishToValueAndCloser_throwsAfterCallingFinishToFuture() throws Exception { 73 ClosingFuture<Closeable> closingFuture = 74 ClosingFuture.submit( 75 new ClosingCallable<Closeable>() { 76 @Override 77 public Closeable call(DeferredCloser closer) throws Exception { 78 return closer.eventuallyClose(mockCloseable, executor); 79 } 80 }, 81 executor); 82 FluentFuture<Closeable> unused = closingFuture.finishToFuture(); 83 assertThrows( 84 IllegalStateException.class, 85 () -> 86 closingFuture.finishToValueAndCloser( 87 new NoOpValueAndCloserConsumer<>(), finishToValueAndCloserExecutor)); 88 } 89 90 @Override getFinalValue(ClosingFuture<T> closingFuture)91 <T> T getFinalValue(ClosingFuture<T> closingFuture) throws ExecutionException { 92 return finishToValueAndCloser(closingFuture).get(); 93 } 94 95 @Override assertFinallyFailsWithException(ClosingFuture<?> closingFuture)96 void assertFinallyFailsWithException(ClosingFuture<?> closingFuture) { 97 assertThatFutureFailsWithException(closingFuture.statusFuture()); 98 ValueAndCloser<?> valueAndCloser = finishToValueAndCloser(closingFuture); 99 try { 100 valueAndCloser.get(); 101 fail(); 102 } catch (ExecutionException expected) { 103 assertThat(expected).hasCauseThat().isSameInstanceAs(exception); 104 } 105 valueAndCloser.closeAsync(); 106 } 107 108 @Override assertBecomesCanceled(ClosingFuture<?> closingFuture)109 void assertBecomesCanceled(ClosingFuture<?> closingFuture) throws ExecutionException { 110 assertThatFutureBecomesCancelled(closingFuture.statusFuture()); 111 } 112 113 @Override waitUntilClosed(ClosingFuture<?> closingFuture)114 void waitUntilClosed(ClosingFuture<?> closingFuture) { 115 if (valueAndCloser != null) { 116 valueAndCloser.closeAsync(); 117 } 118 super.waitUntilClosed(closingFuture); 119 } 120 121 @Override cancelFinalStepAndWait(ClosingFuture<TestCloseable> closingFuture)122 void cancelFinalStepAndWait(ClosingFuture<TestCloseable> closingFuture) { 123 assertThat(closingFuture.cancel(false)).isTrue(); 124 ValueAndCloser<?> unused = finishToValueAndCloser(closingFuture); 125 waitUntilClosed(closingFuture); 126 futureCancelled.countDown(); 127 } 128 finishToValueAndCloser(ClosingFuture<V> closingFuture)129 private <V> ValueAndCloser<V> finishToValueAndCloser(ClosingFuture<V> closingFuture) { 130 final CountDownLatch valueAndCloserSet = new CountDownLatch(1); 131 closingFuture.finishToValueAndCloser( 132 new ValueAndCloserConsumer<V>() { 133 @Override 134 public void accept(ValueAndCloser<V> valueAndCloser) { 135 ClosingFutureFinishToValueAndCloserTest.this.valueAndCloser = valueAndCloser; 136 valueAndCloserSet.countDown(); 137 } 138 }, 139 finishToValueAndCloserExecutor); 140 assertWithMessage("valueAndCloser was set") 141 .that(awaitUninterruptibly(valueAndCloserSet, 10, SECONDS)) 142 .isTrue(); 143 @SuppressWarnings("unchecked") 144 ValueAndCloser<V> valueAndCloserWithType = (ValueAndCloser<V>) valueAndCloser; 145 return valueAndCloserWithType; 146 } 147 } 148