1+ /*
2+ * Licensed to Elasticsearch B.V. under one or more contributor
3+ * license agreements. See the NOTICE file distributed with
4+ * this work for additional information regarding copyright
5+ * ownership. Elasticsearch B.V. licenses this file to you under
6+ * the Apache License, Version 2.0 (the "License"); you may
7+ * not use this file except in compliance with the License.
8+ * 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+
20+ package co .elastic .clients .transport .rest5_client .low_level ;
21+
22+ import org .apache .hc .core5 .concurrent .FutureCallback ;
23+ import org .apache .hc .core5 .http .ContentTooLongException ;
24+ import org .apache .hc .core5 .http .io .entity .ByteArrayEntity ;
25+ import org .junit .jupiter .api .Test ;
26+
27+ import java .nio .ByteBuffer ;
28+ import java .nio .charset .StandardCharsets ;
29+
30+ import static org .junit .jupiter .api .Assertions .assertThrows ;
31+ import static org .junit .jupiter .api .Assertions .assertEquals ;
32+ import static org .junit .jupiter .api .Assertions .assertTrue ;
33+ import static org .junit .jupiter .api .Assertions .assertFalse ;
34+ import static org .junit .jupiter .api .Assertions .fail ;
35+ import static org .junit .jupiter .api .Assertions .assertDoesNotThrow ;
36+ import static org .junit .jupiter .api .Assertions .assertNotNull ;
37+
38+ class BufferedByteConsumerTest extends RestClientTestCase {
39+
40+ @ Test
41+ void testConstructor () {
42+ assertThrows (IllegalArgumentException .class , () -> new BufferedByteConsumer (0 ));
43+ assertThrows (IllegalArgumentException .class , () -> new BufferedByteConsumer (-1 ));
44+ }
45+
46+ @ Test
47+ void testCapacityIncrement () {
48+ int bufferLimit = 1024 ;
49+ BufferedByteConsumer consumer = new BufferedByteConsumer (bufferLimit );
50+ assertEquals (bufferLimit , consumer .capacityIncrement ());
51+ }
52+
53+ @ Test
54+ void testContentTooLongException () {
55+ int bufferLimit = 10 ;
56+ BufferedByteConsumer consumer = new BufferedByteConsumer (bufferLimit );
57+
58+ // Start the stream
59+ consumer .streamStart (null , null );
60+
61+ // Try to add data that exceeds the limit
62+ byte [] data = "This is a long string that exceeds the buffer limit" .getBytes (StandardCharsets .UTF_8 );
63+ ByteBuffer buffer = ByteBuffer .wrap (data );
64+
65+ ContentTooLongException exception = assertThrows (ContentTooLongException .class , () -> {
66+ consumer .data (buffer , false );
67+ });
68+ assertEquals ("entity content is too long [51] for the configured buffer limit [10]" , exception .getMessage ());
69+ }
70+
71+ @ Test
72+ void testContentTooLongExceptionWithTwoCalls () {
73+ int bufferLimit = 100 ;
74+ BufferedByteConsumer consumer = new BufferedByteConsumer (bufferLimit );
75+
76+ // Start the stream
77+ consumer .streamStart (null , null );
78+
79+ // Try to add data that exceeds the limit
80+ byte [] data = "This is a long string that exceeds the buffer limit" .getBytes (StandardCharsets .UTF_8 );
81+ ByteBuffer buffer = ByteBuffer .wrap (data );
82+
83+ ContentTooLongException exception = assertThrows (ContentTooLongException .class , () -> {
84+ consumer .data (buffer , false );
85+ consumer .data (buffer , false ); // This should trigger the exception on the second call
86+ });
87+ assertEquals ("entity content is too long [102] for the configured buffer limit [100]" , exception .getMessage ());
88+ }
89+
90+ @ Test
91+ void testContentTooLongExceptionWithCallback () throws Exception {
92+ int bufferLimit = 10 ;
93+ BufferedByteConsumer consumer = new BufferedByteConsumer (bufferLimit );
94+
95+ TestFutureCallback callback = new TestFutureCallback ();
96+ consumer .streamStart (null , callback );
97+
98+ // Try to add data that exceeds the limit
99+ byte [] data = "This is a long string that exceeds the buffer limit" .getBytes (StandardCharsets .UTF_8 );
100+ ByteBuffer buffer = ByteBuffer .wrap (data );
101+
102+ try {
103+ consumer .data (buffer , false );
104+ fail ("Expected ContentTooLongException" );
105+ } catch (ContentTooLongException e ) {
106+ // Verify the exception message contains the expected values
107+ assertTrue (e .getMessage ().contains ("entity content is too long" ));
108+ assertTrue (e .getMessage ().contains (String .valueOf (bufferLimit )));
109+ }
110+ }
111+
112+ @ Test
113+ void testSuccessfulDataConsumption () throws Exception {
114+ int bufferLimit = 100 ;
115+ BufferedByteConsumer consumer = new BufferedByteConsumer (bufferLimit );
116+
117+ TestFutureCallback callback = new TestFutureCallback ();
118+ consumer .streamStart (null , callback );
119+
120+ // Add data within the limit
121+ byte [] data = "Hello, World!" .getBytes (StandardCharsets .UTF_8 );
122+ ByteBuffer buffer = ByteBuffer .wrap (data );
123+
124+ consumer .data (buffer , true );
125+ consumer .completed ();
126+
127+ // Verify the callback was called successfully
128+ assertTrue (callback .isCompleted ());
129+ assertFalse (callback .isFailed ());
130+ assertNotNull (consumer .getContent ());
131+ }
132+
133+ @ Test
134+ void testContentAtExactLimit () throws Exception {
135+ int bufferLimit = 13 ;
136+ BufferedByteConsumer consumer = new BufferedByteConsumer (bufferLimit );
137+
138+ consumer .streamStart (null , null );
139+
140+ // Add data exactly at the limit
141+ byte [] data = "Hello, World!" .getBytes (StandardCharsets .UTF_8 );
142+ ByteBuffer buffer = ByteBuffer .wrap (data );
143+
144+ // Should not throw exception
145+ assertDoesNotThrow (() -> consumer .data (buffer , true ));
146+ }
147+
148+ @ Test
149+ void testContentJustOverLimit () throws Exception {
150+ int bufferLimit = 12 ;
151+ BufferedByteConsumer consumer = new BufferedByteConsumer (bufferLimit );
152+
153+ consumer .streamStart (null , null );
154+
155+ // Add data just over the limit
156+ byte [] data = "Hello, World!" .getBytes (StandardCharsets .UTF_8 );
157+ ByteBuffer buffer = ByteBuffer .wrap (data );
158+
159+ assertThrows (ContentTooLongException .class , () -> consumer .data (buffer , true ));
160+ }
161+
162+ @ Test
163+ void testFailedCallback () {
164+ int bufferLimit = 100 ;
165+ BufferedByteConsumer consumer = new BufferedByteConsumer (bufferLimit );
166+
167+ TestFutureCallback callback = new TestFutureCallback ();
168+ consumer .streamStart (null , callback );
169+
170+ Exception testException = new RuntimeException ("Test exception" );
171+ consumer .failed (testException );
172+
173+ assertTrue (callback .isFailed ());
174+ assertEquals (testException , callback .getException ());
175+ }
176+
177+ private static class TestFutureCallback implements FutureCallback <ByteArrayEntity > {
178+ private boolean completed = false ;
179+ private boolean failed = false ;
180+ private ByteArrayEntity result ;
181+ private Exception exception ;
182+
183+ @ Override
184+ public void completed (ByteArrayEntity result ) {
185+ this .completed = true ;
186+ this .result = result ;
187+ }
188+
189+ @ Override
190+ public void failed (Exception ex ) {
191+ this .failed = true ;
192+ this .exception = ex ;
193+ }
194+
195+ @ Override
196+ public void cancelled () {
197+ // Not used in tests
198+ }
199+
200+ public boolean isCompleted () {
201+ return completed ;
202+ }
203+
204+ public boolean isFailed () {
205+ return failed ;
206+ }
207+
208+ public ByteArrayEntity getResult () {
209+ return result ;
210+ }
211+
212+ public Exception getException () {
213+ return exception ;
214+ }
215+ }
216+
217+ }
0 commit comments