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