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 "testing/gtest/include/gtest/gtest.h"
6
7#include "base/compiler_specific.h"
8#include "ppapi/shared_impl/proxy_lock.h"
9#include "ppapi/shared_impl/resource.h"
10#include "ppapi/shared_impl/resource_tracker.h"
11#include "ppapi/shared_impl/test_globals.h"
12
13namespace ppapi {
14
15namespace {
16
17int mock_resource_alive_count = 0;
18int last_plugin_ref_was_deleted_count = 0;
19int instance_was_deleted_count = 0;
20
21class MyMockResource : public Resource {
22 public:
23  MyMockResource(PP_Instance instance) : Resource(OBJECT_IS_IMPL, instance) {
24    mock_resource_alive_count++;
25  }
26  virtual ~MyMockResource() {
27    mock_resource_alive_count--;
28  }
29
30  virtual void LastPluginRefWasDeleted() OVERRIDE {
31    last_plugin_ref_was_deleted_count++;
32  }
33  virtual void InstanceWasDeleted() OVERRIDE {
34    instance_was_deleted_count++;
35  }
36};
37
38}  // namespace
39
40class ResourceTrackerTest : public testing::Test {
41 public:
42  ResourceTrackerTest() {}
43
44  // Test implementation.
45  virtual void SetUp() OVERRIDE {
46    ASSERT_EQ(0, mock_resource_alive_count);
47    last_plugin_ref_was_deleted_count = 0;
48    instance_was_deleted_count = 0;
49  }
50  virtual void TearDown() OVERRIDE {
51  }
52
53  ResourceTracker& resource_tracker() { return *globals_.GetResourceTracker(); }
54
55 private:
56  TestGlobals globals_;
57};
58
59// Test that LastPluginRefWasDeleted is called when the last plugin ref was
60// deleted but the object lives on.
61TEST_F(ResourceTrackerTest, LastPluginRef) {
62  PP_Instance instance = 0x1234567;
63  ProxyAutoLock lock;
64  resource_tracker().DidCreateInstance(instance);
65
66  scoped_refptr<MyMockResource> resource(new MyMockResource(instance));
67  PP_Resource pp_resource = resource->GetReference();
68  EXPECT_TRUE(resource_tracker().GetResource(pp_resource));
69
70  // Releasing it should keep the object (because we have a ref) but fire the
71  // "last plugin ref" message.
72  resource_tracker().ReleaseResource(pp_resource);
73  EXPECT_EQ(1, last_plugin_ref_was_deleted_count);
74  EXPECT_EQ(1, mock_resource_alive_count);
75
76  resource_tracker().DidDeleteInstance(instance);
77  resource = NULL;
78  EXPECT_FALSE(resource_tracker().GetResource(pp_resource));
79}
80
81// Tests when the plugin is holding a ref to a resource when the instance is
82// deleted.
83TEST_F(ResourceTrackerTest, InstanceDeletedWithPluginRef) {
84  // Make a resource with one ref held by the plugin, and delete the instance.
85  PP_Instance instance = 0x2345678;
86  ProxyAutoLock lock;
87  resource_tracker().DidCreateInstance(instance);
88  MyMockResource* resource = new MyMockResource(instance);
89  resource->GetReference();
90  EXPECT_EQ(1, mock_resource_alive_count);
91  resource_tracker().DidDeleteInstance(instance);
92
93  // The resource should have been deleted, and before it was, it should have
94  // received a "last plugin ref was deleted" notification.
95  EXPECT_EQ(0, mock_resource_alive_count);
96  EXPECT_EQ(1, last_plugin_ref_was_deleted_count);
97  EXPECT_EQ(0, instance_was_deleted_count);
98}
99
100// Test when the plugin and the internal implementation (via scoped_refptr) is
101// holding a ref to a resource when the instance is deleted.
102TEST_F(ResourceTrackerTest, InstanceDeletedWithBothRefed) {
103  // Create a new instance.
104  PP_Instance instance = 0x3456789;
105  ProxyAutoLock lock;
106
107  // Make a resource with one ref held by the plugin and one ref held by us
108  // (outlives the plugin), and delete the instance.
109  resource_tracker().DidCreateInstance(instance);
110  scoped_refptr<MyMockResource> resource = new MyMockResource(instance);
111  resource->GetReference();
112  EXPECT_EQ(1, mock_resource_alive_count);
113  resource_tracker().DidDeleteInstance(instance);
114
115  // The resource should NOT have been deleted, and it should have received both
116  // a "last plugin ref was deleted" and a "instance was deleted" notification.
117  EXPECT_EQ(1, mock_resource_alive_count);
118  EXPECT_EQ(1, last_plugin_ref_was_deleted_count);
119  EXPECT_EQ(1, instance_was_deleted_count);
120  EXPECT_EQ(0, resource->pp_instance());
121
122  resource = NULL;
123  EXPECT_EQ(0, mock_resource_alive_count);
124}
125
126}  // namespace ppapi
127