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