xref: /openbmc/entity-manager/test/test_topology.cpp (revision f850ecad00900a9d338950e28506c04af42b8883)
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