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