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