xref: /aosp_15_r20/external/cronet/net/base/upload_file_element_reader_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 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/upload_file_element_reader.h"
6 
7 #include <stdint.h>
8 
9 #include <limits>
10 
11 #include "base/files/file_util.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/run_loop.h"
14 #include "base/task/single_thread_task_runner.h"
15 #include "build/build_config.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/test_completion_callback.h"
19 #include "net/test/gtest_util.h"
20 #include "net/test/test_with_task_environment.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 
24 #if BUILDFLAG(IS_APPLE)
25 #include "base/apple/scoped_nsautorelease_pool.h"
26 #include "base/memory/stack_allocated.h"
27 #endif
28 
29 using net::test::IsError;
30 using net::test::IsOk;
31 
32 namespace net {
33 
34 // When the parameter is false, the UploadFileElementReader is passed only a
35 // FilePath and needs to open the file itself. When it's true, it's passed an
36 // already open base::File.
37 class UploadFileElementReaderTest : public testing::TestWithParam<bool>,
38                                     public WithTaskEnvironment {
39  protected:
SetUp()40   void SetUp() override {
41     // Some tests (*.ReadPartially) rely on bytes_.size() being even.
42     bytes_.assign({'1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c',
43                    'd', 'e', 'f', 'g', 'h', 'i'});
44 
45     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
46 
47     ASSERT_TRUE(
48         base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_file_path_));
49     ASSERT_TRUE(base::WriteFile(
50         temp_file_path_, std::string_view(bytes_.data(), bytes_.size())));
51 
52     reader_ =
53         CreateReader(0, std::numeric_limits<uint64_t>::max(), base::Time());
54 
55     TestCompletionCallback callback;
56     ASSERT_THAT(reader_->Init(callback.callback()), IsError(ERR_IO_PENDING));
57     EXPECT_THAT(callback.WaitForResult(), IsOk());
58     EXPECT_EQ(bytes_.size(), reader_->GetContentLength());
59     EXPECT_EQ(bytes_.size(), reader_->BytesRemaining());
60     EXPECT_FALSE(reader_->IsInMemory());
61   }
62 
~UploadFileElementReaderTest()63   ~UploadFileElementReaderTest() override {
64     reader_.reset();
65     base::RunLoop().RunUntilIdle();
66   }
67 
68   // Creates a UploadFileElementReader based on the value of GetParam().
CreateReader(int64_t offset,int64_t length,base::Time expected_modification_time)69   std::unique_ptr<UploadFileElementReader> CreateReader(
70       int64_t offset,
71       int64_t length,
72       base::Time expected_modification_time) {
73     if (GetParam()) {
74       return std::make_unique<UploadFileElementReader>(
75           base::SingleThreadTaskRunner::GetCurrentDefault().get(),
76           temp_file_path_, offset, length, expected_modification_time);
77     }
78 
79     // The base::File::FLAG_WIN_SHARE_DELETE lets the file be deleted without
80     // the test fixture waiting on it to be closed.
81     int open_flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
82                      base::File::FLAG_WIN_SHARE_DELETE;
83 #if BUILDFLAG(IS_WIN)
84     // On Windows, file must be opened for asynchronous operation.
85     open_flags |= base::File::FLAG_ASYNC;
86 #endif  // BUILDFLAG(IS_WIN)
87 
88     base::File file(temp_file_path_, open_flags);
89     EXPECT_TRUE(file.IsValid());
90     return std::make_unique<UploadFileElementReader>(
91         base::SingleThreadTaskRunner::GetCurrentDefault().get(),
92         std::move(file),
93         // Use an incorrect path, to make sure that the file is never re-opened.
94         base::FilePath(FILE_PATH_LITERAL("this_should_be_ignored")), offset,
95         length, expected_modification_time);
96   }
97 
98 #if BUILDFLAG(IS_APPLE)
99   // May be needed to avoid leaks on the Mac.
100   STACK_ALLOCATED_IGNORE("https://crbug.com/1424190")
101   base::apple::ScopedNSAutoreleasePool scoped_pool_;
102 #endif
103 
104   std::vector<char> bytes_;
105   std::unique_ptr<UploadElementReader> reader_;
106   base::ScopedTempDir temp_dir_;
107   base::FilePath temp_file_path_;
108 };
109 
TEST_P(UploadFileElementReaderTest,ReadPartially)110 TEST_P(UploadFileElementReaderTest, ReadPartially) {
111   const size_t kHalfSize = bytes_.size() / 2;
112   ASSERT_EQ(bytes_.size(), kHalfSize * 2);
113   std::vector<char> buf(kHalfSize);
114   auto wrapped_buffer = base::MakeRefCounted<WrappedIOBuffer>(buf);
115   TestCompletionCallback read_callback1;
116   ASSERT_EQ(ERR_IO_PENDING,
117             reader_->Read(
118                 wrapped_buffer.get(), buf.size(), read_callback1.callback()));
119   EXPECT_EQ(static_cast<int>(buf.size()), read_callback1.WaitForResult());
120   EXPECT_EQ(bytes_.size() - buf.size(), reader_->BytesRemaining());
121   EXPECT_EQ(std::vector<char>(bytes_.begin(), bytes_.begin() + kHalfSize), buf);
122 
123   TestCompletionCallback read_callback2;
124   EXPECT_EQ(ERR_IO_PENDING,
125             reader_->Read(
126                 wrapped_buffer.get(), buf.size(), read_callback2.callback()));
127   EXPECT_EQ(static_cast<int>(buf.size()), read_callback2.WaitForResult());
128   EXPECT_EQ(0U, reader_->BytesRemaining());
129   EXPECT_EQ(std::vector<char>(bytes_.begin() + kHalfSize, bytes_.end()), buf);
130 }
131 
TEST_P(UploadFileElementReaderTest,ReadAll)132 TEST_P(UploadFileElementReaderTest, ReadAll) {
133   std::vector<char> buf(bytes_.size());
134   auto wrapped_buffer = base::MakeRefCounted<WrappedIOBuffer>(buf);
135   TestCompletionCallback read_callback;
136   ASSERT_EQ(ERR_IO_PENDING,
137             reader_->Read(
138                 wrapped_buffer.get(), buf.size(), read_callback.callback()));
139   EXPECT_EQ(static_cast<int>(buf.size()), read_callback.WaitForResult());
140   EXPECT_EQ(0U, reader_->BytesRemaining());
141   EXPECT_EQ(bytes_, buf);
142   // Try to read again.
143   EXPECT_EQ(0,
144             reader_->Read(
145                 wrapped_buffer.get(), buf.size(), read_callback.callback()));
146 }
147 
TEST_P(UploadFileElementReaderTest,ReadTooMuch)148 TEST_P(UploadFileElementReaderTest, ReadTooMuch) {
149   const size_t kTooLargeSize = bytes_.size() * 2;
150   std::vector<char> buf(kTooLargeSize);
151   auto wrapped_buffer = base::MakeRefCounted<WrappedIOBuffer>(buf);
152   TestCompletionCallback read_callback;
153   ASSERT_EQ(ERR_IO_PENDING,
154             reader_->Read(
155                 wrapped_buffer.get(), buf.size(), read_callback.callback()));
156   EXPECT_EQ(static_cast<int>(bytes_.size()), read_callback.WaitForResult());
157   EXPECT_EQ(0U, reader_->BytesRemaining());
158   buf.resize(bytes_.size());  // Resize to compare.
159   EXPECT_EQ(bytes_, buf);
160 }
161 
TEST_P(UploadFileElementReaderTest,MultipleInit)162 TEST_P(UploadFileElementReaderTest, MultipleInit) {
163   std::vector<char> buf(bytes_.size());
164   auto wrapped_buffer = base::MakeRefCounted<WrappedIOBuffer>(buf);
165 
166   // Read all.
167   TestCompletionCallback read_callback1;
168   ASSERT_EQ(ERR_IO_PENDING,
169             reader_->Read(
170                 wrapped_buffer.get(), buf.size(), read_callback1.callback()));
171   EXPECT_EQ(static_cast<int>(buf.size()), read_callback1.WaitForResult());
172   EXPECT_EQ(0U, reader_->BytesRemaining());
173   EXPECT_EQ(bytes_, buf);
174 
175   // Call Init() again to reset the state.
176   TestCompletionCallback init_callback;
177   ASSERT_THAT(reader_->Init(init_callback.callback()), IsError(ERR_IO_PENDING));
178   EXPECT_THAT(init_callback.WaitForResult(), IsOk());
179   EXPECT_EQ(bytes_.size(), reader_->GetContentLength());
180   EXPECT_EQ(bytes_.size(), reader_->BytesRemaining());
181 
182   // Read again.
183   TestCompletionCallback read_callback2;
184   ASSERT_EQ(ERR_IO_PENDING,
185             reader_->Read(
186                 wrapped_buffer.get(), buf.size(), read_callback2.callback()));
187   EXPECT_EQ(static_cast<int>(buf.size()), read_callback2.WaitForResult());
188   EXPECT_EQ(0U, reader_->BytesRemaining());
189   EXPECT_EQ(bytes_, buf);
190 }
191 
TEST_P(UploadFileElementReaderTest,InitDuringAsyncOperation)192 TEST_P(UploadFileElementReaderTest, InitDuringAsyncOperation) {
193   std::vector<char> buf(bytes_.size());
194   auto wrapped_buffer = base::MakeRefCounted<WrappedIOBuffer>(buf);
195 
196   // Start reading all.
197   TestCompletionCallback read_callback1;
198   EXPECT_EQ(ERR_IO_PENDING,
199             reader_->Read(
200                 wrapped_buffer.get(), buf.size(), read_callback1.callback()));
201 
202   // Call Init to cancel the previous read.
203   TestCompletionCallback init_callback1;
204   EXPECT_THAT(reader_->Init(init_callback1.callback()),
205               IsError(ERR_IO_PENDING));
206 
207   // Call Init again to cancel the previous init.
208   TestCompletionCallback init_callback2;
209   EXPECT_THAT(reader_->Init(init_callback2.callback()),
210               IsError(ERR_IO_PENDING));
211   EXPECT_THAT(init_callback2.WaitForResult(), IsOk());
212   EXPECT_EQ(bytes_.size(), reader_->GetContentLength());
213   EXPECT_EQ(bytes_.size(), reader_->BytesRemaining());
214 
215   // Read half.
216   std::vector<char> buf2(bytes_.size() / 2);
217   auto wrapped_buffer2 = base::MakeRefCounted<WrappedIOBuffer>(buf2);
218   TestCompletionCallback read_callback2;
219   EXPECT_EQ(ERR_IO_PENDING,
220             reader_->Read(
221                 wrapped_buffer2.get(), buf2.size(), read_callback2.callback()));
222   EXPECT_EQ(static_cast<int>(buf2.size()), read_callback2.WaitForResult());
223   EXPECT_EQ(bytes_.size() - buf2.size(), reader_->BytesRemaining());
224   EXPECT_EQ(std::vector<char>(bytes_.begin(), bytes_.begin() + buf2.size()),
225             buf2);
226 
227   // Make sure callbacks are not called for cancelled operations.
228   EXPECT_FALSE(read_callback1.have_result());
229   EXPECT_FALSE(init_callback1.have_result());
230 }
231 
TEST_P(UploadFileElementReaderTest,RepeatedInitDuringInit)232 TEST_P(UploadFileElementReaderTest, RepeatedInitDuringInit) {
233   std::vector<char> buf(bytes_.size());
234   auto wrapped_buffer = base::MakeRefCounted<WrappedIOBuffer>(buf);
235 
236   TestCompletionCallback init_callback1;
237   EXPECT_THAT(reader_->Init(init_callback1.callback()),
238               IsError(ERR_IO_PENDING));
239 
240   // Call Init again to cancel the previous init.
241   TestCompletionCallback init_callback2;
242   EXPECT_THAT(reader_->Init(init_callback2.callback()),
243               IsError(ERR_IO_PENDING));
244 
245   // Call Init yet again to cancel the previous init.
246   TestCompletionCallback init_callback3;
247   EXPECT_THAT(reader_->Init(init_callback3.callback()),
248               IsError(ERR_IO_PENDING));
249 
250   EXPECT_THAT(init_callback3.WaitForResult(), IsOk());
251   EXPECT_EQ(bytes_.size(), reader_->GetContentLength());
252   EXPECT_EQ(bytes_.size(), reader_->BytesRemaining());
253 
254   // Read all.
255   TestCompletionCallback read_callback;
256   int result =
257       reader_->Read(wrapped_buffer.get(), buf.size(), read_callback.callback());
258   EXPECT_EQ(static_cast<int>(buf.size()), read_callback.GetResult(result));
259   EXPECT_EQ(0U, reader_->BytesRemaining());
260   EXPECT_EQ(bytes_, buf);
261 
262   EXPECT_FALSE(init_callback1.have_result());
263   EXPECT_FALSE(init_callback2.have_result());
264 }
265 
TEST_P(UploadFileElementReaderTest,Range)266 TEST_P(UploadFileElementReaderTest, Range) {
267   const uint64_t kOffset = 2;
268   const uint64_t kLength = bytes_.size() - kOffset * 3;
269   reader_ = CreateReader(kOffset, kLength, base::Time());
270   TestCompletionCallback init_callback;
271   ASSERT_THAT(reader_->Init(init_callback.callback()), IsError(ERR_IO_PENDING));
272   EXPECT_THAT(init_callback.WaitForResult(), IsOk());
273   EXPECT_EQ(kLength, reader_->GetContentLength());
274   EXPECT_EQ(kLength, reader_->BytesRemaining());
275   std::vector<char> buf(kLength);
276   auto wrapped_buffer = base::MakeRefCounted<WrappedIOBuffer>(buf);
277   TestCompletionCallback read_callback;
278   ASSERT_EQ(
279       ERR_IO_PENDING,
280       reader_->Read(wrapped_buffer.get(), kLength, read_callback.callback()));
281   EXPECT_EQ(static_cast<int>(kLength), read_callback.WaitForResult());
282   const std::vector<char> expected(bytes_.begin() + kOffset,
283                                    bytes_.begin() + kOffset + kLength);
284   EXPECT_EQ(expected, buf);
285 }
286 
TEST_P(UploadFileElementReaderTest,FileChanged)287 TEST_P(UploadFileElementReaderTest, FileChanged) {
288   base::File::Info info;
289   ASSERT_TRUE(base::GetFileInfo(temp_file_path_, &info));
290 
291   // Expect one second before the actual modification time to simulate change.
292   const base::Time expected_modification_time =
293       info.last_modified - base::Seconds(1);
294   reader_ = CreateReader(0, std::numeric_limits<uint64_t>::max(),
295                          expected_modification_time);
296   TestCompletionCallback init_callback;
297   ASSERT_THAT(reader_->Init(init_callback.callback()), IsError(ERR_IO_PENDING));
298   EXPECT_THAT(init_callback.WaitForResult(), IsError(ERR_UPLOAD_FILE_CHANGED));
299 }
300 
TEST_P(UploadFileElementReaderTest,InexactExpectedTimeStamp)301 TEST_P(UploadFileElementReaderTest, InexactExpectedTimeStamp) {
302   base::File::Info info;
303   ASSERT_TRUE(base::GetFileInfo(temp_file_path_, &info));
304 
305   const base::Time expected_modification_time =
306       info.last_modified - base::Milliseconds(900);
307   reader_ = CreateReader(0, std::numeric_limits<uint64_t>::max(),
308                          expected_modification_time);
309   TestCompletionCallback init_callback;
310   ASSERT_THAT(reader_->Init(init_callback.callback()), IsError(ERR_IO_PENDING));
311   EXPECT_THAT(init_callback.WaitForResult(), IsOk());
312 }
313 
TEST_P(UploadFileElementReaderTest,WrongPath)314 TEST_P(UploadFileElementReaderTest, WrongPath) {
315   const base::FilePath wrong_path(FILE_PATH_LITERAL("wrong_path"));
316   reader_ = std::make_unique<UploadFileElementReader>(
317       base::SingleThreadTaskRunner::GetCurrentDefault().get(), wrong_path, 0,
318       std::numeric_limits<uint64_t>::max(), base::Time());
319   TestCompletionCallback init_callback;
320   ASSERT_THAT(reader_->Init(init_callback.callback()), IsError(ERR_IO_PENDING));
321   EXPECT_THAT(init_callback.WaitForResult(), IsError(ERR_FILE_NOT_FOUND));
322 }
323 
324 INSTANTIATE_TEST_SUITE_P(All,
325                          UploadFileElementReaderTest,
326                          testing::ValuesIn({false, true}));
327 
328 }  // namespace net
329