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
3 // found in the LICENSE file.
6 #include "base/location.h"
7 #include "base/memory/ref_counted.h"
8 #include "base/run_loop.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/threading/simple_thread.h"
12 #include "ppapi/c/pp_completion_callback.h"
13 #include "ppapi/c/pp_errors.h"
14 #include "ppapi/proxy/ppapi_proxy_test.h"
15 #include "ppapi/proxy/ppb_message_loop_proxy.h"
16 #include "ppapi/shared_impl/callback_tracker.h"
17 #include "ppapi/shared_impl/proxy_lock.h"
18 #include "ppapi/shared_impl/resource.h"
19 #include "ppapi/shared_impl/resource_tracker.h"
20 #include "ppapi/shared_impl/scoped_pp_resource.h"
21 #include "ppapi/shared_impl/test_globals.h"
22 #include "ppapi/shared_impl/tracked_callback.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 // Note, this file tests TrackedCallback which lives in ppapi/shared_impl.
26 // Unfortunately, we need the test to live in ppapi/proxy so that it can use
27 // the thread support there.
33 class CallbackThread
: public base::SimpleThread
{
35 explicit CallbackThread(PP_Instance instance
)
36 : SimpleThread("CallbackThread"), instance_(instance
) {}
37 ~CallbackThread() override
{}
39 // base::SimpleThread overrides.
40 void Start() override
{
42 ProxyAutoLock acquire
;
43 // Create the message loop here, after PpapiGlobals has been created.
44 message_loop_
= new MessageLoopResource(instance_
);
46 base::SimpleThread::Start();
48 void Join() override
{
50 ProxyAutoLock acquire
;
51 message_loop()->PostQuit(PP_TRUE
);
52 message_loop_
= nullptr;
54 base::SimpleThread::Join();
57 ProxyAutoLock acquire
;
58 // Make a local copy of message_loop_ for this thread so we can interact
59 // with it even after the main thread releases it.
60 scoped_refptr
<MessageLoopResource
> message_loop(message_loop_
);
61 message_loop
->AttachToCurrentThread();
62 // Note, run releases the lock to run events.
64 message_loop
->DetachFromThread();
67 MessageLoopResource
* message_loop() { return message_loop_
.get(); }
70 PP_Instance instance_
;
71 scoped_refptr
<MessageLoopResource
> message_loop_
;
74 class TrackedCallbackTest
: public PluginProxyTest
{
76 TrackedCallbackTest() : thread_(pp_instance()) {}
77 CallbackThread
& thread() { return thread_
; }
80 // PluginProxyTest overrides.
81 void SetUp() override
{
82 PluginProxyTest::SetUp();
85 void TearDown() override
{
87 PluginProxyTest::TearDown();
88 base::RunLoop run_loop
;
89 run_loop
.RunUntilIdle();
91 CallbackThread thread_
;
94 // All valid results (PP_OK, PP_ERROR_...) are nonpositive.
95 const int32_t kInitializedResultValue
= 1;
96 const int32_t kOverrideResultValue
= 2;
98 struct CallbackRunInfo
{
99 explicit CallbackRunInfo(base::ThreadChecker
* thread_checker
)
101 result_(kInitializedResultValue
),
102 completion_task_run_count_(0),
103 completion_task_result_(kInitializedResultValue
),
104 thread_checker_(thread_checker
),
105 callback_did_run_event_(true, false) {}
106 void CallbackDidRun(int32_t result
) {
107 CHECK(thread_checker_
->CalledOnValidThread());
111 callback_did_run_event_
.Signal();
113 void CompletionTaskDidRun(int32_t result
) {
114 CHECK(thread_checker_
->CalledOnValidThread());
115 if (!completion_task_run_count_
)
116 completion_task_result_
= result
;
117 ++completion_task_run_count_
;
119 void WaitUntilCompleted() { callback_did_run_event_
.Wait(); }
120 unsigned run_count() { return run_count_
; }
121 int32_t result() { return result_
; }
122 unsigned completion_task_run_count() { return completion_task_run_count_
; }
123 int32_t completion_task_result() { return completion_task_result_
; }
127 unsigned completion_task_run_count_
;
128 int32_t completion_task_result_
;
129 // Weak; owned by the creator of CallbackRunInfo.
130 base::ThreadChecker
* thread_checker_
;
132 base::WaitableEvent callback_did_run_event_
;
135 void TestCallback(void* user_data
, int32_t result
) {
136 CallbackRunInfo
* info
= static_cast<CallbackRunInfo
*>(user_data
);
137 info
->CallbackDidRun(result
);
140 // CallbackShutdownTest --------------------------------------------------------
142 class CallbackShutdownTest
: public TrackedCallbackTest
{
144 CallbackShutdownTest() : info_did_run_(&thread_checker_
),
145 info_did_abort_(&thread_checker_
),
146 info_didnt_run_(&thread_checker_
) {}
149 // (1) A callback which is run (so shouldn't be aborted on shutdown).
150 // (2) A callback which is aborted (so shouldn't be aborted on shutdown).
151 // (3) A callback which isn't run (so should be aborted on shutdown).
152 CallbackRunInfo
& info_did_run() { return info_did_run_
; } // (1)
153 CallbackRunInfo
& info_did_abort() { return info_did_abort_
; } // (2)
154 CallbackRunInfo
& info_didnt_run() { return info_didnt_run_
; } // (3)
157 base::ThreadChecker thread_checker_
;
158 CallbackRunInfo info_did_run_
;
159 CallbackRunInfo info_did_abort_
;
160 CallbackRunInfo info_didnt_run_
;
165 // Tests that callbacks are properly aborted on module shutdown.
166 TEST_F(CallbackShutdownTest
, DISABLED_AbortOnShutdown
) {
168 scoped_refptr
<Resource
> resource(
169 new Resource(OBJECT_IS_PROXY
, pp_instance()));
171 // Set up case (1) (see above).
172 EXPECT_EQ(0U, info_did_run().run_count());
173 // TODO(dmichael): Test this on a background thread?
174 scoped_refptr
<TrackedCallback
> callback_did_run
= new TrackedCallback(
176 PP_MakeCompletionCallback(&TestCallback
, &info_did_run()));
177 EXPECT_EQ(0U, info_did_run().run_count());
178 callback_did_run
->Run(PP_OK
);
179 EXPECT_EQ(1U, info_did_run().run_count());
180 EXPECT_EQ(PP_OK
, info_did_run().result());
183 EXPECT_EQ(0U, info_did_abort().run_count());
184 scoped_refptr
<TrackedCallback
> callback_did_abort
= new TrackedCallback(
186 PP_MakeCompletionCallback(&TestCallback
, &info_did_abort()));
187 EXPECT_EQ(0U, info_did_abort().run_count());
188 callback_did_abort
->Abort();
189 EXPECT_EQ(1U, info_did_abort().run_count());
190 EXPECT_EQ(PP_ERROR_ABORTED
, info_did_abort().result());
193 EXPECT_EQ(0U, info_didnt_run().run_count());
194 scoped_refptr
<TrackedCallback
> callback_didnt_run
= new TrackedCallback(
196 PP_MakeCompletionCallback(&TestCallback
, &info_didnt_run()));
197 EXPECT_EQ(0U, info_didnt_run().run_count());
199 GetGlobals()->GetCallbackTrackerForInstance(pp_instance())->AbortAll();
202 EXPECT_EQ(1U, info_did_run().run_count());
205 EXPECT_EQ(1U, info_did_abort().run_count());
208 EXPECT_EQ(1U, info_didnt_run().run_count());
209 EXPECT_EQ(PP_ERROR_ABORTED
, info_didnt_run().result());
212 // CallbackResourceTest --------------------------------------------------------
216 class CallbackResourceTest
: public TrackedCallbackTest
{
218 CallbackResourceTest() {}
221 class CallbackMockResource
: public Resource
{
223 static scoped_refptr
<CallbackMockResource
> Create(PP_Instance instance
) {
224 ProxyAutoLock acquire
;
225 return scoped_refptr
<CallbackMockResource
>(
226 new CallbackMockResource(instance
));
228 ~CallbackMockResource() {}
230 // Take a reference to this resource, which will add it to the tracker.
232 ProxyAutoLock acquire
;
233 ScopedPPResource
temp_resource(ScopedPPResource::PassRef(), GetReference());
234 EXPECT_NE(0, temp_resource
.get());
235 reference_holder_
= temp_resource
;
237 // Release it, removing it from the tracker.
239 ProxyAutoLock acquire
;
240 reference_holder_
= 0;
243 // Create the test callbacks on a background thread, so that we can verify
244 // they are run on the same thread where they were created.
245 void CreateCallbacksOnLoop(MessageLoopResource
* loop_resource
) {
246 ProxyAutoLock acquire
;
247 // |thread_checker_| will bind to the background thread.
248 thread_checker_
.DetachFromThread();
249 loop_resource
->task_runner()->PostTask(
250 FROM_HERE
, RunWhileLocked(base::Bind(
251 &CallbackMockResource::CreateCallbacks
, this)));
254 int32_t CompletionTask(CallbackRunInfo
* info
, int32_t result
) {
255 // The completion task must run on the thread where the callback was
256 // created, and must hold the proxy lock.
257 CHECK(thread_checker_
.CalledOnValidThread());
258 ProxyLock::AssertAcquired();
260 // We should run before the callback.
261 CHECK_EQ(0U, info
->run_count());
262 info
->CompletionTaskDidRun(result
);
263 return kOverrideResultValue
;
266 void CheckInitialState() {
267 callbacks_created_event_
.Wait();
268 EXPECT_EQ(0U, info_did_run_
.run_count());
269 EXPECT_EQ(0U, info_did_run_
.completion_task_run_count());
271 EXPECT_EQ(0U, info_did_run_with_completion_task_
.run_count());
273 info_did_run_with_completion_task_
.completion_task_run_count());
275 EXPECT_EQ(0U, info_did_abort_
.run_count());
276 EXPECT_EQ(0U, info_did_abort_
.completion_task_run_count());
278 EXPECT_EQ(0U, info_didnt_run_
.run_count());
279 EXPECT_EQ(0U, info_didnt_run_
.completion_task_run_count());
282 void RunCallbacks() {
283 callback_did_run_
->Run(PP_OK
);
284 callback_did_run_with_completion_task_
->Run(PP_OK
);
285 callback_did_abort_
->Abort();
286 info_did_run_
.WaitUntilCompleted();
287 info_did_run_with_completion_task_
.WaitUntilCompleted();
288 info_did_abort_
.WaitUntilCompleted();
291 void CheckIntermediateState() {
292 EXPECT_EQ(1U, info_did_run_
.run_count());
293 EXPECT_EQ(PP_OK
, info_did_run_
.result());
294 EXPECT_EQ(0U, info_did_run_
.completion_task_run_count());
296 EXPECT_EQ(1U, info_did_run_with_completion_task_
.run_count());
297 // completion task should override the result.
298 EXPECT_EQ(kOverrideResultValue
,
299 info_did_run_with_completion_task_
.result());
301 info_did_run_with_completion_task_
.completion_task_run_count());
303 info_did_run_with_completion_task_
.completion_task_result());
305 EXPECT_EQ(1U, info_did_abort_
.run_count());
306 // completion task shouldn't override an abort.
307 EXPECT_EQ(PP_ERROR_ABORTED
, info_did_abort_
.result());
308 EXPECT_EQ(1U, info_did_abort_
.completion_task_run_count());
309 EXPECT_EQ(PP_ERROR_ABORTED
, info_did_abort_
.completion_task_result());
311 EXPECT_EQ(0U, info_didnt_run_
.completion_task_run_count());
312 EXPECT_EQ(0U, info_didnt_run_
.run_count());
315 void CheckFinalState() {
316 info_didnt_run_
.WaitUntilCompleted();
317 EXPECT_EQ(1U, info_did_run_with_completion_task_
.run_count());
318 EXPECT_EQ(kOverrideResultValue
,
319 info_did_run_with_completion_task_
.result());
320 callback_did_run_with_completion_task_
= nullptr;
321 EXPECT_EQ(1U, info_did_run_
.run_count());
322 EXPECT_EQ(PP_OK
, info_did_run_
.result());
323 callback_did_run_
= nullptr;
324 EXPECT_EQ(1U, info_did_abort_
.run_count());
325 EXPECT_EQ(PP_ERROR_ABORTED
, info_did_abort_
.result());
326 callback_did_abort_
= nullptr;
327 EXPECT_EQ(1U, info_didnt_run_
.run_count());
328 EXPECT_EQ(PP_ERROR_ABORTED
, info_didnt_run_
.result());
329 callback_didnt_run_
= nullptr;
333 explicit CallbackMockResource(PP_Instance instance
)
334 : Resource(OBJECT_IS_PROXY
, instance
),
335 info_did_run_(&thread_checker_
),
336 info_did_run_with_completion_task_(&thread_checker_
),
337 info_did_abort_(&thread_checker_
),
338 info_didnt_run_(&thread_checker_
),
339 callbacks_created_event_(true, false) {}
340 void CreateCallbacks() {
341 // Bind thread_checker_ to the thread where we create the callbacks.
342 // Later, when the callback runs, it will check that it was invoked on this
344 CHECK(thread_checker_
.CalledOnValidThread());
346 callback_did_run_
= new TrackedCallback(
347 this, PP_MakeCompletionCallback(&TestCallback
, &info_did_run_
));
349 // In order to test that the completion task can override the callback
350 // result, we need to test callbacks with and without a completion task.
351 callback_did_run_with_completion_task_
= new TrackedCallback(
353 PP_MakeCompletionCallback(&TestCallback
,
354 &info_did_run_with_completion_task_
));
355 callback_did_run_with_completion_task_
->set_completion_task(
356 Bind(&CallbackMockResource::CompletionTask
,
358 &info_did_run_with_completion_task_
));
360 callback_did_abort_
= new TrackedCallback(
361 this, PP_MakeCompletionCallback(&TestCallback
, &info_did_abort_
));
362 callback_did_abort_
->set_completion_task(
363 Bind(&CallbackMockResource::CompletionTask
, this, &info_did_abort_
));
365 callback_didnt_run_
= new TrackedCallback(
366 this, PP_MakeCompletionCallback(&TestCallback
, &info_didnt_run_
));
367 callback_didnt_run_
->set_completion_task(
368 Bind(&CallbackMockResource::CompletionTask
, this, &info_didnt_run_
));
370 callbacks_created_event_
.Signal();
373 // Used to verify that the callback runs on the same thread where it is
375 base::ThreadChecker thread_checker_
;
377 scoped_refptr
<TrackedCallback
> callback_did_run_
;
378 CallbackRunInfo info_did_run_
;
380 scoped_refptr
<TrackedCallback
> callback_did_run_with_completion_task_
;
381 CallbackRunInfo info_did_run_with_completion_task_
;
383 scoped_refptr
<TrackedCallback
> callback_did_abort_
;
384 CallbackRunInfo info_did_abort_
;
386 scoped_refptr
<TrackedCallback
> callback_didnt_run_
;
387 CallbackRunInfo info_didnt_run_
;
389 base::WaitableEvent callbacks_created_event_
;
391 ScopedPPResource reference_holder_
;
396 // Test that callbacks get aborted on the last resource unref.
397 TEST_F(CallbackResourceTest
, DISABLED_AbortOnNoRef
) {
398 // Test several things: Unref-ing a resource (to zero refs) with callbacks
399 // which (1) have been run, (2) have been aborted, (3) haven't been completed.
400 // Check that the uncompleted one gets aborted, and that the others don't get
402 scoped_refptr
<CallbackMockResource
> resource_1(
403 CallbackMockResource::Create(pp_instance()));
404 resource_1
->CreateCallbacksOnLoop(thread().message_loop());
405 resource_1
->CheckInitialState();
406 resource_1
->RunCallbacks();
407 resource_1
->TakeRef();
408 resource_1
->CheckIntermediateState();
410 // Also do the same for a second resource, and make sure that unref-ing the
411 // first resource doesn't much up the second resource.
412 scoped_refptr
<CallbackMockResource
> resource_2(
413 CallbackMockResource::Create(pp_instance()));
414 resource_2
->CreateCallbacksOnLoop(thread().message_loop());
415 resource_2
->CheckInitialState();
416 resource_2
->RunCallbacks();
417 resource_2
->TakeRef();
418 resource_2
->CheckIntermediateState();
420 // Double-check that resource #1 is still okay.
421 resource_1
->CheckIntermediateState();
423 // Kill resource #1, spin the message loop to run posted calls, and check that
424 // things are in the expected states.
425 resource_1
->ReleaseRef();
427 resource_1
->CheckFinalState();
428 resource_2
->CheckIntermediateState();
431 resource_2
->ReleaseRef();
433 resource_1
->CheckFinalState();
434 resource_2
->CheckFinalState();
438 resource_1
= nullptr;
439 resource_2
= nullptr;
443 // Test that "resurrecting" a resource (getting a new ID for a |Resource|)
444 // doesn't resurrect callbacks.
445 TEST_F(CallbackResourceTest
, DISABLED_Resurrection
) {
446 scoped_refptr
<CallbackMockResource
> resource(
447 CallbackMockResource::Create(pp_instance()));
448 resource
->CreateCallbacksOnLoop(thread().message_loop());
449 resource
->CheckInitialState();
450 resource
->RunCallbacks();
452 resource
->CheckIntermediateState();
454 // Unref it and check that things are in the expected states.
455 resource
->ReleaseRef();
456 resource
->CheckFinalState();
458 // "Resurrect" it and check that the callbacks are still dead.
460 resource
->CheckFinalState();
462 // Unref it again and do the same.
463 resource
->ReleaseRef();
464 resource
->CheckFinalState();