1 #include "entity_manager/topology.hpp" 2 3 #include <ranges> 4 5 #include "gmock/gmock.h" 6 #include "gtest/gtest.h" 7 8 using ::testing::UnorderedElementsAre; 9 10 const std::string subchassisPath = 11 "/xyz/openbmc_project/inventory/system/chassis/Subchassis"; 12 const std::string superchassisPath = 13 "/xyz/openbmc_project/inventory/system/chassis/Superchassis"; 14 15 const Association subchassisAssoc = 16 std::make_tuple("contained_by", "containing", superchassisPath); 17 const Association powerAssoc = 18 std::make_tuple("powering", "powered_by", superchassisPath); 19 20 const nlohmann::json subchassisExposesItem = nlohmann::json::parse(R"( 21 { 22 "ConnectsToType": "BackplanePort", 23 "Name": "MyDownstreamPort", 24 "Type": "DownstreamPort" 25 } 26 )"); 27 28 const nlohmann::json powerExposesItem = nlohmann::json::parse(R"( 29 { 30 "ConnectsToType": "BackplanePort", 31 "Name": "MyDownstreamPort", 32 "Type": "DownstreamPort", 33 "PowerPort": true 34 } 35 )"); 36 37 const nlohmann::json superchassisExposesItem = nlohmann::json::parse(R"( 38 { 39 "Name": "MyBackplanePort", 40 "Type": "BackplanePort" 41 } 42 )"); 43 44 const nlohmann::json otherExposesItem = nlohmann::json::parse(R"( 45 { 46 "Name": "MyExposes", 47 "Type": "OtherType" 48 } 49 )"); 50 51 using BoardMap = std::map<std::string, std::string>; 52 53 TEST(Topology, Empty) 54 { 55 Topology topo; 56 BoardMap boards; 57 58 auto assocs = topo.getAssocs(std::views::keys(boards)); 59 60 EXPECT_EQ(assocs.size(), 0U); 61 } 62 63 TEST(Topology, EmptyExposes) 64 { 65 Topology topo; 66 BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}}; 67 68 topo.addBoard(subchassisPath, "Chassis", "BoardA", nlohmann::json()); 69 topo.addBoard(superchassisPath, "Chassis", "BoardB", nlohmann::json()); 70 71 auto assocs = topo.getAssocs(std::views::keys(boards)); 72 73 EXPECT_EQ(assocs.size(), 0U); 74 } 75 76 TEST(Topology, MissingConnectsTo) 77 { 78 const nlohmann::json subchassisMissingConnectsTo = nlohmann::json::parse(R"( 79 { 80 "Name": "MyDownstreamPort", 81 "Type": "DownstreamPort" 82 } 83 )"); 84 85 Topology topo; 86 BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}}; 87 88 topo.addBoard(subchassisPath, "Chassis", "BoardA", 89 subchassisMissingConnectsTo); 90 topo.addBoard(superchassisPath, "Chassis", "BoardB", 91 superchassisExposesItem); 92 93 auto assocs = topo.getAssocs(std::views::keys(boards)); 94 95 EXPECT_EQ(assocs.size(), 0U); 96 } 97 98 TEST(Topology, OtherExposes) 99 { 100 Topology topo; 101 BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}}; 102 103 topo.addBoard(subchassisPath, "Chassis", "BoardA", otherExposesItem); 104 topo.addBoard(superchassisPath, "Chassis", "BoardB", otherExposesItem); 105 106 auto assocs = topo.getAssocs(std::views::keys(boards)); 107 108 EXPECT_EQ(assocs.size(), 0U); 109 } 110 111 TEST(Topology, NoMatchSubchassis) 112 { 113 Topology topo; 114 BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}}; 115 116 topo.addBoard(subchassisPath, "Chassis", "BoardA", otherExposesItem); 117 topo.addBoard(superchassisPath, "Chassis", "BoardB", 118 superchassisExposesItem); 119 120 auto assocs = topo.getAssocs(std::views::keys(boards)); 121 122 EXPECT_EQ(assocs.size(), 0U); 123 } 124 125 TEST(Topology, NoMatchSuperchassis) 126 { 127 Topology topo; 128 BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}}; 129 130 topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem); 131 topo.addBoard(superchassisPath, "Chassis", "BoardB", otherExposesItem); 132 133 auto assocs = topo.getAssocs(std::views::keys(boards)); 134 135 EXPECT_EQ(assocs.size(), 0U); 136 } 137 138 TEST(Topology, Basic) 139 { 140 Topology topo; 141 BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}}; 142 143 topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem); 144 topo.addBoard(superchassisPath, "Chassis", "BoardB", 145 superchassisExposesItem); 146 147 auto assocs = topo.getAssocs(std::views::keys(boards)); 148 149 EXPECT_EQ(assocs.size(), 1U); 150 EXPECT_EQ(assocs[subchassisPath].size(), 1U); 151 EXPECT_TRUE(assocs[subchassisPath].contains(subchassisAssoc)); 152 } 153 154 TEST(Topology, BasicPower) 155 { 156 Topology topo; 157 BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}}; 158 159 topo.addBoard(subchassisPath, "Chassis", "BoardA", powerExposesItem); 160 topo.addBoard(superchassisPath, "Chassis", "BoardB", 161 superchassisExposesItem); 162 163 auto assocs = topo.getAssocs(std::views::keys(boards)); 164 165 EXPECT_EQ(assocs.size(), 1U); 166 EXPECT_EQ(assocs[subchassisPath].size(), 2U); 167 EXPECT_TRUE(assocs[subchassisPath].contains(subchassisAssoc)); 168 EXPECT_TRUE(assocs[subchassisPath].contains(powerAssoc)); 169 } 170 171 TEST(Topology, NoNewBoards) 172 { 173 Topology topo; 174 BoardMap boards; 175 176 topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem); 177 topo.addBoard(superchassisPath, "Chassis", "BoardB", 178 superchassisExposesItem); 179 180 // Boards A and B aren't new, so no assocs are returned. 181 auto assocs = topo.getAssocs(std::views::keys(boards)); 182 183 EXPECT_EQ(assocs.size(), 0U); 184 } 185 186 TEST(Topology, 2Subchassis) 187 { 188 Topology topo; 189 BoardMap boards{{subchassisPath, "BoardA"}, 190 {subchassisPath + "2", "BoardB"}, 191 {superchassisPath, "BoardC"}}; 192 193 topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem); 194 topo.addBoard(subchassisPath + "2", "Chassis", "BoardB", 195 subchassisExposesItem); 196 topo.addBoard(superchassisPath, "Chassis", "BoardC", 197 superchassisExposesItem); 198 199 auto assocs = topo.getAssocs(std::views::keys(boards)); 200 201 EXPECT_EQ(assocs.size(), 2U); 202 EXPECT_EQ(assocs[subchassisPath].size(), 1U); 203 EXPECT_TRUE(assocs[subchassisPath].contains(subchassisAssoc)); 204 EXPECT_EQ(assocs[subchassisPath + "2"].size(), 1U); 205 EXPECT_TRUE(assocs[subchassisPath + "2"].contains(subchassisAssoc)); 206 } 207 208 TEST(Topology, OneNewBoard) 209 { 210 Topology topo; 211 BoardMap boards{{subchassisPath, "BoardA"}}; 212 213 topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem); 214 topo.addBoard(subchassisPath + "2", "Chassis", "BoardB", 215 subchassisExposesItem); 216 topo.addBoard(superchassisPath, "Chassis", "BoardC", 217 superchassisExposesItem); 218 219 // Only the assoc for BoardA should be returned 220 auto assocs = topo.getAssocs(std::views::keys(boards)); 221 222 EXPECT_EQ(assocs.size(), 1U); 223 EXPECT_EQ(assocs[subchassisPath].size(), 1U); 224 EXPECT_TRUE(assocs[subchassisPath].contains(subchassisAssoc)); 225 } 226 227 TEST(Topology, 2Superchassis) 228 { 229 Association subchassisAssoc2 = 230 std::make_tuple("contained_by", "containing", superchassisPath + "2"); 231 232 Topology topo; 233 BoardMap boards{{subchassisPath, "BoardA"}, 234 {superchassisPath, "BoardB"}, 235 {superchassisPath + "2", "BoardC"}}; 236 237 topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem); 238 topo.addBoard(superchassisPath, "Chassis", "BoardB", 239 superchassisExposesItem); 240 topo.addBoard(superchassisPath + "2", "Chassis", "BoardC", 241 superchassisExposesItem); 242 243 auto assocs = topo.getAssocs(std::views::keys(boards)); 244 245 EXPECT_EQ(assocs.size(), 1U); 246 EXPECT_EQ(assocs[subchassisPath].size(), 2U); 247 248 EXPECT_THAT(assocs[subchassisPath], 249 UnorderedElementsAre(subchassisAssoc, subchassisAssoc2)); 250 } 251 252 TEST(Topology, 2SuperchassisAnd2Subchassis) 253 { 254 Association subchassisAssoc2 = 255 std::make_tuple("contained_by", "containing", superchassisPath + "2"); 256 257 Topology topo; 258 BoardMap boards{{subchassisPath, "BoardA"}, 259 {subchassisPath + "2", "BoardB"}, 260 {superchassisPath, "BoardC"}, 261 {superchassisPath + "2", "BoardD"}}; 262 263 topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem); 264 topo.addBoard(subchassisPath + "2", "Chassis", "BoardB", 265 subchassisExposesItem); 266 topo.addBoard(superchassisPath, "Chassis", "BoardC", 267 superchassisExposesItem); 268 topo.addBoard(superchassisPath + "2", "Chassis", "BoardD", 269 superchassisExposesItem); 270 271 auto assocs = topo.getAssocs(std::views::keys(boards)); 272 273 EXPECT_EQ(assocs.size(), 2U); 274 EXPECT_EQ(assocs[subchassisPath].size(), 2U); 275 EXPECT_EQ(assocs[subchassisPath + "2"].size(), 2U); 276 277 EXPECT_THAT(assocs[subchassisPath], 278 UnorderedElementsAre(subchassisAssoc, subchassisAssoc2)); 279 EXPECT_THAT(assocs[subchassisPath + "2"], 280 UnorderedElementsAre(subchassisAssoc, subchassisAssoc2)); 281 } 282 283 TEST(Topology, Remove) 284 { 285 Topology topo; 286 BoardMap boards{{subchassisPath, "BoardA"}, 287 {subchassisPath + "2", "BoardB"}, 288 {superchassisPath, "BoardC"}}; 289 290 topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem); 291 topo.addBoard(subchassisPath + "2", "Chassis", "BoardB", 292 subchassisExposesItem); 293 topo.addBoard(superchassisPath, "Chassis", "BoardC", 294 superchassisExposesItem); 295 296 { 297 auto assocs = topo.getAssocs(std::views::keys(boards)); 298 299 EXPECT_EQ(assocs.size(), 2U); 300 EXPECT_EQ(assocs[subchassisPath].size(), 1U); 301 EXPECT_TRUE(assocs[subchassisPath].contains(subchassisAssoc)); 302 EXPECT_EQ(assocs[subchassisPath + "2"].size(), 1U); 303 EXPECT_TRUE(assocs[subchassisPath + "2"].contains(subchassisAssoc)); 304 } 305 306 { 307 topo.remove("BoardA"); 308 auto assocs = topo.getAssocs(std::views::keys(boards)); 309 310 EXPECT_EQ(assocs.size(), 1U); 311 EXPECT_EQ(assocs[subchassisPath + "2"].size(), 1U); 312 EXPECT_TRUE(assocs[subchassisPath + "2"].contains(subchassisAssoc)); 313 } 314 315 { 316 topo.remove("BoardB"); 317 auto assocs = topo.getAssocs(std::views::keys(boards)); 318 319 EXPECT_EQ(assocs.size(), 0U); 320 } 321 } 322