blob: b8b9c4dbef9caca96281f3ed91d4fc5fd0903b74 [file] [log] [blame]
Christopher Meisfc9e7fd2025-04-03 13:13:35 +02001#include "entity_manager/topology.hpp"
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +00002
Alexander Hansen32e74182025-08-20 16:16:00 +02003#include <ranges>
4
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +00005#include "gmock/gmock.h"
6#include "gtest/gtest.h"
7
8using ::testing::UnorderedElementsAre;
9
10const std::string subchassisPath =
11 "/xyz/openbmc_project/inventory/system/chassis/Subchassis";
12const std::string superchassisPath =
13 "/xyz/openbmc_project/inventory/system/chassis/Superchassis";
14
15const Association subchassisAssoc =
16 std::make_tuple("contained_by", "containing", superchassisPath);
Patrick Williamsb7077432024-08-16 15:22:21 -040017const Association powerAssoc =
Chau Lya454b302025-07-09 09:22:25 +000018 std::make_tuple("powering", "powered_by", superchassisPath);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +000019
20const nlohmann::json subchassisExposesItem = nlohmann::json::parse(R"(
21 {
22 "ConnectsToType": "BackplanePort",
23 "Name": "MyDownstreamPort",
24 "Type": "DownstreamPort"
25 }
26)");
27
Jeff Linb02752f2023-12-01 11:23:54 +080028const nlohmann::json powerExposesItem = nlohmann::json::parse(R"(
29 {
30 "ConnectsToType": "BackplanePort",
31 "Name": "MyDownstreamPort",
32 "Type": "DownstreamPort",
33 "PowerPort": true
34 }
35)");
36
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +000037const nlohmann::json superchassisExposesItem = nlohmann::json::parse(R"(
38 {
39 "Name": "MyBackplanePort",
40 "Type": "BackplanePort"
41 }
42)");
43
44const nlohmann::json otherExposesItem = nlohmann::json::parse(R"(
45 {
46 "Name": "MyExposes",
47 "Type": "OtherType"
48 }
49)");
50
Matt Spinler6eb60972023-08-14 16:36:20 -050051using BoardMap = std::map<std::string, std::string>;
52
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +000053TEST(Topology, Empty)
54{
55 Topology topo;
Matt Spinler6eb60972023-08-14 16:36:20 -050056 BoardMap boards;
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +000057
Alexander Hansen32e74182025-08-20 16:16:00 +020058 auto assocs = topo.getAssocs(std::views::keys(boards));
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +000059
Ed Tanousc6af85c2025-04-08 10:13:33 -070060 EXPECT_EQ(assocs.size(), 0U);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +000061}
62
63TEST(Topology, EmptyExposes)
64{
65 Topology topo;
Matt Spinler6eb60972023-08-14 16:36:20 -050066 BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}};
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +000067
Matt Spinler6eb60972023-08-14 16:36:20 -050068 topo.addBoard(subchassisPath, "Chassis", "BoardA", nlohmann::json());
69 topo.addBoard(superchassisPath, "Chassis", "BoardB", nlohmann::json());
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +000070
Alexander Hansen32e74182025-08-20 16:16:00 +020071 auto assocs = topo.getAssocs(std::views::keys(boards));
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +000072
Ed Tanousc6af85c2025-04-08 10:13:33 -070073 EXPECT_EQ(assocs.size(), 0U);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +000074}
75
76TEST(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;
Matt Spinler6eb60972023-08-14 16:36:20 -050086 BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}};
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +000087
Matt Spinler6eb60972023-08-14 16:36:20 -050088 topo.addBoard(subchassisPath, "Chassis", "BoardA",
89 subchassisMissingConnectsTo);
90 topo.addBoard(superchassisPath, "Chassis", "BoardB",
91 superchassisExposesItem);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +000092
Alexander Hansen32e74182025-08-20 16:16:00 +020093 auto assocs = topo.getAssocs(std::views::keys(boards));
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +000094
Ed Tanousc6af85c2025-04-08 10:13:33 -070095 EXPECT_EQ(assocs.size(), 0U);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +000096}
97
98TEST(Topology, OtherExposes)
99{
100 Topology topo;
Matt Spinler6eb60972023-08-14 16:36:20 -0500101 BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}};
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000102
Matt Spinler6eb60972023-08-14 16:36:20 -0500103 topo.addBoard(subchassisPath, "Chassis", "BoardA", otherExposesItem);
104 topo.addBoard(superchassisPath, "Chassis", "BoardB", otherExposesItem);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000105
Alexander Hansen32e74182025-08-20 16:16:00 +0200106 auto assocs = topo.getAssocs(std::views::keys(boards));
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000107
Ed Tanousc6af85c2025-04-08 10:13:33 -0700108 EXPECT_EQ(assocs.size(), 0U);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000109}
110
111TEST(Topology, NoMatchSubchassis)
112{
113 Topology topo;
Matt Spinler6eb60972023-08-14 16:36:20 -0500114 BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}};
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000115
Matt Spinler6eb60972023-08-14 16:36:20 -0500116 topo.addBoard(subchassisPath, "Chassis", "BoardA", otherExposesItem);
117 topo.addBoard(superchassisPath, "Chassis", "BoardB",
118 superchassisExposesItem);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000119
Alexander Hansen32e74182025-08-20 16:16:00 +0200120 auto assocs = topo.getAssocs(std::views::keys(boards));
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000121
Ed Tanousc6af85c2025-04-08 10:13:33 -0700122 EXPECT_EQ(assocs.size(), 0U);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000123}
124
125TEST(Topology, NoMatchSuperchassis)
126{
127 Topology topo;
Matt Spinler6eb60972023-08-14 16:36:20 -0500128 BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}};
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000129
Matt Spinler6eb60972023-08-14 16:36:20 -0500130 topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem);
131 topo.addBoard(superchassisPath, "Chassis", "BoardB", otherExposesItem);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000132
Alexander Hansen32e74182025-08-20 16:16:00 +0200133 auto assocs = topo.getAssocs(std::views::keys(boards));
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000134
Ed Tanousc6af85c2025-04-08 10:13:33 -0700135 EXPECT_EQ(assocs.size(), 0U);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000136}
137
138TEST(Topology, Basic)
139{
140 Topology topo;
Matt Spinler6eb60972023-08-14 16:36:20 -0500141 BoardMap boards{{subchassisPath, "BoardA"}, {superchassisPath, "BoardB"}};
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000142
Matt Spinler6eb60972023-08-14 16:36:20 -0500143 topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem);
144 topo.addBoard(superchassisPath, "Chassis", "BoardB",
145 superchassisExposesItem);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000146
Alexander Hansen32e74182025-08-20 16:16:00 +0200147 auto assocs = topo.getAssocs(std::views::keys(boards));
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000148
Ed Tanousc6af85c2025-04-08 10:13:33 -0700149 EXPECT_EQ(assocs.size(), 1U);
150 EXPECT_EQ(assocs[subchassisPath].size(), 1U);
Alexander Hansen0519f572025-08-19 18:11:04 +0200151 EXPECT_TRUE(assocs[subchassisPath].contains(subchassisAssoc));
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000152}
153
Jeff Linb02752f2023-12-01 11:23:54 +0800154TEST(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
Alexander Hansen32e74182025-08-20 16:16:00 +0200163 auto assocs = topo.getAssocs(std::views::keys(boards));
Jeff Linb02752f2023-12-01 11:23:54 +0800164
Chau Lya454b302025-07-09 09:22:25 +0000165 EXPECT_EQ(assocs.size(), 1U);
166 EXPECT_EQ(assocs[subchassisPath].size(), 2U);
Alexander Hansen0519f572025-08-19 18:11:04 +0200167 EXPECT_TRUE(assocs[subchassisPath].contains(subchassisAssoc));
168 EXPECT_TRUE(assocs[subchassisPath].contains(powerAssoc));
Jeff Linb02752f2023-12-01 11:23:54 +0800169}
170
Matt Spinler6eb60972023-08-14 16:36:20 -0500171TEST(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.
Alexander Hansen32e74182025-08-20 16:16:00 +0200181 auto assocs = topo.getAssocs(std::views::keys(boards));
Matt Spinler6eb60972023-08-14 16:36:20 -0500182
Ed Tanousc6af85c2025-04-08 10:13:33 -0700183 EXPECT_EQ(assocs.size(), 0U);
Matt Spinler6eb60972023-08-14 16:36:20 -0500184}
185
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000186TEST(Topology, 2Subchassis)
187{
188 Topology topo;
Matt Spinler6eb60972023-08-14 16:36:20 -0500189 BoardMap boards{{subchassisPath, "BoardA"},
190 {subchassisPath + "2", "BoardB"},
191 {superchassisPath, "BoardC"}};
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000192
Matt Spinler6eb60972023-08-14 16:36:20 -0500193 topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem);
194 topo.addBoard(subchassisPath + "2", "Chassis", "BoardB",
195 subchassisExposesItem);
196 topo.addBoard(superchassisPath, "Chassis", "BoardC",
197 superchassisExposesItem);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000198
Alexander Hansen32e74182025-08-20 16:16:00 +0200199 auto assocs = topo.getAssocs(std::views::keys(boards));
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000200
Ed Tanousc6af85c2025-04-08 10:13:33 -0700201 EXPECT_EQ(assocs.size(), 2U);
202 EXPECT_EQ(assocs[subchassisPath].size(), 1U);
Alexander Hansen0519f572025-08-19 18:11:04 +0200203 EXPECT_TRUE(assocs[subchassisPath].contains(subchassisAssoc));
Ed Tanousc6af85c2025-04-08 10:13:33 -0700204 EXPECT_EQ(assocs[subchassisPath + "2"].size(), 1U);
Alexander Hansen0519f572025-08-19 18:11:04 +0200205 EXPECT_TRUE(assocs[subchassisPath + "2"].contains(subchassisAssoc));
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000206}
207
Matt Spinler6eb60972023-08-14 16:36:20 -0500208TEST(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
Alexander Hansen32e74182025-08-20 16:16:00 +0200220 auto assocs = topo.getAssocs(std::views::keys(boards));
Matt Spinler6eb60972023-08-14 16:36:20 -0500221
Ed Tanousc6af85c2025-04-08 10:13:33 -0700222 EXPECT_EQ(assocs.size(), 1U);
223 EXPECT_EQ(assocs[subchassisPath].size(), 1U);
Alexander Hansen0519f572025-08-19 18:11:04 +0200224 EXPECT_TRUE(assocs[subchassisPath].contains(subchassisAssoc));
Matt Spinler6eb60972023-08-14 16:36:20 -0500225}
226
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000227TEST(Topology, 2Superchassis)
228{
Alexander Hansen32e74182025-08-20 16:16:00 +0200229 Association subchassisAssoc2 =
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000230 std::make_tuple("contained_by", "containing", superchassisPath + "2");
231
232 Topology topo;
Matt Spinler6eb60972023-08-14 16:36:20 -0500233 BoardMap boards{{subchassisPath, "BoardA"},
234 {superchassisPath, "BoardB"},
235 {superchassisPath + "2", "BoardC"}};
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000236
Matt Spinler6eb60972023-08-14 16:36:20 -0500237 topo.addBoard(subchassisPath, "Chassis", "BoardA", subchassisExposesItem);
238 topo.addBoard(superchassisPath, "Chassis", "BoardB",
239 superchassisExposesItem);
240 topo.addBoard(superchassisPath + "2", "Chassis", "BoardC",
241 superchassisExposesItem);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000242
Alexander Hansen32e74182025-08-20 16:16:00 +0200243 auto assocs = topo.getAssocs(std::views::keys(boards));
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000244
Ed Tanousc6af85c2025-04-08 10:13:33 -0700245 EXPECT_EQ(assocs.size(), 1U);
246 EXPECT_EQ(assocs[subchassisPath].size(), 2U);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000247
248 EXPECT_THAT(assocs[subchassisPath],
249 UnorderedElementsAre(subchassisAssoc, subchassisAssoc2));
250}
251
252TEST(Topology, 2SuperchassisAnd2Subchassis)
253{
Alexander Hansen32e74182025-08-20 16:16:00 +0200254 Association subchassisAssoc2 =
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000255 std::make_tuple("contained_by", "containing", superchassisPath + "2");
256
257 Topology topo;
Matt Spinler6eb60972023-08-14 16:36:20 -0500258 BoardMap boards{{subchassisPath, "BoardA"},
259 {subchassisPath + "2", "BoardB"},
260 {superchassisPath, "BoardC"},
261 {superchassisPath + "2", "BoardD"}};
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000262
Matt Spinler6eb60972023-08-14 16:36:20 -0500263 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);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000270
Alexander Hansen32e74182025-08-20 16:16:00 +0200271 auto assocs = topo.getAssocs(std::views::keys(boards));
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000272
Ed Tanousc6af85c2025-04-08 10:13:33 -0700273 EXPECT_EQ(assocs.size(), 2U);
274 EXPECT_EQ(assocs[subchassisPath].size(), 2U);
275 EXPECT_EQ(assocs[subchassisPath + "2"].size(), 2U);
Benjamin Fairf2f5b7a2022-09-09 19:45:02 +0000276
277 EXPECT_THAT(assocs[subchassisPath],
278 UnorderedElementsAre(subchassisAssoc, subchassisAssoc2));
279 EXPECT_THAT(assocs[subchassisPath + "2"],
280 UnorderedElementsAre(subchassisAssoc, subchassisAssoc2));
281}
Matt Spinler6eb60972023-08-14 16:36:20 -0500282
283TEST(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 {
Alexander Hansen32e74182025-08-20 16:16:00 +0200297 auto assocs = topo.getAssocs(std::views::keys(boards));
Matt Spinler6eb60972023-08-14 16:36:20 -0500298
Ed Tanousc6af85c2025-04-08 10:13:33 -0700299 EXPECT_EQ(assocs.size(), 2U);
300 EXPECT_EQ(assocs[subchassisPath].size(), 1U);
Alexander Hansen0519f572025-08-19 18:11:04 +0200301 EXPECT_TRUE(assocs[subchassisPath].contains(subchassisAssoc));
Ed Tanousc6af85c2025-04-08 10:13:33 -0700302 EXPECT_EQ(assocs[subchassisPath + "2"].size(), 1U);
Alexander Hansen0519f572025-08-19 18:11:04 +0200303 EXPECT_TRUE(assocs[subchassisPath + "2"].contains(subchassisAssoc));
Matt Spinler6eb60972023-08-14 16:36:20 -0500304 }
305
306 {
307 topo.remove("BoardA");
Alexander Hansen32e74182025-08-20 16:16:00 +0200308 auto assocs = topo.getAssocs(std::views::keys(boards));
Matt Spinler6eb60972023-08-14 16:36:20 -0500309
Ed Tanousc6af85c2025-04-08 10:13:33 -0700310 EXPECT_EQ(assocs.size(), 1U);
311 EXPECT_EQ(assocs[subchassisPath + "2"].size(), 1U);
Alexander Hansen0519f572025-08-19 18:11:04 +0200312 EXPECT_TRUE(assocs[subchassisPath + "2"].contains(subchassisAssoc));
Matt Spinler6eb60972023-08-14 16:36:20 -0500313 }
314
315 {
316 topo.remove("BoardB");
Alexander Hansen32e74182025-08-20 16:16:00 +0200317 auto assocs = topo.getAssocs(std::views::keys(boards));
Matt Spinler6eb60972023-08-14 16:36:20 -0500318
Ed Tanousc6af85c2025-04-08 10:13:33 -0700319 EXPECT_EQ(assocs.size(), 0U);
Matt Spinler6eb60972023-08-14 16:36:20 -0500320 }
321}
Alexander Hansen8ca09402025-08-27 16:15:26 +0200322
323TEST(Topology, SimilarToTyanS8030)
324{
325 const std::string chassisPath =
326 "/xyz/openbmc_project/inventory/system/chassis/ChassisA";
327 const std::string boardPath =
328 "/xyz/openbmc_project/inventory/system/board/BoardA";
329 const std::string psu0Path =
330 "/xyz/openbmc_project/inventory/system/powersupply/PSU0";
331 const std::string psu1Path =
332 "/xyz/openbmc_project/inventory/system/powersupply/PSU1";
333
334 const nlohmann::json chassisContainExposesItem = nlohmann::json::parse(R"(
335 {
336 "Name": "GenericContainPort",
337 "PortType": "containing",
338 "Type": "Port"
339 }
340)");
341 const nlohmann::json containedByExposesItem = nlohmann::json::parse(R"(
342 {
343 "Name": "GenericContainPort",
344 "PortType": "contained_by",
345 "Type": "Port"
346 }
347)");
348 const nlohmann::json boardPowerExposesItem = nlohmann::json::parse(R"(
349 {
350 "Name": "GenericPowerPort",
351 "PortType": "powered_by",
352 "Type": "Port"
353 }
354)");
355 const nlohmann::json psuPowerExposesItem = nlohmann::json::parse(R"(
356 {
357 "Name": "GenericPowerPort",
358 "PortType": "powering",
359 "Type": "Port"
360 }
361)");
362 Topology topo;
363 BoardMap boards{
364 {chassisPath, "ChassisA"},
365 {boardPath, "BoardA"},
366 {psu0Path, "PSU0"},
367 {psu1Path, "PSU1"},
368 };
369
370 // configure the chassis to be containing something
371 topo.addBoard(chassisPath, "Chassis", "ChassisA",
372 chassisContainExposesItem);
373
374 // configure board to be contained by something
375 topo.addBoard(boardPath, "Board", "BoardA", containedByExposesItem);
376
377 // configure the board to be powered by something
378 topo.addBoard(boardPath, "Board", "BoardA", boardPowerExposesItem);
379
380 // configure the PSUs to be powering something
381 topo.addBoard(psu0Path, "PowerSupply", "PSU0", psuPowerExposesItem);
382 topo.addBoard(psu1Path, "PowerSupply", "PSU1", psuPowerExposesItem);
383
384 // configured PSUs to be contained by something
385 topo.addBoard(psu0Path, "PowerSupply", "PSU0", containedByExposesItem);
386 topo.addBoard(psu1Path, "PowerSupply", "PSU1", containedByExposesItem);
387
388 auto assocs = topo.getAssocs(std::views::keys(boards));
389
390 EXPECT_TRUE(assocs.contains(boardPath));
391 EXPECT_TRUE(assocs.contains(psu0Path));
392 EXPECT_TRUE(assocs.contains(psu0Path));
393
394 // expect chassis to contain board
395 EXPECT_EQ(assocs[boardPath].size(), 1);
396 EXPECT_TRUE(assocs[boardPath].contains(
397 {"contained_by", "containing", chassisPath}));
398
399 // expect powering association from each PSU to the board
400 // and expect each PSU to be contained by the chassis
401 EXPECT_EQ(assocs[psu0Path].size(), 2);
402 EXPECT_TRUE(
403 assocs[psu0Path].contains({"powering", "powered_by", boardPath}));
404 EXPECT_TRUE(
405 assocs[psu0Path].contains({"contained_by", "containing", chassisPath}));
406
407 EXPECT_EQ(assocs[psu1Path].size(), 2);
408 EXPECT_TRUE(
409 assocs[psu1Path].contains({"powering", "powered_by", boardPath}));
410 EXPECT_TRUE(
411 assocs[psu1Path].contains({"contained_by", "containing", chassisPath}));
412}
413
414static nlohmann::json makeExposesItem(const std::string& name,
415 const std::string& assocName)
416{
417 nlohmann::json exposesItem = nlohmann::json::parse(R"(
418 {
419 "Name": "REPLACE",
420 "PortType": "REPLACE",
421 "Type": "Port"
422 }
423)");
424
425 exposesItem["Name"] = name;
426 exposesItem["PortType"] = assocName;
427
428 return exposesItem;
429}
430
431static nlohmann::json makeContainedPortExposesItem(const std::string& name)
432{
433 return makeExposesItem(name, "contained_by");
434}
435
436static nlohmann::json makeContainingPortExposesItem(const std::string& name)
437{
438 return makeExposesItem(name, "containing");
439}
440
441TEST(Topology, SimilarToYosemiteV3)
442{
443 const std::string blade1Path =
444 "/xyz/openbmc_project/inventory/system/board/Blade1";
445 const std::string blade2Path =
446 "/xyz/openbmc_project/inventory/system/board/Blade2";
447 const std::string blade3Path =
448 "/xyz/openbmc_project/inventory/system/board/Blade3";
449 const std::string blade4Path =
450 "/xyz/openbmc_project/inventory/system/board/Blade4";
451 const std::string chassis1Path =
452 "/xyz/openbmc_project/inventory/system/chassis/Blade1Chassis";
453 const std::string chassis2Path =
454 "/xyz/openbmc_project/inventory/system/chassis/Blade2Chassis";
455 const std::string chassis3Path =
456 "/xyz/openbmc_project/inventory/system/chassis/Blade3Chassis";
457 const std::string chassis4Path =
458 "/xyz/openbmc_project/inventory/system/chassis/Blade4Chassis";
459 const std::string superChassisPath =
460 "/xyz/openbmc_project/inventory/system/chassis/SuperChassis";
461
462 const nlohmann::json blade1ExposesItem =
463 makeContainedPortExposesItem("Blade1Port");
464 const nlohmann::json blade2ExposesItem =
465 makeContainedPortExposesItem("Blade2Port");
466 const nlohmann::json blade3ExposesItem =
467 makeContainedPortExposesItem("Blade3Port");
468 const nlohmann::json blade4ExposesItem =
469 makeContainedPortExposesItem("Blade4Port");
470
471 const nlohmann::json chassis1ExposesItem =
472 makeContainingPortExposesItem("Blade1Port");
473 const nlohmann::json chassis2ExposesItem =
474 makeContainingPortExposesItem("Blade2Port");
475 const nlohmann::json chassis3ExposesItem =
476 makeContainingPortExposesItem("Blade3Port");
477 const nlohmann::json chassis4ExposesItem =
478 makeContainingPortExposesItem("Blade4Port");
479
480 const nlohmann::json chassis1ExposesItem2 =
481 makeContainedPortExposesItem("SuperChassisPort");
482 const nlohmann::json chassis2ExposesItem2 =
483 makeContainedPortExposesItem("SuperChassisPort");
484 const nlohmann::json chassis3ExposesItem2 =
485 makeContainedPortExposesItem("SuperChassisPort");
486 const nlohmann::json chassis4ExposesItem2 =
487 makeContainedPortExposesItem("SuperChassisPort");
488
489 const nlohmann::json superChassisExposesItem =
490 makeContainingPortExposesItem("SuperChassisPort");
491
492 Topology topo;
493 BoardMap boards{
494 {blade1Path, "Blade1"},
495 {blade2Path, "Blade2"},
496 {blade3Path, "Blade3"},
497 {blade4Path, "Blade4"},
498 {chassis1Path, "Chassis1"},
499 {chassis2Path, "Chassis2"},
500 {chassis3Path, "Chassis3"},
501 {chassis4Path, "Chassis4"},
502 {superChassisPath, "SuperChassis"},
503 };
504
505 topo.addBoard(blade1Path, "Board", "Blade1", blade1ExposesItem);
506 topo.addBoard(blade2Path, "Board", "Blade2", blade2ExposesItem);
507 topo.addBoard(blade3Path, "Board", "Blade3", blade3ExposesItem);
508 topo.addBoard(blade4Path, "Board", "Blade4", blade4ExposesItem);
509
510 topo.addBoard(chassis1Path, "Chassis", "Chassis1", chassis1ExposesItem);
511 topo.addBoard(chassis2Path, "Chassis", "Chassis2", chassis2ExposesItem);
512 topo.addBoard(chassis3Path, "Chassis", "Chassis3", chassis3ExposesItem);
513 topo.addBoard(chassis4Path, "Chassis", "Chassis4", chassis4ExposesItem);
514
515 topo.addBoard(chassis1Path, "Chassis", "Chassis1", chassis1ExposesItem2);
516 topo.addBoard(chassis2Path, "Chassis", "Chassis2", chassis2ExposesItem2);
517 topo.addBoard(chassis3Path, "Chassis", "Chassis3", chassis3ExposesItem2);
518 topo.addBoard(chassis4Path, "Chassis", "Chassis4", chassis4ExposesItem2);
519
520 topo.addBoard(superChassisPath, "Chassis", "SuperChassis",
521 superChassisExposesItem);
522
523 auto assocs = topo.getAssocs(std::views::keys(boards));
524
525 // all blades are contained by their respective chassis
526 EXPECT_EQ(assocs[blade1Path].size(), 1);
527 EXPECT_TRUE(assocs[blade1Path].contains(
528 {"contained_by", "containing", chassis1Path}));
529
530 EXPECT_EQ(assocs[blade2Path].size(), 1);
531 EXPECT_TRUE(assocs[blade2Path].contains(
532 {"contained_by", "containing", chassis2Path}));
533
534 EXPECT_EQ(assocs[blade3Path].size(), 1);
535 EXPECT_TRUE(assocs[blade3Path].contains(
536 {"contained_by", "containing", chassis3Path}));
537
538 EXPECT_EQ(assocs[blade4Path].size(), 1);
539 EXPECT_TRUE(assocs[blade4Path].contains(
540 {"contained_by", "containing", chassis4Path}));
541
542 // all chassis are contained by the superchassis
543 EXPECT_TRUE(assocs[chassis1Path].contains(
544 {"contained_by", "containing", superChassisPath}));
545
546 EXPECT_TRUE(assocs[chassis2Path].contains(
547 {"contained_by", "containing", superChassisPath}));
548
549 EXPECT_TRUE(assocs[chassis3Path].contains(
550 {"contained_by", "containing", superChassisPath}));
551
552 EXPECT_TRUE(assocs[chassis4Path].contains(
553 {"contained_by", "containing", superChassisPath}));
554}