1 /* 2 * Copyright (C) 2014 Square, Inc. 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 package okio; 17 18 import java.io.IOException; 19 import java.io.InterruptedIOException; 20 import java.util.Arrays; 21 import java.util.List; 22 import java.util.concurrent.CopyOnWriteArrayList; 23 import java.util.concurrent.TimeUnit; 24 import org.junit.Before; 25 import org.junit.Test; 26 27 import static org.junit.Assert.assertEquals; 28 import static org.junit.Assert.assertFalse; 29 import static org.junit.Assert.assertTrue; 30 import static org.junit.Assert.fail; 31 32 /** 33 * This test uses four timeouts of varying durations: 250ms, 500ms, 750ms and 34 * 1000ms, named 'a', 'b', 'c' and 'd'. 35 */ 36 public class AsyncTimeoutTest { 37 private final List<Timeout> timedOut = new CopyOnWriteArrayList<Timeout>(); 38 private final AsyncTimeout a = new RecordingAsyncTimeout(); 39 private final AsyncTimeout b = new RecordingAsyncTimeout(); 40 private final AsyncTimeout c = new RecordingAsyncTimeout(); 41 private final AsyncTimeout d = new RecordingAsyncTimeout(); 42 43 @Before public void setUp() throws Exception { 44 a.timeout( 250, TimeUnit.MILLISECONDS); 45 b.timeout( 500, TimeUnit.MILLISECONDS); 46 c.timeout( 750, TimeUnit.MILLISECONDS); 47 d.timeout(1000, TimeUnit.MILLISECONDS); 48 } 49 50 @Test public void zeroTimeoutIsNoTimeout() throws Exception { 51 AsyncTimeout timeout = new RecordingAsyncTimeout(); 52 timeout.timeout(0, TimeUnit.MILLISECONDS); 53 timeout.enter(); 54 Thread.sleep(250); 55 assertFalse(timeout.exit()); 56 assertTimedOut(); 57 } 58 59 @Test public void singleInstanceTimedOut() throws Exception { 60 a.enter(); 61 Thread.sleep(500); 62 assertTrue(a.exit()); 63 assertTimedOut(a); 64 } 65 66 @Test public void singleInstanceNotTimedOut() throws Exception { 67 b.enter(); 68 Thread.sleep(250); 69 b.exit(); 70 assertFalse(b.exit()); 71 assertTimedOut(); 72 } 73 74 @Test public void instancesAddedAtEnd() throws Exception { 75 a.enter(); 76 b.enter(); 77 c.enter(); 78 d.enter(); 79 Thread.sleep(1250); 80 assertTrue(a.exit()); 81 assertTrue(b.exit()); 82 assertTrue(c.exit()); 83 assertTrue(d.exit()); 84 assertTimedOut(a, b, c, d); 85 } 86 87 @Test public void instancesAddedAtFront() throws Exception { 88 d.enter(); 89 c.enter(); 90 b.enter(); 91 a.enter(); 92 Thread.sleep(1250); 93 assertTrue(d.exit()); 94 assertTrue(c.exit()); 95 assertTrue(b.exit()); 96 assertTrue(a.exit()); 97 assertTimedOut(a, b, c, d); 98 } 99 100 @Test public void instancesRemovedAtFront() throws Exception { 101 a.enter(); 102 b.enter(); 103 c.enter(); 104 d.enter(); 105 assertFalse(a.exit()); 106 assertFalse(b.exit()); 107 assertFalse(c.exit()); 108 assertFalse(d.exit()); 109 assertTimedOut(); 110 } 111 112 @Test public void instancesRemovedAtEnd() throws Exception { 113 a.enter(); 114 b.enter(); 115 c.enter(); 116 d.enter(); 117 assertFalse(d.exit()); 118 assertFalse(c.exit()); 119 assertFalse(b.exit()); 120 assertFalse(a.exit()); 121 assertTimedOut(); 122 } 123 124 /** Detecting double-enters is not guaranteed. */ 125 @Test public void doubleEnter() throws Exception { 126 a.enter(); 127 try { 128 a.enter(); 129 fail(); 130 } catch (IllegalStateException expected) { 131 } 132 } 133 134 @Test public void deadlineOnly() throws Exception { 135 RecordingAsyncTimeout timeout = new RecordingAsyncTimeout(); 136 timeout.deadline(250, TimeUnit.MILLISECONDS); 137 timeout.enter(); 138 Thread.sleep(500); 139 assertTrue(timeout.exit()); 140 assertTimedOut(timeout); 141 } 142 143 @Test public void deadlineBeforeTimeout() throws Exception { 144 RecordingAsyncTimeout timeout = new RecordingAsyncTimeout(); 145 timeout.deadline(250, TimeUnit.MILLISECONDS); 146 timeout.timeout(750, TimeUnit.MILLISECONDS); 147 timeout.enter(); 148 Thread.sleep(500); 149 assertTrue(timeout.exit()); 150 assertTimedOut(timeout); 151 } 152 153 @Test public void deadlineAfterTimeout() throws Exception { 154 RecordingAsyncTimeout timeout = new RecordingAsyncTimeout(); 155 timeout.timeout(250, TimeUnit.MILLISECONDS); 156 timeout.deadline(750, TimeUnit.MILLISECONDS); 157 timeout.enter(); 158 Thread.sleep(500); 159 assertTrue(timeout.exit()); 160 assertTimedOut(timeout); 161 } 162 163 @Test public void deadlineStartsBeforeEnter() throws Exception { 164 RecordingAsyncTimeout timeout = new RecordingAsyncTimeout(); 165 timeout.deadline(500, TimeUnit.MILLISECONDS); 166 Thread.sleep(500); 167 timeout.enter(); 168 Thread.sleep(250); 169 assertTrue(timeout.exit()); 170 assertTimedOut(timeout); 171 } 172 173 @Test public void deadlineInThePast() throws Exception { 174 RecordingAsyncTimeout timeout = new RecordingAsyncTimeout(); 175 timeout.deadlineNanoTime(System.nanoTime() - 1); 176 timeout.enter(); 177 Thread.sleep(250); 178 assertTrue(timeout.exit()); 179 assertTimedOut(timeout); 180 } 181 182 @Test public void wrappedSinkTimesOut() throws Exception { 183 Sink sink = new ForwardingSink(new Buffer()) { 184 @Override public void write(Buffer source, long byteCount) throws IOException { 185 try { 186 Thread.sleep(500); 187 } catch (InterruptedException e) { 188 throw new AssertionError(); 189 } 190 } 191 }; 192 AsyncTimeout timeout = new AsyncTimeout(); 193 timeout.timeout(250, TimeUnit.MILLISECONDS); 194 Sink timeoutSink = timeout.sink(sink); 195 try { 196 timeoutSink.write(null, 0); 197 fail(); 198 } catch (InterruptedIOException expected) { 199 } 200 } 201 202 @Test public void wrappedSourceTimesOut() throws Exception { 203 Source source = new ForwardingSource(new Buffer()) { 204 @Override public long read(Buffer sink, long byteCount) throws IOException { 205 try { 206 Thread.sleep(500); 207 return -1; 208 } catch (InterruptedException e) { 209 throw new AssertionError(); 210 } 211 } 212 }; 213 AsyncTimeout timeout = new AsyncTimeout(); 214 timeout.timeout(250, TimeUnit.MILLISECONDS); 215 Source timeoutSource = timeout.source(source); 216 try { 217 timeoutSource.read(null, 0); 218 fail(); 219 } catch (InterruptedIOException expected) { 220 } 221 } 222 223 @Test public void wrappedThrowsWithTimeout() throws Exception { 224 Sink sink = new ForwardingSink(new Buffer()) { 225 @Override public void write(Buffer source, long byteCount) throws IOException { 226 try { 227 Thread.sleep(500); 228 throw new IOException("exception and timeout"); 229 } catch (InterruptedException e) { 230 throw new AssertionError(); 231 } 232 } 233 }; 234 AsyncTimeout timeout = new AsyncTimeout(); 235 timeout.timeout(250, TimeUnit.MILLISECONDS); 236 Sink timeoutSink = timeout.sink(sink); 237 try { 238 timeoutSink.write(null, 0); 239 fail(); 240 } catch (InterruptedIOException expected) { 241 assertEquals("timeout", expected.getMessage()); 242 assertEquals("exception and timeout", expected.getCause().getMessage()); 243 } 244 } 245 246 @Test public void wrappedThrowsWithoutTimeout() throws Exception { 247 Sink sink = new ForwardingSink(new Buffer()) { 248 @Override public void write(Buffer source, long byteCount) throws IOException { 249 throw new IOException("no timeout occurred"); 250 } 251 }; 252 AsyncTimeout timeout = new AsyncTimeout(); 253 timeout.timeout(250, TimeUnit.MILLISECONDS); 254 Sink timeoutSink = timeout.sink(sink); 255 try { 256 timeoutSink.write(null, 0); 257 fail(); 258 } catch (IOException expected) { 259 assertEquals("no timeout occurred", expected.getMessage()); 260 } 261 } 262 263 /** Asserts which timeouts fired, and in which order. */ 264 private void assertTimedOut(Timeout... expected) { 265 assertEquals(Arrays.asList(expected), timedOut); 266 } 267 268 class RecordingAsyncTimeout extends AsyncTimeout { 269 @Override protected void timedOut() { 270 timedOut.add(this); 271 } 272 } 273 } 274