drive_file_stream_reader_unittest.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
1// Copyright 2013 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 "chrome/browser/chromeos/drive/drive_file_stream_reader.h"
6
7#include <string>
8
9#include "base/bind.h"
10#include "base/files/file_path.h"
11#include "base/files/scoped_temp_dir.h"
12#include "base/run_loop.h"
13#include "base/threading/thread.h"
14#include "chrome/browser/chromeos/drive/fake_file_system.h"
15#include "chrome/browser/chromeos/drive/file_system_util.h"
16#include "chrome/browser/chromeos/drive/local_file_reader.h"
17#include "chrome/browser/chromeos/drive/test_util.h"
18#include "chrome/browser/drive/fake_drive_service.h"
19#include "content/public/test/test_browser_thread_bundle.h"
20#include "google_apis/drive/gdata_wapi_parser.h"
21#include "google_apis/drive/test_util.h"
22#include "net/base/io_buffer.h"
23#include "net/base/net_errors.h"
24#include "net/base/test_completion_callback.h"
25#include "net/http/http_byte_range.h"
26#include "testing/gtest/include/gtest/gtest.h"
27
28namespace drive {
29namespace internal {
30namespace {
31
32// Increments the |num_called|, when this method is invoked.
33void IncrementCallback(int* num_called) {
34  DCHECK(num_called);
35  ++*num_called;
36}
37
38}  // namespace
39
40class LocalReaderProxyTest : public ::testing::Test {
41 protected:
42  LocalReaderProxyTest()
43      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
44  }
45
46  virtual void SetUp() OVERRIDE {
47    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
48    ASSERT_TRUE(google_apis::test_util::CreateFileOfSpecifiedSize(
49        temp_dir_.path(), 1024, &file_path_, &file_content_));
50
51    worker_thread_.reset(new base::Thread("ReaderProxyTest"));
52    ASSERT_TRUE(worker_thread_->Start());
53  }
54
55  content::TestBrowserThreadBundle thread_bundle_;
56
57  base::ScopedTempDir temp_dir_;
58  base::FilePath file_path_;
59  std::string file_content_;
60
61  scoped_ptr<base::Thread> worker_thread_;
62};
63
64TEST_F(LocalReaderProxyTest, Read) {
65  // Open the file first.
66  scoped_ptr<util::LocalFileReader> file_reader(
67      new util::LocalFileReader(worker_thread_->message_loop_proxy().get()));
68  net::TestCompletionCallback callback;
69  file_reader->Open(file_path_, 0, callback.callback());
70  ASSERT_EQ(net::OK, callback.WaitForResult());
71
72  // Test instance.
73  LocalReaderProxy proxy(file_reader.Pass(), file_content_.size());
74
75  // Make sure the read content is as same as the file.
76  std::string content;
77  ASSERT_EQ(net::OK, test_util::ReadAllData(&proxy, &content));
78  EXPECT_EQ(file_content_, content);
79}
80
81TEST_F(LocalReaderProxyTest, ReadWithLimit) {
82  // This test case, we only read first half of the file.
83  const std::string expected_content =
84      file_content_.substr(0, file_content_.size() / 2);
85
86  // Open the file first.
87  scoped_ptr<util::LocalFileReader> file_reader(
88      new util::LocalFileReader(worker_thread_->message_loop_proxy().get()));
89  net::TestCompletionCallback callback;
90  file_reader->Open(file_path_, 0, callback.callback());
91  ASSERT_EQ(net::OK, callback.WaitForResult());
92
93  // Test instance.
94  LocalReaderProxy proxy(file_reader.Pass(), expected_content.size());
95
96  // Make sure the read content is as same as the file.
97  std::string content;
98  ASSERT_EQ(net::OK, test_util::ReadAllData(&proxy, &content));
99  EXPECT_EQ(expected_content, content);
100}
101
102class NetworkReaderProxyTest : public ::testing::Test {
103 protected:
104  NetworkReaderProxyTest()
105      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
106  }
107
108  content::TestBrowserThreadBundle thread_bundle_;
109};
110
111TEST_F(NetworkReaderProxyTest, EmptyFile) {
112  NetworkReaderProxy proxy(0, 0, base::Bind(&base::DoNothing));
113
114  net::TestCompletionCallback callback;
115  const int kBufferSize = 10;
116  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
117  int result = proxy.Read(buffer.get(), kBufferSize, callback.callback());
118
119  // For empty file, Read() should return 0 immediately.
120  EXPECT_EQ(0, result);
121}
122
123TEST_F(NetworkReaderProxyTest, Read) {
124  NetworkReaderProxy proxy(0, 10, base::Bind(&base::DoNothing));
125
126  net::TestCompletionCallback callback;
127  const int kBufferSize = 3;
128  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
129
130  // If no data is available yet, ERR_IO_PENDING should be returned.
131  int result = proxy.Read(buffer.get(), kBufferSize, callback.callback());
132  EXPECT_EQ(net::ERR_IO_PENDING, result);
133
134  // And when the data is supplied, the callback will be called.
135  scoped_ptr<std::string> data(new std::string("abcde"));
136  proxy.OnGetContent(data.Pass());
137
138  // The returned data should be fit to the buffer size.
139  result = callback.GetResult(result);
140  EXPECT_EQ(3, result);
141  EXPECT_EQ("abc", std::string(buffer->data(), result));
142
143  // The next Read should return immediately because there is pending data
144  result = proxy.Read(buffer.get(), kBufferSize, callback.callback());
145  EXPECT_EQ(2, result);
146  EXPECT_EQ("de", std::string(buffer->data(), result));
147
148  // Supply the data before calling Read operation.
149  data.reset(new std::string("fg"));
150  proxy.OnGetContent(data.Pass());
151  data.reset(new std::string("hij"));
152  proxy.OnGetContent(data.Pass());  // Now 10 bytes are supplied.
153
154  // The data should be concatenated if possible.
155  result = proxy.Read(buffer.get(), kBufferSize, callback.callback());
156  EXPECT_EQ(3, result);
157  EXPECT_EQ("fgh", std::string(buffer->data(), result));
158
159  result = proxy.Read(buffer.get(), kBufferSize, callback.callback());
160  EXPECT_EQ(2, result);
161  EXPECT_EQ("ij", std::string(buffer->data(), result));
162
163  // The whole data is read, so Read() should return 0 immediately by then.
164  result = proxy.Read(buffer.get(), kBufferSize, callback.callback());
165  EXPECT_EQ(0, result);
166}
167
168TEST_F(NetworkReaderProxyTest, ReadWithLimit) {
169  NetworkReaderProxy proxy(10, 10, base::Bind(&base::DoNothing));
170
171  net::TestCompletionCallback callback;
172  const int kBufferSize = 3;
173  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
174
175  // If no data is available yet, ERR_IO_PENDING should be returned.
176  int result = proxy.Read(buffer.get(), kBufferSize, callback.callback());
177  EXPECT_EQ(net::ERR_IO_PENDING, result);
178
179  // And when the data is supplied, the callback will be called.
180  scoped_ptr<std::string> data(new std::string("abcde"));
181  proxy.OnGetContent(data.Pass());
182  data.reset(new std::string("fgh"));
183  proxy.OnGetContent(data.Pass());
184  data.reset(new std::string("ijklmno"));
185  proxy.OnGetContent(data.Pass());
186
187  // The returned data should be fit to the buffer size.
188  result = callback.GetResult(result);
189  EXPECT_EQ(3, result);
190  EXPECT_EQ("klm", std::string(buffer->data(), result));
191
192  // The next Read should return immediately because there is pending data
193  result = proxy.Read(buffer.get(), kBufferSize, callback.callback());
194  EXPECT_EQ(2, result);
195  EXPECT_EQ("no", std::string(buffer->data(), result));
196
197  // Supply the data before calling Read operation.
198  data.reset(new std::string("pqrs"));
199  proxy.OnGetContent(data.Pass());
200  data.reset(new std::string("tuvwxyz"));
201  proxy.OnGetContent(data.Pass());  // 't' is the 20-th byte.
202
203  // The data should be concatenated if possible.
204  result = proxy.Read(buffer.get(), kBufferSize, callback.callback());
205  EXPECT_EQ(3, result);
206  EXPECT_EQ("pqr", std::string(buffer->data(), result));
207
208  result = proxy.Read(buffer.get(), kBufferSize, callback.callback());
209  EXPECT_EQ(2, result);
210  EXPECT_EQ("st", std::string(buffer->data(), result));
211
212  // The whole data is read, so Read() should return 0 immediately by then.
213  result = proxy.Read(buffer.get(), kBufferSize, callback.callback());
214  EXPECT_EQ(0, result);
215}
216
217TEST_F(NetworkReaderProxyTest, ErrorWithPendingCallback) {
218  NetworkReaderProxy proxy(0, 10, base::Bind(&base::DoNothing));
219
220  net::TestCompletionCallback callback;
221  const int kBufferSize = 3;
222  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
223
224  // Set pending callback.
225  int result = proxy.Read(buffer.get(), kBufferSize, callback.callback());
226  EXPECT_EQ(net::ERR_IO_PENDING, result);
227
228  // Emulate that an error is found. The callback should be called internally.
229  proxy.OnCompleted(FILE_ERROR_FAILED);
230  result = callback.GetResult(result);
231  EXPECT_EQ(net::ERR_FAILED, result);
232
233  // The next Read call should also return the same error code.
234  EXPECT_EQ(net::ERR_FAILED,
235            proxy.Read(buffer.get(), kBufferSize, callback.callback()));
236}
237
238TEST_F(NetworkReaderProxyTest, ErrorWithPendingData) {
239  NetworkReaderProxy proxy(0, 10, base::Bind(&base::DoNothing));
240
241  net::TestCompletionCallback callback;
242  const int kBufferSize = 3;
243  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
244
245  // Supply the data before an error.
246  scoped_ptr<std::string> data(new std::string("abcde"));
247  proxy.OnGetContent(data.Pass());
248
249  // Emulate that an error is found.
250  proxy.OnCompleted(FILE_ERROR_FAILED);
251
252  // The next Read call should return the error code, even if there is
253  // pending data (the pending data should be released in OnCompleted.
254  EXPECT_EQ(net::ERR_FAILED,
255            proxy.Read(buffer.get(), kBufferSize, callback.callback()));
256}
257
258TEST_F(NetworkReaderProxyTest, CancelJob) {
259  int num_called = 0;
260  {
261    NetworkReaderProxy proxy(
262        0, 0, base::Bind(&IncrementCallback, &num_called));
263    proxy.OnCompleted(FILE_ERROR_OK);
264    // Destroy the instance after the network operation is completed.
265    // The cancelling callback shouldn't be called.
266  }
267  EXPECT_EQ(0, num_called);
268
269  num_called = 0;
270  {
271    NetworkReaderProxy proxy(
272        0, 0, base::Bind(&IncrementCallback, &num_called));
273    // Destroy the instance before the network operation is completed.
274    // The cancelling callback should be called.
275  }
276  EXPECT_EQ(1, num_called);
277}
278
279}  // namespace internal
280
281class DriveFileStreamReaderTest : public ::testing::Test {
282 protected:
283  DriveFileStreamReaderTest()
284      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
285  }
286
287  virtual void SetUp() OVERRIDE {
288    worker_thread_.reset(new base::Thread("DriveFileStreamReaderTest"));
289    ASSERT_TRUE(worker_thread_->Start());
290
291    // Initialize FakeDriveService.
292    fake_drive_service_.reset(new FakeDriveService);
293    fake_drive_service_->LoadResourceListForWapi(
294        "gdata/root_feed.json");
295
296    // Create a testee instance.
297    fake_file_system_.reset(
298        new test_util::FakeFileSystem(fake_drive_service_.get()));
299  }
300
301  FileSystemInterface* GetFileSystem() {
302    return fake_file_system_.get();
303  }
304
305  DriveFileStreamReader::FileSystemGetter GetFileSystemGetter() {
306    return base::Bind(&DriveFileStreamReaderTest::GetFileSystem,
307                      base::Unretained(this));
308  }
309
310  content::TestBrowserThreadBundle thread_bundle_;
311
312  scoped_ptr<base::Thread> worker_thread_;
313
314  scoped_ptr<FakeDriveService> fake_drive_service_;
315  scoped_ptr<test_util::FakeFileSystem> fake_file_system_;
316};
317
318TEST_F(DriveFileStreamReaderTest, Read) {
319  const base::FilePath kDriveFile =
320      util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt");
321  // Create the reader, and initialize it.
322  // In this case, the file is not yet locally cached.
323  scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader(
324      GetFileSystemGetter(), worker_thread_->message_loop_proxy().get()));
325  EXPECT_FALSE(reader->IsInitialized());
326
327  int error = net::ERR_FAILED;
328  scoped_ptr<ResourceEntry> entry;
329  {
330    base::RunLoop run_loop;
331    reader->Initialize(
332        kDriveFile,
333        net::HttpByteRange(),
334        google_apis::test_util::CreateQuitCallback(
335            &run_loop,
336            google_apis::test_util::CreateCopyResultCallback(&error, &entry)));
337    run_loop.Run();
338  }
339  EXPECT_EQ(net::OK, error);
340  ASSERT_TRUE(entry);
341  EXPECT_TRUE(reader->IsInitialized());
342  size_t content_size = entry->file_info().size();
343
344  // Read data from the reader.
345  std::string first_content;
346  ASSERT_EQ(net::OK, test_util::ReadAllData(reader.get(), &first_content));
347  EXPECT_EQ(content_size, first_content.size());
348
349  // Create second instance and initialize it.
350  // In this case, the file should be cached one.
351  reader.reset(new DriveFileStreamReader(
352      GetFileSystemGetter(), worker_thread_->message_loop_proxy().get()));
353  EXPECT_FALSE(reader->IsInitialized());
354
355  error = net::ERR_FAILED;
356  entry.reset();
357  {
358    base::RunLoop run_loop;
359    reader->Initialize(
360        kDriveFile,
361        net::HttpByteRange(),
362        google_apis::test_util::CreateQuitCallback(
363            &run_loop,
364            google_apis::test_util::CreateCopyResultCallback(&error, &entry)));
365    run_loop.Run();
366  }
367  EXPECT_EQ(net::OK, error);
368  ASSERT_TRUE(entry);
369  EXPECT_TRUE(reader->IsInitialized());
370
371  // The size should be same.
372  EXPECT_EQ(content_size, static_cast<size_t>(entry->file_info().size()));
373
374  // Read data from the reader, again.
375  std::string second_content;
376  ASSERT_EQ(net::OK, test_util::ReadAllData(reader.get(), &second_content));
377
378  // The same content is expected.
379  EXPECT_EQ(first_content, second_content);
380}
381
382TEST_F(DriveFileStreamReaderTest, ReadRange) {
383  // In this test case, we just confirm that the part of file is read.
384  const int64 kRangeOffset = 3;
385  const int64 kRangeLength = 4;
386
387  const base::FilePath kDriveFile =
388      util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt");
389  // Create the reader, and initialize it.
390  // In this case, the file is not yet locally cached.
391  scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader(
392      GetFileSystemGetter(), worker_thread_->message_loop_proxy().get()));
393  EXPECT_FALSE(reader->IsInitialized());
394
395  int error = net::ERR_FAILED;
396  scoped_ptr<ResourceEntry> entry;
397  net::HttpByteRange byte_range;
398  byte_range.set_first_byte_position(kRangeOffset);
399  // Last byte position is inclusive.
400  byte_range.set_last_byte_position(kRangeOffset + kRangeLength - 1);
401  {
402    base::RunLoop run_loop;
403    reader->Initialize(
404        kDriveFile,
405        byte_range,
406        google_apis::test_util::CreateQuitCallback(
407            &run_loop,
408            google_apis::test_util::CreateCopyResultCallback(&error, &entry)));
409    run_loop.Run();
410  }
411  EXPECT_EQ(net::OK, error);
412  ASSERT_TRUE(entry);
413  EXPECT_TRUE(reader->IsInitialized());
414
415  // Read data from the reader.
416  std::string first_content;
417  ASSERT_EQ(net::OK, test_util::ReadAllData(reader.get(), &first_content));
418
419  // The length should be equal to range length.
420  EXPECT_EQ(kRangeLength, static_cast<int64>(first_content.size()));
421
422  // Create second instance and initialize it.
423  // In this case, the file should be cached one.
424  reader.reset(new DriveFileStreamReader(
425      GetFileSystemGetter(), worker_thread_->message_loop_proxy().get()));
426  EXPECT_FALSE(reader->IsInitialized());
427
428  error = net::ERR_FAILED;
429  entry.reset();
430  {
431    base::RunLoop run_loop;
432    reader->Initialize(
433        kDriveFile,
434        byte_range,
435        google_apis::test_util::CreateQuitCallback(
436            &run_loop,
437            google_apis::test_util::CreateCopyResultCallback(&error, &entry)));
438    run_loop.Run();
439  }
440  EXPECT_EQ(net::OK, error);
441  ASSERT_TRUE(entry);
442  EXPECT_TRUE(reader->IsInitialized());
443
444  // Read data from the reader, again.
445  std::string second_content;
446  ASSERT_EQ(net::OK, test_util::ReadAllData(reader.get(), &second_content));
447
448  // The same content is expected.
449  EXPECT_EQ(first_content, second_content);
450}
451
452TEST_F(DriveFileStreamReaderTest, OutOfRangeError) {
453  const int64 kRangeOffset = 1000000;  // Out of range.
454  const int64 kRangeLength = 4;
455
456  const base::FilePath kDriveFile =
457      util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt");
458  // Create the reader, and initialize it.
459  // In this case, the file is not yet locally cached.
460  scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader(
461      GetFileSystemGetter(), worker_thread_->message_loop_proxy().get()));
462  EXPECT_FALSE(reader->IsInitialized());
463
464  int error = net::ERR_FAILED;
465  scoped_ptr<ResourceEntry> entry;
466  net::HttpByteRange byte_range;
467  byte_range.set_first_byte_position(kRangeOffset);
468  // Last byte position is inclusive.
469  byte_range.set_last_byte_position(kRangeOffset + kRangeLength - 1);
470  {
471    base::RunLoop run_loop;
472    reader->Initialize(
473        kDriveFile,
474        byte_range,
475        google_apis::test_util::CreateQuitCallback(
476            &run_loop,
477            google_apis::test_util::CreateCopyResultCallback(&error, &entry)));
478    run_loop.Run();
479  }
480  EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE, error);
481  EXPECT_FALSE(entry);
482}
483
484TEST_F(DriveFileStreamReaderTest, ZeroByteFileRead) {
485  // Prepare an empty file
486  {
487    google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
488    scoped_ptr<google_apis::ResourceEntry> entry;
489    fake_drive_service_->AddNewFile(
490        "text/plain",
491        "",  // empty
492        fake_drive_service_->GetRootResourceId(),
493        "EmptyFile.txt",
494        false,  // shared_with_me
495        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
496    drive::test_util::RunBlockingPoolTask();
497    ASSERT_EQ(google_apis::HTTP_CREATED, error);
498    ASSERT_TRUE(entry);
499    ASSERT_EQ(0, entry->file_size());
500  }
501
502  const base::FilePath kDriveFile =
503      util::GetDriveMyDriveRootPath().AppendASCII("EmptyFile.txt");
504  // Create the reader, and initialize it.
505  // In this case, the file is not yet locally cached.
506  scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader(
507      GetFileSystemGetter(), worker_thread_->message_loop_proxy().get()));
508  EXPECT_FALSE(reader->IsInitialized());
509
510  int error = net::ERR_FAILED;
511  scoped_ptr<ResourceEntry> entry;
512  {
513    base::RunLoop run_loop;
514    reader->Initialize(
515        kDriveFile,
516        net::HttpByteRange(),
517        google_apis::test_util::CreateQuitCallback(
518            &run_loop,
519            google_apis::test_util::CreateCopyResultCallback(&error, &entry)));
520    run_loop.Run();
521  }
522  EXPECT_EQ(net::OK, error);
523  ASSERT_TRUE(entry);
524  ASSERT_EQ(0u, entry->file_info().size());  // It's a zero-byte file.
525  EXPECT_TRUE(reader->IsInitialized());
526
527  // Read data from the reader. Check that it successfuly reads empty data.
528  std::string first_content;
529  ASSERT_EQ(net::OK, test_util::ReadAllData(reader.get(), &first_content));
530  EXPECT_EQ(0u, first_content.size());
531
532  // Create second instance and initialize it.
533  // In this case, the file should be cached one.
534  reader.reset(new DriveFileStreamReader(
535      GetFileSystemGetter(), worker_thread_->message_loop_proxy().get()));
536  EXPECT_FALSE(reader->IsInitialized());
537
538  error = net::ERR_FAILED;
539  entry.reset();
540  {
541    base::RunLoop run_loop;
542    reader->Initialize(
543        kDriveFile,
544        net::HttpByteRange(),
545        google_apis::test_util::CreateQuitCallback(
546            &run_loop,
547            google_apis::test_util::CreateCopyResultCallback(&error, &entry)));
548    run_loop.Run();
549  }
550  EXPECT_EQ(net::OK, error);
551  ASSERT_TRUE(entry);
552  EXPECT_TRUE(reader->IsInitialized());
553
554  // Read data from the reader, again.
555  std::string second_content;
556  ASSERT_EQ(net::OK, test_util::ReadAllData(reader.get(), &second_content));
557  EXPECT_EQ(0u, second_content.size());
558}
559
560}  // namespace drive
561