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