Elim cr-checkbox
[chromium-blink-merge.git] / ppapi / proxy / file_system_resource_unittest.cc
blob9b5d981242dd92a9c159d4f612c7e0f79e226d4c
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.
5 #include "base/message_loop/message_loop.h"
6 #include "ppapi/c/pp_errors.h"
7 #include "ppapi/c/ppb_file_io.h"
8 #include "ppapi/c/ppb_file_ref.h"
9 #include "ppapi/c/ppb_file_system.h"
10 #include "ppapi/proxy/file_system_resource.h"
11 #include "ppapi/proxy/locking_resource_releaser.h"
12 #include "ppapi/proxy/plugin_message_filter.h"
13 #include "ppapi/proxy/ppapi_message_utils.h"
14 #include "ppapi/proxy/ppapi_messages.h"
15 #include "ppapi/proxy/ppapi_proxy_test.h"
16 #include "ppapi/shared_impl/proxy_lock.h"
17 #include "ppapi/shared_impl/scoped_pp_var.h"
18 #include "ppapi/shared_impl/var.h"
19 #include "ppapi/thunk/enter.h"
20 #include "ppapi/thunk/ppb_file_system_api.h"
21 #include "ppapi/thunk/thunk.h"
23 using ppapi::proxy::ResourceMessageTestSink;
24 using ppapi::thunk::EnterResource;
25 using ppapi::thunk::PPB_FileSystem_API;
27 namespace ppapi {
28 namespace proxy {
30 namespace {
32 const int64_t kExpectedFileSystemSize = 100;
33 const int64_t kQuotaRequestAmount1 = 10;
34 const int64_t kQuotaRequestAmount2 = 20;
36 class MockCompletionCallback {
37 public:
38 MockCompletionCallback() : called_(false) {}
40 bool called() { return called_; }
41 int32_t result() { return result_; }
43 static void Callback(void* user_data, int32_t result) {
44 MockCompletionCallback* that =
45 reinterpret_cast<MockCompletionCallback*>(user_data);
46 that->called_ = true;
47 that->result_ = result;
50 private:
51 bool called_;
52 int32_t result_;
55 class MockRequestQuotaCallback {
56 public:
57 MockRequestQuotaCallback() : called_(false) {}
59 bool called() { return called_; }
60 int64_t result() { return result_; }
62 void Reset() { called_ = false; }
64 void Callback(int64_t result) {
65 ASSERT_FALSE(called_);
66 called_ = true;
67 result_ = result;
70 private:
71 bool called_;
72 int64_t result_;
75 class FileSystemResourceTest : public PluginProxyTest {
76 public:
77 const PPB_FileSystem_1_0* file_system_iface;
78 const PPB_FileRef_1_1* file_ref_iface;
79 const PPB_FileIO_1_1* file_io_iface;
81 FileSystemResourceTest()
82 : file_system_iface(thunk::GetPPB_FileSystem_1_0_Thunk()),
83 file_ref_iface(thunk::GetPPB_FileRef_1_1_Thunk()),
84 file_io_iface(thunk::GetPPB_FileIO_1_1_Thunk()) {
87 void SendReply(const ResourceMessageCallParams& params,
88 int32_t result,
89 const IPC::Message& nested_message) {
90 ResourceMessageReplyParams reply_params(params.pp_resource(),
91 params.sequence());
92 reply_params.set_result(result);
93 PluginMessageFilter::DispatchResourceReplyForTest(
94 reply_params, nested_message);
97 void SendOpenReply(const ResourceMessageCallParams& params, int32_t result) {
98 SendReply(params, result, PpapiPluginMsg_FileSystem_OpenReply());
101 // Opens the given file system.
102 void OpenFileSystem(PP_Resource file_system) {
103 MockCompletionCallback cb;
104 int32_t result = file_system_iface->Open(
105 file_system,
106 kExpectedFileSystemSize,
107 PP_MakeCompletionCallback(&MockCompletionCallback::Callback, &cb));
108 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
110 // Should have sent two new "open" messages to the browser and renderer.
111 ResourceMessageTestSink::ResourceCallVector open_messages =
112 sink().GetAllResourceCallsMatching(PpapiHostMsg_FileSystem_Open::ID);
113 ASSERT_EQ(2U, open_messages.size());
114 sink().ClearMessages();
116 // The resource is expecting two replies.
117 SendOpenReply(open_messages[0].first, PP_OK);
118 SendOpenReply(open_messages[1].first, PP_OK);
120 ASSERT_TRUE(cb.called());
121 ASSERT_EQ(PP_OK, cb.result());
124 // Opens the given file in the given file system. Since there is no host,
125 // the file handle will be invalid.
126 void OpenFile(PP_Resource file_io,
127 PP_Resource file_ref,
128 PP_Resource file_system) {
129 MockCompletionCallback cb;
130 int32_t result = file_io_iface->Open(
131 file_io,
132 file_ref,
133 PP_FILEOPENFLAG_WRITE,
134 PP_MakeCompletionCallback(&MockCompletionCallback::Callback, &cb));
135 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
137 // Should have sent an "open" message.
138 ResourceMessageCallParams params;
139 IPC::Message msg;
140 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
141 PpapiHostMsg_FileIO_Open::ID, &params, &msg));
142 sink().ClearMessages();
144 // Send a success reply.
145 ResourceMessageReplyParams reply_params(params.pp_resource(),
146 params.sequence());
147 reply_params.set_result(PP_OK);
148 PluginMessageFilter::DispatchResourceReplyForTest(
149 reply_params,
150 PpapiPluginMsg_FileIO_OpenReply(file_system,
151 0 /* max_written_offset */));
155 } // namespace
157 // Test that Open fails if either host returns failure. The other tests exercise
158 // the case where both hosts return PP_OK.
159 TEST_F(FileSystemResourceTest, OpenFailure) {
160 // Fail if the first reply doesn't return PP_OK.
162 LockingResourceReleaser file_system(
163 file_system_iface->Create(pp_instance(),
164 PP_FILESYSTEMTYPE_LOCALTEMPORARY));
166 MockCompletionCallback cb;
167 int32_t result = file_system_iface->Open(
168 file_system.get(),
169 kExpectedFileSystemSize,
170 PP_MakeCompletionCallback(&MockCompletionCallback::Callback, &cb));
171 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
173 ResourceMessageTestSink::ResourceCallVector open_messages =
174 sink().GetAllResourceCallsMatching(PpapiHostMsg_FileSystem_Open::ID);
175 ASSERT_EQ(2U, open_messages.size());
176 sink().ClearMessages();
178 SendOpenReply(open_messages[0].first, PP_ERROR_FAILED);
179 SendOpenReply(open_messages[1].first, PP_OK);
181 ASSERT_TRUE(cb.called());
182 ASSERT_EQ(PP_ERROR_FAILED, cb.result());
184 // Fail if the second reply doesn't return PP_OK.
186 LockingResourceReleaser file_system(
187 file_system_iface->Create(pp_instance(),
188 PP_FILESYSTEMTYPE_LOCALTEMPORARY));
190 MockCompletionCallback cb;
191 int32_t result = file_system_iface->Open(
192 file_system.get(),
193 kExpectedFileSystemSize,
194 PP_MakeCompletionCallback(&MockCompletionCallback::Callback, &cb));
195 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
197 ResourceMessageTestSink::ResourceCallVector open_messages =
198 sink().GetAllResourceCallsMatching(PpapiHostMsg_FileSystem_Open::ID);
199 ASSERT_EQ(2U, open_messages.size());
200 sink().ClearMessages();
202 SendOpenReply(open_messages[0].first, PP_OK);
203 SendOpenReply(open_messages[1].first, PP_ERROR_FAILED);
205 ASSERT_TRUE(cb.called());
206 ASSERT_EQ(PP_ERROR_FAILED, cb.result());
210 TEST_F(FileSystemResourceTest, RequestQuota) {
211 LockingResourceReleaser file_system(
212 file_system_iface->Create(pp_instance(),
213 PP_FILESYSTEMTYPE_LOCALTEMPORARY));
215 OpenFileSystem(file_system.get());
217 // Create and open two files in the file system. FileIOResource calls
218 // FileSystemResource::OpenQuotaFile on success.
219 LockingResourceReleaser file_ref1(
220 file_ref_iface->Create(file_system.get(), "/file1"));
221 LockingResourceReleaser file_io1(file_io_iface->Create(pp_instance()));
222 OpenFile(file_io1.get(), file_ref1.get(), file_system.get());
223 LockingResourceReleaser file_ref2(
224 file_ref_iface->Create(file_system.get(), "/file2"));
225 LockingResourceReleaser file_io2(file_io_iface->Create(pp_instance()));
226 OpenFile(file_io2.get(), file_ref2.get(), file_system.get());
228 EnterResource<PPB_FileSystem_API> enter(file_system.get(), true);
229 ASSERT_FALSE(enter.failed());
230 PPB_FileSystem_API* file_system_api = enter.object();
232 MockRequestQuotaCallback cb1;
233 int64_t result = file_system_api->RequestQuota(
234 kQuotaRequestAmount1,
235 base::Bind(&MockRequestQuotaCallback::Callback, base::Unretained(&cb1)));
236 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
238 // Should have sent a "reserve quota" message, with the amount of the request
239 // and a map of all currently open files to their max written offsets.
240 ResourceMessageCallParams params;
241 IPC::Message msg;
242 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
243 PpapiHostMsg_FileSystem_ReserveQuota::ID, &params, &msg));
244 sink().ClearMessages();
246 int64_t amount = 0;
247 FileGrowthMap file_growths;
248 ASSERT_TRUE(UnpackMessage<PpapiHostMsg_FileSystem_ReserveQuota>(
249 msg, &amount, &file_growths));
250 ASSERT_EQ(kQuotaRequestAmount1, amount);
251 ASSERT_EQ(2U, file_growths.size());
252 ASSERT_EQ(0, file_growths[file_io1.get()].max_written_offset);
253 ASSERT_EQ(0, file_growths[file_io2.get()].max_written_offset);
255 // Make another request while the "reserve quota" message is pending.
256 MockRequestQuotaCallback cb2;
257 result = file_system_api->RequestQuota(
258 kQuotaRequestAmount2,
259 base::Bind(&MockRequestQuotaCallback::Callback, base::Unretained(&cb2)));
260 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
261 // No new "reserve quota" message should be sent while one is pending.
262 ASSERT_FALSE(sink().GetFirstResourceCallMatching(
263 PpapiHostMsg_FileSystem_ReserveQuota::ID, &params, &msg));
265 ProxyAutoUnlock unlock_to_prevent_deadlock;
266 // Reply with quota reservation amount sufficient to cover both requests.
267 // Both callbacks should be called with the requests granted.
268 SendReply(params,
269 PP_OK,
270 PpapiPluginMsg_FileSystem_ReserveQuotaReply(
271 kQuotaRequestAmount1 + kQuotaRequestAmount2,
272 FileGrowthMapToFileSizeMapForTesting(file_growths)));
274 ASSERT_TRUE(cb1.called());
275 ASSERT_EQ(kQuotaRequestAmount1, cb1.result());
276 ASSERT_TRUE(cb2.called());
277 ASSERT_EQ(kQuotaRequestAmount2, cb2.result());
278 cb1.Reset();
279 cb2.Reset();
281 // All requests should fail when insufficient quota is returned to satisfy
282 // the first request.
283 result = file_system_api->RequestQuota(
284 kQuotaRequestAmount1,
285 base::Bind(&MockRequestQuotaCallback::Callback, base::Unretained(&cb1)));
286 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
287 result = file_system_api->RequestQuota(
288 kQuotaRequestAmount2,
289 base::Bind(&MockRequestQuotaCallback::Callback, base::Unretained(&cb2)));
290 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
292 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
293 PpapiHostMsg_FileSystem_ReserveQuota::ID, &params, &msg));
294 sink().ClearMessages();
296 ProxyAutoUnlock unlock_to_prevent_deadlock;
297 // Reply with quota reservation amount insufficient to cover the first
298 // request.
299 SendReply(params,
300 PP_OK,
301 PpapiPluginMsg_FileSystem_ReserveQuotaReply(
302 kQuotaRequestAmount1 - 1,
303 FileGrowthMapToFileSizeMapForTesting(file_growths)));
305 ASSERT_TRUE(cb1.called());
306 ASSERT_EQ(0, cb1.result());
307 ASSERT_TRUE(cb2.called());
308 ASSERT_EQ(0, cb2.result());
309 cb1.Reset();
310 cb2.Reset();
312 // A new request should be made if the quota reservation is enough to satisfy
313 // at least one request.
314 result = file_system_api->RequestQuota(
315 kQuotaRequestAmount1,
316 base::Bind(&MockRequestQuotaCallback::Callback, base::Unretained(&cb1)));
317 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
318 result = file_system_api->RequestQuota(
319 kQuotaRequestAmount2,
320 base::Bind(&MockRequestQuotaCallback::Callback, base::Unretained(&cb2)));
321 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
323 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
324 PpapiHostMsg_FileSystem_ReserveQuota::ID, &params, &msg));
325 sink().ClearMessages();
327 ProxyAutoUnlock unlock_to_prevent_deadlock;
328 // Reply with quota reservation amount sufficient only to cover the first
329 // request.
330 SendReply(params,
331 PP_OK,
332 PpapiPluginMsg_FileSystem_ReserveQuotaReply(
333 kQuotaRequestAmount1,
334 FileGrowthMapToFileSizeMapForTesting(file_growths)));
336 ASSERT_TRUE(cb1.called());
337 ASSERT_EQ(kQuotaRequestAmount1, cb1.result());
338 ASSERT_FALSE(cb2.called());
340 // Another request message should have been sent.
341 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
342 PpapiHostMsg_FileSystem_ReserveQuota::ID, &params, &msg));
343 sink().ClearMessages();
345 ProxyAutoUnlock unlock_to_prevent_deadlock;
346 // Reply with quota reservation amount sufficient to cover the second
347 // request and some extra.
348 SendReply(params,
349 PP_OK,
350 PpapiPluginMsg_FileSystem_ReserveQuotaReply(
351 kQuotaRequestAmount1 + kQuotaRequestAmount2,
352 FileGrowthMapToFileSizeMapForTesting(file_growths)));
355 ASSERT_TRUE(cb2.called());
356 ASSERT_EQ(kQuotaRequestAmount2, cb2.result());
357 cb1.Reset();
358 cb2.Reset();
360 // There is kQuotaRequestAmount1 of quota left, and a request for it should
361 // succeed immediately.
362 result = file_system_api->RequestQuota(
363 kQuotaRequestAmount1,
364 base::Bind(&MockRequestQuotaCallback::Callback, base::Unretained(&cb1)));
365 ASSERT_EQ(kQuotaRequestAmount1, result);
368 } // namespace proxy
369 } // namespace ppapi