blob: ce2014f146c429f0a572fd11058211b309b0ae74 [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ipc/ipc_test_sink.h"
#include "ppapi/proxy/plugin_var_tracker.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/ppapi_proxy_test.h"
namespace ppapi {
namespace proxy {
namespace {
PP_Var MakeObject(int32 object_id) {
PP_Var ret;
ret.type = PP_VARTYPE_OBJECT;
ret.value.as_id = object_id;
return ret;
}
} // namespace
class PluginVarTrackerTest : public PluginProxyTest {
public:
PluginVarTrackerTest() {}
protected:
// Asserts that there is a unique "release object" IPC message in the test
// sink. This will return the var ID from the message or -1 if none found.
int32 GetObjectIDForUniqueReleaseObject() {
const IPC::Message* release_msg = sink().GetUniqueMessageMatching(
PpapiHostMsg_PPBVar_ReleaseObject::ID);
if (!release_msg)
return -1;
Tuple1<int64> id;
PpapiHostMsg_PPBVar_ReleaseObject::Read(release_msg, &id);
return id.a;
}
};
TEST_F(PluginVarTrackerTest, GetHostObject) {
PP_Var host_object = MakeObject(12345);
// Round-trip through the tracker to make sure the host object comes out the
// other end.
PP_Var plugin_object = var_tracker().ReceiveObjectPassRef(
host_object, plugin_dispatcher());
PP_Var host_object2 = var_tracker().GetHostObject(plugin_object);
EXPECT_EQ(PP_VARTYPE_OBJECT, host_object2.type);
EXPECT_EQ(host_object.value.as_id, host_object2.value.as_id);
var_tracker().ReleaseVar(plugin_object);
}
TEST_F(PluginVarTrackerTest, ReceiveObjectPassRef) {
PP_Var host_object = MakeObject(12345);
// Receive the object, we should have one ref and no messages.
PP_Var plugin_object = var_tracker().ReceiveObjectPassRef(
host_object, plugin_dispatcher());
EXPECT_EQ(0u, sink().message_count());
EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
EXPECT_EQ(0,
var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_object));
// Receive the same object again, we should get the same plugin ID out.
PP_Var plugin_object2 = var_tracker().ReceiveObjectPassRef(
host_object, plugin_dispatcher());
EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id);
EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object));
EXPECT_EQ(0,
var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_object));
// It should have sent one message to decerment the refcount in the host.
// This is because it only maintains one host refcount for all references
// in the plugin, but the host just sent the second one.
EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject());
sink().ClearMessages();
// Release the object, one ref at a time. The second release should free
// the tracking data and send a release message to the browser.
var_tracker().ReleaseVar(plugin_object);
EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
var_tracker().ReleaseVar(plugin_object);
EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject());
}
// Tests freeing objects that have both refcounts and "tracked with no ref".
TEST_F(PluginVarTrackerTest, FreeTrackedAndReferencedObject) {
PP_Var host_object = MakeObject(12345);
// Phase one: First receive via a "pass ref", then a tracked with no ref.
PP_Var plugin_var = var_tracker().ReceiveObjectPassRef(
host_object, plugin_dispatcher());
PP_Var plugin_var2 = var_tracker().TrackObjectWithNoReference(
host_object, plugin_dispatcher());
EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id);
EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_var));
EXPECT_EQ(1,
var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
// Free via the refcount, this should release the object to the browser but
// maintain the tracked object.
var_tracker().ReleaseVar(plugin_var);
EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_var));
EXPECT_EQ(1u, sink().message_count());
EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject());
// Now free via the tracked object, this should free it.
var_tracker().StopTrackingObjectWithNoReference(plugin_var);
EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_var));
// Phase two: Receive via a tracked, then get an addref.
sink().ClearMessages();
plugin_var = var_tracker().TrackObjectWithNoReference(
host_object, plugin_dispatcher());
plugin_var2 = var_tracker().ReceiveObjectPassRef(
host_object, plugin_dispatcher());
EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id);
EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_var));
EXPECT_EQ(1,
var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
// Free via the tracked object, this should have no effect.
var_tracker().StopTrackingObjectWithNoReference(plugin_var);
EXPECT_EQ(0,
var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
EXPECT_EQ(0u, sink().message_count());
// Now free via the refcount, this should delete it.
var_tracker().ReleaseVar(plugin_var);
EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_var));
EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject());
}
TEST_F(PluginVarTrackerTest, RecursiveTrackWithNoRef) {
PP_Var host_object = MakeObject(12345);
// Receive a tracked object twice.
PP_Var plugin_var = var_tracker().TrackObjectWithNoReference(
host_object, plugin_dispatcher());
EXPECT_EQ(1,
var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
PP_Var plugin_var2 = var_tracker().TrackObjectWithNoReference(
host_object, plugin_dispatcher());
EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id);
EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_var));
EXPECT_EQ(2,
var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
// Now release those tracked items, the reference should be freed.
var_tracker().StopTrackingObjectWithNoReference(plugin_var);
EXPECT_EQ(1,
var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
var_tracker().StopTrackingObjectWithNoReference(plugin_var);
EXPECT_EQ(-1,
var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
}
} // namespace proxy
} // namespace ppapi