summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-17 06:36:09 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-17 06:36:09 +0000
commitff84e05ab824d27fc77890028afa15b2635ff4cd (patch)
treef090e906af48b1959e58d0f0fad97b844e6be49a
parent36b7914e8fa4ca5b0f83a44456c633223560c03d (diff)
downloadchromium_src-ff84e05ab824d27fc77890028afa15b2635ff4cd.zip
chromium_src-ff84e05ab824d27fc77890028afa15b2635ff4cd.tar.gz
chromium_src-ff84e05ab824d27fc77890028afa15b2635ff4cd.tar.bz2
Makes it so a node can only the root of one connection at a time
This resulted in needing to make structural changes. For example, if connection 2 has a root of A, and A has the children B and C then if A is assigned to another connection (by way of the owner calling Embed again), then connection 2 is told A has been deleted and B and C are removed as children of A. Because this does structural changes the server change id is advanced. BUG=389339 TEST=covered by unit tests R=ben@chromium.org Review URL: https://codereview.chromium.org/397803003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@283663 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.cc1
-rw-r--r--mojo/services/public/interfaces/view_manager/view_manager.mojom10
-rw-r--r--mojo/services/view_manager/root_node_manager.cc24
-rw-r--r--mojo/services/view_manager/root_node_manager.h10
-rw-r--r--mojo/services/view_manager/view_manager_service_impl.cc78
-rw-r--r--mojo/services/view_manager/view_manager_service_impl.h18
-rw-r--r--mojo/services/view_manager/view_manager_unittest.cc273
7 files changed, 318 insertions, 96 deletions
diff --git a/mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.cc b/mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.cc
index a949da8..4a69ff0 100644
--- a/mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.cc
+++ b/mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.cc
@@ -478,6 +478,7 @@ class EmbedTransaction : public ViewManagerTransaction {
private:
// Overridden from ViewManagerTransaction:
virtual void DoCommit() OVERRIDE {
+ GetAndAdvanceNextServerChangeId();
service()->Embed(url_, node_id_, ActionCompletedCallback());
}
virtual void DoActionCompleted(bool success) OVERRIDE {
diff --git a/mojo/services/public/interfaces/view_manager/view_manager.mojom b/mojo/services/public/interfaces/view_manager/view_manager.mojom
index 0624f59..e65cc6c 100644
--- a/mojo/services/public/interfaces/view_manager/view_manager.mojom
+++ b/mojo/services/public/interfaces/view_manager/view_manager.mojom
@@ -127,12 +127,20 @@ interface ViewManagerService {
SetFocus(uint32 node_id) => (bool success);
// Embeds the app for |url| in the specified node. More specifically this
- // creates a new connection to the specified url, expecting to get an
+ // creates a new connection to the specified url, expecting to get a
// ViewManagerClient and configures it with the root node |node|. Fails
// if |node| was not created by this connection.
+ //
// If a particular client invokes Embed() multiple times with the same url,
// the connection is reused. When this happens the ViewManagerClient is
// notified of the additional roots by way of OnRootAdded().
+ //
+ // A node may only be a root of one connection at a time. Subsequent calls to
+ // Embed() for the same node result in the node being removed from the
+ // current connection. The current connection is told this by way of
+ // OnNodeDeleted().
+ //
+ // This advances the server change id.
Embed(string url, uint32 node_id) => (bool success);
// TODO(sky): move these to a separate interface when FIFO works.
diff --git a/mojo/services/view_manager/root_node_manager.cc b/mojo/services/view_manager/root_node_manager.cc
index 4da56aa..1b19bf5 100644
--- a/mojo/services/view_manager/root_node_manager.cc
+++ b/mojo/services/view_manager/root_node_manager.cc
@@ -33,6 +33,10 @@ RootNodeManager::ScopedChange::~ScopedChange() {
root_->FinishChange();
}
+void RootNodeManager::ScopedChange::SendServerChangeIdAdvanced() {
+ root_->SendServerChangeIdAdvanced();
+}
+
RootNodeManager::Context::Context() {
// Pass in false as native viewport creates the PlatformEventSource.
aura::Env::CreateInstance(false);
@@ -141,6 +145,16 @@ ViewManagerServiceImpl* RootNodeManager::GetConnectionByCreator(
return NULL;
}
+ViewManagerServiceImpl* RootNodeManager::GetConnectionWithRoot(
+ const NodeId& id) {
+ for (ConnectionMap::const_iterator i = connection_map_.begin();
+ i != connection_map_.end(); ++i) {
+ if (i->second->HasRoot(id))
+ return i->second;
+ }
+ return NULL;
+}
+
void RootNodeManager::DispatchViewInputEventToWindowManager(
const View* view,
const ui::Event* event) {
@@ -236,6 +250,15 @@ void RootNodeManager::FinishChange() {
current_change_ = NULL;
}
+void RootNodeManager::SendServerChangeIdAdvanced() {
+ CHECK(current_change_);
+ for (ConnectionMap::iterator i = connection_map_.begin();
+ i != connection_map_.end(); ++i) {
+ if (!DidConnectionMessageClient(i->first))
+ i->second->client()->OnServerChangeIdAdvanced(next_server_change_id_ + 1);
+ }
+}
+
ViewManagerServiceImpl* RootNodeManager::EmbedImpl(
const ConnectionSpecificId creator_id,
const String& url,
@@ -261,6 +284,7 @@ ViewManagerServiceImpl* RootNodeManager::EmbedImpl(
root_id);
BindToPipe(connection, pipe.handle0.Pass());
connections_created_by_connect_.insert(connection);
+ OnConnectionMessagedClient(connection->id());
return connection;
}
diff --git a/mojo/services/view_manager/root_node_manager.h b/mojo/services/view_manager/root_node_manager.h
index 62932ab..0b20fdc 100644
--- a/mojo/services/view_manager/root_node_manager.h
+++ b/mojo/services/view_manager/root_node_manager.h
@@ -69,6 +69,10 @@ class MOJO_VIEW_MANAGER_EXPORT RootNodeManager
return message_ids_.count(connection_id) > 0;
}
+ // Sends OnServerChangeIdAdvanced() to all connections that have not yet
+ // been messaged.
+ void SendServerChangeIdAdvanced();
+
private:
RootNodeManager* root_;
const ConnectionSpecificId connection_id_;
@@ -133,6 +137,9 @@ class MOJO_VIEW_MANAGER_EXPORT RootNodeManager
ConnectionSpecificId creator_id,
const std::string& url) const;
+ // Returns the ViewManagerServiceImpl that has |id| as a root.
+ ViewManagerServiceImpl* GetConnectionWithRoot(const NodeId& id);
+
void DispatchViewInputEventToWindowManager(const View* view,
const ui::Event* event);
@@ -178,6 +185,9 @@ class MOJO_VIEW_MANAGER_EXPORT RootNodeManager
// Balances a call to PrepareForChange().
void FinishChange();
+ // See description in ScopedChange.
+ void SendServerChangeIdAdvanced();
+
// Returns true if the specified connection originated the current change.
bool IsChangeSource(ConnectionSpecificId connection_id) const {
return current_change_ && current_change_->connection_id() == connection_id;
diff --git a/mojo/services/view_manager/view_manager_service_impl.cc b/mojo/services/view_manager/view_manager_service_impl.cc
index b98b99d..793a4543 100644
--- a/mojo/services/view_manager/view_manager_service_impl.cc
+++ b/mojo/services/view_manager/view_manager_service_impl.cc
@@ -86,6 +86,10 @@ const View* ViewManagerServiceImpl::GetView(const ViewId& id) const {
return root_node_manager_->GetView(id);
}
+bool ViewManagerServiceImpl::HasRoot(const NodeId& id) const {
+ return roots_.find(NodeIdToTransportId(id)) != roots_.end();
+}
+
void ViewManagerServiceImpl::OnViewManagerServiceImplDestroyed(
ConnectionSpecificId id) {
if (creator_id_ == id)
@@ -119,7 +123,7 @@ void ViewManagerServiceImpl::ProcessNodeHierarchyChanged(
if (node->id().connection_id != id_ && !IsNodeDescendantOfRoots(node)) {
// Node was a descendant of roots and is no longer, treat it as though the
// node was deleted.
- RemoveFromKnown(node);
+ RemoveFromKnown(node, NULL);
client()->OnNodeDeleted(NodeIdToTransportId(node->id()),
server_change_id);
root_node_manager_->OnConnectionMessagedClient(id_);
@@ -407,21 +411,24 @@ void ViewManagerServiceImpl::GetUnknownNodesFrom(
GetUnknownNodesFrom(children[i], nodes);
}
-void ViewManagerServiceImpl::RemoveFromKnown(const Node* node) {
- if (node->id().connection_id == id_)
+void ViewManagerServiceImpl::RemoveFromKnown(const Node* node,
+ std::vector<Node*>* local_nodes) {
+ if (node->id().connection_id == id_) {
+ if (local_nodes)
+ local_nodes->push_back(GetNode(node->id()));
return;
+ }
known_nodes_.erase(NodeIdToTransportId(node->id()));
std::vector<const Node*> children = node->GetChildren();
for (size_t i = 0; i < children.size(); ++i)
- RemoveFromKnown(children[i]);
+ RemoveFromKnown(children[i], local_nodes);
}
-bool ViewManagerServiceImpl::AddRoot(Id transport_node_id) {
- if (roots_.count(transport_node_id) > 0)
- return false;
+void ViewManagerServiceImpl::AddRoot(const NodeId& node_id) {
+ const Id transport_node_id(NodeIdToTransportId(node_id));
+ CHECK(roots_.count(transport_node_id) == 0);
std::vector<const Node*> to_send;
- const NodeId node_id(NodeIdFromTransportId(transport_node_id));
CHECK_EQ(creator_id_, node_id.connection_id);
roots_.insert(transport_node_id);
Node* node = GetNode(node_id);
@@ -435,7 +442,31 @@ bool ViewManagerServiceImpl::AddRoot(Id transport_node_id) {
}
client()->OnRootAdded(NodesToNodeDatas(to_send));
- return true;
+ root_node_manager_->OnConnectionMessagedClient(id_);
+}
+
+void ViewManagerServiceImpl::RemoveRoot(const NodeId& node_id) {
+ const Id transport_node_id(NodeIdToTransportId(node_id));
+ CHECK(roots_.count(transport_node_id) > 0);
+
+ roots_.erase(transport_node_id);
+ if (roots_.empty())
+ roots_.insert(NodeIdToTransportId(InvalidNodeId()));
+
+ // No need to do anything if we created the node.
+ if (node_id.connection_id == id_)
+ return;
+
+ client()->OnNodeDeleted(transport_node_id,
+ root_node_manager_->next_server_change_id());
+ root_node_manager_->OnConnectionMessagedClient(id_);
+
+ // This connection no longer knows about the node. Unparent any nodes that
+ // were parented to nodes in the root.
+ std::vector<Node*> local_nodes;
+ RemoveFromKnown(GetNode(node_id), &local_nodes);
+ for (size_t i = 0; i < local_nodes.size(); ++i)
+ local_nodes[i]->GetParent()->Remove(local_nodes[i]);
}
bool ViewManagerServiceImpl::IsNodeDescendantOfRoots(const Node* node) const {
@@ -737,13 +768,30 @@ void ViewManagerServiceImpl::Embed(const String& url,
const Callback<void(bool)>& callback) {
bool success = CanEmbed(transport_node_id);
if (success) {
- // We may already have this connection, if so reuse it.
- ViewManagerServiceImpl* existing_connection =
+ // Only allow a node to be the root for one connection.
+ const NodeId node_id(NodeIdFromTransportId(transport_node_id));
+ ViewManagerServiceImpl* connection_by_url =
root_node_manager_->GetConnectionByCreator(id_, url.To<std::string>());
- if (existing_connection)
- success = existing_connection->AddRoot(transport_node_id);
- else
- root_node_manager_->Embed(id_, url, transport_node_id);
+ ViewManagerServiceImpl* connection_with_node_as_root =
+ root_node_manager_->GetConnectionWithRoot(node_id);
+ if ((connection_by_url != connection_with_node_as_root ||
+ (!connection_by_url && !connection_with_node_as_root)) &&
+ (!connection_by_url || !connection_by_url->HasRoot(node_id))) {
+ RootNodeManager::ScopedChange change(
+ this, root_node_manager_,
+ RootNodeManager::CHANGE_TYPE_ADVANCE_SERVER_CHANGE_ID, true);
+ // Never message the originating connection.
+ root_node_manager_->OnConnectionMessagedClient(id_);
+ if (connection_with_node_as_root)
+ connection_with_node_as_root->RemoveRoot(node_id);
+ if (connection_by_url)
+ connection_by_url->AddRoot(node_id);
+ else
+ root_node_manager_->Embed(id_, url, transport_node_id);
+ change.SendServerChangeIdAdvanced();
+ } else {
+ success = false;
+ }
}
callback.Run(success);
}
diff --git a/mojo/services/view_manager/view_manager_service_impl.h b/mojo/services/view_manager/view_manager_service_impl.h
index bf95854..b9b6de27 100644
--- a/mojo/services/view_manager/view_manager_service_impl.h
+++ b/mojo/services/view_manager/view_manager_service_impl.h
@@ -68,6 +68,9 @@ class MOJO_VIEW_MANAGER_EXPORT ViewManagerServiceImpl
}
const View* GetView(const ViewId& id) const;
+ // Returns true if this has |id| as a root.
+ bool HasRoot(const NodeId& id) const;
+
// Invoked when a connection is destroyed.
void OnViewManagerServiceImplDestroyed(ConnectionSpecificId id);
@@ -141,13 +144,16 @@ class MOJO_VIEW_MANAGER_EXPORT ViewManagerServiceImpl
void GetUnknownNodesFrom(const Node* node, std::vector<const Node*>* nodes);
// Removes |node| and all its descendants from |known_nodes_|. This does not
- // recurse through nodes that were created by this connection.
- void RemoveFromKnown(const Node* node);
+ // recurse through nodes that were created by this connection. All nodes owned
+ // by this connection are added to |local_nodes|.
+ void RemoveFromKnown(const Node* node, std::vector<Node*>* local_nodes);
+
+ // Adds |node_id| to the set of roots this connection knows about. The caller
+ // should have verified |node_id| is not among the roots of this connection.
+ void AddRoot(const NodeId& node_id);
- // Adds |transport_node_id| to the set of roots this connection knows about.
- // Returns true if |transport_node_id| was not already a root for this
- // connection.
- bool AddRoot(Id transport_node_id);
+ // Removes |node_id| from the set of roots this connection knows about.
+ void RemoveRoot(const NodeId& node_id);
// Returns true if |node| is a non-null and a descendant of |roots_| (or
// |roots_| is empty).
diff --git a/mojo/services/view_manager/view_manager_unittest.cc b/mojo/services/view_manager/view_manager_unittest.cc
index da5ae76..e630147 100644
--- a/mojo/services/view_manager/view_manager_unittest.cc
+++ b/mojo/services/view_manager/view_manager_unittest.cc
@@ -37,6 +37,7 @@ namespace service {
namespace {
const char kTestServiceURL[] = "mojo:test_url";
+const char kTestServiceURL2[] = "mojo:test_url2";
// ViewManagerProxy is a proxy to an ViewManagerService. It handles invoking
// ViewManagerService functions on the right thread in a synchronous manner
@@ -89,6 +90,11 @@ class ViewManagerProxy : public TestChangeTracker::Delegate {
router_->CloseMessagePipe();
}
+ void ClearChanges() {
+ changes_.clear();
+ tracker_->changes()->clear();
+ }
+
// The following functions are cover methods for ViewManagerService. They
// block until the result is received.
bool CreateNode(Id node_id) {
@@ -167,11 +173,11 @@ class ViewManagerProxy : public TestChangeTracker::Delegate {
base::Unretained(this), nodes));
RunMainLoop();
}
- bool Embed(const Id node_id) {
+ bool Embed(const Id node_id, const char* url) {
changes_.clear();
base::AutoReset<bool> auto_reset(&in_embed_, true);
bool result = false;
- view_manager_->Embed(kTestServiceURL, node_id,
+ view_manager_->Embed(url, node_id,
base::Bind(&ViewManagerProxy::GotResult,
base::Unretained(this), &result));
RunMainLoop();
@@ -460,6 +466,10 @@ class ViewManagerTest : public testing::Test {
scoped_ptr<ServiceLoader>(new EmbedServiceLoader()),
GURL(kTestServiceURL));
+ test_helper_.SetLoaderForURL(
+ scoped_ptr<ServiceLoader>(new EmbedServiceLoader()),
+ GURL(kTestServiceURL2));
+
test_helper_.service_manager()->ConnectToService(
GURL("mojo:mojo_view_manager"),
&view_manager_init_);
@@ -479,7 +489,7 @@ class ViewManagerTest : public testing::Test {
protected:
void EstablishSecondConnectionWithRoot(Id root_id) {
- ASSERT_TRUE(connection_->Embed(root_id));
+ ASSERT_TRUE(connection_->Embed(root_id, kTestServiceURL));
connection2_ = ViewManagerProxy::WaitForInstance();
ASSERT_TRUE(connection2_ != NULL);
connection2_->DoRunLoopUntilChangesCount(1);
@@ -580,24 +590,24 @@ TEST_F(ViewManagerTest, AddRemoveNotify) {
// Make 3 a child of 2.
{
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 2), BuildNodeId(1, 3), 1));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 2), BuildNodeId(1, 3), 2));
EXPECT_TRUE(connection_->changes().empty());
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
- EXPECT_EQ("ServerChangeIdAdvanced 2", changes[0]);
+ EXPECT_EQ("ServerChangeIdAdvanced 3", changes[0]);
}
// Remove 3 from its parent.
{
- ASSERT_TRUE(connection_->RemoveNodeFromParent(BuildNodeId(1, 3), 2));
+ ASSERT_TRUE(connection_->RemoveNodeFromParent(BuildNodeId(1, 3), 3));
EXPECT_TRUE(connection_->changes().empty());
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
- EXPECT_EQ("ServerChangeIdAdvanced 3", changes[0]);
+ EXPECT_EQ("ServerChangeIdAdvanced 4", changes[0]);
}
}
@@ -610,17 +620,17 @@ TEST_F(ViewManagerTest, AddNodeWithNoChange) {
// Make 3 a child of 2.
{
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 2), BuildNodeId(1, 3), 1));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 2), BuildNodeId(1, 3), 2));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
- EXPECT_EQ("ServerChangeIdAdvanced 2", changes[0]);
+ EXPECT_EQ("ServerChangeIdAdvanced 3", changes[0]);
}
// Try again, this should fail.
{
- EXPECT_FALSE(connection_->AddNode(BuildNodeId(1, 2), BuildNodeId(1, 3), 2));
+ EXPECT_FALSE(connection_->AddNode(BuildNodeId(1, 2), BuildNodeId(1, 3), 3));
}
}
@@ -633,16 +643,16 @@ TEST_F(ViewManagerTest, AddAncestorFails) {
// Make 3 a child of 2.
{
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 2), BuildNodeId(1, 3), 1));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 2), BuildNodeId(1, 3), 2));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
- EXPECT_EQ("ServerChangeIdAdvanced 2", changes[0]);
+ EXPECT_EQ("ServerChangeIdAdvanced 3", changes[0]);
}
// Try to make 2 a child of 3, this should fail since 2 is an ancestor of 3.
{
- EXPECT_FALSE(connection_->AddNode(BuildNodeId(1, 3), BuildNodeId(1, 2), 2));
+ EXPECT_FALSE(connection_->AddNode(BuildNodeId(1, 3), BuildNodeId(1, 2), 3));
}
}
@@ -665,23 +675,23 @@ TEST_F(ViewManagerTest, AddToRoot) {
// Make 3 a child of 21.
{
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 21), BuildNodeId(1, 3), 1));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 21), BuildNodeId(1, 3), 2));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
- EXPECT_EQ("ServerChangeIdAdvanced 2", changes[0]);
+ EXPECT_EQ("ServerChangeIdAdvanced 3", changes[0]);
}
// Make 21 a child of 1.
{
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 21), 2));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 21), 3));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
EXPECT_EQ(
- "HierarchyChanged change_id=2 node=1,21 new_parent=1,1 old_parent=null",
+ "HierarchyChanged change_id=3 node=1,21 new_parent=1,1 old_parent=null",
changes[0]);
}
}
@@ -697,7 +707,7 @@ TEST_F(ViewManagerTest, NodeHierarchyChangedNodes) {
// Make 2 a child of 1.
{
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 2), 2));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 2), 3));
// Client 2 should get a hierarchy change that includes the new nodes as it
// has not yet seen them.
@@ -705,7 +715,7 @@ TEST_F(ViewManagerTest, NodeHierarchyChangedNodes) {
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
EXPECT_EQ(
- "HierarchyChanged change_id=2 node=1,2 new_parent=1,1 old_parent=null",
+ "HierarchyChanged change_id=3 node=1,2 new_parent=1,1 old_parent=null",
changes[0]);
EXPECT_EQ("[node=1,2 parent=1,1 view=null],"
"[node=1,11 parent=1,2 view=null]",
@@ -714,7 +724,7 @@ TEST_F(ViewManagerTest, NodeHierarchyChangedNodes) {
// Add 1 to the root.
{
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(0, 1), BuildNodeId(1, 1), 3));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(0, 1), BuildNodeId(1, 1), 4));
// Client 2 should get a hierarchy change that includes the new nodes as it
// has not yet seen them.
@@ -722,21 +732,21 @@ TEST_F(ViewManagerTest, NodeHierarchyChangedNodes) {
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
EXPECT_EQ(
- "HierarchyChanged change_id=3 node=1,1 new_parent=null old_parent=null",
+ "HierarchyChanged change_id=4 node=1,1 new_parent=null old_parent=null",
changes[0]);
EXPECT_EQ(std::string(), ChangeNodeDescription(connection2_->changes()));
}
// Remove 1 from its parent.
{
- ASSERT_TRUE(connection_->RemoveNodeFromParent(BuildNodeId(1, 1), 4));
+ ASSERT_TRUE(connection_->RemoveNodeFromParent(BuildNodeId(1, 1), 5));
EXPECT_TRUE(connection_->changes().empty());
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
EXPECT_EQ(
- "HierarchyChanged change_id=4 node=1,1 new_parent=null old_parent=null",
+ "HierarchyChanged change_id=5 node=1,1 new_parent=null old_parent=null",
changes[0]);
}
@@ -744,13 +754,13 @@ TEST_F(ViewManagerTest, NodeHierarchyChangedNodes) {
ASSERT_TRUE(connection_->CreateNode(BuildNodeId(1, 111)));
{
ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 11), BuildNodeId(1, 111),
- 5));
+ 6));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
EXPECT_EQ(
- "HierarchyChanged change_id=5 node=1,111 new_parent=1,11 "
+ "HierarchyChanged change_id=6 node=1,111 new_parent=1,11 "
"old_parent=null", changes[0]);
EXPECT_EQ("[node=1,111 parent=1,11 view=null]",
ChangeNodeDescription(connection2_->changes()));
@@ -758,13 +768,13 @@ TEST_F(ViewManagerTest, NodeHierarchyChangedNodes) {
// Reattach 1 to the root.
{
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(0, 1), BuildNodeId(1, 1), 6));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(0, 1), BuildNodeId(1, 1), 7));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
EXPECT_EQ(
- "HierarchyChanged change_id=6 node=1,1 new_parent=null old_parent=null",
+ "HierarchyChanged change_id=7 node=1,1 new_parent=null old_parent=null",
changes[0]);
EXPECT_EQ(std::string(), ChangeNodeDescription(connection2_->changes()));
}
@@ -793,23 +803,23 @@ TEST_F(ViewManagerTest, NodeHierarchyChangedAddingKnownToUnknown) {
// Remove 11, should result in a delete (since 11 is no longer in connection
// 2's root).
{
- ASSERT_TRUE(connection_->RemoveNodeFromParent(BuildNodeId(1, 11), 4));
+ ASSERT_TRUE(connection_->RemoveNodeFromParent(BuildNodeId(1, 11), 5));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
- EXPECT_EQ("NodeDeleted change_id=4 node=1,11", changes[0]);
+ EXPECT_EQ("NodeDeleted change_id=5 node=1,11", changes[0]);
}
// Add 2 to 1.
{
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 2), 5));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 2), 6));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
EXPECT_EQ(
- "HierarchyChanged change_id=5 node=1,2 new_parent=1,1 old_parent=null",
+ "HierarchyChanged change_id=6 node=1,2 new_parent=1,1 old_parent=null",
changes[0]);
EXPECT_EQ("[node=1,2 parent=1,1 view=null],"
"[node=1,21 parent=1,2 view=null]",
@@ -845,55 +855,55 @@ TEST_F(ViewManagerTest, ReorderNode) {
ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
{
- connection_->ReorderNode(node2_id, node3_id, ORDER_DIRECTION_ABOVE, 6);
+ connection_->ReorderNode(node2_id, node3_id, ORDER_DIRECTION_ABOVE, 7);
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
EXPECT_EQ(
- "Reordered change_id=6 node=1,2 relative=1,3 direction=above",
+ "Reordered change_id=7 node=1,2 relative=1,3 direction=above",
changes[0]);
}
{
- connection_->ReorderNode(node2_id, node3_id, ORDER_DIRECTION_BELOW, 7);
+ connection_->ReorderNode(node2_id, node3_id, ORDER_DIRECTION_BELOW, 8);
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
EXPECT_EQ(
- "Reordered change_id=7 node=1,2 relative=1,3 direction=below",
+ "Reordered change_id=8 node=1,2 relative=1,3 direction=below",
changes[0]);
}
{
// node2 is already below node3.
EXPECT_FALSE(
- connection_->ReorderNode(node2_id, node3_id, ORDER_DIRECTION_BELOW, 8));
+ connection_->ReorderNode(node2_id, node3_id, ORDER_DIRECTION_BELOW, 9));
}
{
// node4 & 5 are unknown to connection2_.
EXPECT_FALSE(connection2_->ReorderNode(
- node4_id, node5_id, ORDER_DIRECTION_ABOVE, 8));
+ node4_id, node5_id, ORDER_DIRECTION_ABOVE, 9));
}
{
// node6 & node3 have different parents.
EXPECT_FALSE(
- connection_->ReorderNode(node3_id, node6_id, ORDER_DIRECTION_ABOVE, 8));
+ connection_->ReorderNode(node3_id, node6_id, ORDER_DIRECTION_ABOVE, 9));
}
{
// Non-existent node-ids
EXPECT_FALSE(connection_->ReorderNode(
- BuildNodeId(1, 27), BuildNodeId(1, 28), ORDER_DIRECTION_ABOVE, 8));
+ BuildNodeId(1, 27), BuildNodeId(1, 28), ORDER_DIRECTION_ABOVE, 9));
}
{
// node7 & node8 are un-parented.
EXPECT_FALSE(
- connection_->ReorderNode(node7_id, node8_id, ORDER_DIRECTION_ABOVE, 8));
+ connection_->ReorderNode(node7_id, node8_id, ORDER_DIRECTION_ABOVE, 9));
}
}
@@ -905,23 +915,23 @@ TEST_F(ViewManagerTest, DeleteNode) {
// Make 2 a child of 1.
{
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 2), 1));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 2), 2));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
- EXPECT_EQ("HierarchyChanged change_id=1 node=1,2 new_parent=1,1 "
+ EXPECT_EQ("HierarchyChanged change_id=2 node=1,2 new_parent=1,1 "
"old_parent=null", changes[0]);
}
// Delete 2.
{
- ASSERT_TRUE(connection_->DeleteNode(BuildNodeId(1, 2), 2));
+ ASSERT_TRUE(connection_->DeleteNode(BuildNodeId(1, 2), 3));
EXPECT_TRUE(connection_->changes().empty());
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
- EXPECT_EQ("NodeDeleted change_id=2 node=1,2", changes[0]);
+ EXPECT_EQ("NodeDeleted change_id=3 node=1,2", changes[0]);
}
}
@@ -946,12 +956,12 @@ TEST_F(ViewManagerTest, ReuseDeletedNodeId) {
// Add 2 to 1.
{
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 2), 1));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 2), 2));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
EXPECT_EQ(
- "HierarchyChanged change_id=1 node=1,2 new_parent=1,1 old_parent=null",
+ "HierarchyChanged change_id=2 node=1,2 new_parent=1,1 old_parent=null",
changes[0]);
EXPECT_EQ("[node=1,2 parent=1,1 view=null]",
ChangeNodeDescription(connection2_->changes()));
@@ -959,23 +969,23 @@ TEST_F(ViewManagerTest, ReuseDeletedNodeId) {
// Delete 2.
{
- ASSERT_TRUE(connection_->DeleteNode(BuildNodeId(1, 2), 2));
+ ASSERT_TRUE(connection_->DeleteNode(BuildNodeId(1, 2), 3));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
- EXPECT_EQ("NodeDeleted change_id=2 node=1,2", changes[0]);
+ EXPECT_EQ("NodeDeleted change_id=3 node=1,2", changes[0]);
}
// Create 2 again, and add it back to 1. Should get the same notification.
ASSERT_TRUE(connection_->CreateNode(BuildNodeId(1, 2)));
{
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 2), 3));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 2), 4));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
EXPECT_EQ(
- "HierarchyChanged change_id=3 node=1,2 new_parent=1,1 old_parent=null",
+ "HierarchyChanged change_id=4 node=1,2 new_parent=1,1 old_parent=null",
changes[0]);
EXPECT_EQ("[node=1,2 parent=1,1 view=null]",
ChangeNodeDescription(connection2_->changes()));
@@ -1035,16 +1045,16 @@ TEST_F(ViewManagerTest, DeleteNodeWithView) {
// Delete node 2. The second connection should not see this because the node
// was not known to it.
{
- ASSERT_TRUE(connection_->DeleteNode(BuildNodeId(1, 2), 1));
+ ASSERT_TRUE(connection_->DeleteNode(BuildNodeId(1, 2), 2));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
- EXPECT_EQ("ServerChangeIdAdvanced 2", changes[0]);
+ EXPECT_EQ("ServerChangeIdAdvanced 3", changes[0]);
}
// Parent 3 to 1.
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 3), 2));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 3), 3));
connection2_->DoRunLoopUntilChangesCount(1);
// Set view 11 on node 3.
@@ -1059,12 +1069,12 @@ TEST_F(ViewManagerTest, DeleteNodeWithView) {
// Delete 3.
{
- ASSERT_TRUE(connection_->DeleteNode(BuildNodeId(1, 3), 3));
+ ASSERT_TRUE(connection_->DeleteNode(BuildNodeId(1, 3), 4));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
- EXPECT_EQ("NodeDeleted change_id=3 node=1,3", changes[0]);
+ EXPECT_EQ("NodeDeleted change_id=4 node=1,3", changes[0]);
}
}
@@ -1103,14 +1113,14 @@ TEST_F(ViewManagerTest, GetNodeTree) {
// Create 11 in first connection and make it a child of 1.
ASSERT_TRUE(connection_->CreateNode(BuildNodeId(1, 11)));
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(0, 1), BuildNodeId(1, 1), 1));
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 11), 2));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(0, 1), BuildNodeId(1, 1), 2));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 1), BuildNodeId(1, 11), 3));
// Create two nodes in second connection, 2 and 3, both children of 1.
ASSERT_TRUE(connection2_->CreateNode(BuildNodeId(2, 2)));
ASSERT_TRUE(connection2_->CreateNode(BuildNodeId(2, 3)));
- ASSERT_TRUE(connection2_->AddNode(BuildNodeId(1, 1), BuildNodeId(2, 2), 3));
- ASSERT_TRUE(connection2_->AddNode(BuildNodeId(1, 1), BuildNodeId(2, 3), 4));
+ ASSERT_TRUE(connection2_->AddNode(BuildNodeId(1, 1), BuildNodeId(2, 2), 4));
+ ASSERT_TRUE(connection2_->AddNode(BuildNodeId(1, 1), BuildNodeId(2, 3), 5));
// Attach view to node 11 in the first connection.
ASSERT_TRUE(connection_->CreateView(BuildViewId(1, 51)));
@@ -1182,7 +1192,7 @@ TEST_F(ViewManagerTest, SetRoots) {
{
ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
- ASSERT_TRUE(connection_->Embed(BuildNodeId(1, 3)));
+ ASSERT_TRUE(connection_->Embed(BuildNodeId(1, 3), kTestServiceURL));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
@@ -1194,22 +1204,22 @@ TEST_F(ViewManagerTest, SetRoots) {
// Create 4 and add it to the root, connection 2 should only get id advanced.
{
ASSERT_TRUE(connection_->CreateNode(BuildNodeId(1, 4)));
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(0, 1), BuildNodeId(1, 4), 2));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(0, 1), BuildNodeId(1, 4), 4));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
- EXPECT_EQ("ServerChangeIdAdvanced 3", changes[0]);
+ EXPECT_EQ("ServerChangeIdAdvanced 5", changes[0]);
}
// Move 4 under 3, this should expose 4 to the client.
{
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 3), BuildNodeId(1, 4), 3));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 3), BuildNodeId(1, 4), 5));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
EXPECT_EQ(
- "HierarchyChanged change_id=3 node=1,4 new_parent=1,3 "
+ "HierarchyChanged change_id=5 node=1,4 new_parent=1,3 "
"old_parent=null", changes[0]);
EXPECT_EQ("[node=1,4 parent=1,3 view=null]",
ChangeNodeDescription(connection2_->changes()));
@@ -1217,22 +1227,22 @@ TEST_F(ViewManagerTest, SetRoots) {
// Move 4 under 2, since 2 isn't a root client should get a delete.
{
- ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 2), BuildNodeId(1, 4), 4));
+ ASSERT_TRUE(connection_->AddNode(BuildNodeId(1, 2), BuildNodeId(1, 4), 6));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
- EXPECT_EQ("NodeDeleted change_id=4 node=1,4", changes[0]);
+ EXPECT_EQ("NodeDeleted change_id=6 node=1,4", changes[0]);
}
// Delete 4, client shouldn't receive a delete since it should no longer know
// about 4.
{
- ASSERT_TRUE(connection_->DeleteNode(BuildNodeId(1, 4), 5));
+ ASSERT_TRUE(connection_->DeleteNode(BuildNodeId(1, 4), 7));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
- EXPECT_EQ("ServerChangeIdAdvanced 6", changes[0]);
+ EXPECT_EQ("ServerChangeIdAdvanced 8", changes[0]);
}
}
@@ -1267,17 +1277,17 @@ TEST_F(ViewManagerTest, CantRemoveNodesInOtherRoots) {
ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
// Connection 2 should not be able to remove node 2 or 1 from its parent.
- ASSERT_FALSE(connection2_->RemoveNodeFromParent(BuildNodeId(1, 2), 3));
- ASSERT_FALSE(connection2_->RemoveNodeFromParent(BuildNodeId(1, 1), 3));
+ ASSERT_FALSE(connection2_->RemoveNodeFromParent(BuildNodeId(1, 2), 4));
+ ASSERT_FALSE(connection2_->RemoveNodeFromParent(BuildNodeId(1, 1), 4));
// Create nodes 10 and 11 in 2.
ASSERT_TRUE(connection2_->CreateNode(BuildNodeId(2, 10)));
ASSERT_TRUE(connection2_->CreateNode(BuildNodeId(2, 11)));
// Parent 11 to 10.
- ASSERT_TRUE(connection2_->AddNode(BuildNodeId(2, 10), BuildNodeId(2, 11), 3));
+ ASSERT_TRUE(connection2_->AddNode(BuildNodeId(2, 10), BuildNodeId(2, 11), 4));
// Remove 11 from 10.
- ASSERT_TRUE(connection2_->RemoveNodeFromParent( BuildNodeId(2, 11), 4));
+ ASSERT_TRUE(connection2_->RemoveNodeFromParent( BuildNodeId(2, 11), 5));
// Verify nothing was actually removed.
{
@@ -1348,12 +1358,12 @@ TEST_F(ViewManagerTest, ConnectTwice) {
// Try to connect again to 1,1, this should fail as already connected to that
// root.
{
- ASSERT_FALSE(connection_->Embed(BuildNodeId(1, 1)));
+ ASSERT_FALSE(connection_->Embed(BuildNodeId(1, 1), kTestServiceURL));
}
// Connecting to 1,2 should succeed and end up in connection2.
{
- ASSERT_TRUE(connection_->Embed(BuildNodeId(1, 2)));
+ ASSERT_TRUE(connection_->Embed(BuildNodeId(1, 2), kTestServiceURL));
connection2_->DoRunLoopUntilChangesCount(1);
const Changes changes(ChangesToDescription1(connection2_->changes()));
ASSERT_EQ(1u, changes.size());
@@ -1384,6 +1394,121 @@ TEST_F(ViewManagerTest, OnViewInput) {
}
}
+TEST_F(ViewManagerTest, EmbedWithSameNodeId) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
+
+ // Create a third connection.
+ ViewManagerProxy* connection3 = NULL;
+ {
+ ASSERT_TRUE(connection_->Embed(BuildNodeId(1, 1), kTestServiceURL2));
+ connection3 = ViewManagerProxy::WaitForInstance();
+ ASSERT_TRUE(connection3 != NULL);
+ connection3->DoRunLoopUntilChangesCount(1);
+ const Changes changes(ChangesToDescription1(connection3->changes()));
+ ASSERT_EQ(1u, changes.size());
+ EXPECT_EQ("OnConnectionEstablished creator=mojo:test_url", changes[0]);
+ }
+
+ // Connection2 should have been told the node was deleted.
+ {
+ connection2_->DoRunLoopUntilChangesCount(1);
+ const Changes changes(ChangesToDescription1(connection2_->changes()));
+ ASSERT_EQ(1u, changes.size());
+ EXPECT_EQ("NodeDeleted change_id=2 node=1,1", changes[0]);
+ }
+
+ // Connection2 has no root. Verify it can't see node 1,1 anymore.
+ {
+ std::vector<TestNode> nodes;
+ connection2_->GetNodeTree(BuildNodeId(1, 1), &nodes);
+ EXPECT_TRUE(nodes.empty());
+ }
+
+ connection3->Destroy();
+}
+
+TEST_F(ViewManagerTest, EmbedWithSameNodeId2) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
+
+ // Create a third connection.
+ ViewManagerProxy* connection3 = NULL;
+ {
+ ASSERT_TRUE(connection_->Embed(BuildNodeId(1, 1), kTestServiceURL2));
+ connection3 = ViewManagerProxy::WaitForInstance();
+ ASSERT_TRUE(connection3 != NULL);
+ connection3->DoRunLoopUntilChangesCount(1);
+ const Changes changes(ChangesToDescription1(connection3->changes()));
+ ASSERT_EQ(1u, changes.size());
+ EXPECT_EQ("OnConnectionEstablished creator=mojo:test_url", changes[0]);
+ }
+
+ // Connection2 should have been told the node was deleted.
+ connection2_->DoRunLoopUntilChangesCount(1);
+ connection2_->ClearChanges();
+
+ // Create a node in the third connection and parent it to the root.
+ ASSERT_TRUE(connection3->CreateNode(BuildNodeId(3, 1)));
+ ASSERT_TRUE(connection3->AddNode(BuildNodeId(1, 1), BuildNodeId(3, 1), 3));
+
+ // Connection 1 should have been told about the add (it owns the node).
+ {
+ connection_->DoRunLoopUntilChangesCount(1);
+ const Changes changes(ChangesToDescription1(connection_->changes()));
+ ASSERT_EQ(1u, changes.size());
+ EXPECT_EQ(
+ "HierarchyChanged change_id=3 node=3,1 new_parent=1,1 old_parent=null",
+ changes[0]);
+ }
+
+ // connection2_ should get an advance.
+ connection2_->DoRunLoopUntilChangesCount(1);
+ connection2_->ClearChanges();
+
+ // Embed 1,1 back in connection 2.
+ {
+ // 2 should be told about the new embed.
+ ASSERT_TRUE(connection_->Embed(BuildNodeId(1, 1), kTestServiceURL));
+ connection2_->DoRunLoopUntilChangesCount(1);
+ const std::vector<Change>& changes(connection2_->changes());
+ ASSERT_EQ(1u, changes.size());
+ EXPECT_EQ("OnRootAdded", ChangesToDescription1(changes)[0]);
+ EXPECT_EQ("[node=1,1 parent=null view=null]",
+ ChangeNodeDescription(changes));
+
+ // And 3 should get a delete.
+ connection3->DoRunLoopUntilChangesCount(1);
+ ASSERT_EQ(1u, connection3->changes().size());
+ EXPECT_EQ("NodeDeleted change_id=4 node=1,1",
+ ChangesToDescription1(connection3->changes())[0]);
+ }
+
+ // Connection3 has no root. Verify it can't see node 1,1 anymore.
+ {
+ std::vector<TestNode> nodes;
+ connection3->GetNodeTree(BuildNodeId(1, 1), &nodes);
+ EXPECT_TRUE(nodes.empty());
+ }
+
+ // Verify 3,1 is no longer parented to 1,1. We have to do this from 1,1 as
+ // connection3 can no longer see 1,1.
+ {
+ std::vector<TestNode> nodes;
+ connection_->GetNodeTree(BuildNodeId(1, 1), &nodes);
+ ASSERT_EQ(1u, nodes.size());
+ EXPECT_EQ("node=1,1 parent=null view=null", nodes[0].ToString());
+ }
+
+ // Verify connection3 can still see the node it created 3,1.
+ {
+ std::vector<TestNode> nodes;
+ connection3->GetNodeTree(BuildNodeId(3, 1), &nodes);
+ ASSERT_EQ(1u, nodes.size());
+ EXPECT_EQ("node=3,1 parent=null view=null", nodes[0].ToString());
+ }
+
+ connection3->Destroy();
+}
+
// TODO(sky): add coverage of test that destroys connections and ensures other
// connections get deletion notification (or advanced server id).