OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/memory/ref_counted.h" | 6 #include "base/memory/ref_counted.h" |
7 #include "base/message_loop/message_loop.h" | 7 #include "base/message_loop/message_loop.h" |
8 #include "base/run_loop.h" | |
9 #include "base/synchronization/waitable_event.h" | |
10 #include "base/threading/simple_thread.h" | |
8 #include "ppapi/c/pp_completion_callback.h" | 11 #include "ppapi/c/pp_completion_callback.h" |
9 #include "ppapi/c/pp_errors.h" | 12 #include "ppapi/c/pp_errors.h" |
13 #include "ppapi/proxy/ppapi_proxy_test.h" | |
14 #include "ppapi/proxy/ppb_message_loop_proxy.h" | |
10 #include "ppapi/shared_impl/callback_tracker.h" | 15 #include "ppapi/shared_impl/callback_tracker.h" |
11 #include "ppapi/shared_impl/proxy_lock.h" | 16 #include "ppapi/shared_impl/proxy_lock.h" |
12 #include "ppapi/shared_impl/resource.h" | 17 #include "ppapi/shared_impl/resource.h" |
13 #include "ppapi/shared_impl/resource_tracker.h" | 18 #include "ppapi/shared_impl/resource_tracker.h" |
19 #include "ppapi/shared_impl/scoped_pp_resource.h" | |
14 #include "ppapi/shared_impl/test_globals.h" | 20 #include "ppapi/shared_impl/test_globals.h" |
15 #include "ppapi/shared_impl/tracked_callback.h" | 21 #include "ppapi/shared_impl/tracked_callback.h" |
16 #include "testing/gtest/include/gtest/gtest.h" | 22 #include "testing/gtest/include/gtest/gtest.h" |
17 | 23 |
24 // Note, this file tests TrackedCallback which lives in ppapi/shared_impl. | |
25 // Unfortunately, we need the test to live in ppapi/proxy so that it can use | |
26 // the thread support there. | |
18 namespace ppapi { | 27 namespace ppapi { |
28 namespace proxy { | |
19 | 29 |
20 namespace { | 30 namespace { |
21 | 31 |
22 class TrackedCallbackTest : public testing::Test { | 32 class CallbackThread : public base::SimpleThread { |
23 public: | 33 public: |
24 TrackedCallbackTest() : pp_instance_(1234) {} | 34 explicit CallbackThread(PP_Instance instance) |
35 : SimpleThread("CallbackThread"), instance_(instance) {} | |
36 ~CallbackThread() override {} | |
25 | 37 |
26 PP_Instance pp_instance() const { return pp_instance_; } | 38 // base::SimpleThread overrides. |
27 | 39 void Start() override { |
28 virtual void SetUp() override { | 40 { |
29 ProxyAutoLock lock; | 41 ProxyAutoLock acquire; |
30 globals_.GetResourceTracker()->DidCreateInstance(pp_instance_); | 42 // Create the message loop here, after PpapiGlobals has been created. |
43 message_loop_ = new MessageLoopResource(instance_); | |
44 } | |
45 base::SimpleThread::Start(); | |
31 } | 46 } |
32 virtual void TearDown() override { | 47 void Join() override { |
33 ProxyAutoLock lock; | 48 { |
34 globals_.GetResourceTracker()->DidDeleteInstance(pp_instance_); | 49 ProxyAutoLock acquire; |
50 message_loop()->PostQuit(PP_TRUE); | |
51 message_loop_ = nullptr; | |
52 } | |
53 base::SimpleThread::Join(); | |
54 } | |
55 void Run() override { | |
56 ProxyAutoLock acquire; | |
57 // Make a local copy of message_loop_ for this thread so we can interact | |
58 // with it even after the main thread releases it. | |
59 scoped_refptr<MessageLoopResource> message_loop(message_loop_); | |
60 message_loop->AttachToCurrentThread(); | |
61 // Note, run releases the lock to run events. | |
62 message_loop->Run(); | |
63 message_loop->DetachFromThread(); | |
35 } | 64 } |
36 | 65 |
66 MessageLoopResource* message_loop() { return message_loop_.get(); } | |
67 | |
37 private: | 68 private: |
38 base::MessageLoop message_loop_; | 69 PP_Instance instance_; |
39 TestGlobals globals_; | 70 scoped_refptr<MessageLoopResource> message_loop_; |
40 PP_Instance pp_instance_; | 71 }; |
72 | |
73 class TrackedCallbackTest : public PluginProxyTest { | |
74 public: | |
75 TrackedCallbackTest() : thread_(pp_instance()) {} | |
76 CallbackThread& thread() { return thread_; } | |
77 | |
78 private: | |
79 // PluginProxyTest overrides. | |
80 void SetUp() override { | |
81 PluginProxyTest::SetUp(); | |
82 thread_.Start(); | |
83 } | |
84 void TearDown() override { | |
85 thread_.Join(); | |
86 PluginProxyTest::TearDown(); | |
87 base::RunLoop run_loop; | |
88 run_loop.RunUntilIdle(); | |
89 } | |
90 CallbackThread thread_; | |
41 }; | 91 }; |
42 | 92 |
43 // All valid results (PP_OK, PP_ERROR_...) are nonpositive. | 93 // All valid results (PP_OK, PP_ERROR_...) are nonpositive. |
44 const int32_t kInitializedResultValue = 1; | 94 const int32_t kInitializedResultValue = 1; |
45 const int32_t kOverrideResultValue = 2; | 95 const int32_t kOverrideResultValue = 2; |
46 | 96 |
47 struct CallbackRunInfo { | 97 struct CallbackRunInfo { |
48 CallbackRunInfo() | 98 explicit CallbackRunInfo(base::ThreadChecker* thread_checker) |
49 : run_count(0), | 99 : run_count_(0), |
50 result(kInitializedResultValue), | 100 result_(kInitializedResultValue), |
51 completion_task_run_count(0), | 101 completion_task_run_count_(0), |
52 completion_task_result(kInitializedResultValue) {} | 102 completion_task_result_(kInitializedResultValue), |
53 unsigned run_count; | 103 thread_checker_(thread_checker), |
54 int32_t result; | 104 callback_did_run_event_(true, false) {} |
55 unsigned completion_task_run_count; | 105 void CallbackDidRun(int32_t result) { |
56 int32_t completion_task_result; | 106 CHECK(thread_checker_->CalledOnValidThread()); |
107 if (!run_count_) | |
108 result_ = result; | |
109 ++run_count_; | |
110 callback_did_run_event_.Signal(); | |
111 } | |
112 void CompletionTaskDidRun(int32_t result) { | |
113 CHECK(thread_checker_->CalledOnValidThread()); | |
114 if (!completion_task_run_count_) | |
115 completion_task_result_ = result; | |
116 ++completion_task_run_count_; | |
117 } | |
118 void WaitUntilCompleted() { callback_did_run_event_.Wait(); } | |
bbudge
2015/03/31 21:18:47
nit: Even though it's a one-liner, it would be nic
dmichael (off chromium)
2015/03/31 21:57:26
Done.
| |
119 unsigned run_count() { return run_count_; } | |
120 int32_t result() { return result_; } | |
121 unsigned completion_task_run_count() { return completion_task_run_count_; } | |
122 int32_t completion_task_result() { return completion_task_result_; } | |
123 private: | |
bbudge
2015/03/31 21:18:47
nit: space above private:
dmichael (off chromium)
2015/03/31 21:57:27
Done.
| |
124 unsigned run_count_; | |
125 int32_t result_; | |
126 unsigned completion_task_run_count_; | |
127 int32_t completion_task_result_; | |
128 // Weak; owned by the creator of CallbackRunInfo. | |
129 base::ThreadChecker* thread_checker_; | |
130 | |
131 base::WaitableEvent callback_did_run_event_; | |
57 }; | 132 }; |
58 | 133 |
59 void TestCallback(void* user_data, int32_t result) { | 134 void TestCallback(void* user_data, int32_t result) { |
60 CallbackRunInfo* info = reinterpret_cast<CallbackRunInfo*>(user_data); | 135 CallbackRunInfo* info = static_cast<CallbackRunInfo*>(user_data); |
61 info->run_count++; | 136 info->CallbackDidRun(result); |
62 if (info->run_count == 1) | |
63 info->result = result; | |
64 } | 137 } |
65 | 138 |
66 } // namespace | |
67 | |
68 // CallbackShutdownTest -------------------------------------------------------- | 139 // CallbackShutdownTest -------------------------------------------------------- |
69 | 140 |
70 namespace { | |
71 | |
72 class CallbackShutdownTest : public TrackedCallbackTest { | 141 class CallbackShutdownTest : public TrackedCallbackTest { |
73 public: | 142 public: |
74 CallbackShutdownTest() {} | 143 CallbackShutdownTest() : info_did_run_(&thread_checker_), |
144 info_did_abort_(&thread_checker_), | |
145 info_didnt_run_(&thread_checker_) {} | |
75 | 146 |
76 // Cases: | 147 // Cases: |
77 // (1) A callback which is run (so shouldn't be aborted on shutdown). | 148 // (1) A callback which is run (so shouldn't be aborted on shutdown). |
78 // (2) A callback which is aborted (so shouldn't be aborted on shutdown). | 149 // (2) A callback which is aborted (so shouldn't be aborted on shutdown). |
79 // (3) A callback which isn't run (so should be aborted on shutdown). | 150 // (3) A callback which isn't run (so should be aborted on shutdown). |
80 CallbackRunInfo& info_did_run() { return info_did_run_; } // (1) | 151 CallbackRunInfo& info_did_run() { return info_did_run_; } // (1) |
81 CallbackRunInfo& info_did_abort() { return info_did_abort_; } // (2) | 152 CallbackRunInfo& info_did_abort() { return info_did_abort_; } // (2) |
82 CallbackRunInfo& info_didnt_run() { return info_didnt_run_; } // (3) | 153 CallbackRunInfo& info_didnt_run() { return info_didnt_run_; } // (3) |
83 | 154 |
84 private: | 155 private: |
156 base::ThreadChecker thread_checker_; | |
85 CallbackRunInfo info_did_run_; | 157 CallbackRunInfo info_did_run_; |
86 CallbackRunInfo info_did_abort_; | 158 CallbackRunInfo info_did_abort_; |
87 CallbackRunInfo info_didnt_run_; | 159 CallbackRunInfo info_didnt_run_; |
88 }; | 160 }; |
89 | 161 |
90 } // namespace | 162 } // namespace |
91 | 163 |
92 // Tests that callbacks are properly aborted on module shutdown. | 164 // Tests that callbacks are properly aborted on module shutdown. |
93 TEST_F(CallbackShutdownTest, AbortOnShutdown) { | 165 TEST_F(CallbackShutdownTest, AbortOnShutdown) { |
94 ProxyAutoLock lock; | 166 ProxyAutoLock lock; |
95 scoped_refptr<Resource> resource(new Resource(OBJECT_IS_IMPL, pp_instance())); | 167 scoped_refptr<Resource> resource( |
168 new Resource(OBJECT_IS_PROXY, pp_instance())); | |
96 | 169 |
97 // Set up case (1) (see above). | 170 // Set up case (1) (see above). |
98 EXPECT_EQ(0U, info_did_run().run_count); | 171 EXPECT_EQ(0U, info_did_run().run_count()); |
172 // TODO(dmichael): Test this on a background thread? | |
99 scoped_refptr<TrackedCallback> callback_did_run = new TrackedCallback( | 173 scoped_refptr<TrackedCallback> callback_did_run = new TrackedCallback( |
100 resource.get(), | 174 resource.get(), |
101 PP_MakeCompletionCallback(&TestCallback, &info_did_run())); | 175 PP_MakeCompletionCallback(&TestCallback, &info_did_run())); |
102 EXPECT_EQ(0U, info_did_run().run_count); | 176 EXPECT_EQ(0U, info_did_run().run_count()); |
103 callback_did_run->Run(PP_OK); | 177 callback_did_run->Run(PP_OK); |
104 EXPECT_EQ(1U, info_did_run().run_count); | 178 EXPECT_EQ(1U, info_did_run().run_count()); |
105 EXPECT_EQ(PP_OK, info_did_run().result); | 179 EXPECT_EQ(PP_OK, info_did_run().result()); |
106 | 180 |
107 // Set up case (2). | 181 // Set up case (2). |
108 EXPECT_EQ(0U, info_did_abort().run_count); | 182 EXPECT_EQ(0U, info_did_abort().run_count()); |
109 scoped_refptr<TrackedCallback> callback_did_abort = new TrackedCallback( | 183 scoped_refptr<TrackedCallback> callback_did_abort = new TrackedCallback( |
110 resource.get(), | 184 resource.get(), |
111 PP_MakeCompletionCallback(&TestCallback, &info_did_abort())); | 185 PP_MakeCompletionCallback(&TestCallback, &info_did_abort())); |
112 EXPECT_EQ(0U, info_did_abort().run_count); | 186 EXPECT_EQ(0U, info_did_abort().run_count()); |
113 callback_did_abort->Abort(); | 187 callback_did_abort->Abort(); |
114 EXPECT_EQ(1U, info_did_abort().run_count); | 188 EXPECT_EQ(1U, info_did_abort().run_count()); |
115 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort().result); | 189 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort().result()); |
116 | 190 |
117 // Set up case (3). | 191 // Set up case (3). |
118 EXPECT_EQ(0U, info_didnt_run().run_count); | 192 EXPECT_EQ(0U, info_didnt_run().run_count()); |
119 scoped_refptr<TrackedCallback> callback_didnt_run = new TrackedCallback( | 193 scoped_refptr<TrackedCallback> callback_didnt_run = new TrackedCallback( |
120 resource.get(), | 194 resource.get(), |
121 PP_MakeCompletionCallback(&TestCallback, &info_didnt_run())); | 195 PP_MakeCompletionCallback(&TestCallback, &info_didnt_run())); |
122 EXPECT_EQ(0U, info_didnt_run().run_count); | 196 EXPECT_EQ(0U, info_didnt_run().run_count()); |
123 | 197 |
124 PpapiGlobals::Get()->GetCallbackTrackerForInstance(pp_instance())->AbortAll(); | 198 GetGlobals()->GetCallbackTrackerForInstance(pp_instance())->AbortAll(); |
125 | 199 |
126 // Check case (1). | 200 // Check case (1). |
127 EXPECT_EQ(1U, info_did_run().run_count); | 201 EXPECT_EQ(1U, info_did_run().run_count()); |
128 | 202 |
129 // Check case (2). | 203 // Check case (2). |
130 EXPECT_EQ(1U, info_did_abort().run_count); | 204 EXPECT_EQ(1U, info_did_abort().run_count()); |
131 | 205 |
132 // Check case (3). | 206 // Check case (3). |
133 EXPECT_EQ(1U, info_didnt_run().run_count); | 207 EXPECT_EQ(1U, info_didnt_run().run_count()); |
134 EXPECT_EQ(PP_ERROR_ABORTED, info_didnt_run().result); | 208 EXPECT_EQ(PP_ERROR_ABORTED, info_didnt_run().result()); |
135 } | 209 } |
136 | 210 |
137 // CallbackResourceTest -------------------------------------------------------- | 211 // CallbackResourceTest -------------------------------------------------------- |
138 | 212 |
139 namespace { | 213 namespace { |
140 | 214 |
141 class CallbackResourceTest : public TrackedCallbackTest { | 215 class CallbackResourceTest : public TrackedCallbackTest { |
142 public: | 216 public: |
143 CallbackResourceTest() {} | 217 CallbackResourceTest() {} |
144 }; | 218 }; |
145 | 219 |
146 class CallbackMockResource : public Resource { | 220 class CallbackMockResource : public Resource { |
147 public: | 221 public: |
148 CallbackMockResource(PP_Instance instance) | 222 static scoped_refptr<CallbackMockResource> Create(PP_Instance instance) { |
149 : Resource(OBJECT_IS_IMPL, instance) {} | 223 ProxyAutoLock acquire; |
224 return scoped_refptr<CallbackMockResource>( | |
225 new CallbackMockResource(instance)); | |
226 } | |
150 ~CallbackMockResource() {} | 227 ~CallbackMockResource() {} |
151 | 228 |
152 PP_Resource SetupForTest() { | 229 // Take a reference to this resource, which will add it to the tracker. |
153 PP_Resource resource_id = GetReference(); | 230 void TakeRef() { |
154 EXPECT_NE(0, resource_id); | 231 ProxyAutoLock acquire; |
232 ScopedPPResource temp_resource(ScopedPPResource::PassRef(), GetReference()); | |
233 EXPECT_NE(0, temp_resource.get()); | |
234 reference_holder_ = temp_resource; | |
235 } | |
236 // Release it, removing it from the tracker. | |
237 void ReleaseRef() { | |
238 ProxyAutoLock acquire; | |
239 reference_holder_ = 0; | |
240 } | |
241 | |
242 // Create the test callbacks on a background thread, so that we can verify | |
243 // they are run on the same thread where they were created. | |
244 void CreateCallbacksOnLoop(MessageLoopResource* loop_resource) { | |
245 ProxyAutoLock acquire; | |
246 // |thread_checker_| will bind to the background thread. | |
247 thread_checker_.DetachFromThread(); | |
248 loop_resource->message_loop_proxy()->PostTask(FROM_HERE, | |
249 RunWhileLocked( | |
250 base::Bind(&CallbackMockResource::CreateCallbacks, this))); | |
251 } | |
252 | |
253 int32_t CompletionTask(CallbackRunInfo* info, int32_t result) { | |
254 // The completion task must run on the thread where the callback was | |
255 // created, and must hold the proxy lock. | |
256 CHECK(thread_checker_.CalledOnValidThread()); | |
257 ProxyLock::AssertAcquired(); | |
258 | |
259 // We should run before the callback. | |
260 CHECK_EQ(0U, info->run_count()); | |
261 info->CompletionTaskDidRun(result); | |
262 return kOverrideResultValue; | |
263 } | |
264 | |
265 void CheckInitialState() { | |
266 callbacks_created_event_.Wait(); | |
267 EXPECT_EQ(0U, info_did_run_.run_count()); | |
268 EXPECT_EQ(0U, info_did_run_.completion_task_run_count()); | |
269 | |
270 EXPECT_EQ(0U, info_did_run_with_completion_task_.run_count()); | |
271 EXPECT_EQ(0U, | |
272 info_did_run_with_completion_task_.completion_task_run_count()); | |
273 | |
274 EXPECT_EQ(0U, info_did_abort_.run_count()); | |
275 EXPECT_EQ(0U, info_did_abort_.completion_task_run_count()); | |
276 | |
277 EXPECT_EQ(0U, info_didnt_run_.run_count()); | |
278 EXPECT_EQ(0U, info_didnt_run_.completion_task_run_count()); | |
279 } | |
280 | |
281 void RunCallbacks() { | |
282 callback_did_run_->Run(PP_OK); | |
283 callback_did_run_with_completion_task_->Run(PP_OK); | |
284 callback_did_abort_->Abort(); | |
285 info_did_run_.WaitUntilCompleted(); | |
286 info_did_run_with_completion_task_.WaitUntilCompleted(); | |
287 info_did_abort_.WaitUntilCompleted(); | |
288 } | |
289 | |
290 void CheckIntermediateState() { | |
291 EXPECT_EQ(1U, info_did_run_.run_count()); | |
292 EXPECT_EQ(PP_OK, info_did_run_.result()); | |
293 EXPECT_EQ(0U, info_did_run_.completion_task_run_count()); | |
294 | |
295 EXPECT_EQ(1U, info_did_run_with_completion_task_.run_count()); | |
296 // completion task should override the result. | |
297 EXPECT_EQ(kOverrideResultValue, | |
298 info_did_run_with_completion_task_.result()); | |
299 EXPECT_EQ(1U, | |
300 info_did_run_with_completion_task_.completion_task_run_count()); | |
301 EXPECT_EQ(PP_OK, | |
302 info_did_run_with_completion_task_.completion_task_result()); | |
303 | |
304 EXPECT_EQ(1U, info_did_abort_.run_count()); | |
305 // completion task shouldn't override an abort. | |
306 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort_.result()); | |
307 EXPECT_EQ(1U, info_did_abort_.completion_task_run_count()); | |
308 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort_.completion_task_result()); | |
309 | |
310 EXPECT_EQ(0U, info_didnt_run_.completion_task_run_count()); | |
311 EXPECT_EQ(0U, info_didnt_run_.run_count()); | |
312 } | |
313 | |
314 void CheckFinalState() { | |
315 info_didnt_run_.WaitUntilCompleted(); | |
316 EXPECT_EQ(1U, info_did_run_with_completion_task_.run_count()); | |
317 EXPECT_EQ(kOverrideResultValue, | |
318 info_did_run_with_completion_task_.result()); | |
319 callback_did_run_with_completion_task_ = nullptr; | |
320 EXPECT_EQ(1U, info_did_run_.run_count()); | |
321 EXPECT_EQ(PP_OK, info_did_run_.result()); | |
322 callback_did_run_ = nullptr; | |
323 EXPECT_EQ(1U, info_did_abort_.run_count()); | |
324 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort_.result()); | |
325 callback_did_abort_ = nullptr; | |
326 EXPECT_EQ(1U, info_didnt_run_.run_count()); | |
327 EXPECT_EQ(PP_ERROR_ABORTED, info_didnt_run_.result()); | |
328 callback_didnt_run_ = nullptr; | |
329 } | |
330 | |
331 private: | |
332 explicit CallbackMockResource(PP_Instance instance) | |
333 : Resource(OBJECT_IS_PROXY, instance), | |
334 info_did_run_(&thread_checker_), | |
335 info_did_run_with_completion_task_(&thread_checker_), | |
336 info_did_abort_(&thread_checker_), | |
337 info_didnt_run_(&thread_checker_), | |
338 callbacks_created_event_(true, false) {} | |
339 void CreateCallbacks() { | |
340 // Bind thread_checker_ to the thread where we create the callbacks. | |
341 // Later, when the callback runs, it will check that it was invoked on this | |
342 // same thread. | |
343 CHECK(thread_checker_.CalledOnValidThread()); | |
155 | 344 |
156 callback_did_run_ = new TrackedCallback( | 345 callback_did_run_ = new TrackedCallback( |
157 this, PP_MakeCompletionCallback(&TestCallback, &info_did_run_)); | 346 this, PP_MakeCompletionCallback(&TestCallback, &info_did_run_)); |
158 EXPECT_EQ(0U, info_did_run_.run_count); | |
159 EXPECT_EQ(0U, info_did_run_.completion_task_run_count); | |
160 | 347 |
161 // In order to test that the completion task can override the callback | 348 // In order to test that the completion task can override the callback |
162 // result, we need to test callbacks with and without a completion task. | 349 // result, we need to test callbacks with and without a completion task. |
163 callback_did_run_with_completion_task_ = new TrackedCallback( | 350 callback_did_run_with_completion_task_ = new TrackedCallback( |
164 this, | 351 this, |
165 PP_MakeCompletionCallback(&TestCallback, | 352 PP_MakeCompletionCallback(&TestCallback, |
166 &info_did_run_with_completion_task_)); | 353 &info_did_run_with_completion_task_)); |
167 callback_did_run_with_completion_task_->set_completion_task( | 354 callback_did_run_with_completion_task_->set_completion_task( |
168 Bind(&CallbackMockResource::CompletionTask, | 355 Bind(&CallbackMockResource::CompletionTask, |
169 this, | 356 this, |
170 &info_did_run_with_completion_task_)); | 357 &info_did_run_with_completion_task_)); |
171 EXPECT_EQ(0U, info_did_run_with_completion_task_.run_count); | |
172 EXPECT_EQ(0U, info_did_run_with_completion_task_.completion_task_run_count); | |
173 | 358 |
174 callback_did_abort_ = new TrackedCallback( | 359 callback_did_abort_ = new TrackedCallback( |
175 this, PP_MakeCompletionCallback(&TestCallback, &info_did_abort_)); | 360 this, PP_MakeCompletionCallback(&TestCallback, &info_did_abort_)); |
176 callback_did_abort_->set_completion_task( | 361 callback_did_abort_->set_completion_task( |
177 Bind(&CallbackMockResource::CompletionTask, this, &info_did_abort_)); | 362 Bind(&CallbackMockResource::CompletionTask, this, &info_did_abort_)); |
178 EXPECT_EQ(0U, info_did_abort_.run_count); | |
179 EXPECT_EQ(0U, info_did_abort_.completion_task_run_count); | |
180 | 363 |
181 callback_didnt_run_ = new TrackedCallback( | 364 callback_didnt_run_ = new TrackedCallback( |
182 this, PP_MakeCompletionCallback(&TestCallback, &info_didnt_run_)); | 365 this, PP_MakeCompletionCallback(&TestCallback, &info_didnt_run_)); |
183 callback_didnt_run_->set_completion_task( | 366 callback_didnt_run_->set_completion_task( |
184 Bind(&CallbackMockResource::CompletionTask, this, &info_didnt_run_)); | 367 Bind(&CallbackMockResource::CompletionTask, this, &info_didnt_run_)); |
185 EXPECT_EQ(0U, info_didnt_run_.run_count); | |
186 EXPECT_EQ(0U, info_didnt_run_.completion_task_run_count); | |
187 | 368 |
188 callback_did_run_->Run(PP_OK); | 369 callbacks_created_event_.Signal(); |
189 callback_did_run_with_completion_task_->Run(PP_OK); | |
190 callback_did_abort_->Abort(); | |
191 | |
192 CheckIntermediateState(); | |
193 | |
194 return resource_id; | |
195 } | 370 } |
196 | 371 |
197 int32_t CompletionTask(CallbackRunInfo* info, int32_t result) { | 372 // Used to verify that the callback runs on the same thread where it is |
198 // We should run before the callback. | 373 // created. |
199 EXPECT_EQ(0U, info->run_count); | 374 base::ThreadChecker thread_checker_; |
200 info->completion_task_run_count++; | |
201 if (info->completion_task_run_count == 1) | |
202 info->completion_task_result = result; | |
203 return kOverrideResultValue; | |
204 } | |
205 | |
206 void CheckIntermediateState() { | |
207 EXPECT_EQ(1U, info_did_run_.run_count); | |
208 EXPECT_EQ(PP_OK, info_did_run_.result); | |
209 EXPECT_EQ(0U, info_did_run_.completion_task_run_count); | |
210 | |
211 EXPECT_EQ(1U, info_did_run_with_completion_task_.run_count); | |
212 // completion task should override the result. | |
213 EXPECT_EQ(kOverrideResultValue, info_did_run_with_completion_task_.result); | |
214 EXPECT_EQ(1U, info_did_run_with_completion_task_.completion_task_run_count); | |
215 EXPECT_EQ(PP_OK, info_did_run_with_completion_task_.completion_task_result); | |
216 | |
217 EXPECT_EQ(1U, info_did_abort_.run_count); | |
218 // completion task shouldn't override an abort. | |
219 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort_.result); | |
220 EXPECT_EQ(1U, info_did_abort_.completion_task_run_count); | |
221 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort_.completion_task_result); | |
222 | |
223 EXPECT_EQ(0U, info_didnt_run_.completion_task_run_count); | |
224 EXPECT_EQ(0U, info_didnt_run_.run_count); | |
225 } | |
226 | |
227 void CheckFinalState() { | |
228 EXPECT_EQ(1U, info_did_run_.run_count); | |
229 EXPECT_EQ(PP_OK, info_did_run_.result); | |
230 EXPECT_EQ(1U, info_did_abort_.run_count); | |
231 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort_.result); | |
232 EXPECT_EQ(1U, info_didnt_run_.run_count); | |
233 EXPECT_EQ(PP_ERROR_ABORTED, info_didnt_run_.result); | |
234 } | |
235 | 375 |
236 scoped_refptr<TrackedCallback> callback_did_run_; | 376 scoped_refptr<TrackedCallback> callback_did_run_; |
237 CallbackRunInfo info_did_run_; | 377 CallbackRunInfo info_did_run_; |
238 | 378 |
239 scoped_refptr<TrackedCallback> callback_did_run_with_completion_task_; | 379 scoped_refptr<TrackedCallback> callback_did_run_with_completion_task_; |
240 CallbackRunInfo info_did_run_with_completion_task_; | 380 CallbackRunInfo info_did_run_with_completion_task_; |
241 | 381 |
242 scoped_refptr<TrackedCallback> callback_did_abort_; | 382 scoped_refptr<TrackedCallback> callback_did_abort_; |
243 CallbackRunInfo info_did_abort_; | 383 CallbackRunInfo info_did_abort_; |
244 | 384 |
245 scoped_refptr<TrackedCallback> callback_didnt_run_; | 385 scoped_refptr<TrackedCallback> callback_didnt_run_; |
246 CallbackRunInfo info_didnt_run_; | 386 CallbackRunInfo info_didnt_run_; |
387 | |
388 base::WaitableEvent callbacks_created_event_; | |
389 | |
390 ScopedPPResource reference_holder_; | |
247 }; | 391 }; |
248 | 392 |
249 } // namespace | 393 } // namespace |
250 | 394 |
251 // Test that callbacks get aborted on the last resource unref. | 395 // Test that callbacks get aborted on the last resource unref. |
252 TEST_F(CallbackResourceTest, AbortOnNoRef) { | 396 TEST_F(CallbackResourceTest, AbortOnNoRef) { |
253 ProxyAutoLock lock; | |
254 ResourceTracker* resource_tracker = PpapiGlobals::Get()->GetResourceTracker(); | |
255 | |
256 // Test several things: Unref-ing a resource (to zero refs) with callbacks | 397 // Test several things: Unref-ing a resource (to zero refs) with callbacks |
257 // which (1) have been run, (2) have been aborted, (3) haven't been completed. | 398 // which (1) have been run, (2) have been aborted, (3) haven't been completed. |
258 // Check that the uncompleted one gets aborted, and that the others don't get | 399 // Check that the uncompleted one gets aborted, and that the others don't get |
259 // called again. | 400 // called again. |
260 scoped_refptr<CallbackMockResource> resource_1( | 401 scoped_refptr<CallbackMockResource> resource_1( |
261 new CallbackMockResource(pp_instance())); | 402 CallbackMockResource::Create(pp_instance())); |
262 PP_Resource resource_1_id = resource_1->SetupForTest(); | 403 resource_1->CreateCallbacksOnLoop(thread().message_loop()); |
404 resource_1->CheckInitialState(); | |
405 resource_1->RunCallbacks(); | |
406 resource_1->TakeRef(); | |
407 resource_1->CheckIntermediateState(); | |
263 | 408 |
264 // Also do the same for a second resource, and make sure that unref-ing the | 409 // Also do the same for a second resource, and make sure that unref-ing the |
265 // first resource doesn't much up the second resource. | 410 // first resource doesn't much up the second resource. |
266 scoped_refptr<CallbackMockResource> resource_2( | 411 scoped_refptr<CallbackMockResource> resource_2( |
267 new CallbackMockResource(pp_instance())); | 412 CallbackMockResource::Create(pp_instance())); |
268 PP_Resource resource_2_id = resource_2->SetupForTest(); | 413 resource_2->CreateCallbacksOnLoop(thread().message_loop()); |
414 resource_2->CheckInitialState(); | |
415 resource_2->RunCallbacks(); | |
416 resource_2->TakeRef(); | |
417 resource_2->CheckIntermediateState(); | |
269 | 418 |
270 // Double-check that resource #1 is still okay. | 419 // Double-check that resource #1 is still okay. |
271 resource_1->CheckIntermediateState(); | 420 resource_1->CheckIntermediateState(); |
272 | 421 |
273 // Kill resource #1, spin the message loop to run posted calls, and check that | 422 // Kill resource #1, spin the message loop to run posted calls, and check that |
274 // things are in the expected states. | 423 // things are in the expected states. |
275 resource_tracker->ReleaseResource(resource_1_id); | 424 resource_1->ReleaseRef(); |
276 { | 425 |
277 ProxyAutoUnlock unlock; | |
278 base::MessageLoop::current()->RunUntilIdle(); | |
279 } | |
280 resource_1->CheckFinalState(); | 426 resource_1->CheckFinalState(); |
281 resource_2->CheckIntermediateState(); | 427 resource_2->CheckIntermediateState(); |
282 | 428 |
283 // Kill resource #2. | 429 // Kill resource #2. |
284 resource_tracker->ReleaseResource(resource_2_id); | 430 resource_2->ReleaseRef(); |
285 { | 431 |
286 ProxyAutoUnlock unlock; | |
287 base::MessageLoop::current()->RunUntilIdle(); | |
288 } | |
289 resource_1->CheckFinalState(); | 432 resource_1->CheckFinalState(); |
290 resource_2->CheckFinalState(); | 433 resource_2->CheckFinalState(); |
291 | 434 |
292 // This shouldn't be needed, but make sure there are no stranded tasks. | |
293 { | 435 { |
294 ProxyAutoUnlock unlock; | 436 ProxyAutoLock lock; |
295 base::MessageLoop::current()->RunUntilIdle(); | 437 resource_1 = nullptr; |
438 resource_2 = nullptr; | |
296 } | 439 } |
297 } | 440 } |
298 | 441 |
299 // Test that "resurrecting" a resource (getting a new ID for a |Resource|) | 442 // Test that "resurrecting" a resource (getting a new ID for a |Resource|) |
300 // doesn't resurrect callbacks. | 443 // doesn't resurrect callbacks. |
301 TEST_F(CallbackResourceTest, Resurrection) { | 444 TEST_F(CallbackResourceTest, Resurrection) { |
302 ProxyAutoLock lock; | 445 scoped_refptr<CallbackMockResource> resource( |
303 ResourceTracker* resource_tracker = PpapiGlobals::Get()->GetResourceTracker(); | 446 CallbackMockResource::Create(pp_instance())); |
447 resource->CreateCallbacksOnLoop(thread().message_loop()); | |
448 resource->CheckInitialState(); | |
449 resource->RunCallbacks(); | |
450 resource->TakeRef(); | |
451 resource->CheckIntermediateState(); | |
304 | 452 |
305 scoped_refptr<CallbackMockResource> resource( | 453 // Unref it and check that things are in the expected states. |
306 new CallbackMockResource(pp_instance())); | 454 resource->ReleaseRef(); |
307 PP_Resource resource_id = resource->SetupForTest(); | |
308 | |
309 // Unref it, spin the message loop to run posted calls, and check that things | |
310 // are in the expected states. | |
311 resource_tracker->ReleaseResource(resource_id); | |
312 { | |
313 ProxyAutoUnlock unlock; | |
314 base::MessageLoop::current()->RunUntilIdle(); | |
315 } | |
316 resource->CheckFinalState(); | 455 resource->CheckFinalState(); |
317 | 456 |
318 // "Resurrect" it and check that the callbacks are still dead. | 457 // "Resurrect" it and check that the callbacks are still dead. |
319 PP_Resource new_resource_id = resource->GetReference(); | 458 resource->TakeRef(); |
320 { | |
321 ProxyAutoUnlock unlock; | |
322 base::MessageLoop::current()->RunUntilIdle(); | |
323 } | |
324 resource->CheckFinalState(); | 459 resource->CheckFinalState(); |
325 | 460 |
326 // Unref it again and do the same. | 461 // Unref it again and do the same. |
327 resource_tracker->ReleaseResource(new_resource_id); | 462 resource->ReleaseRef(); |
463 resource->CheckFinalState(); | |
328 { | 464 { |
329 ProxyAutoUnlock unlock; | 465 ProxyAutoLock lock; |
330 base::MessageLoop::current()->RunUntilIdle(); | 466 resource = nullptr; |
331 } | |
332 resource->CheckFinalState(); | |
333 | |
334 // This shouldn't be needed, but make sure there are no stranded tasks. | |
335 { | |
336 ProxyAutoUnlock unlock; | |
337 base::MessageLoop::current()->RunUntilIdle(); | |
338 } | 467 } |
339 } | 468 } |
340 | 469 |
470 } // namespace proxy | |
341 } // namespace ppapi | 471 } // namespace ppapi |
OLD | NEW |