phys-topology: Add late add/remove support
The current physical topology code doesn't yet support adding entities
late (in a different propertiesChangedCallback call) or removing an
entity because:
- The Topology class is just scoped to postToDbus(), so when that is
called again later with new cards it has no concept of existing parent
cards so it will miss creating associations.
- There is nothing to tell the class when an entity is removed, so it
never attempts to remove the association for that entity.
- When the containing/contained_by association is created it doesn't use
the createInterface() function, so if that entity is removed later
that association interface will be left on D-Bus.
To add support for entity adds and removes, this commit will:
- Make the Topology class have a global scoped lifetime so it can
remember entity relationships.
- Now that Topology will outlive postToDbus() calls, pass the
getAssocs() method the list of boards being processed in the current
postToDbus() incantation so it will only return the new associations.
- Use the createInterface() method when creating the association. This
stores the interface in a map with the entity name so that when the
entity is removed the interface will be removed along with all the
other interfaces.
- When an entity is removed, only the board name is known. So pass the
board name into addBoard() so the Topology class knows it, and add a
Topology::remove() method and call it so it can remove the removed
path from all of the connector maps.
Tested:
- All of the containing/contained_by associations still show up on good
path.
- Added new unit tests to cover the new functionality.
- When a downstream entity is added after EM does its initial D-Bus
publish, the containing/contained_by association is now created.
- On an entity remove, there are no left over interfaces for the removed
entity on D-Bus.
- When the removed entity is added back, the association is put back in
place.
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Ie5daaca92c6d2e6e7abc408f3e67e948977581ef
diff --git a/test/test_topology.cpp b/test/test_topology.cpp
index 76ab54a..f9beee3 100644
--- a/test/test_topology.cpp
+++ b/test/test_topology.cpp
@@ -35,11 +35,14 @@
}
)");
+using BoardMap = std::map<std::string, std::string>;
+
TEST(Topology, Empty)
{
Topology topo;
+ BoardMap boards;
- auto assocs = topo.getAssocs();
+ auto assocs = topo.getAssocs(boards);
EXPECT_EQ(assocs.size(), 0);
}
@@ -47,11 +50,12 @@
TEST(Topology, EmptyExposes)
{
Topology topo;
+ BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}};
- topo.addBoard(subchassisPath, "Chassis", nlohmann::json());
- topo.addBoard(superchassisPath, "Chassis", nlohmann::json());
+ topo.addBoard(subchassisPath, "Chassis", "BoardA", nlohmann::json());
+ topo.addBoard(superchassisPath, "Chassis", "BoardB", nlohmann::json());
- auto assocs = topo.getAssocs();
+ auto assocs = topo.getAssocs(boards);
EXPECT_EQ(assocs.size(), 0);
}
@@ -66,11 +70,14 @@
)");
Topology topo;
+ BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}};
- topo.addBoard(subchassisPath, "Chassis", subchassisMissingConnectsTo);
- topo.addBoard(superchassisPath, "Chassis", superchassisExposesItem);
+ topo.addBoard(subchassisPath, "Chassis", "BoardA",
+ subchassisMissingConnectsTo);
+ topo.addBoard(superchassisPath, "Chassis", "BoardB",
+ superchassisExposesItem);
- auto assocs = topo.getAssocs();
+ auto assocs = topo.getAssocs(boards);
EXPECT_EQ(assocs.size(), 0);
}
@@ -78,11 +85,12 @@
TEST(Topology, OtherExposes)
{
Topology topo;
+ BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}};
- topo.addBoard(subchassisPath, "Chassis", otherExposesItem);
- topo.addBoard(superchassisPath, "Chassis", otherExposesItem);
+ topo.addBoard(subchassisPath, "Chassis", "BoardA", otherExposesItem);
+ topo.addBoard(superchassisPath, "Chassis", "BoardB", otherExposesItem);
- auto assocs = topo.getAssocs();
+ auto assocs = topo.getAssocs(boards);
EXPECT_EQ(assocs.size(), 0);
}
@@ -90,11 +98,13 @@
TEST(Topology, NoMatchSubchassis)
{
Topology topo;
+ BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}};
- topo.addBoard(subchassisPath, "Chassis", otherExposesItem);
- topo.addBoard(superchassisPath, "Chassis", superchassisExposesItem);
+ topo.addBoard(subchassisPath, "Chassis", "BoardA", otherExposesItem);
+ topo.addBoard(superchassisPath, "Chassis", "BoardB",
+ superchassisExposesItem);
- auto assocs = topo.getAssocs();
+ auto assocs = topo.getAssocs(boards);
EXPECT_EQ(assocs.size(), 0);
}
@@ -102,11 +112,12 @@
TEST(Topology, NoMatchSuperchassis)
{
Topology topo;
+ BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}};
- topo.addBoard(subchassisPath, "Chassis", subchassisExposesItem);
- topo.addBoard(superchassisPath, "Chassis", otherExposesItem);
+ topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem);
+ topo.addBoard(superchassisPath, "Chassis", "BoardB", otherExposesItem);
- auto assocs = topo.getAssocs();
+ auto assocs = topo.getAssocs(boards);
EXPECT_EQ(assocs.size(), 0);
}
@@ -114,26 +125,48 @@
TEST(Topology, Basic)
{
Topology topo;
+ BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}};
- topo.addBoard(subchassisPath, "Chassis", subchassisExposesItem);
- topo.addBoard(superchassisPath, "Chassis", superchassisExposesItem);
+ topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem);
+ topo.addBoard(superchassisPath, "Chassis", "BoardB",
+ superchassisExposesItem);
- auto assocs = topo.getAssocs();
+ auto assocs = topo.getAssocs(boards);
EXPECT_EQ(assocs.size(), 1);
EXPECT_EQ(assocs[subchassisPath].size(), 1);
EXPECT_EQ(assocs[subchassisPath][0], subchassisAssoc);
}
+TEST(Topology, NoNewBoards)
+{
+ Topology topo;
+ BoardMap boards;
+
+ topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem);
+ topo.addBoard(superchassisPath, "Chassis", "BoardB",
+ superchassisExposesItem);
+
+ // Boards A and B aren't new, so no assocs are returned.
+ auto assocs = topo.getAssocs(boards);
+
+ EXPECT_EQ(assocs.size(), 0);
+}
+
TEST(Topology, 2Subchassis)
{
Topology topo;
+ BoardMap boards{{subchassisPath, "BoardA"},
+ {subchassisPath + "2", "BoardB"},
+ {superchassisPath, "BoardC"}};
- topo.addBoard(subchassisPath, "Chassis", subchassisExposesItem);
- topo.addBoard(subchassisPath + "2", "Chassis", subchassisExposesItem);
- topo.addBoard(superchassisPath, "Chassis", superchassisExposesItem);
+ topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem);
+ topo.addBoard(subchassisPath + "2", "Chassis", "BoardB",
+ subchassisExposesItem);
+ topo.addBoard(superchassisPath, "Chassis", "BoardC",
+ superchassisExposesItem);
- auto assocs = topo.getAssocs();
+ auto assocs = topo.getAssocs(boards);
EXPECT_EQ(assocs.size(), 2);
EXPECT_EQ(assocs[subchassisPath].size(), 1);
@@ -142,18 +175,42 @@
EXPECT_EQ(assocs[subchassisPath + "2"][0], subchassisAssoc);
}
+TEST(Topology, OneNewBoard)
+{
+ Topology topo;
+ BoardMap boards{{subchassisPath, "BoardA"}};
+
+ topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem);
+ topo.addBoard(subchassisPath + "2", "Chassis", "BoardB",
+ subchassisExposesItem);
+ topo.addBoard(superchassisPath, "Chassis", "BoardC",
+ superchassisExposesItem);
+
+ // Only the assoc for BoardA should be returned
+ auto assocs = topo.getAssocs(boards);
+
+ EXPECT_EQ(assocs.size(), 1);
+ EXPECT_EQ(assocs[subchassisPath].size(), 1);
+ EXPECT_EQ(assocs[subchassisPath][0], subchassisAssoc);
+}
+
TEST(Topology, 2Superchassis)
{
const Association subchassisAssoc2 =
std::make_tuple("contained_by", "containing", superchassisPath + "2");
Topology topo;
+ BoardMap boards{{subchassisPath, "BoardA"},
+ {superchassisPath, "BoardB"},
+ {superchassisPath + "2", "BoardC"}};
- topo.addBoard(subchassisPath, "Chassis", subchassisExposesItem);
- topo.addBoard(superchassisPath, "Chassis", superchassisExposesItem);
- topo.addBoard(superchassisPath + "2", "Chassis", superchassisExposesItem);
+ topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem);
+ topo.addBoard(superchassisPath, "Chassis", "BoardB",
+ superchassisExposesItem);
+ topo.addBoard(superchassisPath + "2", "Chassis", "BoardC",
+ superchassisExposesItem);
- auto assocs = topo.getAssocs();
+ auto assocs = topo.getAssocs(boards);
EXPECT_EQ(assocs.size(), 1);
EXPECT_EQ(assocs[subchassisPath].size(), 2);
@@ -168,13 +225,20 @@
std::make_tuple("contained_by", "containing", superchassisPath + "2");
Topology topo;
+ BoardMap boards{{subchassisPath, "BoardA"},
+ {subchassisPath + "2", "BoardB"},
+ {superchassisPath, "BoardC"},
+ {superchassisPath + "2", "BoardD"}};
- topo.addBoard(subchassisPath, "Chassis", subchassisExposesItem);
- topo.addBoard(subchassisPath + "2", "Chassis", subchassisExposesItem);
- topo.addBoard(superchassisPath, "Chassis", superchassisExposesItem);
- topo.addBoard(superchassisPath + "2", "Chassis", superchassisExposesItem);
+ topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem);
+ topo.addBoard(subchassisPath + "2", "Chassis", "BoardB",
+ subchassisExposesItem);
+ topo.addBoard(superchassisPath, "Chassis", "BoardC",
+ superchassisExposesItem);
+ topo.addBoard(superchassisPath + "2", "Chassis", "BoardD",
+ superchassisExposesItem);
- auto assocs = topo.getAssocs();
+ auto assocs = topo.getAssocs(boards);
EXPECT_EQ(assocs.size(), 2);
EXPECT_EQ(assocs[subchassisPath].size(), 2);
@@ -185,3 +249,43 @@
EXPECT_THAT(assocs[subchassisPath + "2"],
UnorderedElementsAre(subchassisAssoc, subchassisAssoc2));
}
+
+TEST(Topology, Remove)
+{
+ Topology topo;
+ BoardMap boards{{subchassisPath, "BoardA"},
+ {subchassisPath + "2", "BoardB"},
+ {superchassisPath, "BoardC"}};
+
+ topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem);
+ topo.addBoard(subchassisPath + "2", "Chassis", "BoardB",
+ subchassisExposesItem);
+ topo.addBoard(superchassisPath, "Chassis", "BoardC",
+ superchassisExposesItem);
+
+ {
+ auto assocs = topo.getAssocs(boards);
+
+ EXPECT_EQ(assocs.size(), 2);
+ EXPECT_EQ(assocs[subchassisPath].size(), 1);
+ EXPECT_EQ(assocs[subchassisPath][0], subchassisAssoc);
+ EXPECT_EQ(assocs[subchassisPath + "2"].size(), 1);
+ EXPECT_EQ(assocs[subchassisPath + "2"][0], subchassisAssoc);
+ }
+
+ {
+ topo.remove("BoardA");
+ auto assocs = topo.getAssocs(boards);
+
+ EXPECT_EQ(assocs.size(), 1);
+ EXPECT_EQ(assocs[subchassisPath + "2"].size(), 1);
+ EXPECT_EQ(assocs[subchassisPath + "2"][0], subchassisAssoc);
+ }
+
+ {
+ topo.remove("BoardB");
+ auto assocs = topo.getAssocs(boards);
+
+ EXPECT_EQ(assocs.size(), 0);
+ }
+}