Add wfh@ to chrome/browser/resources/plugin_metadata OWNERS.
[chromium-blink-merge.git] / ppapi / proxy / plugin_var_tracker_unittest.cc
blobfe0a82dd9b6ae997d7b52b037dae80a9d1d0cc3b
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.
5 #include "ipc/ipc_test_sink.h"
6 #include "ppapi/c/dev/ppp_class_deprecated.h"
7 #include "ppapi/proxy/plugin_var_tracker.h"
8 #include "ppapi/proxy/ppapi_messages.h"
9 #include "ppapi/proxy/ppapi_proxy_test.h"
10 #include "ppapi/proxy/proxy_object_var.h"
11 #include "ppapi/shared_impl/proxy_lock.h"
13 namespace ppapi {
14 namespace proxy {
16 namespace {
18 PP_Var MakeObject(int32 object_id) {
19 PP_Var ret;
20 ret.type = PP_VARTYPE_OBJECT;
21 ret.value.as_id = object_id;
22 return ret;
25 // A Deallocate() function for PPP_Class that just increments the integer
26 // referenced by the pointer so we know how often Deallocate was called.
27 void MarkOnDeallocate(void* object) {
28 (*static_cast<int*>(object))++;
31 // A class that just implements MarkOnDeallocate on destruction.
32 PPP_Class_Deprecated mark_on_deallocate_class = {
33 NULL, // HasProperty,
34 NULL, // HasMethod,
35 NULL, // GetProperty,
36 NULL, // GetAllPropertyNames,
37 NULL, // SetProperty,
38 NULL, // RemoveProperty,
39 NULL, // Call,
40 NULL, // Construct,
41 &MarkOnDeallocate
44 } // namespace
46 class PluginVarTrackerTest : public PluginProxyTest {
47 public:
48 PluginVarTrackerTest() {}
50 protected:
51 // Asserts that there is a unique "release object" IPC message in the test
52 // sink. This will return the var ID from the message or -1 if none found.
53 int32 GetObjectIDForUniqueReleaseObject() {
54 const IPC::Message* release_msg = sink().GetUniqueMessageMatching(
55 PpapiHostMsg_PPBVar_ReleaseObject::ID);
56 if (!release_msg)
57 return -1;
59 Tuple<int64> id;
60 PpapiHostMsg_PPBVar_ReleaseObject::Read(release_msg, &id);
61 return get<0>(id);
65 TEST_F(PluginVarTrackerTest, GetHostObject) {
66 ProxyAutoLock lock;
67 PP_Var host_object = MakeObject(12345);
69 // Round-trip through the tracker to make sure the host object comes out the
70 // other end.
71 PP_Var plugin_object = var_tracker().ReceiveObjectPassRef(
72 host_object, plugin_dispatcher());
73 PP_Var host_object2 = var_tracker().GetHostObject(plugin_object);
74 EXPECT_EQ(PP_VARTYPE_OBJECT, host_object2.type);
75 EXPECT_EQ(host_object.value.as_id, host_object2.value.as_id);
77 var_tracker().ReleaseVar(plugin_object);
80 TEST_F(PluginVarTrackerTest, ReceiveObjectPassRef) {
81 ProxyAutoLock lock;
82 PP_Var host_object = MakeObject(12345);
84 // Receive the object, we should have one ref and no messages.
85 PP_Var plugin_object = var_tracker().ReceiveObjectPassRef(
86 host_object, plugin_dispatcher());
87 EXPECT_EQ(0u, sink().message_count());
88 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
89 EXPECT_EQ(0,
90 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_object));
92 // Receive the same object again, we should get the same plugin ID out.
93 PP_Var plugin_object2 = var_tracker().ReceiveObjectPassRef(
94 host_object, plugin_dispatcher());
95 EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id);
96 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object));
97 EXPECT_EQ(0,
98 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_object));
100 // It should have sent one message to decerment the refcount in the host.
101 // This is because it only maintains one host refcount for all references
102 // in the plugin, but the host just sent the second one.
103 EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject());
104 sink().ClearMessages();
106 // Release the object, one ref at a time. The second release should free
107 // the tracking data and send a release message to the browser.
108 var_tracker().ReleaseVar(plugin_object);
109 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
110 var_tracker().ReleaseVar(plugin_object);
111 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
112 EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject());
115 // Tests freeing objects that have both refcounts and "tracked with no ref".
116 TEST_F(PluginVarTrackerTest, FreeTrackedAndReferencedObject) {
117 ProxyAutoLock lock;
118 PP_Var host_object = MakeObject(12345);
120 // Phase one: First receive via a "pass ref", then a tracked with no ref.
121 PP_Var plugin_var = var_tracker().ReceiveObjectPassRef(
122 host_object, plugin_dispatcher());
123 PP_Var plugin_var2 = var_tracker().TrackObjectWithNoReference(
124 host_object, plugin_dispatcher());
125 EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id);
126 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_var));
127 EXPECT_EQ(1,
128 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
130 // Free via the refcount, this should release the object to the browser but
131 // maintain the tracked object.
132 var_tracker().ReleaseVar(plugin_var);
133 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_var));
134 EXPECT_EQ(1u, sink().message_count());
135 EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject());
137 // Now free via the tracked object, this should free it.
138 var_tracker().StopTrackingObjectWithNoReference(plugin_var);
139 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_var));
141 // Phase two: Receive via a tracked, then get an addref.
142 sink().ClearMessages();
143 plugin_var = var_tracker().TrackObjectWithNoReference(
144 host_object, plugin_dispatcher());
145 plugin_var2 = var_tracker().ReceiveObjectPassRef(
146 host_object, plugin_dispatcher());
147 EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id);
148 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_var));
149 EXPECT_EQ(1,
150 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
152 // Free via the tracked object, this should have no effect.
153 var_tracker().StopTrackingObjectWithNoReference(plugin_var);
154 EXPECT_EQ(0,
155 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
156 EXPECT_EQ(0u, sink().message_count());
158 // Now free via the refcount, this should delete it.
159 var_tracker().ReleaseVar(plugin_var);
160 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_var));
161 EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject());
164 TEST_F(PluginVarTrackerTest, RecursiveTrackWithNoRef) {
165 ProxyAutoLock lock;
166 PP_Var host_object = MakeObject(12345);
168 // Receive a tracked object twice.
169 PP_Var plugin_var = var_tracker().TrackObjectWithNoReference(
170 host_object, plugin_dispatcher());
171 EXPECT_EQ(1,
172 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
173 PP_Var plugin_var2 = var_tracker().TrackObjectWithNoReference(
174 host_object, plugin_dispatcher());
175 EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id);
176 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_var));
177 EXPECT_EQ(2,
178 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
180 // Now release those tracked items, the reference should be freed.
181 var_tracker().StopTrackingObjectWithNoReference(plugin_var);
182 EXPECT_EQ(1,
183 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
184 var_tracker().StopTrackingObjectWithNoReference(plugin_var);
185 EXPECT_EQ(-1,
186 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
189 // Tests that objects implemented by the plugin that have no references by
190 // the plugin get their Deallocate function called on destruction.
191 TEST_F(PluginVarTrackerTest, PluginObjectInstanceDeleted) {
192 ProxyAutoLock lock;
193 PP_Var host_object = MakeObject(12345);
194 PP_Instance pp_instance = 0x12345;
196 int deallocate_called = 0;
197 void* user_data = &deallocate_called;
199 // Make a var with one reference.
200 scoped_refptr<ProxyObjectVar> object(
201 new ProxyObjectVar(plugin_dispatcher(), host_object.value.as_id));
202 PP_Var plugin_var = MakeObject(var_tracker().AddVar(object.get()));
203 var_tracker().PluginImplementedObjectCreated(
204 pp_instance, plugin_var, &mark_on_deallocate_class, user_data);
206 // Release the plugin ref to the var. WebKit hasn't called destroy so
207 // we won't get a destroy call.
208 object = NULL;
209 var_tracker().ReleaseVar(plugin_var);
210 EXPECT_EQ(0, deallocate_called);
212 // Synthesize an instance destuction, this should call Deallocate.
213 var_tracker().DidDeleteInstance(pp_instance);
214 EXPECT_EQ(1, deallocate_called);
217 // Tests what happens when a plugin keeps a ref to a plugin-implemented
218 // object var longer than the instance. We should not call the destructor until
219 // the plugin releases its last ref.
220 TEST_F(PluginVarTrackerTest, PluginObjectLeaked) {
221 ProxyAutoLock lock;
222 PP_Var host_object = MakeObject(12345);
223 PP_Instance pp_instance = 0x12345;
225 int deallocate_called = 0;
226 void* user_data = &deallocate_called;
228 // Make a var with one reference.
229 scoped_refptr<ProxyObjectVar> object(
230 new ProxyObjectVar(plugin_dispatcher(), host_object.value.as_id));
231 PP_Var plugin_var = MakeObject(var_tracker().AddVar(object.get()));
232 var_tracker().PluginImplementedObjectCreated(
233 pp_instance, plugin_var, &mark_on_deallocate_class, user_data);
235 // Destroy the instance. This should not call deallocate since the plugin
236 // still has a ref.
237 var_tracker().DidDeleteInstance(pp_instance);
238 EXPECT_EQ(0, deallocate_called);
240 // Release the plugin ref to the var. Since the instance is gone this should
241 // call deallocate.
242 object = NULL;
243 var_tracker().ReleaseVar(plugin_var);
244 EXPECT_EQ(1, deallocate_called);
247 } // namespace proxy
248 } // namespace ppapi