@Test public void wrappedThrowsWithoutTimeout() throws Exception { Sink sink = new ForwardingSink(new Buffer()) { @Override public void write(Buffer source, long byteCount) throws IOException { throw new IOException("no timeout occurred"); } }; AsyncTimeout timeout = new AsyncTimeout(); timeout.timeout(250, TimeUnit.MILLISECONDS); Sink timeoutSink = timeout.sink(sink); Buffer data = new Buffer().writeUtf8("a"); try { timeoutSink.write(data, 1); fail(); } catch (IOException expected) { assertEquals("no timeout occurred", expected.getMessage()); } }
@Test public void wrappedSinkFlushTimesOut() throws Exception { Sink sink = new ForwardingSink(new Buffer()) { @Override public void flush() throws IOException { try { Thread.sleep(500); } catch (InterruptedException e) { throw new AssertionError(); } } }; AsyncTimeout timeout = new AsyncTimeout(); timeout.timeout(250, TimeUnit.MILLISECONDS); Sink timeoutSink = timeout.sink(sink); try { timeoutSink.flush(); fail(); } catch (InterruptedIOException expected) { } }
@Test public void wrappedSinkCloseTimesOut() throws Exception { Sink sink = new ForwardingSink(new Buffer()) { @Override public void close() throws IOException { try { Thread.sleep(500); } catch (InterruptedException e) { throw new AssertionError(); } } }; AsyncTimeout timeout = new AsyncTimeout(); timeout.timeout(250, TimeUnit.MILLISECONDS); Sink timeoutSink = timeout.sink(sink); try { timeoutSink.close(); fail(); } catch (InterruptedIOException expected) { } }
@Test public void wrappedSinkTimesOut() throws Exception { Sink sink = new ForwardingSink(new Buffer()) { @Override public void write(Buffer source, long byteCount) throws IOException { try { Thread.sleep(500); } catch (InterruptedException e) { throw new AssertionError(); } } }; AsyncTimeout timeout = new AsyncTimeout(); timeout.timeout(250, TimeUnit.MILLISECONDS); Sink timeoutSink = timeout.sink(sink); Buffer data = new Buffer().writeUtf8("a"); try { timeoutSink.write(data, 1); fail(); } catch (InterruptedIOException expected) { } }
/** * We had a bug where writing a very large buffer would fail with an * unexpected timeout because although the sink was making steady forward * progress, doing it all as a single write caused a timeout. */ @Test public void sinkSplitsLargeWrites() throws Exception { byte[] data = new byte[512 * 1024]; Random dice = new Random(0); dice.nextBytes(data); final Buffer source = bufferWithRandomSegmentLayout(dice, data); final Buffer target = new Buffer(); Sink sink = new ForwardingSink(new Buffer()) { @Override public void write(Buffer source, long byteCount) throws IOException { try { Thread.sleep(byteCount / 500); // ~500 KiB/s. target.write(source, byteCount); } catch (InterruptedException e) { throw new AssertionError(); } } }; // Timeout after 250 ms of inactivity. AsyncTimeout timeout = new AsyncTimeout(); timeout.timeout(250, TimeUnit.MILLISECONDS); Sink timeoutSink = timeout.sink(sink); // Transmit 500 KiB of data, which should take ~1 second. But expect no timeout! timeoutSink.write(source, source.size()); // The data should all have arrived. assertEquals(ByteString.of(data), target.readByteString()); }
@Test public void wrappedThrowsWithTimeout() throws Exception { Sink sink = new ForwardingSink(new Buffer()) { @Override public void write(Buffer source, long byteCount) throws IOException { try { Thread.sleep(500); throw new IOException("exception and timeout"); } catch (InterruptedException e) { throw new AssertionError(); } } }; AsyncTimeout timeout = new AsyncTimeout(); timeout.timeout(250, TimeUnit.MILLISECONDS); Sink timeoutSink = timeout.sink(sink); Buffer data = new Buffer().writeUtf8("a"); try { timeoutSink.write(data, 1); fail(); } catch (InterruptedIOException expected) { assertEquals("timeout", expected.getMessage()); assertEquals("exception and timeout", expected.getCause().getMessage()); } }
/** * Returns a sink that writes to {@code socket}. Prefer this over {@link * #sink(OutputStream)} because this method honors timeouts. When the socket * write times out, the socket is asynchronously closed by a watchdog thread. */ public static Sink sink(Socket socket) throws IOException { if (socket == null) throw new IllegalArgumentException("socket == null"); AsyncTimeout timeout = timeout(socket); Sink sink = sink(socket.getOutputStream(), timeout); return timeout.sink(sink); }