xref: /aosp_15_r20/external/cronet/net/base/chunked_upload_data_stream_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/base/chunked_upload_data_stream.h"
6 
7 #include <memory>
8 #include <string>
9 
10 #include "net/base/io_buffer.h"
11 #include "net/base/net_errors.h"
12 #include "net/base/test_completion_callback.h"
13 #include "net/base/upload_data_stream.h"
14 #include "net/log/net_log_with_source.h"
15 #include "net/test/gtest_util.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 
19 using net::test::IsError;
20 using net::test::IsOk;
21 
22 namespace net {
23 
24 namespace {
25 
26 constexpr char kTestData[] = "0123456789";
27 constexpr size_t kTestDataSize = std::size(kTestData) - 1;
28 constexpr size_t kTestBufferSize = 1 << 14;  // 16KB.
29 
30 }  // namespace
31 
32 // Reads data once from the upload data stream, and returns the data as string.
33 // Expects the read to succeed synchronously.
ReadSync(UploadDataStream * stream,int buffer_size)34 std::string ReadSync(UploadDataStream* stream, int buffer_size) {
35   auto buf = base::MakeRefCounted<IOBufferWithSize>(buffer_size);
36   int result = stream->Read(buf.get(),
37                             buffer_size,
38                             TestCompletionCallback().callback());
39   EXPECT_GE(result, 0);
40   return std::string(buf->data(), result);
41 }
42 
43 // Check the case data is added after the first read attempt.
TEST(ChunkedUploadDataStreamTest,AppendOnce)44 TEST(ChunkedUploadDataStreamTest, AppendOnce) {
45   ChunkedUploadDataStream stream(0);
46 
47   ASSERT_THAT(
48       stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
49       IsOk());
50   EXPECT_FALSE(stream.IsInMemory());
51   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
52   EXPECT_EQ(0u, stream.position());
53   EXPECT_FALSE(stream.IsEOF());
54 
55   TestCompletionCallback callback;
56   auto buf = base::MakeRefCounted<IOBufferWithSize>(kTestBufferSize);
57   int result = stream.Read(buf.get(), kTestBufferSize, callback.callback());
58   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
59 
60   stream.AppendData(kTestData, kTestDataSize, true);
61   int read = callback.WaitForResult();
62   ASSERT_GE(read, 0);
63   EXPECT_EQ(kTestData, std::string(buf->data(), read));
64   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
65   EXPECT_EQ(kTestDataSize, stream.position());
66   EXPECT_TRUE(stream.IsEOF());
67 }
68 
TEST(ChunkedUploadDataStreamTest,AppendOnceBeforeRead)69 TEST(ChunkedUploadDataStreamTest, AppendOnceBeforeRead) {
70   ChunkedUploadDataStream stream(0);
71 
72   ASSERT_THAT(
73       stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
74       IsOk());
75   EXPECT_FALSE(stream.IsInMemory());
76   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
77   EXPECT_EQ(0u, stream.position());
78   EXPECT_FALSE(stream.IsEOF());
79 
80   stream.AppendData(kTestData, kTestDataSize, true);
81   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
82   EXPECT_EQ(0u, stream.position());
83   EXPECT_FALSE(stream.IsEOF());
84 
85   std::string data = ReadSync(&stream, kTestBufferSize);
86   EXPECT_EQ(kTestData, data);
87   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
88   EXPECT_EQ(kTestDataSize, stream.position());
89   EXPECT_TRUE(stream.IsEOF());
90 }
91 
TEST(ChunkedUploadDataStreamTest,AppendOnceBeforeInit)92 TEST(ChunkedUploadDataStreamTest, AppendOnceBeforeInit) {
93   ChunkedUploadDataStream stream(0);
94 
95   stream.AppendData(kTestData, kTestDataSize, true);
96   ASSERT_THAT(
97       stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
98       IsOk());
99   EXPECT_FALSE(stream.IsInMemory());
100   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
101   EXPECT_EQ(0u, stream.position());
102   EXPECT_FALSE(stream.IsEOF());
103 
104   std::string data = ReadSync(&stream, kTestBufferSize);
105   EXPECT_EQ(kTestData, data);
106   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
107   EXPECT_EQ(kTestDataSize, stream.position());
108   EXPECT_TRUE(stream.IsEOF());
109 }
110 
TEST(ChunkedUploadDataStreamTest,MultipleAppends)111 TEST(ChunkedUploadDataStreamTest, MultipleAppends) {
112   ChunkedUploadDataStream stream(0);
113 
114   ASSERT_THAT(
115       stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
116       IsOk());
117   EXPECT_FALSE(stream.IsInMemory());
118   EXPECT_EQ(0u, stream.size());
119   EXPECT_EQ(0u, stream.position());
120   EXPECT_FALSE(stream.IsEOF());
121 
122   TestCompletionCallback callback;
123   auto buf = base::MakeRefCounted<IOBufferWithSize>(kTestBufferSize);
124   for (size_t i = 0; i < kTestDataSize; ++i) {
125     EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
126     EXPECT_EQ(i, stream.position());
127     ASSERT_FALSE(stream.IsEOF());
128     int bytes_read = stream.Read(buf.get(),
129                                  kTestBufferSize,
130                                  callback.callback());
131     ASSERT_THAT(bytes_read, IsError(ERR_IO_PENDING));
132     stream.AppendData(&kTestData[i], 1, i == kTestDataSize - 1);
133     ASSERT_EQ(1, callback.WaitForResult());
134     EXPECT_EQ(kTestData[i], buf->data()[0]);
135   }
136 
137   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
138   EXPECT_EQ(kTestDataSize, stream.position());
139   ASSERT_TRUE(stream.IsEOF());
140 }
141 
TEST(ChunkedUploadDataStreamTest,MultipleAppendsBetweenReads)142 TEST(ChunkedUploadDataStreamTest, MultipleAppendsBetweenReads) {
143   ChunkedUploadDataStream stream(0);
144 
145   ASSERT_THAT(
146       stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
147       IsOk());
148   EXPECT_FALSE(stream.IsInMemory());
149   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
150   EXPECT_EQ(0u, stream.position());
151   EXPECT_FALSE(stream.IsEOF());
152 
153   auto buf = base::MakeRefCounted<IOBufferWithSize>(kTestBufferSize);
154   for (size_t i = 0; i < kTestDataSize; ++i) {
155     EXPECT_EQ(i, stream.position());
156     ASSERT_FALSE(stream.IsEOF());
157     stream.AppendData(&kTestData[i], 1, i == kTestDataSize - 1);
158     int bytes_read = stream.Read(buf.get(),
159                                  kTestBufferSize,
160                                  TestCompletionCallback().callback());
161     ASSERT_EQ(1, bytes_read);
162     EXPECT_EQ(kTestData[i], buf->data()[0]);
163   }
164 
165   EXPECT_EQ(kTestDataSize, stream.position());
166   ASSERT_TRUE(stream.IsEOF());
167 }
168 
169 // Checks that multiple reads can be merged.
TEST(ChunkedUploadDataStreamTest,MultipleAppendsBeforeInit)170 TEST(ChunkedUploadDataStreamTest, MultipleAppendsBeforeInit) {
171   ChunkedUploadDataStream stream(0);
172   stream.AppendData(kTestData, 1, false);
173   stream.AppendData(kTestData + 1, 1, false);
174   stream.AppendData(kTestData + 2, kTestDataSize - 2, true);
175 
176   ASSERT_THAT(
177       stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
178       IsOk());
179   EXPECT_FALSE(stream.IsInMemory());
180   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
181   EXPECT_EQ(0u, stream.position());
182   EXPECT_FALSE(stream.IsEOF());
183 
184   std::string data = ReadSync(&stream, kTestBufferSize);
185   EXPECT_EQ(kTestData, data);
186   EXPECT_EQ(kTestDataSize, stream.position());
187   ASSERT_TRUE(stream.IsEOF());
188 }
189 
TEST(ChunkedUploadDataStreamTest,MultipleReads)190 TEST(ChunkedUploadDataStreamTest, MultipleReads) {
191   // Use a read size different from the write size to test bounds checking.
192   const size_t kReadSize = kTestDataSize + 3;
193 
194   ChunkedUploadDataStream stream(0);
195   stream.AppendData(kTestData, kTestDataSize, false);
196   stream.AppendData(kTestData, kTestDataSize, false);
197   stream.AppendData(kTestData, kTestDataSize, false);
198   stream.AppendData(kTestData, kTestDataSize, true);
199 
200   ASSERT_THAT(
201       stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
202       IsOk());
203   EXPECT_FALSE(stream.IsInMemory());
204   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
205   EXPECT_EQ(0u, stream.position());
206   EXPECT_FALSE(stream.IsEOF());
207 
208   std::string data = ReadSync(&stream, kReadSize);
209   EXPECT_EQ("0123456789012", data);
210   EXPECT_EQ(kReadSize, stream.position());
211   EXPECT_FALSE(stream.IsEOF());
212 
213   data = ReadSync(&stream, kReadSize);
214   EXPECT_EQ("3456789012345", data);
215   EXPECT_EQ(2 * kReadSize, stream.position());
216   EXPECT_FALSE(stream.IsEOF());
217 
218   data = ReadSync(&stream, kReadSize);
219   EXPECT_EQ("6789012345678", data);
220   EXPECT_EQ(3 * kReadSize, stream.position());
221   EXPECT_FALSE(stream.IsEOF());
222 
223   data = ReadSync(&stream, kReadSize);
224   EXPECT_EQ("9", data);
225   EXPECT_EQ(4 * kTestDataSize, stream.position());
226   EXPECT_TRUE(stream.IsEOF());
227 }
228 
TEST(ChunkedUploadDataStreamTest,EmptyUpload)229 TEST(ChunkedUploadDataStreamTest, EmptyUpload) {
230   ChunkedUploadDataStream stream(0);
231 
232   ASSERT_THAT(
233       stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
234       IsOk());
235   EXPECT_FALSE(stream.IsInMemory());
236   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
237   EXPECT_EQ(0u, stream.position());
238   EXPECT_FALSE(stream.IsEOF());
239 
240   TestCompletionCallback callback;
241   auto buf = base::MakeRefCounted<IOBufferWithSize>(kTestBufferSize);
242   int result = stream.Read(buf.get(), kTestBufferSize, callback.callback());
243   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
244 
245   stream.AppendData(nullptr, 0, true);
246   int read = callback.WaitForResult();
247   EXPECT_EQ(0, read);
248   EXPECT_EQ(0u, stream.position());
249   EXPECT_TRUE(stream.IsEOF());
250 }
251 
TEST(ChunkedUploadDataStreamTest,EmptyUploadEndedBeforeInit)252 TEST(ChunkedUploadDataStreamTest, EmptyUploadEndedBeforeInit) {
253   ChunkedUploadDataStream stream(0);
254   stream.AppendData(nullptr, 0, true);
255 
256   ASSERT_THAT(
257       stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
258       IsOk());
259   EXPECT_FALSE(stream.IsInMemory());
260   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
261   EXPECT_EQ(0u, stream.position());
262   EXPECT_FALSE(stream.IsEOF());
263 
264   std::string data = ReadSync(&stream, kTestBufferSize);
265   ASSERT_EQ("", data);
266   EXPECT_EQ(0u, stream.position());
267   EXPECT_TRUE(stream.IsEOF());
268 }
269 
TEST(ChunkedUploadDataStreamTest,RewindAfterComplete)270 TEST(ChunkedUploadDataStreamTest, RewindAfterComplete) {
271   ChunkedUploadDataStream stream(0);
272   stream.AppendData(kTestData, 1, false);
273   stream.AppendData(kTestData + 1, kTestDataSize - 1, true);
274 
275   ASSERT_THAT(
276       stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
277       IsOk());
278   EXPECT_FALSE(stream.IsInMemory());
279   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
280   EXPECT_EQ(0u, stream.position());
281   EXPECT_FALSE(stream.IsEOF());
282 
283   std::string data = ReadSync(&stream, kTestBufferSize);
284   EXPECT_EQ(kTestData, data);
285   EXPECT_EQ(kTestDataSize, stream.position());
286   ASSERT_TRUE(stream.IsEOF());
287 
288   // Rewind stream and repeat.
289   ASSERT_THAT(
290       stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
291       IsOk());
292   EXPECT_FALSE(stream.IsInMemory());
293   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
294   EXPECT_EQ(0u, stream.position());
295   EXPECT_FALSE(stream.IsEOF());
296 
297   data = ReadSync(&stream, kTestBufferSize);
298   EXPECT_EQ(kTestData, data);
299   EXPECT_EQ(kTestDataSize, stream.position());
300   ASSERT_TRUE(stream.IsEOF());
301 }
302 
TEST(ChunkedUploadDataStreamTest,RewindWhileReading)303 TEST(ChunkedUploadDataStreamTest, RewindWhileReading) {
304   ChunkedUploadDataStream stream(0);
305 
306   ASSERT_THAT(
307       stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
308       IsOk());
309   EXPECT_FALSE(stream.IsInMemory());
310   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
311   EXPECT_EQ(0u, stream.position());
312   EXPECT_FALSE(stream.IsEOF());
313 
314   TestCompletionCallback callback;
315   auto buf = base::MakeRefCounted<IOBufferWithSize>(kTestBufferSize);
316   int result = stream.Read(buf.get(), kTestBufferSize, callback.callback());
317   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
318 
319   ASSERT_THAT(
320       stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
321       IsOk());
322   EXPECT_FALSE(stream.IsInMemory());
323   EXPECT_EQ(0u, stream.size());  // Content-Length is 0 for chunked data.
324   EXPECT_EQ(0u, stream.position());
325   EXPECT_FALSE(stream.IsEOF());
326 
327   // Adding data now should not result in calling the original read callback,
328   // since the stream was re-initialized for reuse, which cancels all pending
329   // reads.
330   stream.AppendData(kTestData, kTestDataSize, true);
331   EXPECT_FALSE(callback.have_result());
332 
333   std::string data = ReadSync(&stream, kTestBufferSize);
334   EXPECT_EQ(kTestData, data);
335   EXPECT_EQ(kTestDataSize, stream.position());
336   ASSERT_TRUE(stream.IsEOF());
337   EXPECT_FALSE(callback.have_result());
338 }
339 
340 // Check the behavior of ChunkedUploadDataStream::Writer.
TEST(ChunkedUploadDataStreamTest,ChunkedUploadDataStreamWriter)341 TEST(ChunkedUploadDataStreamTest, ChunkedUploadDataStreamWriter) {
342   auto stream = std::make_unique<ChunkedUploadDataStream>(0);
343   std::unique_ptr<ChunkedUploadDataStream::Writer> writer(
344       stream->CreateWriter());
345 
346   // Write before Init.
347   ASSERT_TRUE(writer->AppendData(kTestData, 1, false));
348   ASSERT_THAT(
349       stream->Init(TestCompletionCallback().callback(), NetLogWithSource()),
350       IsOk());
351 
352   // Write after Init.
353   ASSERT_TRUE(writer->AppendData(kTestData + 1, kTestDataSize - 1, false));
354 
355   TestCompletionCallback callback;
356   std::string data = ReadSync(stream.get(), kTestBufferSize);
357   EXPECT_EQ(kTestData, data);
358 
359   // Writing data should gracefully fail if the stream is deleted while still
360   // appending data to it.
361   stream.reset();
362   EXPECT_FALSE(writer->AppendData(kTestData, kTestDataSize, true));
363 }
364 
365 }  // namespace net
366