Disable flaky AnimatedContentSamplerParameterizedTest.FrameTimestampsConvergeTowardsE...
[chromium-blink-merge.git] / ppapi / proxy / tracked_callback_unittest.cc
blob748dcfb4784788956894cf98fddf38db0848e637
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/memory/ref_counted.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"
11 #include "ppapi/c/pp_completion_callback.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"
15 #include "ppapi/shared_impl/callback_tracker.h"
16 #include "ppapi/shared_impl/proxy_lock.h"
17 #include "ppapi/shared_impl/resource.h"
18 #include "ppapi/shared_impl/resource_tracker.h"
19 #include "ppapi/shared_impl/scoped_pp_resource.h"
20 #include "ppapi/shared_impl/test_globals.h"
21 #include "ppapi/shared_impl/tracked_callback.h"
22 #include "testing/gtest/include/gtest/gtest.h"
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.
27 namespace ppapi {
28 namespace proxy {
30 namespace {
32 class CallbackThread : public base::SimpleThread {
33 public:
34 explicit CallbackThread(PP_Instance instance)
35 : SimpleThread("CallbackThread"), instance_(instance) {}
36 ~CallbackThread() override {}
38 // base::SimpleThread overrides.
39 void Start() override {
41 ProxyAutoLock acquire;
42 // Create the message loop here, after PpapiGlobals has been created.
43 message_loop_ = new MessageLoopResource(instance_);
45 base::SimpleThread::Start();
47 void Join() override {
49 ProxyAutoLock acquire;
50 message_loop()->PostQuit(PP_TRUE);
51 message_loop_ = nullptr;
53 base::SimpleThread::Join();
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();
66 MessageLoopResource* message_loop() { return message_loop_.get(); }
68 private:
69 PP_Instance instance_;
70 scoped_refptr<MessageLoopResource> message_loop_;
73 class TrackedCallbackTest : public PluginProxyTest {
74 public:
75 TrackedCallbackTest() : thread_(pp_instance()) {}
76 CallbackThread& thread() { return thread_; }
78 private:
79 // PluginProxyTest overrides.
80 void SetUp() override {
81 PluginProxyTest::SetUp();
82 thread_.Start();
84 void TearDown() override {
85 thread_.Join();
86 PluginProxyTest::TearDown();
87 base::RunLoop run_loop;
88 run_loop.RunUntilIdle();
90 CallbackThread thread_;
93 // All valid results (PP_OK, PP_ERROR_...) are nonpositive.
94 const int32_t kInitializedResultValue = 1;
95 const int32_t kOverrideResultValue = 2;
97 struct CallbackRunInfo {
98 explicit CallbackRunInfo(base::ThreadChecker* thread_checker)
99 : run_count_(0),
100 result_(kInitializedResultValue),
101 completion_task_run_count_(0),
102 completion_task_result_(kInitializedResultValue),
103 thread_checker_(thread_checker),
104 callback_did_run_event_(true, false) {}
105 void CallbackDidRun(int32_t result) {
106 CHECK(thread_checker_->CalledOnValidThread());
107 if (!run_count_)
108 result_ = result;
109 ++run_count_;
110 callback_did_run_event_.Signal();
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_;
118 void WaitUntilCompleted() { callback_did_run_event_.Wait(); }
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:
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_;
131 base::WaitableEvent callback_did_run_event_;
134 void TestCallback(void* user_data, int32_t result) {
135 CallbackRunInfo* info = static_cast<CallbackRunInfo*>(user_data);
136 info->CallbackDidRun(result);
139 // CallbackShutdownTest --------------------------------------------------------
141 class CallbackShutdownTest : public TrackedCallbackTest {
142 public:
143 CallbackShutdownTest() : info_did_run_(&thread_checker_),
144 info_did_abort_(&thread_checker_),
145 info_didnt_run_(&thread_checker_) {}
147 // Cases:
148 // (1) A callback which is run (so shouldn't be aborted on shutdown).
149 // (2) A callback which is aborted (so shouldn't be aborted on shutdown).
150 // (3) A callback which isn't run (so should be aborted on shutdown).
151 CallbackRunInfo& info_did_run() { return info_did_run_; } // (1)
152 CallbackRunInfo& info_did_abort() { return info_did_abort_; } // (2)
153 CallbackRunInfo& info_didnt_run() { return info_didnt_run_; } // (3)
155 private:
156 base::ThreadChecker thread_checker_;
157 CallbackRunInfo info_did_run_;
158 CallbackRunInfo info_did_abort_;
159 CallbackRunInfo info_didnt_run_;
162 } // namespace
164 // Tests that callbacks are properly aborted on module shutdown.
165 TEST_F(CallbackShutdownTest, AbortOnShutdown) {
166 ProxyAutoLock lock;
167 scoped_refptr<Resource> resource(
168 new Resource(OBJECT_IS_PROXY, pp_instance()));
170 // Set up case (1) (see above).
171 EXPECT_EQ(0U, info_did_run().run_count());
172 // TODO(dmichael): Test this on a background thread?
173 scoped_refptr<TrackedCallback> callback_did_run = new TrackedCallback(
174 resource.get(),
175 PP_MakeCompletionCallback(&TestCallback, &info_did_run()));
176 EXPECT_EQ(0U, info_did_run().run_count());
177 callback_did_run->Run(PP_OK);
178 EXPECT_EQ(1U, info_did_run().run_count());
179 EXPECT_EQ(PP_OK, info_did_run().result());
181 // Set up case (2).
182 EXPECT_EQ(0U, info_did_abort().run_count());
183 scoped_refptr<TrackedCallback> callback_did_abort = new TrackedCallback(
184 resource.get(),
185 PP_MakeCompletionCallback(&TestCallback, &info_did_abort()));
186 EXPECT_EQ(0U, info_did_abort().run_count());
187 callback_did_abort->Abort();
188 EXPECT_EQ(1U, info_did_abort().run_count());
189 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort().result());
191 // Set up case (3).
192 EXPECT_EQ(0U, info_didnt_run().run_count());
193 scoped_refptr<TrackedCallback> callback_didnt_run = new TrackedCallback(
194 resource.get(),
195 PP_MakeCompletionCallback(&TestCallback, &info_didnt_run()));
196 EXPECT_EQ(0U, info_didnt_run().run_count());
198 GetGlobals()->GetCallbackTrackerForInstance(pp_instance())->AbortAll();
200 // Check case (1).
201 EXPECT_EQ(1U, info_did_run().run_count());
203 // Check case (2).
204 EXPECT_EQ(1U, info_did_abort().run_count());
206 // Check case (3).
207 EXPECT_EQ(1U, info_didnt_run().run_count());
208 EXPECT_EQ(PP_ERROR_ABORTED, info_didnt_run().result());
211 // CallbackResourceTest --------------------------------------------------------
213 namespace {
215 class CallbackResourceTest : public TrackedCallbackTest {
216 public:
217 CallbackResourceTest() {}
220 class CallbackMockResource : public Resource {
221 public:
222 static scoped_refptr<CallbackMockResource> Create(PP_Instance instance) {
223 ProxyAutoLock acquire;
224 return scoped_refptr<CallbackMockResource>(
225 new CallbackMockResource(instance));
227 ~CallbackMockResource() {}
229 // Take a reference to this resource, which will add it to the tracker.
230 void TakeRef() {
231 ProxyAutoLock acquire;
232 ScopedPPResource temp_resource(ScopedPPResource::PassRef(), GetReference());
233 EXPECT_NE(0, temp_resource.get());
234 reference_holder_ = temp_resource;
236 // Release it, removing it from the tracker.
237 void ReleaseRef() {
238 ProxyAutoLock acquire;
239 reference_holder_ = 0;
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)));
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();
259 // We should run before the callback.
260 CHECK_EQ(0U, info->run_count());
261 info->CompletionTaskDidRun(result);
262 return kOverrideResultValue;
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());
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());
274 EXPECT_EQ(0U, info_did_abort_.run_count());
275 EXPECT_EQ(0U, info_did_abort_.completion_task_run_count());
277 EXPECT_EQ(0U, info_didnt_run_.run_count());
278 EXPECT_EQ(0U, info_didnt_run_.completion_task_run_count());
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();
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());
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());
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());
310 EXPECT_EQ(0U, info_didnt_run_.completion_task_run_count());
311 EXPECT_EQ(0U, info_didnt_run_.run_count());
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;
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());
345 callback_did_run_ = new TrackedCallback(
346 this, PP_MakeCompletionCallback(&TestCallback, &info_did_run_));
348 // In order to test that the completion task can override the callback
349 // result, we need to test callbacks with and without a completion task.
350 callback_did_run_with_completion_task_ = new TrackedCallback(
351 this,
352 PP_MakeCompletionCallback(&TestCallback,
353 &info_did_run_with_completion_task_));
354 callback_did_run_with_completion_task_->set_completion_task(
355 Bind(&CallbackMockResource::CompletionTask,
356 this,
357 &info_did_run_with_completion_task_));
359 callback_did_abort_ = new TrackedCallback(
360 this, PP_MakeCompletionCallback(&TestCallback, &info_did_abort_));
361 callback_did_abort_->set_completion_task(
362 Bind(&CallbackMockResource::CompletionTask, this, &info_did_abort_));
364 callback_didnt_run_ = new TrackedCallback(
365 this, PP_MakeCompletionCallback(&TestCallback, &info_didnt_run_));
366 callback_didnt_run_->set_completion_task(
367 Bind(&CallbackMockResource::CompletionTask, this, &info_didnt_run_));
369 callbacks_created_event_.Signal();
372 // Used to verify that the callback runs on the same thread where it is
373 // created.
374 base::ThreadChecker thread_checker_;
376 scoped_refptr<TrackedCallback> callback_did_run_;
377 CallbackRunInfo info_did_run_;
379 scoped_refptr<TrackedCallback> callback_did_run_with_completion_task_;
380 CallbackRunInfo info_did_run_with_completion_task_;
382 scoped_refptr<TrackedCallback> callback_did_abort_;
383 CallbackRunInfo info_did_abort_;
385 scoped_refptr<TrackedCallback> callback_didnt_run_;
386 CallbackRunInfo info_didnt_run_;
388 base::WaitableEvent callbacks_created_event_;
390 ScopedPPResource reference_holder_;
393 } // namespace
395 // Test that callbacks get aborted on the last resource unref.
396 TEST_F(CallbackResourceTest, AbortOnNoRef) {
397 // Test several things: Unref-ing a resource (to zero refs) with callbacks
398 // which (1) have been run, (2) have been aborted, (3) haven't been completed.
399 // Check that the uncompleted one gets aborted, and that the others don't get
400 // called again.
401 scoped_refptr<CallbackMockResource> resource_1(
402 CallbackMockResource::Create(pp_instance()));
403 resource_1->CreateCallbacksOnLoop(thread().message_loop());
404 resource_1->CheckInitialState();
405 resource_1->RunCallbacks();
406 resource_1->TakeRef();
407 resource_1->CheckIntermediateState();
409 // Also do the same for a second resource, and make sure that unref-ing the
410 // first resource doesn't much up the second resource.
411 scoped_refptr<CallbackMockResource> resource_2(
412 CallbackMockResource::Create(pp_instance()));
413 resource_2->CreateCallbacksOnLoop(thread().message_loop());
414 resource_2->CheckInitialState();
415 resource_2->RunCallbacks();
416 resource_2->TakeRef();
417 resource_2->CheckIntermediateState();
419 // Double-check that resource #1 is still okay.
420 resource_1->CheckIntermediateState();
422 // Kill resource #1, spin the message loop to run posted calls, and check that
423 // things are in the expected states.
424 resource_1->ReleaseRef();
426 resource_1->CheckFinalState();
427 resource_2->CheckIntermediateState();
429 // Kill resource #2.
430 resource_2->ReleaseRef();
432 resource_1->CheckFinalState();
433 resource_2->CheckFinalState();
436 ProxyAutoLock lock;
437 resource_1 = nullptr;
438 resource_2 = nullptr;
442 // Test that "resurrecting" a resource (getting a new ID for a |Resource|)
443 // doesn't resurrect callbacks.
444 TEST_F(CallbackResourceTest, Resurrection) {
445 scoped_refptr<CallbackMockResource> resource(
446 CallbackMockResource::Create(pp_instance()));
447 resource->CreateCallbacksOnLoop(thread().message_loop());
448 resource->CheckInitialState();
449 resource->RunCallbacks();
450 resource->TakeRef();
451 resource->CheckIntermediateState();
453 // Unref it and check that things are in the expected states.
454 resource->ReleaseRef();
455 resource->CheckFinalState();
457 // "Resurrect" it and check that the callbacks are still dead.
458 resource->TakeRef();
459 resource->CheckFinalState();
461 // Unref it again and do the same.
462 resource->ReleaseRef();
463 resource->CheckFinalState();
465 ProxyAutoLock lock;
466 resource = nullptr;
470 } // namespace proxy
471 } // namespace ppapi