xref: /aosp_15_r20/external/cronet/net/base/file_stream_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/file_stream.h"
6 
7 #include <string>
8 #include <utility>
9 
10 #include "base/files/file.h"
11 #include "base/files/file_util.h"
12 #include "base/functional/bind.h"
13 #include "base/functional/callback.h"
14 #include "base/memory/raw_ptr.h"
15 #include "base/path_service.h"
16 #include "base/run_loop.h"
17 #include "base/strings/string_util.h"
18 #include "base/synchronization/waitable_event.h"
19 #include "base/task/current_thread.h"
20 #include "base/task/single_thread_task_runner.h"
21 #include "base/test/test_timeouts.h"
22 #include "base/threading/thread.h"
23 #include "base/threading/thread_restrictions.h"
24 #include "build/build_config.h"
25 #include "net/base/io_buffer.h"
26 #include "net/base/net_errors.h"
27 #include "net/base/test_completion_callback.h"
28 #include "net/log/test_net_log.h"
29 #include "net/test/gtest_util.h"
30 #include "net/test/test_with_task_environment.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33 #include "testing/platform_test.h"
34 
35 using net::test::IsError;
36 using net::test::IsOk;
37 
38 #if BUILDFLAG(IS_ANDROID)
39 #include "base/test/test_file_util.h"
40 #endif
41 
42 namespace net {
43 
44 namespace {
45 
46 constexpr char kTestData[] = "0123456789";
47 constexpr int kTestDataSize = std::size(kTestData) - 1;
48 
49 // Creates an IOBufferWithSize that contains the kTestDataSize.
CreateTestDataBuffer()50 scoped_refptr<IOBufferWithSize> CreateTestDataBuffer() {
51   scoped_refptr<IOBufferWithSize> buf =
52       base::MakeRefCounted<IOBufferWithSize>(kTestDataSize);
53   memcpy(buf->data(), kTestData, kTestDataSize);
54   return buf;
55 }
56 
57 }  // namespace
58 
59 class FileStreamTest : public PlatformTest, public WithTaskEnvironment {
60  public:
SetUp()61   void SetUp() override {
62     PlatformTest::SetUp();
63 
64     base::CreateTemporaryFile(&temp_file_path_);
65     base::WriteFile(temp_file_path_, kTestData);
66   }
TearDown()67   void TearDown() override {
68     // FileStreamContexts must be asynchronously closed on the file task runner
69     // before they can be deleted. Pump the RunLoop to avoid leaks.
70     base::RunLoop().RunUntilIdle();
71     EXPECT_TRUE(base::DeleteFile(temp_file_path_));
72 
73     PlatformTest::TearDown();
74   }
75 
temp_file_path() const76   const base::FilePath temp_file_path() const { return temp_file_path_; }
77 
78  private:
79   base::FilePath temp_file_path_;
80 };
81 
82 namespace {
83 
TEST_F(FileStreamTest,OpenExplicitClose)84 TEST_F(FileStreamTest, OpenExplicitClose) {
85   TestCompletionCallback callback;
86   FileStream stream(base::SingleThreadTaskRunner::GetCurrentDefault());
87   int flags = base::File::FLAG_OPEN |
88               base::File::FLAG_READ |
89               base::File::FLAG_ASYNC;
90   int rv = stream.Open(temp_file_path(), flags, callback.callback());
91   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
92   EXPECT_THAT(callback.WaitForResult(), IsOk());
93   EXPECT_TRUE(stream.IsOpen());
94   EXPECT_THAT(stream.Close(callback.callback()), IsError(ERR_IO_PENDING));
95   EXPECT_THAT(callback.WaitForResult(), IsOk());
96   EXPECT_FALSE(stream.IsOpen());
97 }
98 
TEST_F(FileStreamTest,OpenExplicitCloseOrphaned)99 TEST_F(FileStreamTest, OpenExplicitCloseOrphaned) {
100   TestCompletionCallback callback;
101   auto stream = std::make_unique<FileStream>(
102       base::SingleThreadTaskRunner::GetCurrentDefault());
103   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
104               base::File::FLAG_ASYNC;
105   int rv = stream->Open(temp_file_path(), flags, callback.callback());
106   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
107   EXPECT_THAT(callback.WaitForResult(), IsOk());
108   EXPECT_TRUE(stream->IsOpen());
109   EXPECT_THAT(stream->Close(callback.callback()), IsError(ERR_IO_PENDING));
110   stream.reset();
111   // File isn't actually closed yet.
112   base::RunLoop runloop;
113   runloop.RunUntilIdle();
114   // The file should now be closed, though the callback has not been called.
115 }
116 
117 // Test the use of FileStream with a file handle provided at construction.
TEST_F(FileStreamTest,UseFileHandle)118 TEST_F(FileStreamTest, UseFileHandle) {
119   int rv = 0;
120   TestCompletionCallback callback;
121   TestInt64CompletionCallback callback64;
122   // 1. Test reading with a file handle.
123   ASSERT_TRUE(base::WriteFile(temp_file_path(), kTestData));
124   int flags = base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ |
125               base::File::FLAG_ASYNC;
126   base::File file1(temp_file_path(), flags);
127 
128   // Seek to the beginning of the file and read.
129   auto read_stream = std::make_unique<FileStream>(
130       std::move(file1), base::SingleThreadTaskRunner::GetCurrentDefault());
131   ASSERT_THAT(read_stream->Seek(0, callback64.callback()),
132               IsError(ERR_IO_PENDING));
133   ASSERT_EQ(0, callback64.WaitForResult());
134   // Read into buffer and compare.
135   scoped_refptr<IOBufferWithSize> read_buffer =
136       base::MakeRefCounted<IOBufferWithSize>(kTestDataSize);
137   rv = read_stream->Read(read_buffer.get(), kTestDataSize, callback.callback());
138   ASSERT_EQ(kTestDataSize, callback.GetResult(rv));
139   ASSERT_EQ(0, memcmp(kTestData, read_buffer->data(), kTestDataSize));
140   read_stream.reset();
141 
142   // 2. Test writing with a file handle.
143   base::DeleteFile(temp_file_path());
144   flags = base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE |
145           base::File::FLAG_ASYNC;
146   base::File file2(temp_file_path(), flags);
147 
148   auto write_stream = std::make_unique<FileStream>(
149       std::move(file2), base::SingleThreadTaskRunner::GetCurrentDefault());
150   ASSERT_THAT(write_stream->Seek(0, callback64.callback()),
151               IsError(ERR_IO_PENDING));
152   ASSERT_EQ(0, callback64.WaitForResult());
153   scoped_refptr<IOBufferWithSize> write_buffer = CreateTestDataBuffer();
154   rv = write_stream->Write(write_buffer.get(), kTestDataSize,
155                            callback.callback());
156   ASSERT_EQ(kTestDataSize, callback.GetResult(rv));
157   write_stream.reset();
158 
159   // Read into buffer and compare to make sure the handle worked fine.
160   ASSERT_EQ(kTestDataSize,
161             base::ReadFile(temp_file_path(), read_buffer->data(),
162                            kTestDataSize));
163   ASSERT_EQ(0, memcmp(kTestData, read_buffer->data(), kTestDataSize));
164 }
165 
TEST_F(FileStreamTest,UseClosedStream)166 TEST_F(FileStreamTest, UseClosedStream) {
167   int rv = 0;
168   TestCompletionCallback callback;
169   TestInt64CompletionCallback callback64;
170 
171   FileStream stream(base::SingleThreadTaskRunner::GetCurrentDefault());
172 
173   EXPECT_FALSE(stream.IsOpen());
174 
175   // Try seeking...
176   rv = stream.Seek(5, callback64.callback());
177   EXPECT_THAT(callback64.GetResult(rv), IsError(ERR_UNEXPECTED));
178 
179   // Try reading...
180   scoped_refptr<IOBufferWithSize> buf =
181       base::MakeRefCounted<IOBufferWithSize>(10);
182   rv = stream.Read(buf.get(), buf->size(), callback.callback());
183   EXPECT_THAT(callback.GetResult(rv), IsError(ERR_UNEXPECTED));
184 }
185 
TEST_F(FileStreamTest,Read)186 TEST_F(FileStreamTest, Read) {
187   int64_t file_size;
188   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
189 
190   FileStream stream(base::SingleThreadTaskRunner::GetCurrentDefault());
191   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
192               base::File::FLAG_ASYNC;
193   TestCompletionCallback callback;
194   int rv = stream.Open(temp_file_path(), flags, callback.callback());
195   EXPECT_THAT(callback.GetResult(rv), IsOk());
196 
197   int total_bytes_read = 0;
198 
199   std::string data_read;
200   for (;;) {
201     scoped_refptr<IOBufferWithSize> buf =
202         base::MakeRefCounted<IOBufferWithSize>(4);
203     rv = stream.Read(buf.get(), buf->size(), callback.callback());
204     rv = callback.GetResult(rv);
205     EXPECT_LE(0, rv);
206     if (rv <= 0)
207       break;
208     total_bytes_read += rv;
209     data_read.append(buf->data(), rv);
210   }
211   EXPECT_EQ(file_size, total_bytes_read);
212   EXPECT_EQ(kTestData, data_read);
213 }
214 
TEST_F(FileStreamTest,Read_EarlyDelete)215 TEST_F(FileStreamTest, Read_EarlyDelete) {
216   int64_t file_size;
217   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
218 
219   auto stream = std::make_unique<FileStream>(
220       base::SingleThreadTaskRunner::GetCurrentDefault());
221   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
222               base::File::FLAG_ASYNC;
223   TestCompletionCallback callback;
224   int rv = stream->Open(temp_file_path(), flags, callback.callback());
225   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
226   EXPECT_THAT(callback.WaitForResult(), IsOk());
227 
228   scoped_refptr<IOBufferWithSize> buf =
229       base::MakeRefCounted<IOBufferWithSize>(4);
230   rv = stream->Read(buf.get(), buf->size(), callback.callback());
231   stream.reset();  // Delete instead of closing it.
232   if (rv < 0) {
233     EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
234     // The callback should not be called if the request is cancelled.
235     base::RunLoop().RunUntilIdle();
236     EXPECT_FALSE(callback.have_result());
237   } else {
238     EXPECT_EQ(std::string(kTestData, rv), std::string(buf->data(), rv));
239   }
240 }
241 
TEST_F(FileStreamTest,Read_FromOffset)242 TEST_F(FileStreamTest, Read_FromOffset) {
243   int64_t file_size;
244   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
245 
246   FileStream stream(base::SingleThreadTaskRunner::GetCurrentDefault());
247   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
248               base::File::FLAG_ASYNC;
249   TestCompletionCallback callback;
250   int rv = stream.Open(temp_file_path(), flags, callback.callback());
251   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
252   EXPECT_THAT(callback.WaitForResult(), IsOk());
253 
254   TestInt64CompletionCallback callback64;
255   const int64_t kOffset = 3;
256   rv = stream.Seek(kOffset, callback64.callback());
257   ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
258   int64_t new_offset = callback64.WaitForResult();
259   EXPECT_EQ(kOffset, new_offset);
260 
261   int total_bytes_read = 0;
262 
263   std::string data_read;
264   for (;;) {
265     scoped_refptr<IOBufferWithSize> buf =
266         base::MakeRefCounted<IOBufferWithSize>(4);
267     rv = stream.Read(buf.get(), buf->size(), callback.callback());
268     if (rv == ERR_IO_PENDING)
269       rv = callback.WaitForResult();
270     EXPECT_LE(0, rv);
271     if (rv <= 0)
272       break;
273     total_bytes_read += rv;
274     data_read.append(buf->data(), rv);
275   }
276   EXPECT_EQ(file_size - kOffset, total_bytes_read);
277   EXPECT_EQ(kTestData + kOffset, data_read);
278 }
279 
TEST_F(FileStreamTest,Write)280 TEST_F(FileStreamTest, Write) {
281   FileStream stream(base::SingleThreadTaskRunner::GetCurrentDefault());
282   int flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
283               base::File::FLAG_ASYNC;
284   TestCompletionCallback callback;
285   int rv = stream.Open(temp_file_path(), flags, callback.callback());
286   EXPECT_THAT(callback.GetResult(rv), IsOk());
287 
288   int64_t file_size;
289   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
290   EXPECT_EQ(0, file_size);
291 
292   scoped_refptr<IOBuffer> buf = CreateTestDataBuffer();
293   rv = stream.Write(buf.get(), kTestDataSize, callback.callback());
294   rv = callback.GetResult(rv);
295   EXPECT_EQ(kTestDataSize, rv);
296 
297   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
298   EXPECT_EQ(kTestDataSize, file_size);
299 
300   std::string data_read;
301   EXPECT_TRUE(base::ReadFileToString(temp_file_path(), &data_read));
302   EXPECT_EQ(kTestData, data_read);
303 }
304 
TEST_F(FileStreamTest,Write_EarlyDelete)305 TEST_F(FileStreamTest, Write_EarlyDelete) {
306   auto stream = std::make_unique<FileStream>(
307       base::SingleThreadTaskRunner::GetCurrentDefault());
308   int flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
309               base::File::FLAG_ASYNC;
310   TestCompletionCallback callback;
311   int rv = stream->Open(temp_file_path(), flags, callback.callback());
312   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
313   EXPECT_THAT(callback.WaitForResult(), IsOk());
314 
315   int64_t file_size;
316   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
317   EXPECT_EQ(0, file_size);
318 
319   scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
320   rv = stream->Write(buf.get(), buf->size(), callback.callback());
321   stream.reset();
322   if (rv < 0) {
323     EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
324     // The callback should not be called if the request is cancelled.
325     base::RunLoop().RunUntilIdle();
326     EXPECT_FALSE(callback.have_result());
327   } else {
328     EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
329     EXPECT_EQ(file_size, rv);
330   }
331 }
332 
TEST_F(FileStreamTest,Write_FromOffset)333 TEST_F(FileStreamTest, Write_FromOffset) {
334   int64_t file_size;
335   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
336 
337   FileStream stream(base::SingleThreadTaskRunner::GetCurrentDefault());
338   int flags = base::File::FLAG_OPEN | base::File::FLAG_WRITE |
339               base::File::FLAG_ASYNC;
340   TestCompletionCallback callback;
341   int rv = stream.Open(temp_file_path(), flags, callback.callback());
342   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
343   EXPECT_THAT(callback.WaitForResult(), IsOk());
344 
345   TestInt64CompletionCallback callback64;
346   const int64_t kOffset = kTestDataSize;
347   rv = stream.Seek(kOffset, callback64.callback());
348   ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
349   int64_t new_offset = callback64.WaitForResult();
350   EXPECT_EQ(kTestDataSize, new_offset);
351 
352   int total_bytes_written = 0;
353 
354   scoped_refptr<IOBufferWithSize> buffer = CreateTestDataBuffer();
355   int buffer_size = buffer->size();
356   scoped_refptr<DrainableIOBuffer> drainable =
357       base::MakeRefCounted<DrainableIOBuffer>(std::move(buffer), buffer_size);
358   while (total_bytes_written != kTestDataSize) {
359     rv = stream.Write(drainable.get(), drainable->BytesRemaining(),
360                       callback.callback());
361     if (rv == ERR_IO_PENDING)
362       rv = callback.WaitForResult();
363     EXPECT_LT(0, rv);
364     if (rv <= 0)
365       break;
366     drainable->DidConsume(rv);
367     total_bytes_written += rv;
368   }
369   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
370   EXPECT_EQ(file_size, kTestDataSize * 2);
371 }
372 
TEST_F(FileStreamTest,BasicReadWrite)373 TEST_F(FileStreamTest, BasicReadWrite) {
374   int64_t file_size;
375   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
376 
377   auto stream = std::make_unique<FileStream>(
378       base::SingleThreadTaskRunner::GetCurrentDefault());
379   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
380               base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
381   TestCompletionCallback callback;
382   int rv = stream->Open(temp_file_path(), flags, callback.callback());
383   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
384   EXPECT_THAT(callback.WaitForResult(), IsOk());
385 
386   int64_t total_bytes_read = 0;
387 
388   std::string data_read;
389   for (;;) {
390     scoped_refptr<IOBufferWithSize> buf =
391         base::MakeRefCounted<IOBufferWithSize>(4);
392     rv = stream->Read(buf.get(), buf->size(), callback.callback());
393     if (rv == ERR_IO_PENDING)
394       rv = callback.WaitForResult();
395     EXPECT_LE(0, rv);
396     if (rv <= 0)
397       break;
398     total_bytes_read += rv;
399     data_read.append(buf->data(), rv);
400   }
401   EXPECT_EQ(file_size, total_bytes_read);
402   EXPECT_TRUE(data_read == kTestData);
403 
404   int total_bytes_written = 0;
405 
406   scoped_refptr<IOBufferWithSize> buffer = CreateTestDataBuffer();
407   int buffer_size = buffer->size();
408   scoped_refptr<DrainableIOBuffer> drainable =
409       base::MakeRefCounted<DrainableIOBuffer>(std::move(buffer), buffer_size);
410   while (total_bytes_written != kTestDataSize) {
411     rv = stream->Write(drainable.get(), drainable->BytesRemaining(),
412                        callback.callback());
413     if (rv == ERR_IO_PENDING)
414       rv = callback.WaitForResult();
415     EXPECT_LT(0, rv);
416     if (rv <= 0)
417       break;
418     drainable->DidConsume(rv);
419     total_bytes_written += rv;
420   }
421 
422   stream.reset();
423 
424   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
425   EXPECT_EQ(kTestDataSize * 2, file_size);
426 }
427 
TEST_F(FileStreamTest,BasicWriteRead)428 TEST_F(FileStreamTest, BasicWriteRead) {
429   int64_t file_size;
430   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
431 
432   auto stream = std::make_unique<FileStream>(
433       base::SingleThreadTaskRunner::GetCurrentDefault());
434   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
435               base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
436   TestCompletionCallback callback;
437   int rv = stream->Open(temp_file_path(), flags, callback.callback());
438   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
439   EXPECT_THAT(callback.WaitForResult(), IsOk());
440 
441   TestInt64CompletionCallback callback64;
442   rv = stream->Seek(file_size, callback64.callback());
443   ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
444   int64_t offset = callback64.WaitForResult();
445   EXPECT_EQ(offset, file_size);
446 
447   int total_bytes_written = 0;
448 
449   scoped_refptr<IOBufferWithSize> buffer = CreateTestDataBuffer();
450   int buffer_size = buffer->size();
451   scoped_refptr<DrainableIOBuffer> drainable =
452       base::MakeRefCounted<DrainableIOBuffer>(std::move(buffer), buffer_size);
453   while (total_bytes_written != kTestDataSize) {
454     rv = stream->Write(drainable.get(), drainable->BytesRemaining(),
455                        callback.callback());
456     if (rv == ERR_IO_PENDING)
457       rv = callback.WaitForResult();
458     EXPECT_LT(0, rv);
459     if (rv <= 0)
460       break;
461     drainable->DidConsume(rv);
462     total_bytes_written += rv;
463   }
464 
465   EXPECT_EQ(kTestDataSize, total_bytes_written);
466 
467   rv = stream->Seek(0, callback64.callback());
468   ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
469   offset = callback64.WaitForResult();
470   EXPECT_EQ(0, offset);
471 
472   int total_bytes_read = 0;
473 
474   std::string data_read;
475   for (;;) {
476     scoped_refptr<IOBufferWithSize> buf =
477         base::MakeRefCounted<IOBufferWithSize>(4);
478     rv = stream->Read(buf.get(), buf->size(), callback.callback());
479     if (rv == ERR_IO_PENDING)
480       rv = callback.WaitForResult();
481     EXPECT_LE(0, rv);
482     if (rv <= 0)
483       break;
484     total_bytes_read += rv;
485     data_read.append(buf->data(), rv);
486   }
487   stream.reset();
488 
489   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
490   EXPECT_EQ(kTestDataSize * 2, file_size);
491 
492   EXPECT_EQ(kTestDataSize * 2, total_bytes_read);
493   const std::string kExpectedFileData =
494       std::string(kTestData) + std::string(kTestData);
495   EXPECT_EQ(kExpectedFileData, data_read);
496 }
497 
498 class TestWriteReadCompletionCallback {
499  public:
TestWriteReadCompletionCallback(FileStream * stream,int * total_bytes_written,int * total_bytes_read,std::string * data_read)500   TestWriteReadCompletionCallback(FileStream* stream,
501                                   int* total_bytes_written,
502                                   int* total_bytes_read,
503                                   std::string* data_read)
504       : stream_(stream),
505         total_bytes_written_(total_bytes_written),
506         total_bytes_read_(total_bytes_read),
507         data_read_(data_read),
508         drainable_(
509             base::MakeRefCounted<DrainableIOBuffer>(CreateTestDataBuffer(),
510                                                     kTestDataSize)) {}
511 
512   TestWriteReadCompletionCallback(const TestWriteReadCompletionCallback&) =
513       delete;
514   TestWriteReadCompletionCallback& operator=(
515       const TestWriteReadCompletionCallback&) = delete;
516 
WaitForResult()517   int WaitForResult() {
518     DCHECK(!waiting_for_result_);
519     while (!have_result_) {
520       base::RunLoop loop;
521       quit_closure_ = loop.QuitWhenIdleClosure();
522       waiting_for_result_ = true;
523       loop.Run();
524       waiting_for_result_ = false;
525     }
526     have_result_ = false;  // auto-reset for next callback
527     return result_;
528   }
529 
callback()530   CompletionOnceCallback callback() {
531     return base::BindOnce(&TestWriteReadCompletionCallback::OnComplete,
532                           base::Unretained(this));
533   }
534 
ValidateWrittenData()535   void ValidateWrittenData() {
536     TestCompletionCallback callback;
537     int rv = 0;
538     for (;;) {
539       scoped_refptr<IOBufferWithSize> buf =
540           base::MakeRefCounted<IOBufferWithSize>(4);
541       rv = stream_->Read(buf.get(), buf->size(), callback.callback());
542       if (rv == ERR_IO_PENDING) {
543         rv = callback.WaitForResult();
544       }
545       EXPECT_LE(0, rv);
546       if (rv <= 0)
547         break;
548       *total_bytes_read_ += rv;
549       data_read_->append(buf->data(), rv);
550     }
551   }
552 
553  private:
OnComplete(int result)554   void OnComplete(int result) {
555     DCHECK_LT(0, result);
556     *total_bytes_written_ += result;
557 
558     int rv;
559 
560     if (*total_bytes_written_ != kTestDataSize) {
561       // Recurse to finish writing all data.
562       int total_bytes_written = 0, total_bytes_read = 0;
563       std::string data_read;
564       TestWriteReadCompletionCallback callback(
565           stream_, &total_bytes_written, &total_bytes_read, &data_read);
566       rv = stream_->Write(
567           drainable_.get(), drainable_->BytesRemaining(), callback.callback());
568       DCHECK_EQ(ERR_IO_PENDING, rv);
569       rv = callback.WaitForResult();
570       drainable_->DidConsume(total_bytes_written);
571       *total_bytes_written_ += total_bytes_written;
572       *total_bytes_read_ += total_bytes_read;
573       *data_read_ += data_read;
574     } else {  // We're done writing all data.  Start reading the data.
575       TestInt64CompletionCallback callback64;
576       EXPECT_THAT(stream_->Seek(0, callback64.callback()),
577                   IsError(ERR_IO_PENDING));
578       {
579         EXPECT_LE(0, callback64.WaitForResult());
580       }
581     }
582 
583     result_ = *total_bytes_written_;
584     have_result_ = true;
585     if (waiting_for_result_)
586       std::move(quit_closure_).Run();
587   }
588 
589   int result_ = 0;
590   bool have_result_ = false;
591   bool waiting_for_result_ = false;
592   raw_ptr<FileStream> stream_;
593   raw_ptr<int> total_bytes_written_;
594   raw_ptr<int> total_bytes_read_;
595   raw_ptr<std::string> data_read_;
596   scoped_refptr<DrainableIOBuffer> drainable_;
597   base::OnceClosure quit_closure_;
598 };
599 
TEST_F(FileStreamTest,WriteRead)600 TEST_F(FileStreamTest, WriteRead) {
601   int64_t file_size;
602   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
603 
604   auto stream = std::make_unique<FileStream>(
605       base::SingleThreadTaskRunner::GetCurrentDefault());
606   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
607               base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
608   TestCompletionCallback open_callback;
609   int rv = stream->Open(temp_file_path(), flags, open_callback.callback());
610   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
611   EXPECT_THAT(open_callback.WaitForResult(), IsOk());
612 
613   TestInt64CompletionCallback callback64;
614   EXPECT_THAT(stream->Seek(file_size, callback64.callback()),
615               IsError(ERR_IO_PENDING));
616   EXPECT_EQ(file_size, callback64.WaitForResult());
617 
618   int total_bytes_written = 0;
619   int total_bytes_read = 0;
620   std::string data_read;
621   {
622     // `callback` can't outlive `stream`.
623     TestWriteReadCompletionCallback callback(stream.get(), &total_bytes_written,
624                                              &total_bytes_read, &data_read);
625 
626     scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
627     rv = stream->Write(buf.get(), buf->size(), callback.callback());
628     if (rv == ERR_IO_PENDING) {
629       rv = callback.WaitForResult();
630     }
631     EXPECT_LT(0, rv);
632     EXPECT_EQ(kTestDataSize, total_bytes_written);
633 
634     callback.ValidateWrittenData();
635   }
636   stream.reset();
637 
638   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
639   EXPECT_EQ(kTestDataSize * 2, file_size);
640 
641   EXPECT_EQ(kTestDataSize * 2, total_bytes_read);
642   const std::string kExpectedFileData =
643       std::string(kTestData) + std::string(kTestData);
644   EXPECT_EQ(kExpectedFileData, data_read);
645 }
646 
647 class TestWriteCloseCompletionCallback {
648  public:
TestWriteCloseCompletionCallback(FileStream * stream,int * total_bytes_written)649   TestWriteCloseCompletionCallback(FileStream* stream, int* total_bytes_written)
650       : stream_(stream),
651         total_bytes_written_(total_bytes_written),
652         drainable_(
653             base::MakeRefCounted<DrainableIOBuffer>(CreateTestDataBuffer(),
654                                                     kTestDataSize)) {}
655   TestWriteCloseCompletionCallback(const TestWriteCloseCompletionCallback&) =
656       delete;
657   TestWriteCloseCompletionCallback& operator=(
658       const TestWriteCloseCompletionCallback&) = delete;
659 
WaitForResult()660   int WaitForResult() {
661     DCHECK(!waiting_for_result_);
662     while (!have_result_) {
663       base::RunLoop loop;
664       quit_closure_ = loop.QuitWhenIdleClosure();
665       waiting_for_result_ = true;
666       loop.Run();
667       waiting_for_result_ = false;
668     }
669     have_result_ = false;  // auto-reset for next callback
670     return result_;
671   }
672 
callback()673   CompletionOnceCallback callback() {
674     return base::BindOnce(&TestWriteCloseCompletionCallback::OnComplete,
675                           base::Unretained(this));
676   }
677 
678  private:
OnComplete(int result)679   void OnComplete(int result) {
680     DCHECK_LT(0, result);
681     *total_bytes_written_ += result;
682 
683     int rv;
684 
685     if (*total_bytes_written_ != kTestDataSize) {
686       // Recurse to finish writing all data.
687       int total_bytes_written = 0;
688       TestWriteCloseCompletionCallback callback(stream_, &total_bytes_written);
689       rv = stream_->Write(
690           drainable_.get(), drainable_->BytesRemaining(), callback.callback());
691       DCHECK_EQ(ERR_IO_PENDING, rv);
692       rv = callback.WaitForResult();
693       drainable_->DidConsume(total_bytes_written);
694       *total_bytes_written_ += total_bytes_written;
695     }
696 
697     result_ = *total_bytes_written_;
698     have_result_ = true;
699     if (waiting_for_result_)
700       std::move(quit_closure_).Run();
701   }
702 
703   int result_ = 0;
704   bool have_result_ = false;
705   bool waiting_for_result_ = false;
706   raw_ptr<FileStream> stream_;
707   raw_ptr<int> total_bytes_written_;
708   scoped_refptr<DrainableIOBuffer> drainable_;
709   base::OnceClosure quit_closure_;
710 };
711 
TEST_F(FileStreamTest,WriteClose)712 TEST_F(FileStreamTest, WriteClose) {
713   int64_t file_size;
714   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
715 
716   auto stream = std::make_unique<FileStream>(
717       base::SingleThreadTaskRunner::GetCurrentDefault());
718   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
719               base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
720   TestCompletionCallback open_callback;
721   int rv = stream->Open(temp_file_path(), flags, open_callback.callback());
722   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
723   EXPECT_THAT(open_callback.WaitForResult(), IsOk());
724 
725   TestInt64CompletionCallback callback64;
726   EXPECT_THAT(stream->Seek(file_size, callback64.callback()),
727               IsError(ERR_IO_PENDING));
728   EXPECT_EQ(file_size, callback64.WaitForResult());
729 
730   int total_bytes_written = 0;
731   {
732     // `callback` can't outlive `stream`.
733     TestWriteCloseCompletionCallback callback(stream.get(),
734                                               &total_bytes_written);
735     scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
736     rv = stream->Write(buf.get(), buf->size(), callback.callback());
737     if (rv == ERR_IO_PENDING) {
738       total_bytes_written = callback.WaitForResult();
739     }
740     EXPECT_LT(0, total_bytes_written);
741     EXPECT_EQ(kTestDataSize, total_bytes_written);
742   }
743   stream.reset();
744 
745   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
746   EXPECT_EQ(kTestDataSize * 2, file_size);
747 }
748 
TEST_F(FileStreamTest,OpenAndDelete)749 TEST_F(FileStreamTest, OpenAndDelete) {
750   base::Thread worker_thread("StreamTest");
751   ASSERT_TRUE(worker_thread.Start());
752 
753   base::ScopedDisallowBlocking disallow_blocking;
754   auto stream = std::make_unique<FileStream>(worker_thread.task_runner());
755   int flags = base::File::FLAG_OPEN | base::File::FLAG_WRITE |
756               base::File::FLAG_ASYNC;
757   TestCompletionCallback open_callback;
758   int rv = stream->Open(temp_file_path(), flags, open_callback.callback());
759   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
760 
761   // Delete the stream without waiting for the open operation to be
762   // complete. Should be safe.
763   stream.reset();
764 
765   // Force an operation through the worker.
766   auto stream2 = std::make_unique<FileStream>(worker_thread.task_runner());
767   TestCompletionCallback open_callback2;
768   rv = stream2->Open(temp_file_path(), flags, open_callback2.callback());
769   EXPECT_THAT(open_callback2.GetResult(rv), IsOk());
770   stream2.reset();
771 
772   // open_callback won't be called.
773   base::RunLoop().RunUntilIdle();
774   EXPECT_FALSE(open_callback.have_result());
775 }
776 
777 // Verify that Write() errors are mapped correctly.
TEST_F(FileStreamTest,WriteError)778 TEST_F(FileStreamTest, WriteError) {
779   // Try opening file as read-only and then writing to it using FileStream.
780   uint32_t flags =
781       base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_ASYNC;
782 
783   base::File file(temp_file_path(), flags);
784   ASSERT_TRUE(file.IsValid());
785 
786   auto stream = std::make_unique<FileStream>(
787       std::move(file), base::SingleThreadTaskRunner::GetCurrentDefault());
788 
789   scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBufferWithSize>(1);
790   buf->data()[0] = 0;
791 
792   TestCompletionCallback callback;
793   int rv = stream->Write(buf.get(), 1, callback.callback());
794   if (rv == ERR_IO_PENDING)
795     rv = callback.WaitForResult();
796   EXPECT_LT(rv, 0);
797 
798   stream.reset();
799   base::RunLoop().RunUntilIdle();
800 }
801 
802 // Verify that Read() errors are mapped correctly.
TEST_F(FileStreamTest,ReadError)803 TEST_F(FileStreamTest, ReadError) {
804   // Try opening file for write and then reading from it using FileStream.
805   uint32_t flags =
806       base::File::FLAG_OPEN | base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
807 
808   base::File file(temp_file_path(), flags);
809   ASSERT_TRUE(file.IsValid());
810 
811   auto stream = std::make_unique<FileStream>(
812       std::move(file), base::SingleThreadTaskRunner::GetCurrentDefault());
813 
814   scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBufferWithSize>(1);
815   TestCompletionCallback callback;
816   int rv = stream->Read(buf.get(), 1, callback.callback());
817   if (rv == ERR_IO_PENDING)
818     rv = callback.WaitForResult();
819   EXPECT_LT(rv, 0);
820 
821   stream.reset();
822   base::RunLoop().RunUntilIdle();
823 }
824 
825 #if BUILDFLAG(IS_WIN)
826 // Verifies that a FileStream will close itself if it receives a File whose
827 // async flag doesn't match the async state of the underlying handle.
TEST_F(FileStreamTest,AsyncFlagMismatch)828 TEST_F(FileStreamTest, AsyncFlagMismatch) {
829   // Open the test file without async, then make a File with the same sync
830   // handle but with the async flag set to true.
831   uint32_t flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
832   base::File file(temp_file_path(), flags);
833   base::File lying_file(file.TakePlatformFile(), true);
834   ASSERT_TRUE(lying_file.IsValid());
835 
836   FileStream stream(std::move(lying_file),
837                     base::SingleThreadTaskRunner::GetCurrentDefault());
838   ASSERT_FALSE(stream.IsOpen());
839   TestCompletionCallback callback;
840   scoped_refptr<IOBufferWithSize> buf =
841       base::MakeRefCounted<IOBufferWithSize>(4);
842   int rv = stream.Read(buf.get(), buf->size(), callback.callback());
843   EXPECT_THAT(callback.GetResult(rv), IsError(ERR_UNEXPECTED));
844 }
845 #endif
846 
847 #if BUILDFLAG(IS_ANDROID)
848 // TODO(https://crbug.com/894599): flaky on both android and cronet bots.
TEST_F(FileStreamTest,DISABLED_ContentUriRead)849 TEST_F(FileStreamTest, DISABLED_ContentUriRead) {
850   base::FilePath test_dir;
851   base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &test_dir);
852   test_dir = test_dir.AppendASCII("net");
853   test_dir = test_dir.AppendASCII("data");
854   test_dir = test_dir.AppendASCII("file_stream_unittest");
855   ASSERT_TRUE(base::PathExists(test_dir));
856   base::FilePath image_file = test_dir.Append(FILE_PATH_LITERAL("red.png"));
857 
858   // Insert the image into MediaStore. MediaStore will do some conversions, and
859   // return the content URI.
860   base::FilePath path = base::InsertImageIntoMediaStore(image_file);
861   EXPECT_TRUE(path.IsContentUri());
862   EXPECT_TRUE(base::PathExists(path));
863   int64_t file_size;
864   EXPECT_TRUE(base::GetFileSize(path, &file_size));
865   EXPECT_LT(0, file_size);
866 
867   FileStream stream(base::SingleThreadTaskRunner::GetCurrentDefault());
868   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
869               base::File::FLAG_ASYNC;
870   TestCompletionCallback callback;
871   int rv = stream.Open(path, flags, callback.callback());
872   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
873   EXPECT_THAT(callback.WaitForResult(), IsOk());
874 
875   int total_bytes_read = 0;
876 
877   std::string data_read;
878   for (;;) {
879     scoped_refptr<IOBufferWithSize> buf =
880         base::MakeRefCounted<IOBufferWithSize>(4);
881     rv = stream.Read(buf.get(), buf->size(), callback.callback());
882     if (rv == ERR_IO_PENDING)
883       rv = callback.WaitForResult();
884     EXPECT_LE(0, rv);
885     if (rv <= 0)
886       break;
887     total_bytes_read += rv;
888     data_read.append(buf->data(), rv);
889   }
890   EXPECT_EQ(file_size, total_bytes_read);
891 }
892 #endif
893 
894 }  // namespace
895 
896 }  // namespace net
897