file_stream_reader_unittest.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
1// Copyright 2014 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/file_system_provider/fileapi/file_stream_reader.h"
6
7#include <string>
8#include <vector>
9
10#include "base/files/file.h"
11#include "base/files/file_path.h"
12#include "base/files/scoped_temp_dir.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/memory/weak_ptr.h"
15#include "base/run_loop.h"
16#include "chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h"
17#include "chrome/browser/chromeos/file_system_provider/service.h"
18#include "chrome/browser/chromeos/file_system_provider/service_factory.h"
19#include "chrome/test/base/testing_browser_process.h"
20#include "chrome/test/base/testing_profile.h"
21#include "chrome/test/base/testing_profile_manager.h"
22#include "content/public/test/test_browser_thread_bundle.h"
23#include "content/public/test/test_file_system_context.h"
24#include "extensions/browser/extension_registry.h"
25#include "net/base/io_buffer.h"
26#include "net/base/net_errors.h"
27#include "testing/gtest/include/gtest/gtest.h"
28#include "webkit/browser/fileapi/async_file_util.h"
29#include "webkit/browser/fileapi/external_mount_points.h"
30#include "webkit/browser/fileapi/file_system_url.h"
31
32namespace chromeos {
33namespace file_system_provider {
34namespace {
35
36const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj";
37const char kFileSystemId[] = "testing-file-system";
38
39// Logs callbacks invocations on the file stream reader.
40class EventLogger {
41 public:
42  EventLogger() : weak_ptr_factory_(this) {}
43  virtual ~EventLogger() {}
44
45  void OnRead(int result) { results_.push_back(result); }
46  void OnGetLength(int64 result) { results_.push_back(result); }
47
48  base::WeakPtr<EventLogger> GetWeakPtr() {
49    return weak_ptr_factory_.GetWeakPtr();
50  }
51
52  const std::vector<int64>& results() const { return results_; }
53
54 private:
55  std::vector<int64> results_;
56  base::WeakPtrFactory<EventLogger> weak_ptr_factory_;
57
58  DISALLOW_COPY_AND_ASSIGN(EventLogger);
59};
60
61// Creates a cracked FileSystemURL for tests.
62storage::FileSystemURL CreateFileSystemURL(const std::string& mount_point_name,
63                                           const base::FilePath& file_path) {
64  const std::string origin = std::string("chrome-extension://") + kExtensionId;
65  const storage::ExternalMountPoints* const mount_points =
66      storage::ExternalMountPoints::GetSystemInstance();
67  return mount_points->CreateCrackedFileSystemURL(
68      GURL(origin),
69      storage::kFileSystemTypeExternal,
70      base::FilePath::FromUTF8Unsafe(mount_point_name).Append(file_path));
71}
72
73// Creates a Service instance. Used to be able to destroy the service in
74// TearDown().
75KeyedService* CreateService(content::BrowserContext* context) {
76  return new Service(Profile::FromBrowserContext(context),
77                     extensions::ExtensionRegistry::Get(context));
78}
79
80}  // namespace
81
82class FileSystemProviderFileStreamReader : public testing::Test {
83 protected:
84  FileSystemProviderFileStreamReader() {}
85  virtual ~FileSystemProviderFileStreamReader() {}
86
87  virtual void SetUp() OVERRIDE {
88    ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
89    profile_manager_.reset(
90        new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
91    ASSERT_TRUE(profile_manager_->SetUp());
92    profile_ = profile_manager_->CreateTestingProfile("testing-profile");
93
94    ServiceFactory::GetInstance()->SetTestingFactory(profile_, &CreateService);
95    Service* service = Service::Get(profile_);  // Owned by its factory.
96    service->SetFileSystemFactoryForTesting(
97        base::Bind(&FakeProvidedFileSystem::Create));
98
99    const bool result = service->MountFileSystem(kExtensionId,
100                                                 kFileSystemId,
101                                                 "Testing File System",
102                                                 false /* writable */);
103    ASSERT_TRUE(result);
104    FakeProvidedFileSystem* provided_file_system =
105        static_cast<FakeProvidedFileSystem*>(
106            service->GetProvidedFileSystem(kExtensionId, kFileSystemId));
107    ASSERT_TRUE(provided_file_system);
108    ASSERT_TRUE(provided_file_system->GetEntry(
109        base::FilePath::FromUTF8Unsafe(kFakeFilePath), &fake_file_));
110    const ProvidedFileSystemInfo& file_system_info =
111        service->GetProvidedFileSystem(kExtensionId, kFileSystemId)
112            ->GetFileSystemInfo();
113    const std::string mount_point_name =
114        file_system_info.mount_path().BaseName().AsUTF8Unsafe();
115
116    file_url_ = CreateFileSystemURL(
117        mount_point_name, base::FilePath::FromUTF8Unsafe(kFakeFilePath + 1));
118    ASSERT_TRUE(file_url_.is_valid());
119    wrong_file_url_ = CreateFileSystemURL(
120        mount_point_name, base::FilePath::FromUTF8Unsafe("im-not-here.txt"));
121    ASSERT_TRUE(wrong_file_url_.is_valid());
122  }
123
124  virtual void TearDown() OVERRIDE {
125    // Setting the testing factory to NULL will destroy the created service
126    // associated with the testing profile.
127    ServiceFactory::GetInstance()->SetTestingFactory(profile_, NULL);
128  }
129
130  content::TestBrowserThreadBundle thread_bundle_;
131  base::ScopedTempDir data_dir_;
132  scoped_ptr<TestingProfileManager> profile_manager_;
133  TestingProfile* profile_;  // Owned by TestingProfileManager.
134  FakeEntry fake_file_;
135  storage::FileSystemURL file_url_;
136  storage::FileSystemURL wrong_file_url_;
137};
138
139TEST_F(FileSystemProviderFileStreamReader, Read_AllAtOnce) {
140  EventLogger logger;
141
142  const int64 initial_offset = 0;
143  FileStreamReader reader(
144      NULL, file_url_, initial_offset, fake_file_.metadata.modification_time);
145  scoped_refptr<net::IOBuffer> io_buffer(
146      new net::IOBuffer(fake_file_.metadata.size));
147
148  const int result =
149      reader.Read(io_buffer.get(),
150                  fake_file_.metadata.size,
151                  base::Bind(&EventLogger::OnRead, logger.GetWeakPtr()));
152  EXPECT_EQ(net::ERR_IO_PENDING, result);
153  base::RunLoop().RunUntilIdle();
154
155  ASSERT_EQ(1u, logger.results().size());
156  EXPECT_LT(0, logger.results()[0]);
157  EXPECT_EQ(fake_file_.metadata.size, logger.results()[0]);
158
159  std::string buffer_as_string(io_buffer->data(), fake_file_.metadata.size);
160  EXPECT_EQ(fake_file_.contents, buffer_as_string);
161}
162
163TEST_F(FileSystemProviderFileStreamReader, Read_WrongFile) {
164  EventLogger logger;
165
166  const int64 initial_offset = 0;
167  FileStreamReader reader(NULL,
168                          wrong_file_url_,
169                          initial_offset,
170                          fake_file_.metadata.modification_time);
171  scoped_refptr<net::IOBuffer> io_buffer(
172      new net::IOBuffer(fake_file_.metadata.size));
173
174  const int result =
175      reader.Read(io_buffer.get(),
176                  fake_file_.metadata.size,
177                  base::Bind(&EventLogger::OnRead, logger.GetWeakPtr()));
178  EXPECT_EQ(net::ERR_IO_PENDING, result);
179  base::RunLoop().RunUntilIdle();
180
181  ASSERT_EQ(1u, logger.results().size());
182  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, logger.results()[0]);
183}
184
185TEST_F(FileSystemProviderFileStreamReader, Read_InChunks) {
186  EventLogger logger;
187
188  const int64 initial_offset = 0;
189  FileStreamReader reader(
190      NULL, file_url_, initial_offset, fake_file_.metadata.modification_time);
191
192  for (int64 offset = 0; offset < fake_file_.metadata.size; ++offset) {
193    scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(1));
194    const int result =
195        reader.Read(io_buffer.get(),
196                    1,
197                    base::Bind(&EventLogger::OnRead, logger.GetWeakPtr()));
198    EXPECT_EQ(net::ERR_IO_PENDING, result);
199    base::RunLoop().RunUntilIdle();
200    ASSERT_EQ(offset + 1, static_cast<int64>(logger.results().size()));
201    EXPECT_EQ(1, logger.results()[offset]);
202    EXPECT_EQ(fake_file_.contents[offset], io_buffer->data()[0]);
203  }
204}
205
206TEST_F(FileSystemProviderFileStreamReader, Read_Slice) {
207  EventLogger logger;
208
209  // Trim first 3 and last 3 characters.
210  const int64 initial_offset = 3;
211  const int length = fake_file_.metadata.size - initial_offset - 3;
212  ASSERT_GT(fake_file_.metadata.size, initial_offset);
213  ASSERT_LT(0, length);
214
215  FileStreamReader reader(
216      NULL, file_url_, initial_offset, fake_file_.metadata.modification_time);
217  scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(length));
218
219  const int result =
220      reader.Read(io_buffer.get(),
221                  length,
222                  base::Bind(&EventLogger::OnRead, logger.GetWeakPtr()));
223  EXPECT_EQ(net::ERR_IO_PENDING, result);
224  base::RunLoop().RunUntilIdle();
225
226  ASSERT_EQ(1u, logger.results().size());
227  EXPECT_EQ(length, logger.results()[0]);
228
229  std::string buffer_as_string(io_buffer->data(), length);
230  std::string expected_buffer(fake_file_.contents.data() + initial_offset,
231                              length);
232  EXPECT_EQ(expected_buffer, buffer_as_string);
233}
234
235TEST_F(FileSystemProviderFileStreamReader, Read_Beyond) {
236  EventLogger logger;
237
238  // Request reading 1KB more than available.
239  const int64 initial_offset = 0;
240  const int length = fake_file_.metadata.size + 1024;
241
242  FileStreamReader reader(
243      NULL, file_url_, initial_offset, fake_file_.metadata.modification_time);
244  scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(length));
245
246  const int result =
247      reader.Read(io_buffer.get(),
248                  length,
249                  base::Bind(&EventLogger::OnRead, logger.GetWeakPtr()));
250  EXPECT_EQ(net::ERR_IO_PENDING, result);
251  base::RunLoop().RunUntilIdle();
252
253  ASSERT_EQ(1u, logger.results().size());
254  EXPECT_LT(0, logger.results()[0]);
255  EXPECT_EQ(fake_file_.metadata.size, logger.results()[0]);
256
257  std::string buffer_as_string(io_buffer->data(), fake_file_.metadata.size);
258  EXPECT_EQ(fake_file_.contents, buffer_as_string);
259}
260
261TEST_F(FileSystemProviderFileStreamReader, Read_ModifiedFile) {
262  EventLogger logger;
263
264  const int64 initial_offset = 0;
265  FileStreamReader reader(NULL, file_url_, initial_offset, base::Time::Max());
266
267  scoped_refptr<net::IOBuffer> io_buffer(
268      new net::IOBuffer(fake_file_.metadata.size));
269  const int result =
270      reader.Read(io_buffer.get(),
271                  fake_file_.metadata.size,
272                  base::Bind(&EventLogger::OnRead, logger.GetWeakPtr()));
273
274  EXPECT_EQ(net::ERR_IO_PENDING, result);
275  base::RunLoop().RunUntilIdle();
276
277  ASSERT_EQ(1u, logger.results().size());
278  EXPECT_EQ(net::ERR_UPLOAD_FILE_CHANGED, logger.results()[0]);
279}
280
281TEST_F(FileSystemProviderFileStreamReader, Read_ExpectedModificationTimeNull) {
282  EventLogger logger;
283
284  const int64 initial_offset = 0;
285  FileStreamReader reader(NULL, file_url_, initial_offset, base::Time());
286
287  scoped_refptr<net::IOBuffer> io_buffer(
288      new net::IOBuffer(fake_file_.metadata.size));
289  const int result =
290      reader.Read(io_buffer.get(),
291                  fake_file_.metadata.size,
292                  base::Bind(&EventLogger::OnRead, logger.GetWeakPtr()));
293
294  EXPECT_EQ(net::ERR_IO_PENDING, result);
295  base::RunLoop().RunUntilIdle();
296
297  ASSERT_EQ(1u, logger.results().size());
298  EXPECT_EQ(fake_file_.metadata.size, logger.results()[0]);
299
300  std::string buffer_as_string(io_buffer->data(), fake_file_.metadata.size);
301  EXPECT_EQ(fake_file_.contents, buffer_as_string);
302}
303
304TEST_F(FileSystemProviderFileStreamReader, GetLength) {
305  EventLogger logger;
306
307  const int64 initial_offset = 0;
308  FileStreamReader reader(
309      NULL, file_url_, initial_offset, fake_file_.metadata.modification_time);
310
311  const int result = reader.GetLength(
312      base::Bind(&EventLogger::OnGetLength, logger.GetWeakPtr()));
313  EXPECT_EQ(net::ERR_IO_PENDING, result);
314  base::RunLoop().RunUntilIdle();
315
316  ASSERT_EQ(1u, logger.results().size());
317  EXPECT_LT(0, logger.results()[0]);
318  EXPECT_EQ(fake_file_.metadata.size, logger.results()[0]);
319}
320
321TEST_F(FileSystemProviderFileStreamReader, GetLength_WrongFile) {
322  EventLogger logger;
323
324  const int64 initial_offset = 0;
325  FileStreamReader reader(NULL,
326                          wrong_file_url_,
327                          initial_offset,
328                          fake_file_.metadata.modification_time);
329
330  const int result = reader.GetLength(
331      base::Bind(&EventLogger::OnGetLength, logger.GetWeakPtr()));
332  EXPECT_EQ(net::ERR_IO_PENDING, result);
333  base::RunLoop().RunUntilIdle();
334
335  ASSERT_EQ(1u, logger.results().size());
336  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, logger.results()[0]);
337}
338
339TEST_F(FileSystemProviderFileStreamReader, GetLength_ModifiedFile) {
340  EventLogger logger;
341
342  const int64 initial_offset = 0;
343  FileStreamReader reader(NULL, file_url_, initial_offset, base::Time::Max());
344
345  const int result = reader.GetLength(
346      base::Bind(&EventLogger::OnGetLength, logger.GetWeakPtr()));
347  EXPECT_EQ(net::ERR_IO_PENDING, result);
348  base::RunLoop().RunUntilIdle();
349
350  ASSERT_EQ(1u, logger.results().size());
351  EXPECT_EQ(net::ERR_UPLOAD_FILE_CHANGED, logger.results()[0]);
352}
353
354TEST_F(FileSystemProviderFileStreamReader,
355       GetLength_ExpectedModificationTimeNull) {
356  EventLogger logger;
357
358  const int64 initial_offset = 0;
359  FileStreamReader reader(NULL, file_url_, initial_offset, base::Time());
360
361  const int result = reader.GetLength(
362      base::Bind(&EventLogger::OnGetLength, logger.GetWeakPtr()));
363  EXPECT_EQ(net::ERR_IO_PENDING, result);
364  base::RunLoop().RunUntilIdle();
365
366  ASSERT_EQ(1u, logger.results().size());
367  EXPECT_LT(0, logger.results()[0]);
368  EXPECT_EQ(fake_file_.metadata.size, logger.results()[0]);
369}
370
371}  // namespace file_system_provider
372}  // namespace chromeos
373