blob: fcde77795a37b71cf2fa5baa718b040779c420dc [file] [log] [blame]
[email protected]73097562012-01-12 19:38:551// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]f24448db2011-01-27 20:40:392// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/proxy/ppapi_proxy_test.h"
6
7#include "ppapi/proxy/serialized_var.h"
[email protected]4c41d3f2012-02-15 01:44:478#include "ppapi/shared_impl/proxy_lock.h"
[email protected]f24448db2011-01-27 20:40:399
[email protected]4d2efd22011-08-18 21:58:0210namespace ppapi {
[email protected]f24448db2011-01-27 20:40:3911namespace proxy {
12
13namespace {
14
[email protected]f24448db2011-01-27 20:40:3915PP_Var MakeObjectVar(int64_t object_id) {
16 PP_Var ret;
17 ret.type = PP_VARTYPE_OBJECT;
18 ret.value.as_id = object_id;
19 return ret;
20}
21
22class SerializedVarTest : public PluginProxyTest {
23 public:
24 SerializedVarTest() {}
25};
26
27} // namespace
28
[email protected]7d6fd8a2011-08-01 18:13:5429// Tests output arguments in the plugin. This is when the host calls into the
30// plugin and the plugin returns something via an out param, like an exception.
[email protected]a732cec2011-12-22 08:35:5231TEST_F(SerializedVarTest, PluginSerializedVarInOutParam) {
[email protected]4c41d3f2012-02-15 01:44:4732 ProxyAutoLock lock;
[email protected]a732cec2011-12-22 08:35:5233 PP_Var host_object = MakeObjectVar(0x31337);
34
35 PP_Var plugin_object;
36 {
37 // Receive the object param, we should be tracking it with no refcount, and
38 // no messages sent.
39 SerializedVarTestConstructor input(host_object);
40 SerializedVarReceiveInput receive_input(input);
41 plugin_object = receive_input.Get(plugin_dispatcher());
42 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
43 EXPECT_EQ(0u, sink().message_count());
44
45 SerializedVar sv;
46 {
47 // The "OutParam" does its work in its destructor, it will write the
48 // information to the SerializedVar we passed in the constructor.
49 SerializedVarOutParam out_param(&sv);
50 // An out-param needs to pass a reference to the caller, so it's the
51 // responsibility of the plugin to bump the ref-count on an input
52 // parameter.
53 var_tracker().AddRefVar(plugin_object);
54 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
55 // We should have informed the host that a reference was taken.
56 EXPECT_EQ(1u, sink().message_count());
57 *out_param.OutParam(plugin_dispatcher()) = plugin_object;
58 }
59
60 // The object should have transformed the plugin object back to the host
61 // object ID. Nothing in the var tracker should have changed yet, and no
62 // messages should have been sent.
63 SerializedVarTestReader reader(sv);
[email protected]2d449b32012-02-07 05:38:0064 EXPECT_EQ(host_object.value.as_id, reader.GetVar().value.as_id);
[email protected]a732cec2011-12-22 08:35:5265 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
66 EXPECT_EQ(1u, sink().message_count());
67 }
68
69 // The out param should have done an "end receive caller owned" on the plugin
70 // var serialization rules, which should have released the "track-with-no-
71 // reference" count in the var tracker as well as the 1 reference we passed
72 // back to the host, so the object should no longer be in the tracker. The
73 // reference we added has been removed, so another message should be sent to
74 // the host to tell it we're done with the object.
75 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
76 EXPECT_EQ(2u, sink().message_count());
77}
78
79// Tests output strings in the plugin. This is when the host calls into the
80// plugin with a string and the plugin returns it via an out param.
81TEST_F(SerializedVarTest, PluginSerializedStringVarInOutParam) {
[email protected]4c41d3f2012-02-15 01:44:4782 ProxyAutoLock lock;
[email protected]a732cec2011-12-22 08:35:5283 PP_Var plugin_string;
84 const std::string kTestString("elite");
85 {
86 // Receive the string param. We should track it with 1 refcount.
87 SerializedVarTestConstructor input(kTestString);
88 SerializedVarReceiveInput receive_input(input);
89 plugin_string = receive_input.Get(plugin_dispatcher());
90 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_string));
91 EXPECT_EQ(0u, sink().message_count());
92
93 SerializedVar sv;
94 {
95 // The "OutParam" does its work in its destructor, it will write the
96 // information to the SerializedVar we passed in the constructor.
97 SerializedVarOutParam out_param(&sv);
98 // An out-param needs to pass a reference to the caller, so it's the
99 // responsibility of the plugin to bump the ref-count of an input
100 // parameter.
101 var_tracker().AddRefVar(plugin_string);
102 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string));
103 EXPECT_EQ(0u, sink().message_count());
104 *out_param.OutParam(plugin_dispatcher()) = plugin_string;
105 }
106
107 // The SerializedVar should have set the string value internally. Nothing in
108 // the var tracker should have changed yet, and no messages should have been
109 // sent.
110 SerializedVarTestReader reader(sv);
[email protected]2d449b32012-02-07 05:38:00111 //EXPECT_EQ(kTestString, *reader.GetTrackerStringPtr());
[email protected]a732cec2011-12-22 08:35:52112 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string));
113 EXPECT_EQ(0u, sink().message_count());
114 }
115 // The reference the string had initially should be gone, and the reference we
116 // passed to the host should also be gone, so the string should be removed.
117 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_string));
118 EXPECT_EQ(0u, sink().message_count());
119}
120
[email protected]73097562012-01-12 19:38:55121// Tests receiving an argument and passing it back to the browser as an output
122// parameter.
[email protected]f24448db2011-01-27 20:40:39123TEST_F(SerializedVarTest, PluginSerializedVarOutParam) {
[email protected]4c41d3f2012-02-15 01:44:47124 ProxyAutoLock lock;
[email protected]f24448db2011-01-27 20:40:39125 PP_Var host_object = MakeObjectVar(0x31337);
126
127 // Start tracking this object in the plugin.
128 PP_Var plugin_object = var_tracker().ReceiveObjectPassRef(
129 host_object, plugin_dispatcher());
130 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
131
132 {
133 SerializedVar sv;
134 {
135 // The "OutParam" does its work in its destructor, it will write the
136 // information to the SerializedVar we passed in the constructor.
137 SerializedVarOutParam out_param(&sv);
138 *out_param.OutParam(plugin_dispatcher()) = plugin_object;
139 }
140
141 // The object should have transformed the plugin object back to the host
142 // object ID. Nothing in the var tracker should have changed yet, and no
143 // messages should have been sent.
144 SerializedVarTestReader reader(sv);
[email protected]2d449b32012-02-07 05:38:00145 EXPECT_EQ(host_object.value.as_id, reader.GetVar().value.as_id);
[email protected]f24448db2011-01-27 20:40:39146 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
147 EXPECT_EQ(0u, sink().message_count());
148 }
149
150 // The out param should have done an "end send pass ref" on the plugin
151 // var serialization rules, which should have in turn released the reference
152 // in the var tracker. Since we only had one reference, this should have sent
153 // a release to the browser.
154 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
155 EXPECT_EQ(1u, sink().message_count());
156
157 // We don't bother validating that message since it's nontrivial and the
158 // PluginVarTracker test has cases that cover that this message is correct.
159}
160
[email protected]7d6fd8a2011-08-01 18:13:54161// Tests the case that the plugin receives the same var twice as an input
162// parameter (not passing ownership).
163TEST_F(SerializedVarTest, PluginReceiveInput) {
[email protected]4c41d3f2012-02-15 01:44:47164 ProxyAutoLock lock;
[email protected]7d6fd8a2011-08-01 18:13:54165 PP_Var host_object = MakeObjectVar(0x31337);
166
167 PP_Var plugin_object;
168 {
169 // Receive the first param, we should be tracking it with no refcount, and
170 // no messages sent.
171 SerializedVarTestConstructor input1(host_object);
172 SerializedVarReceiveInput receive_input(input1);
173 plugin_object = receive_input.Get(plugin_dispatcher());
174 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
175 EXPECT_EQ(0u, sink().message_count());
176
177 // Receive the second param, it should be resolved to the same plugin
178 // object and there should still be no refcount.
179 SerializedVarTestConstructor input2(host_object);
180 SerializedVarReceiveInput receive_input2(input2);
181 PP_Var plugin_object2 = receive_input2.Get(plugin_dispatcher());
182 EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id);
183 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
184 EXPECT_EQ(0u, sink().message_count());
185
186 // Take a reference to the object, as if the plugin was using it, and then
187 // release it, we should still be tracking the object since the
188 // ReceiveInputs keep the "track_with_no_reference_count" alive until
189 // they're destroyed.
[email protected]2bbd2c672011-08-09 23:14:13190 var_tracker().AddRefVar(plugin_object);
[email protected]7d6fd8a2011-08-01 18:13:54191 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
[email protected]2bbd2c672011-08-09 23:14:13192 var_tracker().ReleaseVar(plugin_object);
[email protected]7d6fd8a2011-08-01 18:13:54193 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
194 EXPECT_EQ(2u, sink().message_count());
195 }
196
197 // Since we didn't keep any refs to the objects, it should have freed the
198 // object.
199 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
200}
201
[email protected]a732cec2011-12-22 08:35:52202// Tests the case that the plugin receives the same vars twice as an input
203// parameter (not passing ownership) within a vector.
[email protected]ecac5732012-10-06 02:06:21204TEST_F(SerializedVarTest, PluginVectorReceiveInput) {
[email protected]4c41d3f2012-02-15 01:44:47205 ProxyAutoLock lock;
[email protected]a732cec2011-12-22 08:35:52206 PP_Var host_object = MakeObjectVar(0x31337);
207
[email protected]ecac5732012-10-06 02:06:21208 std::vector<PP_Var> plugin_objects;
209 std::vector<PP_Var> plugin_objects2;
[email protected]a732cec2011-12-22 08:35:52210 {
211 // Receive the params. The object should be tracked with no refcount and
212 // no messages sent. The string should is plugin-side only and should have
213 // a reference-count of 1.
214 std::vector<SerializedVar> input1;
215 input1.push_back(SerializedVarTestConstructor(host_object));
216 input1.push_back(SerializedVarTestConstructor("elite"));
217 SerializedVarVectorReceiveInput receive_input(input1);
218 uint32_t array_size = 0;
[email protected]ecac5732012-10-06 02:06:21219 PP_Var* plugin_objects_array =
220 receive_input.Get(plugin_dispatcher(), &array_size);
221 plugin_objects.insert(plugin_objects.begin(), plugin_objects_array,
222 plugin_objects_array + array_size);
[email protected]a732cec2011-12-22 08:35:52223 ASSERT_EQ(2u, array_size);
224 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0]));
225 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[1]));
226 EXPECT_EQ(0u, sink().message_count());
227
228 // Receive the second param, it should be resolved to the same plugin
229 // object and there should still be no refcount.
230 std::vector<SerializedVar> input2;
231 input2.push_back(SerializedVarTestConstructor(host_object));
232 input2.push_back(SerializedVarTestConstructor("elite"));
233 SerializedVarVectorReceiveInput receive_input2(input2);
234 uint32_t array_size2 = 0;
[email protected]ecac5732012-10-06 02:06:21235 PP_Var* plugin_objects_array2 =
236 receive_input2.Get(plugin_dispatcher(), &array_size2);
237 plugin_objects2.insert(plugin_objects2.begin(), plugin_objects_array2,
238 plugin_objects_array2 + array_size2);
[email protected]a732cec2011-12-22 08:35:52239 ASSERT_EQ(2u, array_size2);
240 EXPECT_EQ(plugin_objects[0].value.as_id, plugin_objects2[0].value.as_id);
241 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0]));
242 // Strings get re-created with a new ID. We don't try to reuse strings in
243 // the tracker, so the string should get a new ID.
244 EXPECT_NE(plugin_objects[1].value.as_id, plugin_objects2[1].value.as_id);
245 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects2[1]));
246 EXPECT_EQ(0u, sink().message_count());
247
248 // Take a reference to the object, as if the plugin was using it, and then
249 // release it, we should still be tracking the object since the
250 // ReceiveInputs keep the "track_with_no_reference_count" alive until
251 // they're destroyed.
252 var_tracker().AddRefVar(plugin_objects[0]);
253 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[0]));
254 var_tracker().ReleaseVar(plugin_objects[0]);
255 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0]));
256 EXPECT_EQ(2u, sink().message_count());
257
258 // Take a reference to a string and then release it. Make sure no messages
259 // are sent.
260 uint32_t old_message_count = sink().message_count();
261 var_tracker().AddRefVar(plugin_objects[1]);
262 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_objects[1]));
263 var_tracker().ReleaseVar(plugin_objects[1]);
264 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[1]));
265 EXPECT_EQ(old_message_count, sink().message_count());
266 }
267
268 // Since we didn't keep any refs to the objects or strings, so they should
269 // have been freed.
270 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects[0]));
271 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects[1]));
272 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects2[1]));
273}
274
[email protected]7d6fd8a2011-08-01 18:13:54275// Tests the plugin receiving a var as a return value from the browser
276// two different times (passing ownership).
277TEST_F(SerializedVarTest, PluginReceiveReturn) {
[email protected]4c41d3f2012-02-15 01:44:47278 ProxyAutoLock lock;
[email protected]7d6fd8a2011-08-01 18:13:54279 PP_Var host_object = MakeObjectVar(0x31337);
280
281 PP_Var plugin_object;
282 {
283 // Receive the first param, we should be tracking it with a refcount of 1.
284 SerializedVarTestConstructor input1(host_object);
285 ReceiveSerializedVarReturnValue receive_input(input1);
286 plugin_object = receive_input.Return(plugin_dispatcher());
287 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
288 EXPECT_EQ(0u, sink().message_count());
289
290 // Receive the second param, it should be resolved to the same plugin
291 // object and there should be a plugin refcount of 2. There should have
292 // been an IPC message sent that released the duplicated ref in the browser
293 // (so both of our refs are represented by one in the browser).
294 SerializedVarTestConstructor input2(host_object);
295 ReceiveSerializedVarReturnValue receive_input2(input2);
296 PP_Var plugin_object2 = receive_input2.Return(plugin_dispatcher());
297 EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id);
298 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object));
299 EXPECT_EQ(1u, sink().message_count());
300 }
301
302 // The ReceiveSerializedVarReturnValue destructor shouldn't have affected
303 // the refcount or sent any messages.
304 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object));
305 EXPECT_EQ(1u, sink().message_count());
306
307 // Manually release one refcount, it shouldn't have sent any more messages.
[email protected]2bbd2c672011-08-09 23:14:13308 var_tracker().ReleaseVar(plugin_object);
[email protected]7d6fd8a2011-08-01 18:13:54309 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
310 EXPECT_EQ(1u, sink().message_count());
311
312 // Manually release the last refcount, it should have freed it and sent a
313 // release message to the browser.
[email protected]2bbd2c672011-08-09 23:14:13314 var_tracker().ReleaseVar(plugin_object);
[email protected]7d6fd8a2011-08-01 18:13:54315 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
316 EXPECT_EQ(2u, sink().message_count());
317}
318
319// Returns a value from the browser to the plugin, then return that one ref
320// back to the browser.
321TEST_F(SerializedVarTest, PluginReturnValue) {
[email protected]4c41d3f2012-02-15 01:44:47322 ProxyAutoLock lock;
[email protected]7d6fd8a2011-08-01 18:13:54323 PP_Var host_object = MakeObjectVar(0x31337);
324
325 PP_Var plugin_object;
326 {
327 // Receive the param in the plugin.
328 SerializedVarTestConstructor input1(host_object);
329 ReceiveSerializedVarReturnValue receive_input(input1);
330 plugin_object = receive_input.Return(plugin_dispatcher());
331 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
332 EXPECT_EQ(0u, sink().message_count());
333 }
334
335 {
336 // Now return to the browser.
337 SerializedVar output;
338 SerializedVarReturnValue return_output(&output);
339 return_output.Return(plugin_dispatcher(), plugin_object);
340
341 // The ref in the plugin should be alive until the ReturnValue goes out of
342 // scope, since the release needs to be after the browser processes the
343 // message.
344 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
345 }
346
347 // When the ReturnValue object goes out of scope, it should have sent a
348 // release message to the browser.
349 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
350 EXPECT_EQ(1u, sink().message_count());
351}
352
[email protected]f24448db2011-01-27 20:40:39353} // namespace proxy
[email protected]4d2efd22011-08-18 21:58:02354} // namespace ppapi