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