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