1 // Copyright 2015 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/throttled_file_system.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <vector>
11 
12 #include "base/bind.h"
13 #include "base/files/file.h"
14 #include "base/run_loop.h"
15 #include "chrome/browser/chromeos/file_system_provider/abort_callback.h"
16 #include "chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h"
17 #include "chrome/browser/chromeos/file_system_provider/icon_set.h"
18 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
19 #include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
20 #include "content/public/test/browser_task_environment.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 
23 namespace chromeos {
24 namespace file_system_provider {
25 namespace {
26 
27 const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj";
28 const char kFileSystemId[] = "camera-pictures";
29 const char kDisplayName[] = "Camera Pictures";
30 
31 typedef std::vector<base::File::Error> StatusLog;
32 typedef std::vector<std::pair<int, base::File::Error>> OpenLog;
33 
34 // Writes a |result| to the |log| vector for a status callback.
LogStatus(StatusLog * log,base::File::Error result)35 void LogStatus(StatusLog* log, base::File::Error result) {
36   log->push_back(result);
37 }
38 
39 // Writes a |result| to the |log| vector for opening a file.
LogOpen(OpenLog * log,int handle,base::File::Error result)40 void LogOpen(OpenLog* log, int handle, base::File::Error result) {
41   log->push_back(std::make_pair(handle, result));
42 }
43 
44 }  // namespace
45 
46 class FileSystemProviderThrottledFileSystemTest : public testing::Test {
47  protected:
FileSystemProviderThrottledFileSystemTest()48   FileSystemProviderThrottledFileSystemTest() {}
~FileSystemProviderThrottledFileSystemTest()49   ~FileSystemProviderThrottledFileSystemTest() override {}
50 
SetUp()51   void SetUp() override {}
52 
53   // Initializes the throttled file system with |limit| number of opened files
54   // at once. If 0, then no limit.
SetUpFileSystem(size_t limit)55   void SetUpFileSystem(size_t limit) {
56     MountOptions options(kFileSystemId, kDisplayName);
57     options.opened_files_limit = limit;
58 
59     ProvidedFileSystemInfo file_system_info(
60         kExtensionId, options, base::FilePath() /* mount_path */,
61         false /* configurable */, true /* watchable */, extensions::SOURCE_FILE,
62         IconSet());
63 
64     file_system_.reset(new ThrottledFileSystem(
65         std::make_unique<FakeProvidedFileSystem>(file_system_info)));
66   }
67 
68   content::BrowserTaskEnvironment task_environment_;
69   std::unique_ptr<ThrottledFileSystem> file_system_;
70 };
71 
TEST_F(FileSystemProviderThrottledFileSystemTest,OpenFile_LimitedToOneAtOnce)72 TEST_F(FileSystemProviderThrottledFileSystemTest, OpenFile_LimitedToOneAtOnce) {
73   SetUpFileSystem(1);
74 
75   OpenLog first_open_log;
76   file_system_->OpenFile(base::FilePath(kFakeFilePath), OPEN_FILE_MODE_READ,
77                          base::BindOnce(&LogOpen, &first_open_log));
78 
79   OpenLog second_open_log;
80   file_system_->OpenFile(base::FilePath(kFakeFilePath), OPEN_FILE_MODE_READ,
81                          base::BindOnce(&LogOpen, &second_open_log));
82 
83   base::RunLoop().RunUntilIdle();
84 
85   ASSERT_EQ(1u, first_open_log.size());
86   EXPECT_EQ(base::File::FILE_OK, first_open_log[0].second);
87   EXPECT_EQ(0u, second_open_log.size());
88 
89   // Close the first file.
90   StatusLog close_log;
91   file_system_->CloseFile(first_open_log[0].first,
92                           base::BindOnce(&LogStatus, &close_log));
93 
94   base::RunLoop().RunUntilIdle();
95   ASSERT_EQ(1u, close_log.size());
96   EXPECT_EQ(base::File::FILE_OK, close_log[0]);
97 
98   // The second enqueued file should be opened.
99   ASSERT_EQ(1u, first_open_log.size());
100   EXPECT_EQ(base::File::FILE_OK, first_open_log[0].second);
101   ASSERT_EQ(1u, second_open_log.size());
102   EXPECT_EQ(base::File::FILE_OK, second_open_log[0].second);
103 }
104 
TEST_F(FileSystemProviderThrottledFileSystemTest,OpenFile_NoLimit)105 TEST_F(FileSystemProviderThrottledFileSystemTest, OpenFile_NoLimit) {
106   SetUpFileSystem(0);  // No limit.
107 
108   OpenLog first_open_log;
109   file_system_->OpenFile(base::FilePath(kFakeFilePath), OPEN_FILE_MODE_READ,
110                          base::BindOnce(&LogOpen, &first_open_log));
111 
112   OpenLog second_open_log;
113   file_system_->OpenFile(base::FilePath(kFakeFilePath), OPEN_FILE_MODE_READ,
114                          base::BindOnce(&LogOpen, &second_open_log));
115 
116   base::RunLoop().RunUntilIdle();
117 
118   ASSERT_EQ(1u, first_open_log.size());
119   EXPECT_EQ(base::File::FILE_OK, first_open_log[0].second);
120   ASSERT_EQ(1u, second_open_log.size());
121   EXPECT_EQ(base::File::FILE_OK, second_open_log[0].second);
122 
123   // Close files.
124   StatusLog first_close_log;
125   file_system_->CloseFile(first_open_log[0].first,
126                           base::BindOnce(&LogStatus, &first_close_log));
127 
128   StatusLog second_close_log;
129   file_system_->CloseFile(second_open_log[0].first,
130                           base::BindOnce(&LogStatus, &second_close_log));
131 
132   base::RunLoop().RunUntilIdle();
133   ASSERT_EQ(1u, first_close_log.size());
134   EXPECT_EQ(base::File::FILE_OK, first_close_log[0]);
135   ASSERT_EQ(1u, second_close_log.size());
136   EXPECT_EQ(base::File::FILE_OK, second_close_log[0]);
137 
138   // Confirm, that files are not opened again.
139   EXPECT_EQ(1u, first_open_log.size());
140   EXPECT_EQ(1u, second_open_log.size());
141 }
142 
TEST_F(FileSystemProviderThrottledFileSystemTest,AbortAfterRun)143 TEST_F(FileSystemProviderThrottledFileSystemTest, AbortAfterRun) {
144   SetUpFileSystem(1);
145 
146   OpenLog first_open_log;
147   AbortCallback abort_callback =
148       file_system_->OpenFile(base::FilePath(kFakeFilePath), OPEN_FILE_MODE_READ,
149                              base::BindOnce(&LogOpen, &first_open_log));
150 
151   OpenLog second_open_log;
152   file_system_->OpenFile(base::FilePath(kFakeFilePath), OPEN_FILE_MODE_READ,
153                          base::BindOnce(&LogOpen, &second_open_log));
154 
155   base::RunLoop().RunUntilIdle();
156 
157   ASSERT_EQ(1u, first_open_log.size());
158   EXPECT_EQ(base::File::FILE_OK, first_open_log[0].second);
159   EXPECT_EQ(0u, second_open_log.size());
160 }
161 
162 }  // namespace file_system_provider
163 }  // namespace chromeos
164