View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
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          // :maven-surefire-event:8:sys-prop:10:normal-run:1:5:UTF-8:0003:kkk:0003:vvv:
71          assertThat(streamEncoder.estimateBufferLength(
72                          BOOTERCODE_SYSPROPS.getOpcodeBinary().length, NORMAL_RUN, encoder, 0, 1, "k", "v"))
73                  .isEqualTo(82);
74  
75          // :maven-surefire-event:16:testset-starting:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
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          // :maven-surefire-event:17:testset-completed:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
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         // :maven-surefire-event:13:test-starting:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
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         // :maven-surefire-event:14:test-succeeded:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
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         // :maven-surefire-event:11:test-failed:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
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         // :maven-surefire-event:12:test-skipped:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
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         // :maven-surefire-event:10:test-error:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
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         // :maven-surefire-event:23:test-assumption-failure:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
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         // :maven-surefire-event:14:std-out-stream:10:normal-run:1:5:UTF-8:0003:sss:
220         assertThat(streamEncoder.estimateBufferLength(
221                         BOOTERCODE_STDOUT.getOpcodeBinary().length, NORMAL_RUN, encoder, 0, 1, "s"))
222                 .isEqualTo(79);
223 
224         // :maven-surefire-event:23:std-out-stream-new-line:10:normal-run:1:5:UTF-8:0003:sss:
225         assertThat(streamEncoder.estimateBufferLength(
226                         BOOTERCODE_STDOUT_NEW_LINE.getOpcodeBinary().length, NORMAL_RUN, encoder, 0, 1, "s"))
227                 .isEqualTo(88);
228 
229         // :maven-surefire-event:14:std-err-stream:10:normal-run:1:5:UTF-8:0003:sss:
230         assertThat(streamEncoder.estimateBufferLength(
231                         BOOTERCODE_STDERR.getOpcodeBinary().length, NORMAL_RUN, encoder, 0, 1, "s"))
232                 .isEqualTo(79);
233 
234         // :maven-surefire-event:23:std-err-stream-new-line:10:normal-run:1:5:UTF-8:0003:sss:
235         assertThat(streamEncoder.estimateBufferLength(
236                         BOOTERCODE_STDERR_NEW_LINE.getOpcodeBinary().length, NORMAL_RUN, encoder, 0, 1, "s"))
237                 .isEqualTo(88);
238 
239         // :maven-surefire-event:16:console-info-log:0::5:UTF-8:0001:s:
240         assertThat(streamEncoder.estimateBufferLength(
241                         BOOTERCODE_CONSOLE_INFO.getOpcodeBinary().length, null, encoder, 0, 0, "s"))
242                 .isEqualTo(61);
243 
244         // :maven-surefire-event:17:console-debug-log:0::5:UTF-8:0001:s:
245         assertThat(streamEncoder.estimateBufferLength(
246                         BOOTERCODE_CONSOLE_DEBUG.getOpcodeBinary().length, null, encoder, 0, 0, "s"))
247                 .isEqualTo(62);
248 
249         // :maven-surefire-event:19:console-warning-log:0::5:UTF-8:0001:s:
250         assertThat(streamEncoder.estimateBufferLength(
251                         BOOTERCODE_CONSOLE_WARNING.getOpcodeBinary().length, null, encoder, 0, 0, "s"))
252                 .isEqualTo(64);
253 
254         // :maven-surefire-event:17:console-error-log:0::5:UTF-8:0001:s:
255         assertThat(streamEncoder.estimateBufferLength(
256                         BOOTERCODE_CONSOLE_ERROR.getOpcodeBinary().length, null, encoder, 0, 0, "s"))
257                 .isEqualTo(62);
258 
259         // :maven-surefire-event:3:bye:0::
260         assertThat(streamEncoder.estimateBufferLength(BOOTERCODE_BYE.getOpcodeBinary().length, null, null, 0, 0))
261                 .isEqualTo(31);
262 
263         // :maven-surefire-event:17:stop-on-next-test:0::
264         assertThat(streamEncoder.estimateBufferLength(
265                         BOOTERCODE_STOP_ON_NEXT_TEST.getOpcodeBinary().length, null, null, 0, 0))
266                 .isEqualTo(45);
267 
268         // :maven-surefire-event:9:next-test:0::
269         assertThat(streamEncoder.estimateBufferLength(BOOTERCODE_NEXT_TEST.getOpcodeBinary().length, null, null, 0, 0))
270                 .isEqualTo(37);
271 
272         // :maven-surefire-event:14:jvm-exit-error:0::
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 }