Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ppapi / proxy / tracked_callback_unittest.cc
blob0a9278a3c72e2f784b3bc3e39ea55355b23cfebc
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.
5 #include "base/bind.h"
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.
28 namespace ppapi {
29 namespace proxy {
31 namespace {
33 class CallbackThread : public base::SimpleThread {
34 public:
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();
56 void Run() override {
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.
63 message_loop->Run();
64 message_loop->DetachFromThread();
67 MessageLoopResource* message_loop() { return message_loop_.get(); }
69 private:
70 PP_Instance instance_;
71 scoped_refptr<MessageLoopResource> message_loop_;
74 class TrackedCallbackTest : public PluginProxyTest {
75 public:
76 TrackedCallbackTest() : thread_(pp_instance()) {}
77 CallbackThread& thread() { return thread_; }
79 private:
80 // PluginProxyTest overrides.
81 void SetUp() override {
82 PluginProxyTest::SetUp();
83 thread_.Start();
85 void TearDown() override {
86 thread_.Join();
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)
100 : run_count_(0),
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());
108 if (!run_count_)
109 result_ = result;
110 ++run_count_;
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_; }
124 private:
125 unsigned run_count_;
126 int32_t 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 {
143 public:
144 CallbackShutdownTest() : info_did_run_(&thread_checker_),
145 info_did_abort_(&thread_checker_),
146 info_didnt_run_(&thread_checker_) {}
148 // Cases:
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)
156 private:
157 base::ThreadChecker thread_checker_;
158 CallbackRunInfo info_did_run_;
159 CallbackRunInfo info_did_abort_;
160 CallbackRunInfo info_didnt_run_;
163 } // namespace
165 // Tests that callbacks are properly aborted on module shutdown.
166 TEST_F(CallbackShutdownTest, DISABLED_AbortOnShutdown) {
167 ProxyAutoLock lock;
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(
175 resource.get(),
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());
182 // Set up case (2).
183 EXPECT_EQ(0U, info_did_abort().run_count());
184 scoped_refptr<TrackedCallback> callback_did_abort = new TrackedCallback(
185 resource.get(),
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());
192 // Set up case (3).
193 EXPECT_EQ(0U, info_didnt_run().run_count());
194 scoped_refptr<TrackedCallback> callback_didnt_run = new TrackedCallback(
195 resource.get(),
196 PP_MakeCompletionCallback(&TestCallback, &info_didnt_run()));
197 EXPECT_EQ(0U, info_didnt_run().run_count());
199 GetGlobals()->GetCallbackTrackerForInstance(pp_instance())->AbortAll();
201 // Check case (1).
202 EXPECT_EQ(1U, info_did_run().run_count());
204 // Check case (2).
205 EXPECT_EQ(1U, info_did_abort().run_count());
207 // Check case (3).
208 EXPECT_EQ(1U, info_didnt_run().run_count());
209 EXPECT_EQ(PP_ERROR_ABORTED, info_didnt_run().result());
212 // CallbackResourceTest --------------------------------------------------------
214 namespace {
216 class CallbackResourceTest : public TrackedCallbackTest {
217 public:
218 CallbackResourceTest() {}
221 class CallbackMockResource : public Resource {
222 public:
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.
231 void TakeRef() {
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.
238 void ReleaseRef() {
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());
272 EXPECT_EQ(0U,
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());
300 EXPECT_EQ(1U,
301 info_did_run_with_completion_task_.completion_task_run_count());
302 EXPECT_EQ(PP_OK,
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;
332 private:
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
343 // same thread.
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(
352 this,
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,
357 this,
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
374 // created.
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_;
394 } // namespace
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
401 // called again.
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();
430 // Kill resource #2.
431 resource_2->ReleaseRef();
433 resource_1->CheckFinalState();
434 resource_2->CheckFinalState();
437 ProxyAutoLock lock;
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();
451 resource->TakeRef();
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.
459 resource->TakeRef();
460 resource->CheckFinalState();
462 // Unref it again and do the same.
463 resource->ReleaseRef();
464 resource->CheckFinalState();
466 ProxyAutoLock lock;
467 resource = nullptr;
471 } // namespace proxy
472 } // namespace ppapi