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