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.stream;
20
21 import javax.annotation.Nonnull;
22
23 import java.io.ByteArrayOutputStream;
24 import java.nio.Buffer;
25 import java.nio.ByteBuffer;
26 import java.nio.charset.Charset;
27 import java.nio.charset.CharsetEncoder;
28
29 import org.apache.maven.surefire.api.booter.ForkedProcessEventType;
30 import org.apache.maven.surefire.api.util.internal.WritableBufferedByteChannel;
31 import org.junit.Test;
32
33 import static java.nio.charset.StandardCharsets.US_ASCII;
34 import static java.nio.charset.StandardCharsets.UTF_8;
35 import static org.apache.maven.surefire.api.booter.Constants.MAGIC_NUMBER_FOR_EVENTS_BYTES;
36 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_BYE;
37 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_DEBUG;
38 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_ERROR;
39 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_INFO;
40 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_WARNING;
41 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_JVM_EXIT_ERROR;
42 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_NEXT_TEST;
43 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDERR;
44 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDERR_NEW_LINE;
45 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDOUT;
46 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDOUT_NEW_LINE;
47 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STOP_ON_NEXT_TEST;
48 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_SYSPROPS;
49 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TESTSET_COMPLETED;
50 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TESTSET_STARTING;
51 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_ASSUMPTIONFAILURE;
52 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_ERROR;
53 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_FAILED;
54 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_SKIPPED;
55 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_STARTING;
56 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_SUCCEEDED;
57 import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN;
58 import static org.assertj.core.api.Assertions.assertThat;
59
60
61
62
63 @SuppressWarnings({"checkstyle:linelength", "checkstyle:magicnumber"})
64 public class AbstractStreamEncoderTest {
65 @Test
66 public void shouldComputeStreamPreemptiveLength() {
67 Encoder streamEncoder = new Encoder(new DummyChannel());
68 CharsetEncoder encoder = streamEncoder.newCharsetEncoder();
69
70
71 assertThat(streamEncoder.estimateBufferLength(
72 BOOTERCODE_SYSPROPS.getOpcodeBinary().length, NORMAL_RUN, encoder, 0, 1, "k", "v"))
73 .isEqualTo(82);
74
75
76 assertThat(streamEncoder.estimateBufferLength(
77 BOOTERCODE_TESTSET_STARTING.getOpcodeBinary().length,
78 NORMAL_RUN,
79 encoder,
80 1,
81 1,
82 "s",
83 "s",
84 "s",
85 "s",
86 "s",
87 "s",
88 "s",
89 "s",
90 "s"))
91 .isEqualTo(159);
92
93
94 assertThat(streamEncoder.estimateBufferLength(
95 BOOTERCODE_TESTSET_COMPLETED.getOpcodeBinary().length,
96 NORMAL_RUN,
97 encoder,
98 1,
99 1,
100 "s",
101 "s",
102 "s",
103 "s",
104 "s",
105 "s",
106 "s",
107 "s",
108 "s"))
109 .isEqualTo(160);
110
111
112 assertThat(streamEncoder.estimateBufferLength(
113 BOOTERCODE_TEST_STARTING.getOpcodeBinary().length,
114 NORMAL_RUN,
115 encoder,
116 1,
117 1,
118 "s",
119 "s",
120 "s",
121 "s",
122 "s",
123 "s",
124 "s",
125 "s",
126 "s"))
127 .isEqualTo(156);
128
129
130 assertThat(streamEncoder.estimateBufferLength(
131 BOOTERCODE_TEST_SUCCEEDED.getOpcodeBinary().length,
132 NORMAL_RUN,
133 encoder,
134 1,
135 1,
136 "s",
137 "s",
138 "s",
139 "s",
140 "s",
141 "s",
142 "s",
143 "s",
144 "s"))
145 .isEqualTo(157);
146
147
148 assertThat(streamEncoder.estimateBufferLength(
149 BOOTERCODE_TEST_FAILED.getOpcodeBinary().length,
150 NORMAL_RUN,
151 encoder,
152 1,
153 1,
154 "s",
155 "s",
156 "s",
157 "s",
158 "s",
159 "s",
160 "s",
161 "s",
162 "s"))
163 .isEqualTo(154);
164
165
166 assertThat(streamEncoder.estimateBufferLength(
167 BOOTERCODE_TEST_SKIPPED.getOpcodeBinary().length,
168 NORMAL_RUN,
169 encoder,
170 1,
171 1,
172 "s",
173 "s",
174 "s",
175 "s",
176 "s",
177 "s",
178 "s",
179 "s",
180 "s"))
181 .isEqualTo(155);
182
183
184 assertThat(streamEncoder.estimateBufferLength(
185 BOOTERCODE_TEST_ERROR.getOpcodeBinary().length,
186 NORMAL_RUN,
187 encoder,
188 1,
189 1,
190 "s",
191 "s",
192 "s",
193 "s",
194 "s",
195 "s",
196 "s",
197 "s",
198 "s"))
199 .isEqualTo(153);
200
201
202 assertThat(streamEncoder.estimateBufferLength(
203 BOOTERCODE_TEST_ASSUMPTIONFAILURE.getOpcodeBinary().length,
204 NORMAL_RUN,
205 encoder,
206 1,
207 1,
208 "s",
209 "s",
210 "s",
211 "s",
212 "s",
213 "s",
214 "s",
215 "s",
216 "s"))
217 .isEqualTo(166);
218
219
220 assertThat(streamEncoder.estimateBufferLength(
221 BOOTERCODE_STDOUT.getOpcodeBinary().length, NORMAL_RUN, encoder, 0, 1, "s"))
222 .isEqualTo(79);
223
224
225 assertThat(streamEncoder.estimateBufferLength(
226 BOOTERCODE_STDOUT_NEW_LINE.getOpcodeBinary().length, NORMAL_RUN, encoder, 0, 1, "s"))
227 .isEqualTo(88);
228
229
230 assertThat(streamEncoder.estimateBufferLength(
231 BOOTERCODE_STDERR.getOpcodeBinary().length, NORMAL_RUN, encoder, 0, 1, "s"))
232 .isEqualTo(79);
233
234
235 assertThat(streamEncoder.estimateBufferLength(
236 BOOTERCODE_STDERR_NEW_LINE.getOpcodeBinary().length, NORMAL_RUN, encoder, 0, 1, "s"))
237 .isEqualTo(88);
238
239
240 assertThat(streamEncoder.estimateBufferLength(
241 BOOTERCODE_CONSOLE_INFO.getOpcodeBinary().length, null, encoder, 0, 0, "s"))
242 .isEqualTo(61);
243
244
245 assertThat(streamEncoder.estimateBufferLength(
246 BOOTERCODE_CONSOLE_DEBUG.getOpcodeBinary().length, null, encoder, 0, 0, "s"))
247 .isEqualTo(62);
248
249
250 assertThat(streamEncoder.estimateBufferLength(
251 BOOTERCODE_CONSOLE_WARNING.getOpcodeBinary().length, null, encoder, 0, 0, "s"))
252 .isEqualTo(64);
253
254
255 assertThat(streamEncoder.estimateBufferLength(
256 BOOTERCODE_CONSOLE_ERROR.getOpcodeBinary().length, null, encoder, 0, 0, "s"))
257 .isEqualTo(62);
258
259
260 assertThat(streamEncoder.estimateBufferLength(BOOTERCODE_BYE.getOpcodeBinary().length, null, null, 0, 0))
261 .isEqualTo(31);
262
263
264 assertThat(streamEncoder.estimateBufferLength(
265 BOOTERCODE_STOP_ON_NEXT_TEST.getOpcodeBinary().length, null, null, 0, 0))
266 .isEqualTo(45);
267
268
269 assertThat(streamEncoder.estimateBufferLength(BOOTERCODE_NEXT_TEST.getOpcodeBinary().length, null, null, 0, 0))
270 .isEqualTo(37);
271
272
273 assertThat(streamEncoder.estimateBufferLength(
274 BOOTERCODE_JVM_EXIT_ERROR.getOpcodeBinary().length, null, null, 0, 0))
275 .isEqualTo(42);
276 }
277
278 @Test
279 public void testSendOpcode() {
280 Encoder streamEncoder = new Encoder(new DummyChannel());
281 ByteBuffer result = ByteBuffer.allocate(128);
282 streamEncoder.encodeHeader(result, BOOTERCODE_TEST_ERROR, NORMAL_RUN, 1L);
283 assertThat(toString(result))
284 .isEqualTo(":maven-surefire-event:" + (char) 10 + ":test-error:" + (char) 10
285 + ":normal-run:\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:");
286
287 result = ByteBuffer.allocate(1024);
288 streamEncoder.encodeHeader(result, BOOTERCODE_CONSOLE_ERROR);
289 streamEncoder.encodeCharset(result);
290 assertThat(toString(result))
291 .isEqualTo(":maven-surefire-event:" + (char) 17 + ":console-error-log:" + (char) 5 + ":UTF-8:");
292 }
293
294 @Test
295 public void testEncodedString() {
296 Encoder streamEncoder = new Encoder(new DummyChannel());
297 ByteBuffer result = ByteBuffer.allocate(128);
298 streamEncoder.encode(streamEncoder.newCharsetEncoder(), result, BOOTERCODE_STDOUT, NORMAL_RUN, 1L, "msg");
299 assertThat(toString(result))
300 .isEqualTo(":maven-surefire-event:\u000e:std-out-stream:"
301 + (char) 10 + ":normal-run:\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001"
302 + ":\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:");
303 }
304
305 @Test
306 public void testIntegerAsNull() {
307 Encoder streamEncoder = new Encoder(new DummyChannel());
308 ByteBuffer result = ByteBuffer.allocate(4);
309 streamEncoder.encodeInteger(result, null);
310 assertThat(((Buffer) result).position()).isEqualTo(2);
311 assertThat(result.get(0)).isEqualTo((byte) 0);
312 assertThat(result.get(1)).isEqualTo((byte) ':');
313 }
314
315 @Test
316 public void testInteger() {
317 Encoder streamEncoder = new Encoder(new DummyChannel());
318 ByteBuffer result = ByteBuffer.allocate(8);
319 streamEncoder.encodeInteger(result, 5);
320 assertThat(((Buffer) result).position()).isEqualTo(6);
321 ((Buffer) result).position(0);
322 assertThat(result.get()).isEqualTo((byte) 0xff);
323 assertThat(result.getInt()).isEqualTo((byte) 5);
324 assertThat(result.get(5)).isEqualTo((byte) ':');
325 }
326
327 @Test
328 public void testWrite() throws Exception {
329 DummyChannel channel = new DummyChannel();
330 Encoder streamEncoder = new Encoder(channel);
331 streamEncoder.write(ByteBuffer.allocate(0), false);
332 assertThat(channel.writeBuffered).isTrue();
333 assertThat(channel.write).isFalse();
334 channel.writeBuffered = false;
335 channel.write = false;
336 streamEncoder.write(ByteBuffer.allocate(0), true);
337 assertThat(channel.writeBuffered).isFalse();
338 assertThat(channel.write).isTrue();
339 }
340
341 private static String toString(ByteBuffer frame) {
342 ByteArrayOutputStream os = new ByteArrayOutputStream();
343 ((Buffer) frame).flip();
344 os.write(frame.array(), frame.arrayOffset() + ((Buffer) frame).position(), frame.remaining());
345 return new String(os.toByteArray(), UTF_8);
346 }
347
348 private static class Encoder extends AbstractStreamEncoder<ForkedProcessEventType> {
349
350 Encoder(WritableBufferedByteChannel out) {
351 super(out);
352 }
353
354 @Nonnull
355 @Override
356 public byte[] getEncodedMagicNumber() {
357 return MAGIC_NUMBER_FOR_EVENTS_BYTES;
358 }
359
360 @Nonnull
361 @Override
362 protected byte[] enumToByteArray(ForkedProcessEventType forkedProcessEventType) {
363 return forkedProcessEventType.getOpcodeBinary();
364 }
365
366 @Nonnull
367 @Override
368 protected byte[] getEncodedCharsetName() {
369 return getCharset().name().getBytes(US_ASCII);
370 }
371
372 @Nonnull
373 @Override
374 public Charset getCharset() {
375 return UTF_8;
376 }
377
378 @Nonnull
379 @Override
380 public CharsetEncoder newCharsetEncoder() {
381 return getCharset().newEncoder();
382 }
383 }
384
385 private static class DummyChannel implements WritableBufferedByteChannel {
386 boolean writeBuffered;
387 boolean write;
388
389 @Override
390 public void writeBuffered(ByteBuffer src) {
391 writeBuffered = true;
392 }
393
394 @Override
395 public long countBufferOverflows() {
396 return 0;
397 }
398
399 @Override
400 public int write(ByteBuffer src) {
401 write = true;
402 return 0;
403 }
404
405 @Override
406 public boolean isOpen() {
407 return false;
408 }
409
410 @Override
411 public void close() {}
412 }
413 }