Home | History | Annotate | Download | only in shared_impl
      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/bind.h"
      6 #include "base/memory/ref_counted.h"
      7 #include "base/message_loop/message_loop.h"
      8 #include "ppapi/c/pp_completion_callback.h"
      9 #include "ppapi/c/pp_errors.h"
     10 #include "ppapi/shared_impl/callback_tracker.h"
     11 #include "ppapi/shared_impl/resource.h"
     12 #include "ppapi/shared_impl/resource_tracker.h"
     13 #include "ppapi/shared_impl/test_globals.h"
     14 #include "ppapi/shared_impl/tracked_callback.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 namespace ppapi {
     18 
     19 namespace {
     20 
     21 class TrackedCallbackTest : public testing::Test {
     22  public:
     23   TrackedCallbackTest()
     24       : message_loop_(base::MessageLoop::TYPE_DEFAULT), 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   base::MessageLoop message_loop_;
     37   TestGlobals globals_;
     38   PP_Instance pp_instance_;
     39 };
     40 
     41 // All valid results (PP_OK, PP_ERROR_...) are nonpositive.
     42 const int32_t kInitializedResultValue = 1;
     43 const int32_t kOverrideResultValue = 2;
     44 
     45 struct CallbackRunInfo {
     46   CallbackRunInfo()
     47       : run_count(0),
     48         result(kInitializedResultValue),
     49         completion_task_run_count(0),
     50         completion_task_result(kInitializedResultValue) {}
     51   unsigned run_count;
     52   int32_t result;
     53   unsigned completion_task_run_count;
     54   int32_t completion_task_result;
     55 };
     56 
     57 void TestCallback(void* user_data, int32_t result) {
     58   CallbackRunInfo* info = reinterpret_cast<CallbackRunInfo*>(user_data);
     59   info->run_count++;
     60   if (info->run_count == 1)
     61     info->result = result;
     62 }
     63 
     64 }  // namespace
     65 
     66 // CallbackShutdownTest --------------------------------------------------------
     67 
     68 namespace {
     69 
     70 class CallbackShutdownTest : public TrackedCallbackTest {
     71  public:
     72   CallbackShutdownTest() {}
     73 
     74   // Cases:
     75   // (1) A callback which is run (so shouldn't be aborted on shutdown).
     76   // (2) A callback which is aborted (so shouldn't be aborted on shutdown).
     77   // (3) A callback which isn't run (so should be aborted on shutdown).
     78   CallbackRunInfo& info_did_run() { return info_did_run_; }  // (1)
     79   CallbackRunInfo& info_did_abort() { return info_did_abort_; }  // (2)
     80   CallbackRunInfo& info_didnt_run() { return info_didnt_run_; }  // (3)
     81 
     82  private:
     83   CallbackRunInfo info_did_run_;
     84   CallbackRunInfo info_did_abort_;
     85   CallbackRunInfo info_didnt_run_;
     86 };
     87 
     88 }  // namespace
     89 
     90 // Tests that callbacks are properly aborted on module shutdown.
     91 TEST_F(CallbackShutdownTest, AbortOnShutdown) {
     92   scoped_refptr<Resource> resource(new Resource(OBJECT_IS_IMPL, pp_instance()));
     93 
     94   // Set up case (1) (see above).
     95   EXPECT_EQ(0U, info_did_run().run_count);
     96   scoped_refptr<TrackedCallback> callback_did_run = new TrackedCallback(
     97       resource.get(),
     98       PP_MakeCompletionCallback(&TestCallback, &info_did_run()));
     99   EXPECT_EQ(0U, info_did_run().run_count);
    100   callback_did_run->Run(PP_OK);
    101   EXPECT_EQ(1U, info_did_run().run_count);
    102   EXPECT_EQ(PP_OK, info_did_run().result);
    103 
    104   // Set up case (2).
    105   EXPECT_EQ(0U, info_did_abort().run_count);
    106   scoped_refptr<TrackedCallback> callback_did_abort = new TrackedCallback(
    107       resource.get(),
    108       PP_MakeCompletionCallback(&TestCallback, &info_did_abort()));
    109   EXPECT_EQ(0U, info_did_abort().run_count);
    110   callback_did_abort->Abort();
    111   EXPECT_EQ(1U, info_did_abort().run_count);
    112   EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort().result);
    113 
    114   // Set up case (3).
    115   EXPECT_EQ(0U, info_didnt_run().run_count);
    116   scoped_refptr<TrackedCallback> callback_didnt_run = new TrackedCallback(
    117       resource.get(),
    118       PP_MakeCompletionCallback(&TestCallback, &info_didnt_run()));
    119   EXPECT_EQ(0U, info_didnt_run().run_count);
    120 
    121   PpapiGlobals::Get()->GetCallbackTrackerForInstance(pp_instance())->AbortAll();
    122 
    123   // Check case (1).
    124   EXPECT_EQ(1U, info_did_run().run_count);
    125 
    126   // Check case (2).
    127   EXPECT_EQ(1U, info_did_abort().run_count);
    128 
    129   // Check case (3).
    130   EXPECT_EQ(1U, info_didnt_run().run_count);
    131   EXPECT_EQ(PP_ERROR_ABORTED, info_didnt_run().result);
    132 }
    133 
    134 // CallbackResourceTest --------------------------------------------------------
    135 
    136 namespace {
    137 
    138 class CallbackResourceTest : public TrackedCallbackTest {
    139  public:
    140   CallbackResourceTest() {}
    141 };
    142 
    143 class CallbackMockResource : public Resource {
    144  public:
    145   CallbackMockResource(PP_Instance instance)
    146       : Resource(OBJECT_IS_IMPL, instance) {}
    147   ~CallbackMockResource() {}
    148 
    149   PP_Resource SetupForTest() {
    150     PP_Resource resource_id = GetReference();
    151     EXPECT_NE(0, resource_id);
    152 
    153     callback_did_run_ = new TrackedCallback(
    154         this,
    155         PP_MakeCompletionCallback(&TestCallback, &info_did_run_));
    156     EXPECT_EQ(0U, info_did_run_.run_count);
    157     EXPECT_EQ(0U, info_did_run_.completion_task_run_count);
    158 
    159     // In order to test that the completion task can override the callback
    160     // result, we need to test callbacks with and without a completion task.
    161     callback_did_run_with_completion_task_ = new TrackedCallback(
    162         this,
    163         PP_MakeCompletionCallback(&TestCallback,
    164                                   &info_did_run_with_completion_task_));
    165     callback_did_run_with_completion_task_->set_completion_task(
    166         Bind(&CallbackMockResource::CompletionTask, this,
    167              &info_did_run_with_completion_task_));
    168     EXPECT_EQ(0U, info_did_run_with_completion_task_.run_count);
    169     EXPECT_EQ(0U, info_did_run_with_completion_task_.completion_task_run_count);
    170 
    171     callback_did_abort_ = new TrackedCallback(
    172         this,
    173         PP_MakeCompletionCallback(&TestCallback, &info_did_abort_));
    174     callback_did_abort_->set_completion_task(
    175         Bind(&CallbackMockResource::CompletionTask, this, &info_did_abort_));
    176     EXPECT_EQ(0U, info_did_abort_.run_count);
    177     EXPECT_EQ(0U, info_did_abort_.completion_task_run_count);
    178 
    179     callback_didnt_run_ = new TrackedCallback(
    180         this,
    181         PP_MakeCompletionCallback(&TestCallback, &info_didnt_run_));
    182     callback_didnt_run_->set_completion_task(
    183         Bind(&CallbackMockResource::CompletionTask, this, &info_didnt_run_));
    184     EXPECT_EQ(0U, info_didnt_run_.run_count);
    185     EXPECT_EQ(0U, info_didnt_run_.completion_task_run_count);
    186 
    187     callback_did_run_->Run(PP_OK);
    188     callback_did_run_with_completion_task_->Run(PP_OK);
    189     callback_did_abort_->Abort();
    190 
    191     CheckIntermediateState();
    192 
    193     return resource_id;
    194   }
    195 
    196   int32_t CompletionTask(CallbackRunInfo* info, int32_t result) {
    197     // We should run before the callback.
    198     EXPECT_EQ(0U, info->run_count);
    199     info->completion_task_run_count++;
    200     if (info->completion_task_run_count == 1)
    201       info->completion_task_result = result;
    202     return kOverrideResultValue;
    203   }
    204 
    205   void CheckIntermediateState() {
    206     EXPECT_EQ(1U, info_did_run_.run_count);
    207     EXPECT_EQ(PP_OK, info_did_run_.result);
    208     EXPECT_EQ(0U, info_did_run_.completion_task_run_count);
    209 
    210     EXPECT_EQ(1U, info_did_run_with_completion_task_.run_count);
    211     // completion task should override the result.
    212     EXPECT_EQ(kOverrideResultValue, info_did_run_with_completion_task_.result);
    213     EXPECT_EQ(1U, info_did_run_with_completion_task_.completion_task_run_count);
    214     EXPECT_EQ(PP_OK,
    215               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 
    236   scoped_refptr<TrackedCallback> callback_did_run_;
    237   CallbackRunInfo info_did_run_;
    238 
    239   scoped_refptr<TrackedCallback> callback_did_run_with_completion_task_;
    240   CallbackRunInfo info_did_run_with_completion_task_;
    241 
    242   scoped_refptr<TrackedCallback> callback_did_abort_;
    243   CallbackRunInfo info_did_abort_;
    244 
    245   scoped_refptr<TrackedCallback> callback_didnt_run_;
    246   CallbackRunInfo info_didnt_run_;
    247 };
    248 
    249 }  // namespace
    250 
    251 // Test that callbacks get aborted on the last resource unref.
    252 TEST_F(CallbackResourceTest, AbortOnNoRef) {
    253   ResourceTracker* resource_tracker =
    254       PpapiGlobals::Get()->GetResourceTracker();
    255 
    256   // 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.
    258   // Check that the uncompleted one gets aborted, and that the others don't get
    259   // called again.
    260   scoped_refptr<CallbackMockResource> resource_1(
    261       new CallbackMockResource(pp_instance()));
    262   PP_Resource resource_1_id = resource_1->SetupForTest();
    263 
    264   // 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.
    266   scoped_refptr<CallbackMockResource> resource_2(
    267       new CallbackMockResource(pp_instance()));
    268   PP_Resource resource_2_id = resource_2->SetupForTest();
    269 
    270   // Double-check that resource #1 is still okay.
    271   resource_1->CheckIntermediateState();
    272 
    273   // Kill resource #1, spin the message loop to run posted calls, and check that
    274   // things are in the expected states.
    275   resource_tracker->ReleaseResource(resource_1_id);
    276   base::MessageLoop::current()->RunUntilIdle();
    277   resource_1->CheckFinalState();
    278   resource_2->CheckIntermediateState();
    279 
    280   // Kill resource #2.
    281   resource_tracker->ReleaseResource(resource_2_id);
    282   base::MessageLoop::current()->RunUntilIdle();
    283   resource_1->CheckFinalState();
    284   resource_2->CheckFinalState();
    285 
    286   // This shouldn't be needed, but make sure there are no stranded tasks.
    287   base::MessageLoop::current()->RunUntilIdle();
    288 }
    289 
    290 // Test that "resurrecting" a resource (getting a new ID for a |Resource|)
    291 // doesn't resurrect callbacks.
    292 TEST_F(CallbackResourceTest, Resurrection) {
    293   ResourceTracker* resource_tracker =
    294       PpapiGlobals::Get()->GetResourceTracker();
    295 
    296   scoped_refptr<CallbackMockResource> resource(
    297       new CallbackMockResource(pp_instance()));
    298   PP_Resource resource_id = resource->SetupForTest();
    299 
    300   // Unref it, spin the message loop to run posted calls, and check that things
    301   // are in the expected states.
    302   resource_tracker->ReleaseResource(resource_id);
    303   base::MessageLoop::current()->RunUntilIdle();
    304   resource->CheckFinalState();
    305 
    306   // "Resurrect" it and check that the callbacks are still dead.
    307   PP_Resource new_resource_id = resource->GetReference();
    308   base::MessageLoop::current()->RunUntilIdle();
    309   resource->CheckFinalState();
    310 
    311   // Unref it again and do the same.
    312   resource_tracker->ReleaseResource(new_resource_id);
    313   base::MessageLoop::current()->RunUntilIdle();
    314   resource->CheckFinalState();
    315 
    316   // This shouldn't be needed, but make sure there are no stranded tasks.
    317   base::MessageLoop::current()->RunUntilIdle();
    318 }
    319 
    320 }  // namespace ppapi
    321