Elim cr-checkbox
[chromium-blink-merge.git] / ppapi / proxy / serialized_var_unittest.cc
blobd88c848317e400c7f2c8cef6c3fd5471b50e16ca
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 "ppapi/proxy/ppapi_proxy_test.h"
7 #include "ppapi/proxy/proxy_object_var.h"
8 #include "ppapi/proxy/serialized_var.h"
9 #include "ppapi/shared_impl/proxy_lock.h"
11 namespace ppapi {
12 namespace proxy {
14 namespace {
16 PP_Var MakeObjectVar(int64_t object_id) {
17 PP_Var ret;
18 ret.type = PP_VARTYPE_OBJECT;
19 ret.value.as_id = object_id;
20 return ret;
23 class SerializedVarTest : public PluginProxyTest {
24 public:
25 SerializedVarTest() {}
28 } // namespace
30 // Tests output arguments in the plugin. This is when the host calls into the
31 // plugin and the plugin returns something via an out param, like an exception.
32 TEST_F(SerializedVarTest, PluginSerializedVarInOutParam) {
33 ProxyAutoLock lock;
34 PP_Var host_object = MakeObjectVar(0x31337);
36 PP_Var plugin_object;
38 // Receive the object param, we should be tracking it with no refcount, and
39 // no messages sent.
40 SerializedVarTestConstructor input(host_object);
41 SerializedVarReceiveInput receive_input(input);
42 plugin_object = receive_input.Get(plugin_dispatcher());
43 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
44 EXPECT_EQ(0u, sink().message_count());
46 SerializedVar sv;
48 // The "OutParam" does its work in its destructor, it will write the
49 // information to the SerializedVar we passed in the constructor.
50 SerializedVarOutParam out_param(&sv);
51 // An out-param needs to pass a reference to the caller, so it's the
52 // responsibility of the plugin to bump the ref-count on an input
53 // parameter.
54 var_tracker().AddRefVar(plugin_object);
55 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
56 // We should have informed the host that a reference was taken.
57 EXPECT_EQ(1u, sink().message_count());
58 *out_param.OutParam(plugin_dispatcher()) = plugin_object;
61 // The object should have transformed the plugin object back to the host
62 // object ID. Nothing in the var tracker should have changed yet, and no
63 // messages should have been sent.
64 SerializedVarTestReader reader(sv);
65 EXPECT_EQ(host_object.value.as_id, reader.GetVar().value.as_id);
66 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
67 EXPECT_EQ(1u, sink().message_count());
70 // The out param should have done an "end receive caller owned" on the plugin
71 // var serialization rules, which should have released the "track-with-no-
72 // reference" count in the var tracker as well as the 1 reference we passed
73 // back to the host, so the object should no longer be in the tracker. The
74 // reference we added has been removed, so another message should be sent to
75 // the host to tell it we're done with the object.
76 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
77 EXPECT_EQ(2u, sink().message_count());
80 // Tests output strings in the plugin. This is when the host calls into the
81 // plugin with a string and the plugin returns it via an out param.
82 TEST_F(SerializedVarTest, PluginSerializedStringVarInOutParam) {
83 ProxyAutoLock lock;
84 PP_Var plugin_string;
85 const std::string kTestString("elite");
87 // Receive the string param. We should track it with 1 refcount.
88 SerializedVarTestConstructor input(kTestString);
89 SerializedVarReceiveInput receive_input(input);
90 plugin_string = receive_input.Get(plugin_dispatcher());
91 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_string));
92 EXPECT_EQ(0u, sink().message_count());
94 SerializedVar sv;
96 // The "OutParam" does its work in its destructor, it will write the
97 // information to the SerializedVar we passed in the constructor.
98 SerializedVarOutParam out_param(&sv);
99 // An out-param needs to pass a reference to the caller, so it's the
100 // responsibility of the plugin to bump the ref-count of an input
101 // parameter.
102 var_tracker().AddRefVar(plugin_string);
103 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string));
104 EXPECT_EQ(0u, sink().message_count());
105 *out_param.OutParam(plugin_dispatcher()) = plugin_string;
108 // The SerializedVar should have set the string value internally. Nothing in
109 // the var tracker should have changed yet, and no messages should have been
110 // sent.
111 SerializedVarTestReader reader(sv);
112 //EXPECT_EQ(kTestString, *reader.GetTrackerStringPtr());
113 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string));
114 EXPECT_EQ(0u, sink().message_count());
116 // The reference the string had initially should be gone, and the reference we
117 // passed to the host should also be gone, so the string should be removed.
118 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_string));
119 EXPECT_EQ(0u, sink().message_count());
122 // Tests receiving an argument and passing it back to the browser as an output
123 // parameter.
124 TEST_F(SerializedVarTest, PluginSerializedVarOutParam) {
125 ProxyAutoLock lock;
126 PP_Var host_object = MakeObjectVar(0x31337);
128 // Start tracking this object in the plugin.
129 PP_Var plugin_object = var_tracker().ReceiveObjectPassRef(
130 host_object, plugin_dispatcher());
131 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
134 SerializedVar sv;
136 // The "OutParam" does its work in its destructor, it will write the
137 // information to the SerializedVar we passed in the constructor.
138 SerializedVarOutParam out_param(&sv);
139 *out_param.OutParam(plugin_dispatcher()) = plugin_object;
142 // The object should have transformed the plugin object back to the host
143 // object ID. Nothing in the var tracker should have changed yet, and no
144 // messages should have been sent.
145 SerializedVarTestReader reader(sv);
146 EXPECT_EQ(host_object.value.as_id, reader.GetVar().value.as_id);
147 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
148 EXPECT_EQ(0u, sink().message_count());
151 // The out param should have done an "end send pass ref" on the plugin
152 // var serialization rules, which should have in turn released the reference
153 // in the var tracker. Since we only had one reference, this should have sent
154 // a release to the browser.
155 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
156 EXPECT_EQ(1u, sink().message_count());
158 // We don't bother validating that message since it's nontrivial and the
159 // PluginVarTracker test has cases that cover that this message is correct.
162 // Tests the case that the plugin receives the same var twice as an input
163 // parameter (not passing ownership).
164 TEST_F(SerializedVarTest, PluginReceiveInput) {
165 ProxyAutoLock lock;
166 PP_Var host_object = MakeObjectVar(0x31337);
168 PP_Var plugin_object;
170 // Receive the first param, we should be tracking it with no refcount, and
171 // no messages sent.
172 SerializedVarTestConstructor input1(host_object);
173 SerializedVarReceiveInput receive_input(input1);
174 plugin_object = receive_input.Get(plugin_dispatcher());
175 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
176 EXPECT_EQ(0u, sink().message_count());
178 // Receive the second param, it should be resolved to the same plugin
179 // object and there should still be no refcount.
180 SerializedVarTestConstructor input2(host_object);
181 SerializedVarReceiveInput receive_input2(input2);
182 PP_Var plugin_object2 = receive_input2.Get(plugin_dispatcher());
183 EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id);
184 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
185 EXPECT_EQ(0u, sink().message_count());
187 // Take a reference to the object, as if the plugin was using it, and then
188 // release it, we should still be tracking the object since the
189 // ReceiveInputs keep the "track_with_no_reference_count" alive until
190 // they're destroyed.
191 var_tracker().AddRefVar(plugin_object);
192 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
193 var_tracker().ReleaseVar(plugin_object);
194 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
195 EXPECT_EQ(2u, sink().message_count());
198 // Since we didn't keep any refs to the objects, it should have freed the
199 // object.
200 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
203 // Tests the case that the plugin receives the same vars twice as an input
204 // parameter (not passing ownership) within a vector.
205 TEST_F(SerializedVarTest, PluginVectorReceiveInput) {
206 ProxyAutoLock lock;
207 PP_Var host_object = MakeObjectVar(0x31337);
209 std::vector<PP_Var> plugin_objects;
210 std::vector<PP_Var> plugin_objects2;
212 // Receive the params. The object should be tracked with no refcount and
213 // no messages sent. The string should is plugin-side only and should have
214 // a reference-count of 1.
215 std::vector<SerializedVar> input1;
216 input1.push_back(SerializedVarTestConstructor(host_object));
217 input1.push_back(SerializedVarTestConstructor("elite"));
218 SerializedVarVectorReceiveInput receive_input(input1);
219 uint32_t array_size = 0;
220 PP_Var* plugin_objects_array =
221 receive_input.Get(plugin_dispatcher(), &array_size);
222 plugin_objects.insert(plugin_objects.begin(), plugin_objects_array,
223 plugin_objects_array + array_size);
224 ASSERT_EQ(2u, array_size);
225 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0]));
226 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[1]));
227 EXPECT_EQ(0u, sink().message_count());
229 // Receive the second param, it should be resolved to the same plugin
230 // object and there should still be no refcount.
231 std::vector<SerializedVar> input2;
232 input2.push_back(SerializedVarTestConstructor(host_object));
233 input2.push_back(SerializedVarTestConstructor("elite"));
234 SerializedVarVectorReceiveInput receive_input2(input2);
235 uint32_t array_size2 = 0;
236 PP_Var* plugin_objects_array2 =
237 receive_input2.Get(plugin_dispatcher(), &array_size2);
238 plugin_objects2.insert(plugin_objects2.begin(), plugin_objects_array2,
239 plugin_objects_array2 + array_size2);
240 ASSERT_EQ(2u, array_size2);
241 EXPECT_EQ(plugin_objects[0].value.as_id, plugin_objects2[0].value.as_id);
242 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0]));
243 // Strings get re-created with a new ID. We don't try to reuse strings in
244 // the tracker, so the string should get a new ID.
245 EXPECT_NE(plugin_objects[1].value.as_id, plugin_objects2[1].value.as_id);
246 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects2[1]));
247 EXPECT_EQ(0u, sink().message_count());
249 // Take a reference to the object, as if the plugin was using it, and then
250 // release it, we should still be tracking the object since the
251 // ReceiveInputs keep the "track_with_no_reference_count" alive until
252 // they're destroyed.
253 var_tracker().AddRefVar(plugin_objects[0]);
254 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[0]));
255 var_tracker().ReleaseVar(plugin_objects[0]);
256 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0]));
257 EXPECT_EQ(2u, sink().message_count());
259 // Take a reference to a string and then release it. Make sure no messages
260 // are sent.
261 uint32_t old_message_count = static_cast<uint32_t>(sink().message_count());
262 var_tracker().AddRefVar(plugin_objects[1]);
263 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_objects[1]));
264 var_tracker().ReleaseVar(plugin_objects[1]);
265 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[1]));
266 EXPECT_EQ(old_message_count, sink().message_count());
269 // Since we didn't keep any refs to the objects or strings, so they should
270 // have been freed.
271 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects[0]));
272 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects[1]));
273 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects2[1]));
276 // Tests the browser sending a String var as a return value to make sure we
277 // ref-count the host side properly.
278 typedef HostProxyTest HostSerializedVarTest;
279 TEST_F(HostSerializedVarTest, PluginReceiveStringReturn) {
281 PP_Var string_var = StringVar::StringToPPVar("Hello");
282 EXPECT_EQ(1, var_tracker().GetRefCountForObject(string_var));
283 GetDispatcher()->serialization_rules()->BeginSendPassRef(string_var);
284 GetDispatcher()->serialization_rules()->EndSendPassRef(string_var);
285 // It should be gone, so we should get -1 to indicate that.
286 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(string_var));
290 // Note this is as little weird; we're testing the behavior of the host-
291 // side of the proxy, but we use ProxyObjectVar, because this unit test
292 // doesn't have access to stuff in content/renderer/pepper. The ref-counting
293 // behavior should be the same, however. All we're really testing
294 // is the code in ppapi/proxy (HostVarSerializationRules).
295 scoped_refptr<Var> obj_var = new ProxyObjectVar(NULL, 1234);
296 PP_Var obj_pp_var = obj_var->GetPPVar();
297 EXPECT_EQ(1, var_tracker().GetRefCountForObject(obj_pp_var));
298 GetDispatcher()->serialization_rules()->BeginSendPassRef(obj_pp_var);
299 GetDispatcher()->serialization_rules()->EndSendPassRef(obj_pp_var);
300 // The host side for object vars always keeps 1 ref on behalf of the plugin.
301 // See HostVarSerializationRules and PluginVarSerializationRules for an
302 // explanation.
303 EXPECT_EQ(1, var_tracker().GetRefCountForObject(obj_pp_var));
304 var_tracker().ReleaseVar(obj_pp_var);
308 // Tests the plugin receiving a var as a return value from the browser
309 // two different times (passing ownership).
310 TEST_F(SerializedVarTest, PluginReceiveReturn) {
311 ProxyAutoLock lock;
312 PP_Var host_object = MakeObjectVar(0x31337);
314 PP_Var plugin_object;
316 // Receive the first param, we should be tracking it with a refcount of 1.
317 SerializedVarTestConstructor input1(host_object);
318 ReceiveSerializedVarReturnValue receive_input(input1);
319 plugin_object = receive_input.Return(plugin_dispatcher());
320 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
321 EXPECT_EQ(0u, sink().message_count());
323 // Receive the second param, it should be resolved to the same plugin
324 // object and there should be a plugin refcount of 2. There should have
325 // been an IPC message sent that released the duplicated ref in the browser
326 // (so both of our refs are represented by one in the browser).
327 SerializedVarTestConstructor input2(host_object);
328 ReceiveSerializedVarReturnValue receive_input2(input2);
329 PP_Var plugin_object2 = receive_input2.Return(plugin_dispatcher());
330 EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id);
331 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object));
332 EXPECT_EQ(1u, sink().message_count());
335 // The ReceiveSerializedVarReturnValue destructor shouldn't have affected
336 // the refcount or sent any messages.
337 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object));
338 EXPECT_EQ(1u, sink().message_count());
340 // Manually release one refcount, it shouldn't have sent any more messages.
341 var_tracker().ReleaseVar(plugin_object);
342 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
343 EXPECT_EQ(1u, sink().message_count());
345 // Manually release the last refcount, it should have freed it and sent a
346 // release message to the browser.
347 var_tracker().ReleaseVar(plugin_object);
348 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
349 EXPECT_EQ(2u, sink().message_count());
352 // Returns a value from the browser to the plugin, then return that one ref
353 // back to the browser.
354 TEST_F(SerializedVarTest, PluginReturnValue) {
355 ProxyAutoLock lock;
356 PP_Var host_object = MakeObjectVar(0x31337);
358 PP_Var plugin_object;
360 // Receive the param in the plugin.
361 SerializedVarTestConstructor input1(host_object);
362 ReceiveSerializedVarReturnValue receive_input(input1);
363 plugin_object = receive_input.Return(plugin_dispatcher());
364 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
365 EXPECT_EQ(0u, sink().message_count());
369 // Now return to the browser.
370 SerializedVar output;
371 SerializedVarReturnValue return_output(&output);
372 return_output.Return(plugin_dispatcher(), plugin_object);
374 // The ref in the plugin should be alive until the ReturnValue goes out of
375 // scope, since the release needs to be after the browser processes the
376 // message.
377 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
380 // When the ReturnValue object goes out of scope, it should have sent a
381 // release message to the browser.
382 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
383 EXPECT_EQ(1u, sink().message_count());
386 } // namespace proxy
387 } // namespace ppapi