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