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