file_stream_unittest.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/message_loop.h"
11#include "base/path_service.h"
12#include "base/platform_file.h"
13#include "base/synchronization/waitable_event.h"
14#include "base/test/test_timeouts.h"
15#include "net/base/capturing_net_log.h"
16#include "net/base/io_buffer.h"
17#include "net/base/net_errors.h"
18#include "net/base/test_completion_callback.h"
19#include "testing/gtest/include/gtest/gtest.h"
20#include "testing/platform_test.h"
21
22namespace net {
23
24namespace {
25
26const char kTestData[] = "0123456789";
27const int kTestDataSize = arraysize(kTestData) - 1;
28
29// Creates an IOBufferWithSize that contains the kTestDataSize.
30IOBufferWithSize* CreateTestDataBuffer() {
31  IOBufferWithSize* buf = new IOBufferWithSize(kTestDataSize);
32  memcpy(buf->data(), kTestData, kTestDataSize);
33  return buf;
34}
35
36}  // namespace
37
38class FileStreamTest : public PlatformTest {
39 public:
40  virtual void SetUp() {
41    PlatformTest::SetUp();
42
43    file_util::CreateTemporaryFile(&temp_file_path_);
44    file_util::WriteFile(temp_file_path_, kTestData, kTestDataSize);
45  }
46  virtual void TearDown() {
47    file_util::Delete(temp_file_path_, false);
48
49    PlatformTest::TearDown();
50  }
51
52  const FilePath temp_file_path() const { return temp_file_path_; }
53
54 private:
55  FilePath temp_file_path_;
56};
57
58namespace {
59
60TEST_F(FileStreamTest, BasicOpenClose) {
61  base::PlatformFile file = base::kInvalidPlatformFileValue;
62  {
63    FileStream stream(NULL);
64    int rv = stream.OpenSync(temp_file_path(),
65        base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ);
66    EXPECT_EQ(OK, rv);
67    EXPECT_TRUE(stream.IsOpen());
68    file = stream.GetPlatformFileForTesting();
69  }
70  EXPECT_NE(base::kInvalidPlatformFileValue, file);
71  base::PlatformFileInfo info;
72  // The file should be closed.
73  EXPECT_FALSE(base::GetPlatformFileInfo(file, &info));
74}
75
76TEST_F(FileStreamTest, FileHandleNotLeftOpen) {
77  bool created = false;
78  ASSERT_EQ(kTestDataSize,
79      file_util::WriteFile(temp_file_path(), kTestData, kTestDataSize));
80  int flags = base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_READ;
81  base::PlatformFile file = base::CreatePlatformFile(
82      temp_file_path(), flags, &created, NULL);
83
84  {
85    // Seek to the beginning of the file and read.
86    FileStream read_stream(file, flags, NULL);
87    EXPECT_TRUE(read_stream.IsOpen());
88  }
89
90  EXPECT_NE(base::kInvalidPlatformFileValue, file);
91  base::PlatformFileInfo info;
92  // The file should be closed.
93  EXPECT_FALSE(base::GetPlatformFileInfo(file, &info));
94  EXPECT_FALSE(base::ClosePlatformFile(file));
95}
96
97// Test the use of FileStream with a file handle provided at construction.
98TEST_F(FileStreamTest, UseFileHandle) {
99  bool created = false;
100
101  // 1. Test reading with a file handle.
102  ASSERT_EQ(kTestDataSize,
103      file_util::WriteFile(temp_file_path(), kTestData, kTestDataSize));
104  int flags = base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_READ;
105  base::PlatformFile file = base::CreatePlatformFile(
106      temp_file_path(), flags, &created, NULL);
107
108  // Seek to the beginning of the file and read.
109  scoped_ptr<FileStream> read_stream(new FileStream(file, flags, NULL));
110  ASSERT_EQ(0, read_stream->SeekSync(FROM_BEGIN, 0));
111  ASSERT_EQ(kTestDataSize, read_stream->Available());
112  // Read into buffer and compare.
113  char buffer[kTestDataSize];
114  ASSERT_EQ(kTestDataSize,
115            read_stream->ReadSync(buffer, kTestDataSize));
116  ASSERT_EQ(0, memcmp(kTestData, buffer, kTestDataSize));
117  read_stream.reset();
118
119  // 2. Test writing with a file handle.
120  file_util::Delete(temp_file_path(), false);
121  flags = base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_WRITE;
122  file = base::CreatePlatformFile(temp_file_path(), flags, &created, NULL);
123
124  scoped_ptr<FileStream> write_stream(new FileStream(file, flags, NULL));
125  ASSERT_EQ(0, write_stream->SeekSync(FROM_BEGIN, 0));
126  ASSERT_EQ(kTestDataSize,
127            write_stream->WriteSync(kTestData, kTestDataSize));
128  write_stream.reset();
129
130  // Read into buffer and compare to make sure the handle worked fine.
131  ASSERT_EQ(kTestDataSize,
132      file_util::ReadFile(temp_file_path(), buffer, kTestDataSize));
133  ASSERT_EQ(0, memcmp(kTestData, buffer, kTestDataSize));
134}
135
136TEST_F(FileStreamTest, UseClosedStream) {
137  FileStream stream(NULL);
138
139  EXPECT_FALSE(stream.IsOpen());
140
141  // Try seeking...
142  int64 new_offset = stream.SeekSync(FROM_BEGIN, 5);
143  EXPECT_EQ(ERR_UNEXPECTED, new_offset);
144
145  // Try available...
146  int64 avail = stream.Available();
147  EXPECT_EQ(ERR_UNEXPECTED, avail);
148
149  // Try reading...
150  char buf[10];
151  int rv = stream.ReadSync(buf, arraysize(buf));
152  EXPECT_EQ(ERR_UNEXPECTED, rv);
153}
154
155TEST_F(FileStreamTest, BasicRead) {
156  int64 file_size;
157  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
158  EXPECT_TRUE(ok);
159
160  FileStream stream(NULL);
161  int flags = base::PLATFORM_FILE_OPEN |
162              base::PLATFORM_FILE_READ;
163  int rv = stream.OpenSync(temp_file_path(), flags);
164  EXPECT_EQ(OK, rv);
165
166  int64 total_bytes_avail = stream.Available();
167  EXPECT_EQ(file_size, total_bytes_avail);
168
169  int total_bytes_read = 0;
170
171  std::string data_read;
172  for (;;) {
173    char buf[4];
174    rv = stream.ReadSync(buf, arraysize(buf));
175    EXPECT_LE(0, rv);
176    if (rv <= 0)
177      break;
178    total_bytes_read += rv;
179    data_read.append(buf, rv);
180  }
181  EXPECT_EQ(file_size, total_bytes_read);
182  EXPECT_EQ(kTestData, data_read);
183}
184
185TEST_F(FileStreamTest, AsyncRead) {
186  int64 file_size;
187  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
188  EXPECT_TRUE(ok);
189
190  FileStream stream(NULL);
191  int flags = base::PLATFORM_FILE_OPEN |
192              base::PLATFORM_FILE_READ |
193              base::PLATFORM_FILE_ASYNC;
194  int rv = stream.OpenSync(temp_file_path(), flags);
195  EXPECT_EQ(OK, rv);
196
197  int64 total_bytes_avail = stream.Available();
198  EXPECT_EQ(file_size, total_bytes_avail);
199
200  TestCompletionCallback callback;
201
202  int total_bytes_read = 0;
203
204  std::string data_read;
205  for (;;) {
206    scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
207    rv = stream.Read(buf, buf->size(), callback.callback());
208    if (rv == ERR_IO_PENDING)
209      rv = callback.WaitForResult();
210    EXPECT_LE(0, rv);
211    if (rv <= 0)
212      break;
213    total_bytes_read += rv;
214    data_read.append(buf->data(), rv);
215  }
216  EXPECT_EQ(file_size, total_bytes_read);
217  EXPECT_EQ(kTestData, data_read);
218}
219
220TEST_F(FileStreamTest, AsyncRead_EarlyDelete) {
221  int64 file_size;
222  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
223  EXPECT_TRUE(ok);
224
225  scoped_ptr<FileStream> stream(new FileStream(NULL));
226  int flags = base::PLATFORM_FILE_OPEN |
227              base::PLATFORM_FILE_READ |
228              base::PLATFORM_FILE_ASYNC;
229  TestCompletionCallback callback;
230  int rv = stream->Open(temp_file_path(), flags, callback.callback());
231  EXPECT_EQ(ERR_IO_PENDING, rv);
232  EXPECT_EQ(OK, callback.WaitForResult());
233
234  int64 total_bytes_avail = stream->Available();
235  EXPECT_EQ(file_size, total_bytes_avail);
236
237  scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
238  rv = stream->Read(buf, buf->size(), callback.callback());
239  stream.reset();  // Delete instead of closing it.
240  if (rv < 0) {
241    EXPECT_EQ(ERR_IO_PENDING, rv);
242    // The callback should not be called if the request is cancelled.
243    MessageLoop::current()->RunAllPending();
244    EXPECT_FALSE(callback.have_result());
245  } else {
246    EXPECT_EQ(std::string(kTestData, rv), std::string(buf->data(), rv));
247  }
248}
249
250TEST_F(FileStreamTest, BasicRead_FromOffset) {
251  int64 file_size;
252  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
253  EXPECT_TRUE(ok);
254
255  FileStream stream(NULL);
256  int flags = base::PLATFORM_FILE_OPEN |
257              base::PLATFORM_FILE_READ;
258  int rv = stream.OpenSync(temp_file_path(), flags);
259  EXPECT_EQ(OK, rv);
260
261  const int64 kOffset = 3;
262  int64 new_offset = stream.SeekSync(FROM_BEGIN, kOffset);
263  EXPECT_EQ(kOffset, new_offset);
264
265  int64 total_bytes_avail = stream.Available();
266  EXPECT_EQ(file_size - kOffset, total_bytes_avail);
267
268  int64 total_bytes_read = 0;
269
270  std::string data_read;
271  for (;;) {
272    char buf[4];
273    rv = stream.ReadSync(buf, arraysize(buf));
274    EXPECT_LE(0, rv);
275    if (rv <= 0)
276      break;
277    total_bytes_read += rv;
278    data_read.append(buf, rv);
279  }
280  EXPECT_EQ(file_size - kOffset, total_bytes_read);
281  EXPECT_TRUE(data_read == kTestData + kOffset);
282  EXPECT_EQ(kTestData + kOffset, data_read);
283}
284
285TEST_F(FileStreamTest, AsyncRead_FromOffset) {
286  int64 file_size;
287  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
288  EXPECT_TRUE(ok);
289
290  FileStream stream(NULL);
291  int flags = base::PLATFORM_FILE_OPEN |
292              base::PLATFORM_FILE_READ |
293              base::PLATFORM_FILE_ASYNC;
294  int rv = stream.OpenSync(temp_file_path(), flags);
295  EXPECT_EQ(OK, rv);
296
297  TestInt64CompletionCallback callback64;
298  const int64 kOffset = 3;
299  rv = stream.Seek(FROM_BEGIN, kOffset, callback64.callback());
300  ASSERT_EQ(ERR_IO_PENDING, rv);
301  int64 new_offset = callback64.WaitForResult();
302  EXPECT_EQ(kOffset, new_offset);
303
304  int64 total_bytes_avail = stream.Available();
305  EXPECT_EQ(file_size - kOffset, total_bytes_avail);
306
307  TestCompletionCallback callback;
308
309  int total_bytes_read = 0;
310
311  std::string data_read;
312  for (;;) {
313    scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
314    rv = stream.Read(buf, buf->size(), callback.callback());
315    if (rv == ERR_IO_PENDING)
316      rv = callback.WaitForResult();
317    EXPECT_LE(0, rv);
318    if (rv <= 0)
319      break;
320    total_bytes_read += rv;
321    data_read.append(buf->data(), rv);
322  }
323  EXPECT_EQ(file_size - kOffset, total_bytes_read);
324  EXPECT_EQ(kTestData + kOffset, data_read);
325}
326
327TEST_F(FileStreamTest, SeekAround) {
328  FileStream stream(NULL);
329  int flags = base::PLATFORM_FILE_OPEN |
330              base::PLATFORM_FILE_READ;
331  int rv = stream.OpenSync(temp_file_path(), flags);
332  EXPECT_EQ(OK, rv);
333
334  const int64 kOffset = 3;
335  int64 new_offset = stream.SeekSync(FROM_BEGIN, kOffset);
336  EXPECT_EQ(kOffset, new_offset);
337
338  new_offset = stream.SeekSync(FROM_CURRENT, kOffset);
339  EXPECT_EQ(2 * kOffset, new_offset);
340
341  new_offset = stream.SeekSync(FROM_CURRENT, -kOffset);
342  EXPECT_EQ(kOffset, new_offset);
343
344  const int kTestDataLen = arraysize(kTestData) - 1;
345
346  new_offset = stream.SeekSync(FROM_END, -kTestDataLen);
347  EXPECT_EQ(0, new_offset);
348}
349
350TEST_F(FileStreamTest, AsyncSeekAround) {
351  FileStream stream(NULL);
352  int flags = base::PLATFORM_FILE_OPEN |
353              base::PLATFORM_FILE_ASYNC |
354              base::PLATFORM_FILE_READ;
355  int rv = stream.OpenSync(temp_file_path(), flags);
356  EXPECT_EQ(OK, rv);
357
358  TestInt64CompletionCallback callback;
359
360  const int64 kOffset = 3;
361  rv = stream.Seek(FROM_BEGIN, kOffset, callback.callback());
362  ASSERT_EQ(ERR_IO_PENDING, rv);
363  int64 new_offset = callback.WaitForResult();
364  EXPECT_EQ(kOffset, new_offset);
365
366  rv = stream.Seek(FROM_CURRENT, kOffset, callback.callback());
367  ASSERT_EQ(ERR_IO_PENDING, rv);
368  new_offset = callback.WaitForResult();
369  EXPECT_EQ(2 * kOffset, new_offset);
370
371  rv = stream.Seek(FROM_CURRENT, -kOffset, callback.callback());
372  ASSERT_EQ(ERR_IO_PENDING, rv);
373  new_offset = callback.WaitForResult();
374  EXPECT_EQ(kOffset, new_offset);
375
376  const int kTestDataLen = arraysize(kTestData) - 1;
377
378  rv = stream.Seek(FROM_END, -kTestDataLen, callback.callback());
379  ASSERT_EQ(ERR_IO_PENDING, rv);
380  new_offset = callback.WaitForResult();
381  EXPECT_EQ(0, new_offset);
382}
383
384TEST_F(FileStreamTest, BasicWrite) {
385  scoped_ptr<FileStream> stream(new FileStream(NULL));
386  int flags = base::PLATFORM_FILE_CREATE_ALWAYS |
387              base::PLATFORM_FILE_WRITE;
388  int rv = stream->OpenSync(temp_file_path(), flags);
389  EXPECT_EQ(OK, rv);
390
391  int64 file_size;
392  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
393  EXPECT_TRUE(ok);
394  EXPECT_EQ(0, file_size);
395
396  rv = stream->WriteSync(kTestData, kTestDataSize);
397  EXPECT_EQ(kTestDataSize, rv);
398  stream.reset();
399
400  ok = file_util::GetFileSize(temp_file_path(), &file_size);
401  EXPECT_TRUE(ok);
402  EXPECT_EQ(kTestDataSize, file_size);
403}
404
405TEST_F(FileStreamTest, AsyncWrite) {
406  FileStream stream(NULL);
407  int flags = base::PLATFORM_FILE_CREATE_ALWAYS |
408              base::PLATFORM_FILE_WRITE |
409              base::PLATFORM_FILE_ASYNC;
410  int rv = stream.OpenSync(temp_file_path(), flags);
411  EXPECT_EQ(OK, rv);
412
413  int64 file_size;
414  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
415  EXPECT_TRUE(ok);
416  EXPECT_EQ(0, file_size);
417
418  TestCompletionCallback callback;
419  int total_bytes_written = 0;
420
421  scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
422  scoped_refptr<DrainableIOBuffer> drainable =
423      new DrainableIOBuffer(buf, buf->size());
424  while (total_bytes_written != kTestDataSize) {
425    rv = stream.Write(drainable, drainable->BytesRemaining(),
426                      callback.callback());
427    if (rv == ERR_IO_PENDING)
428      rv = callback.WaitForResult();
429    EXPECT_LT(0, rv);
430    if (rv <= 0)
431      break;
432    drainable->DidConsume(rv);
433    total_bytes_written += rv;
434  }
435  ok = file_util::GetFileSize(temp_file_path(), &file_size);
436  EXPECT_TRUE(ok);
437  EXPECT_EQ(file_size, total_bytes_written);
438}
439
440TEST_F(FileStreamTest, AsyncWrite_EarlyDelete) {
441  scoped_ptr<FileStream> stream(new FileStream(NULL));
442  int flags = base::PLATFORM_FILE_CREATE_ALWAYS |
443              base::PLATFORM_FILE_WRITE |
444              base::PLATFORM_FILE_ASYNC;
445  int rv = stream->OpenSync(temp_file_path(), flags);
446  EXPECT_EQ(OK, rv);
447
448  int64 file_size;
449  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
450  EXPECT_TRUE(ok);
451  EXPECT_EQ(0, file_size);
452
453  TestCompletionCallback callback;
454
455  scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
456  rv = stream->Write(buf, buf->size(), callback.callback());
457  stream.reset();
458  if (rv < 0) {
459    EXPECT_EQ(ERR_IO_PENDING, rv);
460    // The callback should not be called if the request is cancelled.
461    MessageLoop::current()->RunAllPending();
462    EXPECT_FALSE(callback.have_result());
463  } else {
464    ok = file_util::GetFileSize(temp_file_path(), &file_size);
465    EXPECT_TRUE(ok);
466    EXPECT_EQ(file_size, rv);
467  }
468}
469
470TEST_F(FileStreamTest, BasicWrite_FromOffset) {
471  scoped_ptr<FileStream> stream(new FileStream(NULL));
472  int flags = base::PLATFORM_FILE_OPEN |
473              base::PLATFORM_FILE_WRITE;
474  int rv = stream->OpenSync(temp_file_path(), flags);
475  EXPECT_EQ(OK, rv);
476
477  int64 file_size;
478  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
479  EXPECT_TRUE(ok);
480  EXPECT_EQ(kTestDataSize, file_size);
481
482  const int64 kOffset = 0;
483  int64 new_offset = stream->SeekSync(FROM_END, kOffset);
484  EXPECT_EQ(kTestDataSize, new_offset);
485
486  rv = stream->WriteSync(kTestData, kTestDataSize);
487  EXPECT_EQ(kTestDataSize, rv);
488  stream.reset();
489
490  ok = file_util::GetFileSize(temp_file_path(), &file_size);
491  EXPECT_TRUE(ok);
492  EXPECT_EQ(kTestDataSize * 2, file_size);
493}
494
495TEST_F(FileStreamTest, AsyncWrite_FromOffset) {
496  int64 file_size;
497  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
498  EXPECT_TRUE(ok);
499
500  FileStream stream(NULL);
501  int flags = base::PLATFORM_FILE_OPEN |
502              base::PLATFORM_FILE_WRITE |
503              base::PLATFORM_FILE_ASYNC;
504  int rv = stream.OpenSync(temp_file_path(), flags);
505  EXPECT_EQ(OK, rv);
506
507  TestInt64CompletionCallback callback64;
508  const int64 kOffset = 0;
509  rv = stream.Seek(FROM_END, kOffset, callback64.callback());
510  ASSERT_EQ(ERR_IO_PENDING, rv);
511  int64 new_offset = callback64.WaitForResult();
512  EXPECT_EQ(kTestDataSize, new_offset);
513
514  TestCompletionCallback callback;
515  int total_bytes_written = 0;
516
517  scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
518  scoped_refptr<DrainableIOBuffer> drainable =
519      new DrainableIOBuffer(buf, buf->size());
520  while (total_bytes_written != kTestDataSize) {
521    rv = stream.Write(drainable, drainable->BytesRemaining(),
522                      callback.callback());
523    if (rv == ERR_IO_PENDING)
524      rv = callback.WaitForResult();
525    EXPECT_LT(0, rv);
526    if (rv <= 0)
527      break;
528    drainable->DidConsume(rv);
529    total_bytes_written += rv;
530  }
531  ok = file_util::GetFileSize(temp_file_path(), &file_size);
532  EXPECT_TRUE(ok);
533  EXPECT_EQ(file_size, kTestDataSize * 2);
534}
535
536TEST_F(FileStreamTest, BasicReadWrite) {
537  int64 file_size;
538  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
539  EXPECT_TRUE(ok);
540
541  scoped_ptr<FileStream> stream(new FileStream(NULL));
542  int flags = base::PLATFORM_FILE_OPEN |
543              base::PLATFORM_FILE_READ |
544              base::PLATFORM_FILE_WRITE;
545  int rv = stream->OpenSync(temp_file_path(), flags);
546  EXPECT_EQ(OK, rv);
547
548  int64 total_bytes_avail = stream->Available();
549  EXPECT_EQ(file_size, total_bytes_avail);
550
551  int total_bytes_read = 0;
552
553  std::string data_read;
554  for (;;) {
555    char buf[4];
556    rv = stream->ReadSync(buf, arraysize(buf));
557    EXPECT_LE(0, rv);
558    if (rv <= 0)
559      break;
560    total_bytes_read += rv;
561    data_read.append(buf, rv);
562  }
563  EXPECT_EQ(file_size, total_bytes_read);
564  EXPECT_TRUE(data_read == kTestData);
565
566  rv = stream->WriteSync(kTestData, kTestDataSize);
567  EXPECT_EQ(kTestDataSize, rv);
568  stream.reset();
569
570  ok = file_util::GetFileSize(temp_file_path(), &file_size);
571  EXPECT_TRUE(ok);
572  EXPECT_EQ(kTestDataSize * 2, file_size);
573}
574
575TEST_F(FileStreamTest, BasicWriteRead) {
576  int64 file_size;
577  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
578  EXPECT_TRUE(ok);
579
580  scoped_ptr<FileStream> stream(new FileStream(NULL));
581  int flags = base::PLATFORM_FILE_OPEN |
582              base::PLATFORM_FILE_READ |
583              base::PLATFORM_FILE_WRITE;
584  int rv = stream->OpenSync(temp_file_path(), flags);
585  EXPECT_EQ(OK, rv);
586
587  int64 total_bytes_avail = stream->Available();
588  EXPECT_EQ(file_size, total_bytes_avail);
589
590  int64 offset = stream->SeekSync(FROM_END, 0);
591  EXPECT_EQ(offset, file_size);
592
593  rv = stream->WriteSync(kTestData, kTestDataSize);
594  EXPECT_EQ(kTestDataSize, rv);
595
596  offset = stream->SeekSync(FROM_BEGIN, 0);
597  EXPECT_EQ(0, offset);
598
599  int64 total_bytes_read = 0;
600
601  std::string data_read;
602  for (;;) {
603    char buf[4];
604    rv = stream->ReadSync(buf, arraysize(buf));
605    EXPECT_LE(0, rv);
606    if (rv <= 0)
607      break;
608    total_bytes_read += rv;
609    data_read.append(buf, rv);
610  }
611  stream.reset();
612
613  ok = file_util::GetFileSize(temp_file_path(), &file_size);
614  EXPECT_TRUE(ok);
615  EXPECT_EQ(kTestDataSize * 2, file_size);
616  EXPECT_EQ(kTestDataSize * 2, total_bytes_read);
617
618  const std::string kExpectedFileData =
619      std::string(kTestData) + std::string(kTestData);
620  EXPECT_EQ(kExpectedFileData, data_read);
621}
622
623TEST_F(FileStreamTest, BasicAsyncReadWrite) {
624  int64 file_size;
625  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
626  EXPECT_TRUE(ok);
627
628  scoped_ptr<FileStream> stream(new FileStream(NULL));
629  int flags = base::PLATFORM_FILE_OPEN |
630              base::PLATFORM_FILE_READ |
631              base::PLATFORM_FILE_WRITE |
632              base::PLATFORM_FILE_ASYNC;
633  int rv = stream->OpenSync(temp_file_path(), flags);
634  EXPECT_EQ(OK, rv);
635
636  int64 total_bytes_avail = stream->Available();
637  EXPECT_EQ(file_size, total_bytes_avail);
638
639  TestCompletionCallback callback;
640  int64 total_bytes_read = 0;
641
642  std::string data_read;
643  for (;;) {
644    scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
645    rv = stream->Read(buf, buf->size(), callback.callback());
646    if (rv == ERR_IO_PENDING)
647      rv = callback.WaitForResult();
648    EXPECT_LE(0, rv);
649    if (rv <= 0)
650      break;
651    total_bytes_read += rv;
652    data_read.append(buf->data(), rv);
653  }
654  EXPECT_EQ(file_size, total_bytes_read);
655  EXPECT_TRUE(data_read == kTestData);
656
657  int total_bytes_written = 0;
658
659  scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
660  scoped_refptr<DrainableIOBuffer> drainable =
661      new DrainableIOBuffer(buf, buf->size());
662  while (total_bytes_written != kTestDataSize) {
663    rv = stream->Write(drainable, drainable->BytesRemaining(),
664                       callback.callback());
665    if (rv == ERR_IO_PENDING)
666      rv = callback.WaitForResult();
667    EXPECT_LT(0, rv);
668    if (rv <= 0)
669      break;
670    drainable->DidConsume(rv);
671    total_bytes_written += rv;
672  }
673
674  stream.reset();
675
676  ok = file_util::GetFileSize(temp_file_path(), &file_size);
677  EXPECT_TRUE(ok);
678  EXPECT_EQ(kTestDataSize * 2, file_size);
679}
680
681TEST_F(FileStreamTest, BasicAsyncWriteRead) {
682  int64 file_size;
683  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
684  EXPECT_TRUE(ok);
685
686  scoped_ptr<FileStream> stream(new FileStream(NULL));
687  int flags = base::PLATFORM_FILE_OPEN |
688              base::PLATFORM_FILE_READ |
689              base::PLATFORM_FILE_WRITE |
690              base::PLATFORM_FILE_ASYNC;
691  int rv = stream->OpenSync(temp_file_path(), flags);
692  EXPECT_EQ(OK, rv);
693
694  int64 total_bytes_avail = stream->Available();
695  EXPECT_EQ(file_size, total_bytes_avail);
696
697  TestInt64CompletionCallback callback64;
698  rv = stream->Seek(FROM_END, 0, callback64.callback());
699  ASSERT_EQ(ERR_IO_PENDING, rv);
700  int64 offset = callback64.WaitForResult();
701  EXPECT_EQ(offset, file_size);
702
703  TestCompletionCallback callback;
704  int total_bytes_written = 0;
705
706  scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
707  scoped_refptr<DrainableIOBuffer> drainable =
708      new DrainableIOBuffer(buf, buf->size());
709  while (total_bytes_written != kTestDataSize) {
710    rv = stream->Write(drainable, drainable->BytesRemaining(),
711                      callback.callback());
712    if (rv == ERR_IO_PENDING)
713      rv = callback.WaitForResult();
714    EXPECT_LT(0, rv);
715    if (rv <= 0)
716      break;
717    drainable->DidConsume(rv);
718    total_bytes_written += rv;
719  }
720
721  EXPECT_EQ(kTestDataSize, total_bytes_written);
722
723  rv = stream->Seek(FROM_BEGIN, 0, callback64.callback());
724  ASSERT_EQ(ERR_IO_PENDING, rv);
725  offset = callback64.WaitForResult();
726  EXPECT_EQ(0, offset);
727
728  int total_bytes_read = 0;
729
730  std::string data_read;
731  for (;;) {
732    scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
733    rv = stream->Read(buf, buf->size(), callback.callback());
734    if (rv == ERR_IO_PENDING)
735      rv = callback.WaitForResult();
736    EXPECT_LE(0, rv);
737    if (rv <= 0)
738      break;
739    total_bytes_read += rv;
740    data_read.append(buf->data(), rv);
741  }
742  stream.reset();
743
744  ok = file_util::GetFileSize(temp_file_path(), &file_size);
745  EXPECT_TRUE(ok);
746  EXPECT_EQ(kTestDataSize * 2, file_size);
747
748  EXPECT_EQ(kTestDataSize * 2, total_bytes_read);
749  const std::string kExpectedFileData =
750      std::string(kTestData) + std::string(kTestData);
751  EXPECT_EQ(kExpectedFileData, data_read);
752}
753
754class TestWriteReadCompletionCallback {
755 public:
756  TestWriteReadCompletionCallback(
757      FileStream* stream,
758      int* total_bytes_written,
759      int* total_bytes_read,
760      std::string* data_read)
761      : result_(0),
762        have_result_(false),
763        waiting_for_result_(false),
764        stream_(stream),
765        total_bytes_written_(total_bytes_written),
766        total_bytes_read_(total_bytes_read),
767        data_read_(data_read),
768        callback_(base::Bind(&TestWriteReadCompletionCallback::OnComplete,
769                             base::Unretained(this))),
770        test_data_(CreateTestDataBuffer()),
771        drainable_(new DrainableIOBuffer(test_data_, kTestDataSize)) {
772  }
773
774  int WaitForResult() {
775    DCHECK(!waiting_for_result_);
776    while (!have_result_) {
777      waiting_for_result_ = true;
778      MessageLoop::current()->Run();
779      waiting_for_result_ = false;
780    }
781    have_result_ = false;  // auto-reset for next callback
782    return result_;
783  }
784
785  const CompletionCallback& callback() const { return callback_; }
786
787 private:
788  void OnComplete(int result) {
789    DCHECK_LT(0, result);
790    *total_bytes_written_ += result;
791
792    int rv;
793
794    if (*total_bytes_written_ != kTestDataSize) {
795      // Recurse to finish writing all data.
796      int total_bytes_written = 0, total_bytes_read = 0;
797      std::string data_read;
798      TestWriteReadCompletionCallback callback(
799          stream_, &total_bytes_written, &total_bytes_read, &data_read);
800      rv = stream_->Write(drainable_, drainable_->BytesRemaining(),
801                          callback.callback());
802      DCHECK_EQ(ERR_IO_PENDING, rv);
803      rv = callback.WaitForResult();
804      drainable_->DidConsume(total_bytes_written);
805      *total_bytes_written_ += total_bytes_written;
806      *total_bytes_read_ += total_bytes_read;
807      *data_read_ += data_read;
808    } else {  // We're done writing all data.  Start reading the data.
809      stream_->SeekSync(FROM_BEGIN, 0);
810
811      TestCompletionCallback callback;
812      for (;;) {
813        scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
814        rv = stream_->Read(buf, buf->size(), callback.callback());
815        if (rv == ERR_IO_PENDING) {
816          MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
817          rv = callback.WaitForResult();
818        }
819        EXPECT_LE(0, rv);
820        if (rv <= 0)
821          break;
822        *total_bytes_read_ += rv;
823        data_read_->append(buf->data(), rv);
824      }
825    }
826
827    result_ = *total_bytes_written_;
828    have_result_ = true;
829    if (waiting_for_result_)
830      MessageLoop::current()->Quit();
831  }
832
833  int result_;
834  bool have_result_;
835  bool waiting_for_result_;
836  FileStream* stream_;
837  int* total_bytes_written_;
838  int* total_bytes_read_;
839  std::string* data_read_;
840  const CompletionCallback callback_;
841  scoped_refptr<IOBufferWithSize> test_data_;
842  scoped_refptr<DrainableIOBuffer> drainable_;
843
844  DISALLOW_COPY_AND_ASSIGN(TestWriteReadCompletionCallback);
845};
846
847TEST_F(FileStreamTest, AsyncWriteRead) {
848  int64 file_size;
849  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
850  EXPECT_TRUE(ok);
851
852  scoped_ptr<FileStream> stream(new FileStream(NULL));
853  int flags = base::PLATFORM_FILE_OPEN |
854              base::PLATFORM_FILE_READ |
855              base::PLATFORM_FILE_WRITE |
856              base::PLATFORM_FILE_ASYNC;
857  int rv = stream->OpenSync(temp_file_path(), flags);
858  EXPECT_EQ(OK, rv);
859
860  int64 total_bytes_avail = stream->Available();
861  EXPECT_EQ(file_size, total_bytes_avail);
862
863  int64 offset = stream->SeekSync(FROM_END, 0);
864  EXPECT_EQ(offset, file_size);
865
866  int total_bytes_written = 0;
867  int total_bytes_read = 0;
868  std::string data_read;
869  TestWriteReadCompletionCallback callback(stream.get(), &total_bytes_written,
870                                           &total_bytes_read, &data_read);
871
872  scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
873  rv = stream->Write(buf, buf->size(), callback.callback());
874  if (rv == ERR_IO_PENDING)
875    rv = callback.WaitForResult();
876  EXPECT_LT(0, rv);
877  EXPECT_EQ(kTestDataSize, total_bytes_written);
878
879  stream.reset();
880
881  ok = file_util::GetFileSize(temp_file_path(), &file_size);
882  EXPECT_TRUE(ok);
883  EXPECT_EQ(kTestDataSize * 2, file_size);
884
885  EXPECT_EQ(kTestDataSize * 2, total_bytes_read);
886  const std::string kExpectedFileData =
887      std::string(kTestData) + std::string(kTestData);
888  EXPECT_EQ(kExpectedFileData, data_read);
889}
890
891class TestWriteCloseCompletionCallback {
892 public:
893  TestWriteCloseCompletionCallback(FileStream* stream, int* total_bytes_written)
894      : result_(0),
895        have_result_(false),
896        waiting_for_result_(false),
897        stream_(stream),
898        total_bytes_written_(total_bytes_written),
899        callback_(base::Bind(&TestWriteCloseCompletionCallback::OnComplete,
900                             base::Unretained(this))),
901        test_data_(CreateTestDataBuffer()),
902        drainable_(new DrainableIOBuffer(test_data_, kTestDataSize)) {
903  }
904
905  int WaitForResult() {
906    DCHECK(!waiting_for_result_);
907    while (!have_result_) {
908      waiting_for_result_ = true;
909      MessageLoop::current()->Run();
910      waiting_for_result_ = false;
911    }
912    have_result_ = false;  // auto-reset for next callback
913    return result_;
914  }
915
916  const CompletionCallback& callback() const { return callback_; }
917
918 private:
919  void OnComplete(int result) {
920    DCHECK_LT(0, result);
921    *total_bytes_written_ += result;
922
923    int rv;
924
925    if (*total_bytes_written_ != kTestDataSize) {
926      // Recurse to finish writing all data.
927      int total_bytes_written = 0;
928      TestWriteCloseCompletionCallback callback(stream_, &total_bytes_written);
929      rv = stream_->Write(drainable_, drainable_->BytesRemaining(),
930                          callback.callback());
931      DCHECK_EQ(ERR_IO_PENDING, rv);
932      rv = callback.WaitForResult();
933      drainable_->DidConsume(total_bytes_written);
934      *total_bytes_written_ += total_bytes_written;
935    }
936
937    result_ = *total_bytes_written_;
938    have_result_ = true;
939    if (waiting_for_result_)
940      MessageLoop::current()->Quit();
941  }
942
943  int result_;
944  bool have_result_;
945  bool waiting_for_result_;
946  FileStream* stream_;
947  int* total_bytes_written_;
948  const CompletionCallback callback_;
949  scoped_refptr<IOBufferWithSize> test_data_;
950  scoped_refptr<DrainableIOBuffer> drainable_;
951
952  DISALLOW_COPY_AND_ASSIGN(TestWriteCloseCompletionCallback);
953};
954
955TEST_F(FileStreamTest, AsyncWriteClose) {
956  int64 file_size;
957  bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
958  EXPECT_TRUE(ok);
959
960  scoped_ptr<FileStream> stream(new FileStream(NULL));
961  int flags = base::PLATFORM_FILE_OPEN |
962              base::PLATFORM_FILE_READ |
963              base::PLATFORM_FILE_WRITE |
964              base::PLATFORM_FILE_ASYNC;
965  int rv = stream->OpenSync(temp_file_path(), flags);
966  EXPECT_EQ(OK, rv);
967
968  int64 total_bytes_avail = stream->Available();
969  EXPECT_EQ(file_size, total_bytes_avail);
970
971  int64 offset = stream->SeekSync(FROM_END, 0);
972  EXPECT_EQ(offset, file_size);
973
974  int total_bytes_written = 0;
975  TestWriteCloseCompletionCallback callback(stream.get(), &total_bytes_written);
976
977  scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
978  rv = stream->Write(buf, buf->size(), callback.callback());
979  if (rv == ERR_IO_PENDING)
980    total_bytes_written = callback.WaitForResult();
981  EXPECT_LT(0, total_bytes_written);
982  EXPECT_EQ(kTestDataSize, total_bytes_written);
983
984  stream.reset();
985
986  ok = file_util::GetFileSize(temp_file_path(), &file_size);
987  EXPECT_TRUE(ok);
988  EXPECT_EQ(kTestDataSize * 2, file_size);
989}
990
991// Tests truncating a file.
992TEST_F(FileStreamTest, Truncate) {
993  int flags = base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE;
994
995  scoped_ptr<FileStream> write_stream(new FileStream(NULL));
996  ASSERT_EQ(OK, write_stream->OpenSync(temp_file_path(), flags));
997
998  // Write some data to the file.
999  const char test_data[] = "0123456789";
1000  write_stream->WriteSync(test_data, arraysize(test_data));
1001
1002  // Truncate the file.
1003  ASSERT_EQ(4, write_stream->Truncate(4));
1004
1005  // Write again.
1006  write_stream->WriteSync(test_data, 4);
1007
1008  // Close the stream.
1009  write_stream.reset();
1010
1011  // Read in the contents and make sure we get back what we expected.
1012  std::string read_contents;
1013  EXPECT_TRUE(file_util::ReadFileToString(temp_file_path(), &read_contents));
1014
1015  EXPECT_EQ("01230123", read_contents);
1016}
1017
1018TEST_F(FileStreamTest, AsyncOpenAndDelete) {
1019  scoped_ptr<FileStream> stream(new FileStream(NULL));
1020  int flags = base::PLATFORM_FILE_OPEN |
1021      base::PLATFORM_FILE_WRITE |
1022      base::PLATFORM_FILE_ASYNC;
1023  TestCompletionCallback open_callback;
1024  int rv = stream->Open(temp_file_path(), flags, open_callback.callback());
1025  EXPECT_EQ(ERR_IO_PENDING, rv);
1026
1027  // Delete the stream without waiting for the open operation to be
1028  // complete. Should be safe.
1029  stream.reset();
1030  // open_callback won't be called.
1031  MessageLoop::current()->RunUntilIdle();
1032  EXPECT_FALSE(open_callback.have_result());
1033}
1034
1035}  // namespace
1036
1037}  // namespace net
1038