xref: /aosp_15_r20/external/aws-eventstream-java/src/test/java/software/amazon/eventstream/MessageTest.java (revision 3990ee4244bcecb5cb057ac1935381dd16da2e31)
1 /*
2  * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */
15 package software.amazon.eventstream;
16 
17 import org.junit.jupiter.api.Test;
18 
19 import java.io.ByteArrayOutputStream;
20 import java.nio.ByteBuffer;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.LinkedHashMap;
24 import java.util.Map;
25 import java.util.Map.Entry;
26 import java.util.Random;
27 
28 import static java.nio.charset.StandardCharsets.UTF_8;
29 import static java.util.Collections.emptyMap;
30 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
31 import static org.junit.jupiter.api.Assertions.assertEquals;
32 import static org.junit.jupiter.api.Assertions.assertThrows;
33 
34 public class MessageTest {
35     @Test
emptyVector()36     public void emptyVector() {
37         Message message = new Message(emptyMap(), new byte[]{});
38         ByteArrayOutputStream baos = new ByteArrayOutputStream();
39         message.encode(baos);
40         byte[] bytes = baos.toByteArray();
41 
42         byte[] expected = new byte[]{
43             0, 0, 0, 16,       // total_length
44             0, 0, 0, 0,        // headers_length
45             5, -62, 72, -21,   // prelude_crc
46             125, -104, -56, -1 // message_crc
47         };
48 
49         assertArrayEquals(expected, bytes);
50 
51         assertEquals(message, Message.decode(ByteBuffer.wrap(expected)));
52     }
53 
54     @Test
appdataVector()55     public void appdataVector() {
56         byte[] bytes = new byte[]{
57             0, 0, 0, 0x1d,                              // total_length
58             0, 0, 0, 0,                                 // headers_length
59             (byte) 0xfd, 0x52, (byte) 0x8c, 0x5a,       // prelude_crc
60             0x7b, 0x27, 0x66, 0x6f, 0x6f, 0x27, 0x3a,   // payload
61             0x27, 0x62, 0x61, 0x72, 0x27, 0x7d,
62             // 0xc3 65 39 36
63             (byte) 0xc3, 0x65, 0x39, 0x36               // message_crc
64         };
65 
66         Message message = new Message(emptyMap(), "{'foo':'bar'}".getBytes(UTF_8));
67 
68         assertEquals(message, Message.decode(ByteBuffer.wrap(bytes)));
69     }
70 
71     @Test
roundTripTests()72     public void roundTripTests() {
73         roundTrip(new Message(emptyMap(), new byte[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }));
74 
75         Map<String, HeaderValue> headers = new HashMap<>();
76         headers.put(":content-type", HeaderValue.fromString("application/json"));
77         headers.put("content-encoding", HeaderValue.fromString("gzip"));
78         headers.put("request-id", HeaderValue.fromByteArray(new byte[]{ 1, 2, 3, 4, 5 }));
79         headers.put("more-stuff", HeaderValue.fromInteger(27));
80         roundTrip(new Message(headers, new byte[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }));
81     }
82 
83     @Test
generativeTest()84     public void generativeTest() throws Exception {
85         long SEED = 8912374098123423L;
86         TestUtils utils = new TestUtils(SEED);
87         Random rand = new Random(SEED);
88         for (int i = 0; i < 10_000; i++) {
89             byte[] padding = new byte[rand.nextInt(128 * 1024)];
90             rand.nextBytes(padding);
91 
92             ByteArrayOutputStream baos = new ByteArrayOutputStream();
93             baos.write(padding);
94             Message message = utils.randomMessage();
95             message.encode(baos);
96 
97             int arraylen = 256 * 1024;
98             int arrayoffset = rand.nextInt(4 * 1024);
99             ByteBuffer buf = ((ByteBuffer) ByteBuffer.allocate(arraylen).position(arrayoffset)).slice();
100             byte[] encodedBytes = baos.toByteArray();
101             buf.put(encodedBytes);
102             buf.flip();
103 
104             buf.get(padding);
105             Message decoded = Message.decode(buf);
106 
107             assertEquals(message, decoded);
108 
109             // Corrupt a random byte and verify that decoding fails
110             encodedBytes[rand.nextInt(encodedBytes.length)]++;
111             assertThrows(IllegalArgumentException.class, () -> Message.decode(ByteBuffer.wrap(encodedBytes)));
112         }
113     }
114 
115     @Test
headerOrder()116     public void headerOrder() {
117         Map<String, HeaderValue> expectedHeaders = new LinkedHashMap<>();
118         for (int i = 0; i < 255; i++) {
119             expectedHeaders.put(String.valueOf(i), HeaderValue.fromInteger(i));
120         }
121         Message expected = new Message(expectedHeaders, new byte[]{});
122 
123         ByteArrayOutputStream baos = new ByteArrayOutputStream();
124         expected.encode(baos);
125         Message actual = Message.decode(ByteBuffer.wrap(baos.toByteArray()));
126 
127         Map<String, HeaderValue> actualHeaders = actual.getHeaders();
128         Iterator<Entry<String, HeaderValue>> expectedIter = expectedHeaders.entrySet().iterator();
129         Iterator<Entry<String, HeaderValue>> actualIter = actualHeaders.entrySet().iterator();
130         for (int i = 0; i < 255; i++) {
131             assertEquals(expectedIter.next(), actualIter.next());
132         }
133     }
134 
roundTrip(Message expected)135     static void roundTrip(Message expected) {
136         ByteArrayOutputStream baos = new ByteArrayOutputStream();
137         expected.encode(baos);
138         Message actual = Message.decode(ByteBuffer.wrap(baos.toByteArray()));
139         assertEquals(expected, actual);
140     }
141 }
142