1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.util.io;
45
46 import static org.junit.Assert.assertArrayEquals;
47 import static org.junit.Assert.assertEquals;
48 import static org.junit.Assert.assertFalse;
49 import static org.junit.Assert.assertTrue;
50 import static org.junit.Assert.fail;
51
52 import java.io.IOException;
53 import java.io.InterruptedIOException;
54 import java.io.OutputStream;
55 import java.io.PipedInputStream;
56 import java.io.PipedOutputStream;
57 import java.util.Arrays;
58 import java.util.List;
59
60 import org.eclipse.jgit.util.IO;
61 import org.junit.After;
62 import org.junit.Before;
63 import org.junit.Test;
64
65 public class TimeoutOutputStreamTest {
66 private static final int timeout = 250;
67
68 private PipedOutputStream out;
69
70 private FullPipeInputStream in;
71
72 private InterruptTimer timer;
73
74 private TimeoutOutputStream os;
75
76 private long start;
77
78 @Before
79 public void setUp() throws Exception {
80 out = new PipedOutputStream();
81 in = new FullPipeInputStream(out);
82 timer = new InterruptTimer();
83 os = new TimeoutOutputStream(out, timer);
84 os.setTimeout(timeout);
85 }
86
87 @After
88 public void tearDown() throws Exception {
89 timer.terminate();
90 for (Thread t : active())
91 assertFalse(t instanceof InterruptTimer.AlarmThread);
92 }
93
94 @Test
95 public void testTimeout_writeByte_Success1() throws IOException {
96 in.free(1);
97 os.write('a');
98 in.want(1);
99 assertEquals('a', in.read());
100 }
101
102 @Test
103 public void testTimeout_writeByte_Success2() throws IOException {
104 final byte[] exp = new byte[] { 'a', 'b', 'c' };
105 final byte[] act = new byte[exp.length];
106 in.free(exp.length);
107 os.write(exp[0]);
108 os.write(exp[1]);
109 os.write(exp[2]);
110 in.want(exp.length);
111 in.read(act);
112 assertArrayEquals(exp, act);
113 }
114
115 @Test
116 public void testTimeout_writeByte_Timeout() throws IOException {
117 beginWrite();
118 try {
119 os.write('\n');
120 fail("incorrectly write a byte");
121 } catch (InterruptedIOException e) {
122
123 }
124 assertTimeout();
125 }
126
127 @Test
128 public void testTimeout_writeBuffer_Success1() throws IOException {
129 final byte[] exp = new byte[] { 'a', 'b', 'c' };
130 final byte[] act = new byte[exp.length];
131 in.free(exp.length);
132 os.write(exp);
133 in.want(exp.length);
134 in.read(act);
135 assertArrayEquals(exp, act);
136 }
137
138 @Test
139 public void testTimeout_writeBuffer_Timeout() throws IOException {
140 beginWrite();
141 try {
142 os.write(new byte[512]);
143 fail("incorrectly wrote bytes");
144 } catch (InterruptedIOException e) {
145
146 }
147 assertTimeout();
148 }
149
150 @Test
151 public void testTimeout_flush_Success() throws IOException {
152 final boolean[] called = new boolean[1];
153 os = new TimeoutOutputStream(new OutputStream() {
154 @Override
155 public void write(int b) throws IOException {
156 fail("should not have written");
157 }
158
159 @Override
160 public void flush() throws IOException {
161 called[0] = true;
162 }
163 }, timer);
164 os.setTimeout(timeout);
165 os.flush();
166 assertTrue(called[0]);
167 }
168
169 @Test
170 public void testTimeout_flush_Timeout() throws IOException {
171 final boolean[] called = new boolean[1];
172 os = new TimeoutOutputStream(new OutputStream() {
173 @Override
174 public void write(int b) throws IOException {
175 fail("should not have written");
176 }
177
178 @Override
179 public void flush() throws IOException {
180 called[0] = true;
181 for (;;) {
182 try {
183 Thread.sleep(1000);
184 } catch (InterruptedException e) {
185 throw new InterruptedIOException();
186 }
187 }
188 }
189 }, timer);
190 os.setTimeout(timeout);
191
192 beginWrite();
193 try {
194 os.flush();
195 fail("incorrectly flushed");
196 } catch (InterruptedIOException e) {
197
198 }
199 assertTimeout();
200 assertTrue(called[0]);
201 }
202
203 @Test
204 public void testTimeout_close_Success() throws IOException {
205 final boolean[] called = new boolean[1];
206 os = new TimeoutOutputStream(new OutputStream() {
207 @Override
208 public void write(int b) throws IOException {
209 fail("should not have written");
210 }
211
212 @Override
213 public void close() throws IOException {
214 called[0] = true;
215 }
216 }, timer);
217 os.setTimeout(timeout);
218 os.close();
219 assertTrue(called[0]);
220 }
221
222 @Test
223 public void testTimeout_close_Timeout() throws IOException {
224 final boolean[] called = new boolean[1];
225 os = new TimeoutOutputStream(new OutputStream() {
226 @Override
227 public void write(int b) throws IOException {
228 fail("should not have written");
229 }
230
231 @Override
232 public void close() throws IOException {
233 called[0] = true;
234 for (;;) {
235 try {
236 Thread.sleep(1000);
237 } catch (InterruptedException e) {
238 throw new InterruptedIOException();
239 }
240 }
241 }
242 }, timer);
243 os.setTimeout(timeout);
244
245 beginWrite();
246 try {
247 os.close();
248 fail("incorrectly closed");
249 } catch (InterruptedIOException e) {
250
251 }
252 assertTimeout();
253 assertTrue(called[0]);
254 }
255
256 private void beginWrite() {
257 start = now();
258 }
259
260 private void assertTimeout() {
261
262
263
264
265
266
267 final long wait = now() - start;
268 assertTrue("waited only " + wait + " ms", timeout - wait < 50);
269 }
270
271 private static List<Thread> active() {
272 Thread[] all = new Thread[16];
273 int n = Thread.currentThread().getThreadGroup().enumerate(all);
274 while (n == all.length) {
275 all = new Thread[all.length * 2];
276 n = Thread.currentThread().getThreadGroup().enumerate(all);
277 }
278 return Arrays.asList(all).subList(0, n);
279 }
280
281 private static long now() {
282 return System.currentTimeMillis();
283 }
284
285 private static final class FullPipeInputStream extends PipedInputStream {
286 FullPipeInputStream(PipedOutputStream src) throws IOException {
287 super(src);
288 src.write(new byte[PIPE_SIZE]);
289 }
290
291 void want(int cnt) throws IOException {
292 IO.skipFully(this, PIPE_SIZE - cnt);
293 }
294
295 void free(int cnt) throws IOException {
296 IO.skipFully(this, cnt);
297 }
298 }
299 }