• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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       waiting_for_result_ = true;
521       base::RunLoop().Run();
522       waiting_for_result_ = false;
523     }
524     have_result_ = false;  // auto-reset for next callback
525     return result_;
526   }
527 
callback()528   CompletionOnceCallback callback() {
529     return base::BindOnce(&TestWriteReadCompletionCallback::OnComplete,
530                           base::Unretained(this));
531   }
532 
ValidateWrittenData()533   void ValidateWrittenData() {
534     TestCompletionCallback callback;
535     int rv = 0;
536     for (;;) {
537       scoped_refptr<IOBufferWithSize> buf =
538           base::MakeRefCounted<IOBufferWithSize>(4);
539       rv = stream_->Read(buf.get(), buf->size(), callback.callback());
540       if (rv == ERR_IO_PENDING) {
541         rv = callback.WaitForResult();
542       }
543       EXPECT_LE(0, rv);
544       if (rv <= 0)
545         break;
546       *total_bytes_read_ += rv;
547       data_read_->append(buf->data(), rv);
548     }
549   }
550 
551  private:
OnComplete(int result)552   void OnComplete(int result) {
553     DCHECK_LT(0, result);
554     *total_bytes_written_ += result;
555 
556     int rv;
557 
558     if (*total_bytes_written_ != kTestDataSize) {
559       // Recurse to finish writing all data.
560       int total_bytes_written = 0, total_bytes_read = 0;
561       std::string data_read;
562       TestWriteReadCompletionCallback callback(
563           stream_, &total_bytes_written, &total_bytes_read, &data_read);
564       rv = stream_->Write(
565           drainable_.get(), drainable_->BytesRemaining(), callback.callback());
566       DCHECK_EQ(ERR_IO_PENDING, rv);
567       rv = callback.WaitForResult();
568       drainable_->DidConsume(total_bytes_written);
569       *total_bytes_written_ += total_bytes_written;
570       *total_bytes_read_ += total_bytes_read;
571       *data_read_ += data_read;
572     } else {  // We're done writing all data.  Start reading the data.
573       TestInt64CompletionCallback callback64;
574       EXPECT_THAT(stream_->Seek(0, callback64.callback()),
575                   IsError(ERR_IO_PENDING));
576       {
577         EXPECT_LE(0, callback64.WaitForResult());
578       }
579     }
580 
581     result_ = *total_bytes_written_;
582     have_result_ = true;
583     if (waiting_for_result_)
584       base::RunLoop::QuitCurrentWhenIdleDeprecated();
585   }
586 
587   int result_ = 0;
588   bool have_result_ = false;
589   bool waiting_for_result_ = false;
590   raw_ptr<FileStream> stream_;
591   raw_ptr<int> total_bytes_written_;
592   raw_ptr<int> total_bytes_read_;
593   raw_ptr<std::string> data_read_;
594   scoped_refptr<DrainableIOBuffer> drainable_;
595 };
596 
TEST_F(FileStreamTest,WriteRead)597 TEST_F(FileStreamTest, WriteRead) {
598   int64_t file_size;
599   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
600 
601   auto stream = std::make_unique<FileStream>(
602       base::SingleThreadTaskRunner::GetCurrentDefault());
603   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
604               base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
605   TestCompletionCallback open_callback;
606   int rv = stream->Open(temp_file_path(), flags, open_callback.callback());
607   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
608   EXPECT_THAT(open_callback.WaitForResult(), IsOk());
609 
610   TestInt64CompletionCallback callback64;
611   EXPECT_THAT(stream->Seek(file_size, callback64.callback()),
612               IsError(ERR_IO_PENDING));
613   EXPECT_EQ(file_size, callback64.WaitForResult());
614 
615   int total_bytes_written = 0;
616   int total_bytes_read = 0;
617   std::string data_read;
618   {
619     // `callback` can't outlive `stream`.
620     TestWriteReadCompletionCallback callback(stream.get(), &total_bytes_written,
621                                              &total_bytes_read, &data_read);
622 
623     scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
624     rv = stream->Write(buf.get(), buf->size(), callback.callback());
625     if (rv == ERR_IO_PENDING) {
626       rv = callback.WaitForResult();
627     }
628     EXPECT_LT(0, rv);
629     EXPECT_EQ(kTestDataSize, total_bytes_written);
630 
631     callback.ValidateWrittenData();
632   }
633   stream.reset();
634 
635   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
636   EXPECT_EQ(kTestDataSize * 2, file_size);
637 
638   EXPECT_EQ(kTestDataSize * 2, total_bytes_read);
639   const std::string kExpectedFileData =
640       std::string(kTestData) + std::string(kTestData);
641   EXPECT_EQ(kExpectedFileData, data_read);
642 }
643 
644 class TestWriteCloseCompletionCallback {
645  public:
TestWriteCloseCompletionCallback(FileStream * stream,int * total_bytes_written)646   TestWriteCloseCompletionCallback(FileStream* stream, int* total_bytes_written)
647       : stream_(stream),
648         total_bytes_written_(total_bytes_written),
649         drainable_(
650             base::MakeRefCounted<DrainableIOBuffer>(CreateTestDataBuffer(),
651                                                     kTestDataSize)) {}
652   TestWriteCloseCompletionCallback(const TestWriteCloseCompletionCallback&) =
653       delete;
654   TestWriteCloseCompletionCallback& operator=(
655       const TestWriteCloseCompletionCallback&) = delete;
656 
WaitForResult()657   int WaitForResult() {
658     DCHECK(!waiting_for_result_);
659     while (!have_result_) {
660       waiting_for_result_ = true;
661       base::RunLoop().Run();
662       waiting_for_result_ = false;
663     }
664     have_result_ = false;  // auto-reset for next callback
665     return result_;
666   }
667 
callback()668   CompletionOnceCallback callback() {
669     return base::BindOnce(&TestWriteCloseCompletionCallback::OnComplete,
670                           base::Unretained(this));
671   }
672 
673  private:
OnComplete(int result)674   void OnComplete(int result) {
675     DCHECK_LT(0, result);
676     *total_bytes_written_ += result;
677 
678     int rv;
679 
680     if (*total_bytes_written_ != kTestDataSize) {
681       // Recurse to finish writing all data.
682       int total_bytes_written = 0;
683       TestWriteCloseCompletionCallback callback(stream_, &total_bytes_written);
684       rv = stream_->Write(
685           drainable_.get(), drainable_->BytesRemaining(), callback.callback());
686       DCHECK_EQ(ERR_IO_PENDING, rv);
687       rv = callback.WaitForResult();
688       drainable_->DidConsume(total_bytes_written);
689       *total_bytes_written_ += total_bytes_written;
690     }
691 
692     result_ = *total_bytes_written_;
693     have_result_ = true;
694     if (waiting_for_result_)
695       base::RunLoop::QuitCurrentWhenIdleDeprecated();
696   }
697 
698   int result_ = 0;
699   bool have_result_ = false;
700   bool waiting_for_result_ = false;
701   raw_ptr<FileStream> stream_;
702   raw_ptr<int> total_bytes_written_;
703   scoped_refptr<DrainableIOBuffer> drainable_;
704 };
705 
TEST_F(FileStreamTest,WriteClose)706 TEST_F(FileStreamTest, WriteClose) {
707   int64_t file_size;
708   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
709 
710   auto stream = std::make_unique<FileStream>(
711       base::SingleThreadTaskRunner::GetCurrentDefault());
712   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
713               base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
714   TestCompletionCallback open_callback;
715   int rv = stream->Open(temp_file_path(), flags, open_callback.callback());
716   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
717   EXPECT_THAT(open_callback.WaitForResult(), IsOk());
718 
719   TestInt64CompletionCallback callback64;
720   EXPECT_THAT(stream->Seek(file_size, callback64.callback()),
721               IsError(ERR_IO_PENDING));
722   EXPECT_EQ(file_size, callback64.WaitForResult());
723 
724   int total_bytes_written = 0;
725   {
726     // `callback` can't outlive `stream`.
727     TestWriteCloseCompletionCallback callback(stream.get(),
728                                               &total_bytes_written);
729     scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
730     rv = stream->Write(buf.get(), buf->size(), callback.callback());
731     if (rv == ERR_IO_PENDING) {
732       total_bytes_written = callback.WaitForResult();
733     }
734     EXPECT_LT(0, total_bytes_written);
735     EXPECT_EQ(kTestDataSize, total_bytes_written);
736   }
737   stream.reset();
738 
739   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
740   EXPECT_EQ(kTestDataSize * 2, file_size);
741 }
742 
TEST_F(FileStreamTest,OpenAndDelete)743 TEST_F(FileStreamTest, OpenAndDelete) {
744   base::Thread worker_thread("StreamTest");
745   ASSERT_TRUE(worker_thread.Start());
746 
747   base::ScopedDisallowBlocking disallow_blocking;
748   auto stream = std::make_unique<FileStream>(worker_thread.task_runner());
749   int flags = base::File::FLAG_OPEN | base::File::FLAG_WRITE |
750               base::File::FLAG_ASYNC;
751   TestCompletionCallback open_callback;
752   int rv = stream->Open(temp_file_path(), flags, open_callback.callback());
753   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
754 
755   // Delete the stream without waiting for the open operation to be
756   // complete. Should be safe.
757   stream.reset();
758 
759   // Force an operation through the worker.
760   auto stream2 = std::make_unique<FileStream>(worker_thread.task_runner());
761   TestCompletionCallback open_callback2;
762   rv = stream2->Open(temp_file_path(), flags, open_callback2.callback());
763   EXPECT_THAT(open_callback2.GetResult(rv), IsOk());
764   stream2.reset();
765 
766   // open_callback won't be called.
767   base::RunLoop().RunUntilIdle();
768   EXPECT_FALSE(open_callback.have_result());
769 }
770 
771 // Verify that Write() errors are mapped correctly.
TEST_F(FileStreamTest,WriteError)772 TEST_F(FileStreamTest, WriteError) {
773   // Try opening file as read-only and then writing to it using FileStream.
774   uint32_t flags =
775       base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_ASYNC;
776 
777   base::File file(temp_file_path(), flags);
778   ASSERT_TRUE(file.IsValid());
779 
780   auto stream = std::make_unique<FileStream>(
781       std::move(file), base::SingleThreadTaskRunner::GetCurrentDefault());
782 
783   scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBufferWithSize>(1);
784   buf->data()[0] = 0;
785 
786   TestCompletionCallback callback;
787   int rv = stream->Write(buf.get(), 1, callback.callback());
788   if (rv == ERR_IO_PENDING)
789     rv = callback.WaitForResult();
790   EXPECT_LT(rv, 0);
791 
792   stream.reset();
793   base::RunLoop().RunUntilIdle();
794 }
795 
796 // Verify that Read() errors are mapped correctly.
TEST_F(FileStreamTest,ReadError)797 TEST_F(FileStreamTest, ReadError) {
798   // Try opening file for write and then reading from it using FileStream.
799   uint32_t flags =
800       base::File::FLAG_OPEN | base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
801 
802   base::File file(temp_file_path(), flags);
803   ASSERT_TRUE(file.IsValid());
804 
805   auto stream = std::make_unique<FileStream>(
806       std::move(file), base::SingleThreadTaskRunner::GetCurrentDefault());
807 
808   scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBufferWithSize>(1);
809   TestCompletionCallback callback;
810   int rv = stream->Read(buf.get(), 1, callback.callback());
811   if (rv == ERR_IO_PENDING)
812     rv = callback.WaitForResult();
813   EXPECT_LT(rv, 0);
814 
815   stream.reset();
816   base::RunLoop().RunUntilIdle();
817 }
818 
819 #if BUILDFLAG(IS_WIN)
820 // Verifies that a FileStream will close itself if it receives a File whose
821 // async flag doesn't match the async state of the underlying handle.
TEST_F(FileStreamTest,AsyncFlagMismatch)822 TEST_F(FileStreamTest, AsyncFlagMismatch) {
823   // Open the test file without async, then make a File with the same sync
824   // handle but with the async flag set to true.
825   uint32_t flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
826   base::File file(temp_file_path(), flags);
827   base::File lying_file(file.TakePlatformFile(), true);
828   ASSERT_TRUE(lying_file.IsValid());
829 
830   FileStream stream(std::move(lying_file),
831                     base::SingleThreadTaskRunner::GetCurrentDefault());
832   ASSERT_FALSE(stream.IsOpen());
833   TestCompletionCallback callback;
834   scoped_refptr<IOBufferWithSize> buf =
835       base::MakeRefCounted<IOBufferWithSize>(4);
836   int rv = stream.Read(buf.get(), buf->size(), callback.callback());
837   EXPECT_THAT(callback.GetResult(rv), IsError(ERR_UNEXPECTED));
838 }
839 #endif
840 
841 #if BUILDFLAG(IS_ANDROID)
842 // TODO(https://crbug.com/894599): flaky on both android and cronet bots.
TEST_F(FileStreamTest,DISABLED_ContentUriRead)843 TEST_F(FileStreamTest, DISABLED_ContentUriRead) {
844   base::FilePath test_dir;
845   base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &test_dir);
846   test_dir = test_dir.AppendASCII("net");
847   test_dir = test_dir.AppendASCII("data");
848   test_dir = test_dir.AppendASCII("file_stream_unittest");
849   ASSERT_TRUE(base::PathExists(test_dir));
850   base::FilePath image_file = test_dir.Append(FILE_PATH_LITERAL("red.png"));
851 
852   // Insert the image into MediaStore. MediaStore will do some conversions, and
853   // return the content URI.
854   base::FilePath path = base::InsertImageIntoMediaStore(image_file);
855   EXPECT_TRUE(path.IsContentUri());
856   EXPECT_TRUE(base::PathExists(path));
857   int64_t file_size;
858   EXPECT_TRUE(base::GetFileSize(path, &file_size));
859   EXPECT_LT(0, file_size);
860 
861   FileStream stream(base::SingleThreadTaskRunner::GetCurrentDefault());
862   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
863               base::File::FLAG_ASYNC;
864   TestCompletionCallback callback;
865   int rv = stream.Open(path, flags, callback.callback());
866   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
867   EXPECT_THAT(callback.WaitForResult(), IsOk());
868 
869   int total_bytes_read = 0;
870 
871   std::string data_read;
872   for (;;) {
873     scoped_refptr<IOBufferWithSize> buf =
874         base::MakeRefCounted<IOBufferWithSize>(4);
875     rv = stream.Read(buf.get(), buf->size(), callback.callback());
876     if (rv == ERR_IO_PENDING)
877       rv = callback.WaitForResult();
878     EXPECT_LE(0, rv);
879     if (rv <= 0)
880       break;
881     total_bytes_read += rv;
882     data_read.append(buf->data(), rv);
883   }
884   EXPECT_EQ(file_size, total_bytes_read);
885 }
886 #endif
887 
888 }  // namespace
889 
890 }  // namespace net
891