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