tracked_callback_unittest.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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. 4 5#include "base/memory/ref_counted.h" 6#include "base/message_loop.h" 7#include "ppapi/c/pp_completion_callback.h" 8#include "ppapi/c/pp_errors.h" 9#include "ppapi/shared_impl/callback_tracker.h" 10#include "ppapi/shared_impl/resource.h" 11#include "ppapi/shared_impl/resource_tracker.h" 12#include "ppapi/shared_impl/test_globals.h" 13#include "ppapi/shared_impl/tracked_callback.h" 14#include "testing/gtest/include/gtest/gtest.h" 15 16namespace ppapi { 17 18namespace { 19 20class TrackedCallbackTest : public testing::Test { 21 public: 22 TrackedCallbackTest() 23 : message_loop_(MessageLoop::TYPE_DEFAULT), 24 pp_instance_(1234) {} 25 26 PP_Instance pp_instance() const { return pp_instance_; } 27 28 virtual void SetUp() OVERRIDE { 29 globals_.GetResourceTracker()->DidCreateInstance(pp_instance_); 30 } 31 virtual void TearDown() OVERRIDE { 32 globals_.GetResourceTracker()->DidDeleteInstance(pp_instance_); 33 } 34 35 private: 36 MessageLoop message_loop_; 37 TestGlobals globals_; 38 PP_Instance pp_instance_; 39}; 40 41struct CallbackRunInfo { 42 // All valid results (PP_OK, PP_ERROR_...) are nonpositive. 43 CallbackRunInfo() : run_count(0), result(1) {} 44 unsigned run_count; 45 int32_t result; 46}; 47 48void TestCallback(void* user_data, int32_t result) { 49 CallbackRunInfo* info = reinterpret_cast<CallbackRunInfo*>(user_data); 50 info->run_count++; 51 if (info->run_count == 1) 52 info->result = result; 53} 54 55} // namespace 56 57// CallbackShutdownTest -------------------------------------------------------- 58 59namespace { 60 61class CallbackShutdownTest : public TrackedCallbackTest { 62 public: 63 CallbackShutdownTest() {} 64 65 // Cases: 66 // (1) A callback which is run (so shouldn't be aborted on shutdown). 67 // (2) A callback which is aborted (so shouldn't be aborted on shutdown). 68 // (3) A callback which isn't run (so should be aborted on shutdown). 69 CallbackRunInfo& info_did_run() { return info_did_run_; } // (1) 70 CallbackRunInfo& info_did_abort() { return info_did_abort_; } // (2) 71 CallbackRunInfo& info_didnt_run() { return info_didnt_run_; } // (3) 72 73 private: 74 CallbackRunInfo info_did_run_; 75 CallbackRunInfo info_did_abort_; 76 CallbackRunInfo info_didnt_run_; 77}; 78 79} // namespace 80 81// Tests that callbacks are properly aborted on module shutdown. 82TEST_F(CallbackShutdownTest, AbortOnShutdown) { 83 scoped_refptr<Resource> resource(new Resource(OBJECT_IS_IMPL, pp_instance())); 84 85 // Set up case (1) (see above). 86 EXPECT_EQ(0U, info_did_run().run_count); 87 scoped_refptr<TrackedCallback> callback_did_run = new TrackedCallback( 88 resource.get(), 89 PP_MakeCompletionCallback(&TestCallback, &info_did_run())); 90 EXPECT_EQ(0U, info_did_run().run_count); 91 callback_did_run->Run(PP_OK); 92 EXPECT_EQ(1U, info_did_run().run_count); 93 EXPECT_EQ(PP_OK, info_did_run().result); 94 95 // Set up case (2). 96 EXPECT_EQ(0U, info_did_abort().run_count); 97 scoped_refptr<TrackedCallback> callback_did_abort = new TrackedCallback( 98 resource.get(), 99 PP_MakeCompletionCallback(&TestCallback, &info_did_abort())); 100 EXPECT_EQ(0U, info_did_abort().run_count); 101 callback_did_abort->Abort(); 102 EXPECT_EQ(1U, info_did_abort().run_count); 103 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort().result); 104 105 // Set up case (3). 106 EXPECT_EQ(0U, info_didnt_run().run_count); 107 scoped_refptr<TrackedCallback> callback_didnt_run = new TrackedCallback( 108 resource.get(), 109 PP_MakeCompletionCallback(&TestCallback, &info_didnt_run())); 110 EXPECT_EQ(0U, info_didnt_run().run_count); 111 112 PpapiGlobals::Get()->GetCallbackTrackerForInstance(pp_instance())->AbortAll(); 113 114 // Check case (1). 115 EXPECT_EQ(1U, info_did_run().run_count); 116 117 // Check case (2). 118 EXPECT_EQ(1U, info_did_abort().run_count); 119 120 // Check case (3). 121 EXPECT_EQ(1U, info_didnt_run().run_count); 122 EXPECT_EQ(PP_ERROR_ABORTED, info_didnt_run().result); 123} 124 125// CallbackResourceTest -------------------------------------------------------- 126 127namespace { 128 129class CallbackResourceTest : public TrackedCallbackTest { 130 public: 131 CallbackResourceTest() {} 132}; 133 134class CallbackMockResource : public Resource { 135 public: 136 CallbackMockResource(PP_Instance instance) 137 : Resource(OBJECT_IS_IMPL, instance) {} 138 ~CallbackMockResource() {} 139 140 PP_Resource SetupForTest() { 141 PP_Resource resource_id = GetReference(); 142 EXPECT_NE(0, resource_id); 143 144 callback_did_run_ = new TrackedCallback( 145 this, 146 PP_MakeCompletionCallback(&TestCallback, &info_did_run_)); 147 EXPECT_EQ(0U, info_did_run_.run_count); 148 149 callback_did_abort_ = new TrackedCallback( 150 this, 151 PP_MakeCompletionCallback(&TestCallback, &info_did_abort_)); 152 EXPECT_EQ(0U, info_did_abort_.run_count); 153 154 callback_didnt_run_ = new TrackedCallback( 155 this, 156 PP_MakeCompletionCallback(&TestCallback, &info_didnt_run_)); 157 EXPECT_EQ(0U, info_didnt_run_.run_count); 158 159 callback_did_run_->Run(PP_OK); 160 callback_did_abort_->Abort(); 161 162 CheckIntermediateState(); 163 164 return resource_id; 165 } 166 167 void CheckIntermediateState() { 168 EXPECT_EQ(1U, info_did_run_.run_count); 169 EXPECT_EQ(PP_OK, info_did_run_.result); 170 171 EXPECT_EQ(1U, info_did_abort_.run_count); 172 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort_.result); 173 174 EXPECT_EQ(0U, info_didnt_run_.run_count); 175 } 176 177 void CheckFinalState() { 178 EXPECT_EQ(1U, info_did_run_.run_count); 179 EXPECT_EQ(PP_OK, info_did_run_.result); 180 EXPECT_EQ(1U, info_did_abort_.run_count); 181 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort_.result); 182 EXPECT_EQ(1U, info_didnt_run_.run_count); 183 EXPECT_EQ(PP_ERROR_ABORTED, info_didnt_run_.result); 184 } 185 186 scoped_refptr<TrackedCallback> callback_did_run_; 187 CallbackRunInfo info_did_run_; 188 189 scoped_refptr<TrackedCallback> callback_did_abort_; 190 CallbackRunInfo info_did_abort_; 191 192 scoped_refptr<TrackedCallback> callback_didnt_run_; 193 CallbackRunInfo info_didnt_run_; 194}; 195 196} // namespace 197 198// Test that callbacks get aborted on the last resource unref. 199TEST_F(CallbackResourceTest, AbortOnNoRef) { 200 ResourceTracker* resource_tracker = 201 PpapiGlobals::Get()->GetResourceTracker(); 202 203 // Test several things: Unref-ing a resource (to zero refs) with callbacks 204 // which (1) have been run, (2) have been aborted, (3) haven't been completed. 205 // Check that the uncompleted one gets aborted, and that the others don't get 206 // called again. 207 scoped_refptr<CallbackMockResource> resource_1( 208 new CallbackMockResource(pp_instance())); 209 PP_Resource resource_1_id = resource_1->SetupForTest(); 210 211 // Also do the same for a second resource, and make sure that unref-ing the 212 // first resource doesn't much up the second resource. 213 scoped_refptr<CallbackMockResource> resource_2( 214 new CallbackMockResource(pp_instance())); 215 PP_Resource resource_2_id = resource_2->SetupForTest(); 216 217 // Double-check that resource #1 is still okay. 218 resource_1->CheckIntermediateState(); 219 220 // Kill resource #1, spin the message loop to run posted calls, and check that 221 // things are in the expected states. 222 resource_tracker->ReleaseResource(resource_1_id); 223 MessageLoop::current()->RunUntilIdle(); 224 resource_1->CheckFinalState(); 225 resource_2->CheckIntermediateState(); 226 227 // Kill resource #2. 228 resource_tracker->ReleaseResource(resource_2_id); 229 MessageLoop::current()->RunUntilIdle(); 230 resource_1->CheckFinalState(); 231 resource_2->CheckFinalState(); 232 233 // This shouldn't be needed, but make sure there are no stranded tasks. 234 MessageLoop::current()->RunUntilIdle(); 235} 236 237// Test that "resurrecting" a resource (getting a new ID for a |Resource|) 238// doesn't resurrect callbacks. 239TEST_F(CallbackResourceTest, Resurrection) { 240 ResourceTracker* resource_tracker = 241 PpapiGlobals::Get()->GetResourceTracker(); 242 243 scoped_refptr<CallbackMockResource> resource( 244 new CallbackMockResource(pp_instance())); 245 PP_Resource resource_id = resource->SetupForTest(); 246 247 // Unref it, spin the message loop to run posted calls, and check that things 248 // are in the expected states. 249 resource_tracker->ReleaseResource(resource_id); 250 MessageLoop::current()->RunUntilIdle(); 251 resource->CheckFinalState(); 252 253 // "Resurrect" it and check that the callbacks are still dead. 254 PP_Resource new_resource_id = resource->GetReference(); 255 MessageLoop::current()->RunUntilIdle(); 256 resource->CheckFinalState(); 257 258 // Unref it again and do the same. 259 resource_tracker->ReleaseResource(new_resource_id); 260 MessageLoop::current()->RunUntilIdle(); 261 resource->CheckFinalState(); 262 263 // This shouldn't be needed, but make sure there are no stranded tasks. 264 MessageLoop::current()->RunUntilIdle(); 265} 266 267} // namespace ppapi 268