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