1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.surefire.api.util.internal;
20
21 import java.io.ByteArrayInputStream;
22 import java.io.ByteArrayOutputStream;
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InterruptedIOException;
28 import java.io.OutputStream;
29 import java.nio.Buffer;
30 import java.nio.ByteBuffer;
31 import java.nio.channels.AsynchronousByteChannel;
32 import java.nio.channels.ClosedChannelException;
33 import java.nio.channels.NonReadableChannelException;
34 import java.nio.channels.ReadableByteChannel;
35 import java.nio.channels.ShutdownChannelGroupException;
36 import java.util.concurrent.ExecutionException;
37 import java.util.concurrent.Future;
38
39 import org.junit.Rule;
40 import org.junit.Test;
41 import org.junit.rules.ExpectedException;
42 import org.junit.rules.TemporaryFolder;
43 import org.mockito.ArgumentCaptor;
44 import org.mockito.invocation.InvocationOnMock;
45 import org.mockito.stubbing.Answer;
46
47 import static java.nio.file.Files.write;
48 import static org.assertj.core.api.Assertions.assertThat;
49 import static org.hamcrest.Matchers.instanceOf;
50 import static org.mockito.ArgumentMatchers.any;
51 import static org.mockito.Mockito.doThrow;
52 import static org.mockito.Mockito.mock;
53 import static org.mockito.Mockito.never;
54 import static org.mockito.Mockito.times;
55 import static org.mockito.Mockito.verify;
56 import static org.mockito.Mockito.verifyNoMoreInteractions;
57 import static org.mockito.Mockito.verifyZeroInteractions;
58 import static org.mockito.Mockito.when;
59 import static org.powermock.reflect.Whitebox.invokeMethod;
60
61
62
63
64 public class ChannelsReaderTest {
65 @Rule
66 public final ExpectedException ee = ExpectedException.none();
67
68 @Rule
69 public final TemporaryFolder tmp =
70 TemporaryFolder.builder().assureDeletion().build();
71
72 @Test
73 public void shouldOverflowBuffer() throws Exception {
74 ByteArrayOutputStream out = new ByteArrayOutputStream();
75
76 WritableBufferedByteChannel channel = invokeMethod(
77 Channels.class, "newChannel", new Class[] {OutputStream.class, int.class}, new Object[] {out, 8});
78
79 assertThat(channel.countBufferOverflows()).isEqualTo(0);
80
81 channel.write(ByteBuffer.wrap(new byte[] {1, 2, 3}));
82
83 assertThat(channel.countBufferOverflows()).isEqualTo(0);
84
85 channel.write(ByteBuffer.wrap(new byte[] {4, 5, 6, 7, 8}));
86
87 assertThat(channel.countBufferOverflows()).isEqualTo(0);
88
89 channel.write(ByteBuffer.wrap(new byte[] {9}));
90
91 assertThat(channel.countBufferOverflows()).isEqualTo(1);
92
93 assertThat(out.toByteArray()).isEqualTo(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9});
94 }
95
96 @Test
97 public void exactBufferSize() throws Exception {
98 ByteArrayInputStream is = new ByteArrayInputStream(new byte[] {1, 2, 3});
99 ReadableByteChannel channel = Channels.newChannel(is);
100 ByteBuffer bb = ByteBuffer.allocate(3);
101
102 int countWritten = channel.read(bb);
103
104 assertThat(countWritten).isEqualTo(3);
105
106 assertThat(bb.arrayOffset()).isEqualTo(0);
107
108 assertThat(((Buffer) bb).position()).isEqualTo(3);
109
110 assertThat(bb.remaining()).isEqualTo(0);
111
112 assertThat(((Buffer) bb).limit()).isEqualTo(3);
113
114 assertThat(bb.capacity()).isEqualTo(3);
115
116 ((Buffer) bb).flip();
117
118 assertThat(bb.arrayOffset()).isEqualTo(0);
119
120 assertThat(((Buffer) bb).position()).isEqualTo(0);
121
122 assertThat(bb.remaining()).isEqualTo(3);
123
124 assertThat(((Buffer) bb).limit()).isEqualTo(3);
125
126 assertThat(bb.capacity()).isEqualTo(3);
127
128 assertThat(bb.array()).isEqualTo(new byte[] {1, 2, 3});
129
130 assertThat(channel.isOpen()).isTrue();
131
132 channel.close();
133
134 assertThat(channel.isOpen()).isFalse();
135 }
136
137 @Test
138 public void bufferedChannel() throws Exception {
139 ByteArrayInputStream is = new ByteArrayInputStream(new byte[] {1, 2, 3});
140 ReadableByteChannel channel = Channels.newBufferedChannel(is);
141 ByteBuffer bb = ByteBuffer.allocate(4);
142
143 int countWritten = channel.read(bb);
144
145 assertThat(countWritten).isEqualTo(3);
146
147 assertThat(bb.arrayOffset()).isEqualTo(0);
148
149 assertThat(((Buffer) bb).position()).isEqualTo(3);
150
151 assertThat(bb.remaining()).isEqualTo(1);
152
153 assertThat(((Buffer) bb).limit()).isEqualTo(4);
154
155 assertThat(bb.capacity()).isEqualTo(4);
156
157 ((Buffer) bb).flip();
158
159 assertThat(bb.arrayOffset()).isEqualTo(0);
160
161 assertThat(((Buffer) bb).position()).isEqualTo(0);
162
163 assertThat(bb.remaining()).isEqualTo(3);
164
165 assertThat(((Buffer) bb).limit()).isEqualTo(3);
166
167 assertThat(bb.capacity()).isEqualTo(4);
168
169 assertThat(bb.array()).isEqualTo(new byte[] {1, 2, 3, 0});
170
171 assertThat(channel.isOpen()).isTrue();
172
173 channel.close();
174
175 assertThat(channel.isOpen()).isFalse();
176 }
177
178 @Test
179 public void biggerBuffer() throws Exception {
180 ByteArrayInputStream is = new ByteArrayInputStream(new byte[] {1, 2, 3});
181 ReadableByteChannel channel = Channels.newChannel(is);
182 ByteBuffer bb = ByteBuffer.allocate(4);
183
184 int countWritten = channel.read(bb);
185
186 assertThat(countWritten).isEqualTo(3);
187
188 assertThat(bb.arrayOffset()).isEqualTo(0);
189
190 assertThat(((Buffer) bb).position()).isEqualTo(3);
191
192 assertThat(bb.remaining()).isEqualTo(1);
193
194 assertThat(((Buffer) bb).limit()).isEqualTo(4);
195
196 assertThat(bb.capacity()).isEqualTo(4);
197
198 ((Buffer) bb).flip();
199
200 assertThat(bb.arrayOffset()).isEqualTo(0);
201
202 assertThat(((Buffer) bb).position()).isEqualTo(0);
203
204 assertThat(bb.remaining()).isEqualTo(3);
205
206 assertThat(((Buffer) bb).limit()).isEqualTo(3);
207
208 assertThat(bb.capacity()).isEqualTo(4);
209
210 assertThat(bb.array()).isEqualTo(new byte[] {1, 2, 3, 0});
211
212 assertThat(channel.isOpen()).isTrue();
213
214 channel.close();
215
216 assertThat(channel.isOpen()).isFalse();
217 }
218
219 @Test
220 public void shouldFailAfterClosed() throws IOException {
221 ByteArrayInputStream is = new ByteArrayInputStream(new byte[] {1, 2, 3});
222 ReadableByteChannel channel = Channels.newChannel(is);
223 channel.close();
224 assertThat(channel.isOpen()).isFalse();
225 ee.expect(ClosedChannelException.class);
226 channel.read(ByteBuffer.allocate(0));
227 }
228
229 @Test
230 public void shouldFailIfNotReadable() throws IOException {
231 ByteArrayInputStream is = new ByteArrayInputStream(new byte[] {1, 2, 3});
232 ReadableByteChannel channel = Channels.newChannel(is);
233 ee.expect(NonReadableChannelException.class);
234 channel.read(ByteBuffer.allocate(0).asReadOnlyBuffer());
235 }
236
237 @Test
238 public void shouldFailIOnDirectBuffer() throws IOException {
239 ByteArrayInputStream is = new ByteArrayInputStream(new byte[] {1, 2, 3});
240 ReadableByteChannel channel = Channels.newChannel(is);
241 ee.expect(NonReadableChannelException.class);
242 channel.read(ByteBuffer.allocateDirect(0));
243 }
244
245 @Test
246 public void shouldUseFileChannel() throws IOException {
247 File f = tmp.newFile();
248 write(f.toPath(), new byte[] {1, 2, 3});
249 FileInputStream is = new FileInputStream(f);
250 ReadableByteChannel channel = Channels.newChannel(is);
251 ByteBuffer bb = ByteBuffer.allocate(4);
252 int countWritten = channel.read(bb);
253
254 assertThat(channel.isOpen()).isTrue();
255
256 channel.close();
257
258 assertThat(channel.isOpen()).isFalse();
259
260 assertThat(countWritten).isEqualTo(3);
261
262 assertThat(bb.arrayOffset()).isEqualTo(0);
263
264 assertThat(((Buffer) bb).position()).isEqualTo(3);
265
266 assertThat(bb.remaining()).isEqualTo(1);
267
268 assertThat(((Buffer) bb).limit()).isEqualTo(4);
269
270 assertThat(bb.capacity()).isEqualTo(4);
271
272 ((Buffer) bb).flip();
273
274 assertThat(bb.arrayOffset()).isEqualTo(0);
275
276 assertThat(((Buffer) bb).position()).isEqualTo(0);
277
278 assertThat(bb.remaining()).isEqualTo(3);
279
280 assertThat(((Buffer) bb).limit()).isEqualTo(3);
281
282 assertThat(bb.capacity()).isEqualTo(4);
283
284 assertThat(bb.array()).isEqualTo(new byte[] {1, 2, 3, 0});
285 }
286
287 @Test(expected = IndexOutOfBoundsException.class)
288 public void shouldValidateInput1() throws Exception {
289 AsynchronousByteChannel channel = mock(AsynchronousByteChannel.class);
290 InputStream is = Channels.newInputStream(channel);
291 is.read(new byte[0], -1, 0);
292 }
293
294 @Test(expected = IndexOutOfBoundsException.class)
295 public void shouldValidateInput2() throws Exception {
296 AsynchronousByteChannel channel = mock(AsynchronousByteChannel.class);
297 InputStream is = Channels.newInputStream(channel);
298 is.read(new byte[0], 0, -1);
299 }
300
301 @Test(expected = IndexOutOfBoundsException.class)
302 public void shouldValidateInput3() throws Exception {
303 AsynchronousByteChannel channel = mock(AsynchronousByteChannel.class);
304 InputStream is = Channels.newInputStream(channel);
305 is.read(new byte[0], 1, 0);
306 }
307
308 @Test(expected = IndexOutOfBoundsException.class)
309 public void shouldValidateInput4() throws Exception {
310 AsynchronousByteChannel channel = mock(AsynchronousByteChannel.class);
311 InputStream is = Channels.newInputStream(channel);
312 is.read(new byte[0], 0, 1);
313 }
314
315 @Test
316 public void shouldClose() throws Exception {
317 AsynchronousByteChannel channel = mock(AsynchronousByteChannel.class);
318 when(channel.isOpen()).thenReturn(true);
319 InputStream is = Channels.newInputStream(channel);
320 is.close();
321 verify(channel, times(1)).close();
322 }
323
324 @Test
325 public void shouldNotClose() throws Exception {
326 AsynchronousByteChannel channel = mock(AsynchronousByteChannel.class);
327 when(channel.isOpen()).thenReturn(false);
328 InputStream is = Channels.newInputStream(channel);
329 is.close();
330 verify(channel, never()).close();
331 }
332
333 @Test
334 public void shouldAlreadyClosed() throws Exception {
335 AsynchronousByteChannel channel = mock(AsynchronousByteChannel.class);
336 when(channel.isOpen()).thenReturn(true);
337 doThrow(ClosedChannelException.class).when(channel).close();
338 InputStream is = Channels.newInputStream(channel);
339 is.close();
340 verify(channel).close();
341 }
342
343 @Test
344 public void shouldReadZeroLength() throws Exception {
345 AsynchronousByteChannel channel = mock(AsynchronousByteChannel.class);
346 InputStream is = Channels.newInputStream(channel);
347 is.read(new byte[] {5}, 0, 0);
348 verifyZeroInteractions(channel);
349 }
350
351 @Test
352 public void shouldReadArray() throws Exception {
353 AsynchronousByteChannel channel = mock(AsynchronousByteChannel.class);
354 when(channel.read(any(ByteBuffer.class))).thenAnswer(new Answer<Future<Integer>>() {
355 @Override
356 public Future<Integer> answer(InvocationOnMock invocation) throws Throwable {
357 ByteBuffer bb = (ByteBuffer) invocation.getArguments()[0];
358 bb.put((byte) 3);
359 bb.put((byte) 4);
360 Future<Integer> future = mock(Future.class);
361 when(future.get()).thenReturn(2);
362 return future;
363 }
364 });
365
366 InputStream is = Channels.newInputStream(channel);
367 ArgumentCaptor<ByteBuffer> captured = ArgumentCaptor.forClass(ByteBuffer.class);
368 byte[] b = new byte[] {1, 2, 0, 0, 5};
369 is.read(b, 2, 2);
370
371 verify(channel).read(captured.capture());
372 verifyNoMoreInteractions(channel);
373
374 assertThat(captured.getAllValues()).hasSize(1);
375
376 assertThat(captured.getAllValues().get(0).array()).containsOnly(new byte[] {1, 2, 3, 4, 5});
377
378 assertThat(captured.getAllValues().get(0).arrayOffset()).isEqualTo(0);
379
380 assertThat(captured.getAllValues().get(0).position()).isEqualTo(4);
381
382 assertThat(captured.getAllValues().get(0).limit()).isEqualTo(4);
383
384 assertThat(captured.getAllValues().get(0).capacity()).isEqualTo(5);
385 }
386
387 @Test
388 public void shouldRead() throws Exception {
389 AsynchronousByteChannel channel = mock(AsynchronousByteChannel.class);
390 when(channel.read(any(ByteBuffer.class))).thenAnswer(new Answer<Future<Integer>>() {
391 @Override
392 public Future<Integer> answer(InvocationOnMock invocation) throws Throwable {
393 ByteBuffer bb = (ByteBuffer) invocation.getArguments()[0];
394 bb.put((byte) 3);
395 Future<Integer> future = mock(Future.class);
396 when(future.get()).thenReturn(1);
397 return future;
398 }
399 });
400
401 InputStream is = Channels.newInputStream(channel);
402 ArgumentCaptor<ByteBuffer> captured = ArgumentCaptor.forClass(ByteBuffer.class);
403 int b = is.read();
404 assertThat(b).isEqualTo(3);
405
406 verify(channel).read(captured.capture());
407 verifyNoMoreInteractions(channel);
408
409 assertThat(captured.getAllValues()).hasSize(1);
410
411 assertThat(captured.getAllValues().get(0).array()).containsOnly(new byte[] {3});
412
413 assertThat(captured.getAllValues().get(0).arrayOffset()).isEqualTo(0);
414
415 assertThat(captured.getAllValues().get(0).position()).isEqualTo(1);
416
417 assertThat(captured.getAllValues().get(0).limit()).isEqualTo(1);
418
419 assertThat(captured.getAllValues().get(0).capacity()).isEqualTo(1);
420 }
421
422 @Test
423 public void shouldThrowExceptionOnRead() throws Exception {
424 AsynchronousByteChannel channel = mock(AsynchronousByteChannel.class);
425 when(channel.read(any(ByteBuffer.class))).thenThrow(ShutdownChannelGroupException.class);
426 InputStream is = Channels.newInputStream(channel);
427 ee.expect(IOException.class);
428 ee.expectCause(instanceOf(ShutdownChannelGroupException.class));
429 is.read(new byte[1], 0, 1);
430 }
431
432 @Test
433 public void shouldThrowExceptionOnFuture1() throws Exception {
434 AsynchronousByteChannel channel = mock(AsynchronousByteChannel.class);
435 Future<Integer> future = mock(Future.class);
436 when(future.get()).thenThrow(new ExecutionException(new InterruptedIOException()));
437 when(channel.read(any(ByteBuffer.class))).thenReturn(future);
438 InputStream is = Channels.newInputStream(channel);
439 ee.expect(InterruptedIOException.class);
440 is.read(new byte[1], 0, 1);
441 }
442
443 @Test
444 public void shouldThrowExceptionOnFuture2() throws Exception {
445 AsynchronousByteChannel channel = mock(AsynchronousByteChannel.class);
446 Future<Integer> future = mock(Future.class);
447 when(future.get()).thenThrow(new ExecutionException(new RuntimeException("msg")));
448 when(channel.read(any(ByteBuffer.class))).thenReturn(future);
449 InputStream is = Channels.newInputStream(channel);
450 ee.expect(IOException.class);
451 ee.expectCause(instanceOf(RuntimeException.class));
452 ee.expectMessage("msg");
453 is.read(new byte[1], 0, 1);
454 }
455
456 @Test
457 public void shouldThrowExceptionOnFuture3() throws Exception {
458 AsynchronousByteChannel channel = mock(AsynchronousByteChannel.class);
459 Future<Integer> future = mock(Future.class);
460 when(future.get()).thenThrow(new ExecutionException("msg", null));
461 when(channel.read(any(ByteBuffer.class))).thenReturn(future);
462 InputStream is = Channels.newInputStream(channel);
463 ee.expect(IOException.class);
464 ee.expectMessage("msg");
465 is.read(new byte[1], 0, 1);
466 }
467 }