xref: /openbmc/phosphor-objmgr/src/test/associations.cpp (revision 86436ac025f569f16512e71c979d4c2d4e514135)
1 #include "src/associations.hpp"
2 
3 #include "src/test/util/asio_server_class.hpp"
4 #include "src/test/util/association_objects.hpp"
5 #include "src/test/util/debug_output.hpp"
6 
7 #include <sdbusplus/asio/connection.hpp>
8 #include <sdbusplus/asio/object_server.hpp>
9 
10 #include <gtest/gtest.h>
11 
12 class TestAssociations : public AsioServerClassTest
13 {
14   public:
15     boost::asio::io_context io;
SetUp()16     virtual void SetUp() override
17     {
18         io.run();
19     }
20 };
21 sdbusplus::asio::object_server* TestAssociations::AsioServerClassTest::server =
22     nullptr;
23 
24 // Verify call when path is not in associated owners
TEST_F(TestAssociations,SourcePathNotInAssociations)25 TEST_F(TestAssociations, SourcePathNotInAssociations)
26 {
27     EXPECT_NE(nullptr, server);
28     std::string sourcePath = "/xyz/openbmc_project/no/association";
29     AssociationMaps assocMaps;
30 
31     removeAssociation(io, sourcePath, defaultDbusSvc, *server, assocMaps);
32 }
33 
34 // Verify call when owner is not in associated owners
TEST_F(TestAssociations,OwnerNotInAssociations)35 TEST_F(TestAssociations, OwnerNotInAssociations)
36 {
37     AssociationMaps assocMaps;
38     assocMaps.owners = createDefaultOwnerAssociation();
39 
40     removeAssociation(io, defaultSourcePath, defaultDbusSvc, *server,
41                       assocMaps);
42 }
43 
44 // Verify call when path is not in associated interfaces
TEST_F(TestAssociations,PathNotInAssocInterfaces)45 TEST_F(TestAssociations, PathNotInAssocInterfaces)
46 {
47     AssociationMaps assocMaps;
48 
49     assocMaps.owners = createDefaultOwnerAssociation();
50 
51     removeAssociation(io, defaultSourcePath, defaultDbusSvc, *server,
52                       assocMaps);
53 
54     EXPECT_TRUE(assocMaps.owners.empty());
55 }
56 
57 // Verify call when path is in associated interfaces
TEST_F(TestAssociations,PathIsInAssociatedInterfaces)58 TEST_F(TestAssociations, PathIsInAssociatedInterfaces)
59 {
60     // Build up these objects so that an associated interface will match
61     // with the associated owner being removed
62     AssociationMaps assocMaps;
63     assocMaps.owners = createDefaultOwnerAssociation();
64     assocMaps.ifaces = createDefaultInterfaceAssociation(server);
65 
66     removeAssociation(io, defaultSourcePath, defaultDbusSvc, *server,
67                       assocMaps);
68 
69     // Verify owner association was deleted
70     EXPECT_TRUE(assocMaps.owners.empty());
71 
72     // Verify endpoint was deleted from interface association
73     auto intfEndpoints =
74         std::get<endpointsPos>(assocMaps.ifaces[defaultFwdPath]);
75     EXPECT_EQ(intfEndpoints.size(), 0);
76     intfEndpoints = std::get<endpointsPos>(assocMaps.ifaces[defaultRevPath]);
77     EXPECT_EQ(intfEndpoints.size(), 0);
78 }
79 
80 // Verify call when path is in associated interfaces, with extra endpoints
TEST_F(TestAssociations,PathIsInAssociatedInterfacesExtraEndpoints)81 TEST_F(TestAssociations, PathIsInAssociatedInterfacesExtraEndpoints)
82 {
83     // Build up these objects so that an associated interface will match
84     // with the associated owner being removed
85     AssociationMaps assocMaps;
86     assocMaps.owners = createDefaultOwnerAssociation();
87     assocMaps.ifaces = createDefaultInterfaceAssociation(server);
88 
89     // Add another endpoint to the assoc interfaces
90     addEndpointToInterfaceAssociation(assocMaps.ifaces);
91 
92     removeAssociation(io, defaultSourcePath, defaultDbusSvc, *server,
93                       assocMaps);
94 
95     // Verify owner association was deleted
96     EXPECT_TRUE(assocMaps.owners.empty());
97 
98     // Verify all endpoints are deleted since source path was deleted
99     auto intfEndpoints =
100         std::get<endpointsPos>(assocMaps.ifaces[defaultFwdPath]);
101     EXPECT_EQ(intfEndpoints.size(), 0);
102     intfEndpoints = std::get<endpointsPos>(assocMaps.ifaces[defaultRevPath]);
103     EXPECT_EQ(intfEndpoints.size(), 0);
104 }
105 
106 // Verify no associations or endpoints removed when the change is identical
TEST_F(TestAssociations,checkAssociationEndpointRemovesNoEpRemove)107 TEST_F(TestAssociations, checkAssociationEndpointRemovesNoEpRemove)
108 {
109     AssociationPaths newAssocPaths = {{defaultFwdPath, {defaultEndpoint}},
110                                       {defaultRevPath, {defaultSourcePath}}};
111 
112     AssociationMaps assocMaps;
113     assocMaps.owners = createDefaultOwnerAssociation();
114     assocMaps.ifaces = createDefaultInterfaceAssociation(server);
115 
116     checkAssociationEndpointRemoves(io, defaultSourcePath, defaultDbusSvc,
117                                     newAssocPaths, *server, assocMaps);
118 
119     // Verify endpoints were not deleted because they matche with what was
120     // in the original
121     auto intfEndpoints =
122         std::get<endpointsPos>(assocMaps.ifaces[defaultFwdPath]);
123     EXPECT_EQ(intfEndpoints.size(), 1);
124     intfEndpoints = std::get<endpointsPos>(assocMaps.ifaces[defaultRevPath]);
125     EXPECT_EQ(intfEndpoints.size(), 1);
126 }
127 
128 // Verify endpoint is removed when assoc path is different
TEST_F(TestAssociations,checkAssociationEndpointRemovesEpRemoveApDiff)129 TEST_F(TestAssociations, checkAssociationEndpointRemovesEpRemoveApDiff)
130 {
131     AssociationPaths newAssocPaths = {{"/different/path", {defaultEndpoint}}};
132 
133     AssociationMaps assocMaps;
134     assocMaps.owners = createDefaultOwnerAssociation();
135     assocMaps.ifaces = createDefaultInterfaceAssociation(server);
136 
137     checkAssociationEndpointRemoves(io, defaultSourcePath, defaultDbusSvc,
138                                     newAssocPaths, *server, assocMaps);
139 
140     // Verify initial endpoints were deleted because the new path
141     auto intfEndpoints =
142         std::get<endpointsPos>(assocMaps.ifaces[defaultFwdPath]);
143     EXPECT_EQ(intfEndpoints.size(), 0);
144     intfEndpoints = std::get<endpointsPos>(assocMaps.ifaces[defaultRevPath]);
145     EXPECT_EQ(intfEndpoints.size(), 0);
146 }
147 
148 // Verify endpoint is removed when endpoint is different
TEST_F(TestAssociations,checkAssociationEndpointRemovesEpRemoveEpChanged)149 TEST_F(TestAssociations, checkAssociationEndpointRemovesEpRemoveEpChanged)
150 {
151     AssociationPaths newAssocPaths = {
152         {defaultFwdPath, {defaultEndpoint + "/different"}},
153         {defaultRevPath, {defaultSourcePath + "/different"}}};
154 
155     AssociationMaps assocMaps;
156     assocMaps.owners = createDefaultOwnerAssociation();
157     assocMaps.ifaces = createDefaultInterfaceAssociation(server);
158 
159     checkAssociationEndpointRemoves(io, defaultSourcePath, defaultDbusSvc,
160                                     newAssocPaths, *server, assocMaps);
161 
162     // Verify initial endpoints were deleted because of different endpoints
163     auto intfEndpoints =
164         std::get<endpointsPos>(assocMaps.ifaces[defaultFwdPath]);
165     EXPECT_EQ(intfEndpoints.size(), 0);
166     intfEndpoints = std::get<endpointsPos>(assocMaps.ifaces[defaultRevPath]);
167     EXPECT_EQ(intfEndpoints.size(), 0);
168 }
169 
170 // Verify existing endpoint deleted when empty endpoint is provided
TEST_F(TestAssociations,associationChangedEmptyEndpoint)171 TEST_F(TestAssociations, associationChangedEmptyEndpoint)
172 {
173     std::vector<Association> associations = {
174         {"inventory_cee", "error_cee", ""}};
175     InterfaceMapType interfaceMap;
176 
177     AssociationMaps assocMaps;
178     assocMaps.owners = createDefaultOwnerAssociation();
179     assocMaps.ifaces = createDefaultInterfaceAssociation(server);
180 
181     // Empty endpoint will result in deletion of corresponding assocInterface
182     associationChanged(io, *server, associations, defaultSourcePath,
183                        defaultDbusSvc, interfaceMap, assocMaps);
184 
185     // Both of these should be 0 since we have an invalid endpoint
186     auto intfEndpoints =
187         std::get<endpointsPos>(assocMaps.ifaces[defaultFwdPath]);
188     EXPECT_EQ(intfEndpoints.size(), 0);
189     intfEndpoints = std::get<endpointsPos>(assocMaps.ifaces[defaultRevPath]);
190     EXPECT_EQ(intfEndpoints.size(), 0);
191 
192     EXPECT_EQ(assocMaps.pending.size(), 0);
193 }
194 
195 // Add a new association with endpoint
TEST_F(TestAssociations,associationChangedAddNewAssoc)196 TEST_F(TestAssociations, associationChangedAddNewAssoc)
197 {
198     std::vector<Association> associations = {
199         {"abc", "def", "/xyz/openbmc_project/new/endpoint"}};
200 
201     AssociationMaps assocMaps;
202     assocMaps.owners = createDefaultOwnerAssociation();
203     assocMaps.ifaces = createDefaultInterfaceAssociation(server);
204 
205     // Make it look like the assoc endpoints are on D-Bus
206     InterfaceMapType interfaceMap = {
207         {"/new/source/path", {{defaultDbusSvc, {"a"}}}},
208         {"/xyz/openbmc_project/new/endpoint", {{defaultDbusSvc, {"a"}}}}};
209 
210     associationChanged(io, *server, associations, "/new/source/path",
211                        defaultDbusSvc, interfaceMap, assocMaps);
212 
213     // Two source paths
214     EXPECT_EQ(assocMaps.owners.size(), 2);
215 
216     // Four interfaces
217     EXPECT_EQ(assocMaps.ifaces.size(), 4);
218 
219     // Nothing pending
220     EXPECT_EQ(assocMaps.pending.size(), 0);
221 
222     // New endpoint so assocMaps.ifaces should be same size
223     auto intfEndpoints =
224         std::get<endpointsPos>(assocMaps.ifaces[defaultFwdPath]);
225     EXPECT_EQ(intfEndpoints.size(), 1);
226 }
227 
228 // Add a new association to empty objects
TEST_F(TestAssociations,associationChangedAddNewAssocEmptyObj)229 TEST_F(TestAssociations, associationChangedAddNewAssocEmptyObj)
230 {
231     std::vector<Association> associations = {
232         {"inventory_canaeo", "error_canaeo",
233          "/xyz/openbmc_project/inventory/system/chassis"}};
234 
235     // Empty objects because this test will ensure assocOwners adds the
236     // changed association and interface
237     AssociationMaps assocMaps;
238 
239     // Make it look like the assoc endpoints are on D-Bus
240     InterfaceMapType interfaceMap = createDefaultInterfaceMap();
241 
242     associationChanged(io, *server, associations, defaultSourcePath,
243                        defaultDbusSvc, interfaceMap, assocMaps);
244 
245     // New associations so ensure it now contains a single entry
246     EXPECT_EQ(assocMaps.owners.size(), 1);
247 
248     // Nothing pending
249     EXPECT_EQ(assocMaps.pending.size(), 0);
250 
251     // Verify corresponding assoc paths each have one endpoint in assoc
252     // interfaces and that those endpoints match
253     auto singleOwner = assocMaps.owners[defaultSourcePath];
254     auto singleIntf = singleOwner[defaultDbusSvc];
255     for (auto i : singleIntf)
256     {
257         auto intfEndpoints = std::get<endpointsPos>(assocMaps.ifaces[i.first]);
258         EXPECT_EQ(intfEndpoints.size(), 1);
259         EXPECT_EQ(intfEndpoints[0], *i.second.begin());
260     }
261 }
262 
263 // Add a new association to same source path but with new owner
TEST_F(TestAssociations,associationChangedAddNewAssocNewOwner)264 TEST_F(TestAssociations, associationChangedAddNewAssocNewOwner)
265 {
266     std::string newOwner = "xyz.openbmc_project.Test2";
267     std::vector<Association> associations = {
268         {"inventory_canano", "error_canano",
269          "/xyz/openbmc_project/inventory/system/chassis"}};
270 
271     // Make it look like the assoc endpoints are on D-Bus
272     InterfaceMapType interfaceMap = createDefaultInterfaceMap();
273 
274     AssociationMaps assocMaps;
275     assocMaps.owners = createDefaultOwnerAssociation();
276     assocMaps.ifaces = createDefaultInterfaceAssociation(server);
277 
278     associationChanged(io, *server, associations, defaultSourcePath, newOwner,
279                        interfaceMap, assocMaps);
280 
281     // New endpoint so assocOwners should be same size
282     EXPECT_EQ(assocMaps.owners.size(), 1);
283 
284     // Ensure only one endpoint under first path
285     auto intfEndpoints =
286         std::get<endpointsPos>(assocMaps.ifaces[defaultFwdPath]);
287     EXPECT_EQ(intfEndpoints.size(), 1);
288 
289     // Ensure the 2 new association endpoints are under the new owner
290     auto a = assocMaps.owners.find(defaultSourcePath);
291     auto o = a->second.find(newOwner);
292     EXPECT_EQ(o->second.size(), 2);
293 
294     // Nothing pending
295     EXPECT_EQ(assocMaps.pending.size(), 0);
296 }
297 
298 // Add a new association to existing interface path
TEST_F(TestAssociations,associationChangedAddNewAssocSameInterface)299 TEST_F(TestAssociations, associationChangedAddNewAssocSameInterface)
300 {
301     std::vector<Association> associations = {
302         {"abc", "error", "/xyz/openbmc_project/inventory/system/chassis"}};
303 
304     // Make it look like the assoc endpoints are on D-Bus
305     InterfaceMapType interfaceMap = createDefaultInterfaceMap();
306 
307     AssociationMaps assocMaps;
308     assocMaps.owners = createDefaultOwnerAssociation();
309     assocMaps.ifaces = createDefaultInterfaceAssociation(server);
310 
311     associationChanged(io, *server, associations, defaultSourcePath,
312                        defaultDbusSvc, interfaceMap, assocMaps);
313 
314     // Should have 2 entries in AssociationInterfaces
315     // The one missing an endpoint is not added.
316     EXPECT_EQ(assocMaps.ifaces.size(), 2);
317 
318     // Change to existing interface so it will be removed here
319     auto intfEndpoints =
320         std::get<endpointsPos>(assocMaps.ifaces[defaultFwdPath]);
321     EXPECT_EQ(intfEndpoints.size(), 0);
322 
323     // The new endpoint should exist though in it's place
324     intfEndpoints = std::get<endpointsPos>(
325         assocMaps.ifaces[defaultSourcePath + "/" + "abc"]);
326     EXPECT_EQ(intfEndpoints.size(), 1);
327 
328     // Added to an existing owner path so still 1
329     EXPECT_EQ(assocMaps.owners.size(), 1);
330 
331     EXPECT_EQ(assocMaps.pending.size(), 0);
332 }
333 
334 // Add 2 pending associations
TEST_F(TestAssociations,addPendingAssocs)335 TEST_F(TestAssociations, addPendingAssocs)
336 {
337     AssociationMaps assocMaps;
338 
339     addPendingAssociation(defaultSourcePath, "inventory", defaultEndpoint,
340                           "error", defaultDbusSvc, assocMaps);
341 
342     EXPECT_TRUE(assocMaps.ifaces.empty());
343     EXPECT_TRUE(assocMaps.owners.empty());
344 
345     EXPECT_EQ(assocMaps.pending.size(), 1);
346 
347     addPendingAssociation("some/other/path", "inventory", defaultEndpoint,
348                           "error", defaultDbusSvc, assocMaps);
349 
350     EXPECT_TRUE(assocMaps.ifaces.empty());
351     EXPECT_TRUE(assocMaps.owners.empty());
352 
353     EXPECT_EQ(assocMaps.pending.size(), 2);
354 }
355 
356 // Test adding a new endpoint to a pending association
TEST_F(TestAssociations,addPendingAssocsNewEndpoints)357 TEST_F(TestAssociations, addPendingAssocsNewEndpoints)
358 {
359     AssociationMaps assocMaps;
360 
361     addPendingAssociation(defaultSourcePath, "inventory", defaultEndpoint,
362                           "error", defaultDbusSvc, assocMaps);
363 
364     EXPECT_EQ(assocMaps.pending.size(), 1);
365 
366     addPendingAssociation(defaultSourcePath, "inventory", "some/other/endpoint",
367                           "error", defaultDbusSvc, assocMaps);
368 
369     // Same pending path, so still just 1 entry
370     EXPECT_EQ(assocMaps.pending.size(), 1);
371 
372     auto assoc = assocMaps.pending.find(defaultSourcePath);
373     EXPECT_NE(assoc, assocMaps.pending.end());
374 
375     auto& endpoints = assoc->second;
376     EXPECT_EQ(endpoints.size(), 2);
377 }
378 
379 // Test adding a new owner to a pending association
TEST_F(TestAssociations,addPendingAssocsNewOwner)380 TEST_F(TestAssociations, addPendingAssocsNewOwner)
381 {
382     AssociationMaps assocMaps;
383 
384     addPendingAssociation(defaultSourcePath, "inventory", defaultEndpoint,
385                           "error", defaultDbusSvc, assocMaps);
386 
387     EXPECT_EQ(assocMaps.pending.size(), 1);
388 
389     addPendingAssociation(defaultSourcePath, "inventory", defaultEndpoint,
390                           "error", "new owner", assocMaps);
391 
392     EXPECT_EQ(assocMaps.pending.size(), 1);
393 
394     auto assoc = assocMaps.pending.find(defaultSourcePath);
395     EXPECT_NE(assoc, assocMaps.pending.end());
396 
397     auto& endpoints = assoc->second;
398     EXPECT_EQ(endpoints.size(), 2);
399 }
400 
401 // Add a pending association inside associationChanged
TEST_F(TestAssociations,associationChangedPending)402 TEST_F(TestAssociations, associationChangedPending)
403 {
404     std::vector<Association> associations = {
405         {"abc", "def", "/xyz/openbmc_project/new/endpoint"}};
406 
407     AssociationMaps assocMaps;
408     InterfaceMapType interfaceMap;
409 
410     associationChanged(io, *server, associations, "/new/source/path",
411                        defaultDbusSvc, interfaceMap, assocMaps);
412 
413     // No associations were actually added
414     EXPECT_EQ(assocMaps.owners.size(), 0);
415     EXPECT_EQ(assocMaps.ifaces.size(), 0);
416 
417     // 1 pending association
418     EXPECT_EQ(assocMaps.pending.size(), 1);
419 }
420 
421 // Test removing pending associations
TEST_F(TestAssociations,testRemoveFromPendingAssociations)422 TEST_F(TestAssociations, testRemoveFromPendingAssociations)
423 {
424     AssociationMaps assocMaps;
425 
426     addPendingAssociation(defaultSourcePath, "inventory", defaultEndpoint,
427                           "error", defaultDbusSvc, assocMaps);
428 
429     addPendingAssociation(defaultSourcePath, "inventory", "some/other/endpoint",
430                           "error", defaultDbusSvc, assocMaps);
431 
432     EXPECT_EQ(assocMaps.pending.size(), 1);
433 
434     removeFromPendingAssociations("some/other/endpoint", assocMaps);
435 
436     // Still 1 pending entry, but down to 1 endpoint
437     EXPECT_EQ(assocMaps.pending.size(), 1);
438 
439     auto assoc = assocMaps.pending.find(defaultSourcePath);
440     EXPECT_NE(assoc, assocMaps.pending.end());
441     auto& endpoints = assoc->second;
442     EXPECT_EQ(endpoints.size(), 1);
443 
444     // Now nothing pending
445     removeFromPendingAssociations(defaultEndpoint, assocMaps);
446     EXPECT_EQ(assocMaps.pending.size(), 0);
447 }
448 
449 // Test moving a pending association to a real one
TEST_F(TestAssociations,checkIfPending)450 TEST_F(TestAssociations, checkIfPending)
451 {
452     AssociationMaps assocMaps;
453     InterfaceMapType interfaceMap = {
454         {defaultSourcePath, {{defaultDbusSvc, {"a"}}}},
455         {defaultEndpoint, {{defaultDbusSvc, {"b"}}}}};
456 
457     addPendingAssociation(defaultSourcePath, "inventory_cip", defaultEndpoint,
458                           "error_cip", defaultDbusSvc, assocMaps);
459     EXPECT_EQ(assocMaps.pending.size(), 1);
460 
461     // Move the pending association to a real association
462     checkIfPendingAssociation(io, defaultSourcePath, interfaceMap, assocMaps,
463                               *server);
464 
465     EXPECT_TRUE(assocMaps.pending.empty());
466     EXPECT_EQ(assocMaps.owners.size(), 1);
467     EXPECT_EQ(assocMaps.ifaces.size(), 2);
468 
469     // This shouldn't do anything, since /new/path isn't pending
470     checkIfPendingAssociation(io, "/new/path", interfaceMap, assocMaps,
471                               *server);
472     EXPECT_TRUE(assocMaps.pending.empty());
473     EXPECT_EQ(assocMaps.owners.size(), 1);
474     EXPECT_EQ(assocMaps.ifaces.size(), 2);
475 }
476 
TEST_F(TestAssociations,findAssociations)477 TEST_F(TestAssociations, findAssociations)
478 {
479     std::vector<std::tuple<std::string, Association>> associationData;
480     AssociationMaps assocMaps;
481 
482     assocMaps.owners = {
483         {"pathA",
484          {{"ownerA",
485            {{"pathA/typeA", {"endpointA", "endpointB"}},
486             {"endpointA/type0", {"pathA"}}}}}},
487 
488         {"pathJ",
489          {{"ownerC",
490            {{"pathJ/typeA", {"endpointF"}}, {"endpointF/type0", {"pathJ"}}}}}},
491 
492         {"pathX",
493          {{"ownerB",
494            {{"pathX/typeB", {"endpointA"}}, {"endpointA/type1", {"pathX"}}}}}}};
495 
496     findAssociations("endpointA", assocMaps, associationData);
497     ASSERT_EQ(associationData.size(), 2);
498 
499     {
500         auto it = std::find_if(
501             associationData.begin(), associationData.end(),
502             [](const auto& ad) { return std::get<0>(ad) == "ownerA"; });
503         ASSERT_NE(it, associationData.end());
504 
505         auto& a = std::get<1>(*it);
506         ASSERT_EQ(std::get<0>(a), "type0");
507         ASSERT_EQ(std::get<1>(a), "typeA");
508         ASSERT_EQ(std::get<2>(a), "pathA");
509     }
510     {
511         auto it = std::find_if(
512             associationData.begin(), associationData.end(),
513             [](const auto& ad) { return std::get<0>(ad) == "ownerB"; });
514         ASSERT_NE(it, associationData.end());
515 
516         auto& a = std::get<1>(*it);
517         ASSERT_EQ(std::get<0>(a), "type1");
518         ASSERT_EQ(std::get<1>(a), "typeB");
519         ASSERT_EQ(std::get<2>(a), "pathX");
520     }
521 }
522 
TEST_F(TestAssociations,moveAssocToPendingNoOp)523 TEST_F(TestAssociations, moveAssocToPendingNoOp)
524 {
525     AssociationMaps assocMaps;
526 
527     // Not an association, so it shouldn't do anything
528     moveAssociationToPending(io, defaultEndpoint, assocMaps, *server);
529 
530     EXPECT_TRUE(assocMaps.pending.empty());
531     EXPECT_TRUE(assocMaps.owners.empty());
532     EXPECT_TRUE(assocMaps.ifaces.empty());
533 }
534 
TEST_F(TestAssociations,moveAssocToPending)535 TEST_F(TestAssociations, moveAssocToPending)
536 {
537     AssociationMaps assocMaps;
538     assocMaps.owners = createDefaultOwnerAssociation();
539     assocMaps.ifaces = createDefaultInterfaceAssociation(server);
540 
541     moveAssociationToPending(io, defaultEndpoint, assocMaps, *server);
542 
543     // Check it's now pending
544     EXPECT_EQ(assocMaps.pending.size(), 1);
545     EXPECT_EQ(assocMaps.pending.begin()->first, defaultEndpoint);
546 
547     // No more assoc owners
548     EXPECT_TRUE(assocMaps.owners.empty());
549 
550     // Check the association interfaces were removed
551     {
552         auto assocs = assocMaps.ifaces.find(defaultFwdPath);
553         auto& iface = std::get<ifacePos>(assocs->second);
554         auto& endpoints = std::get<endpointsPos>(assocs->second);
555 
556         EXPECT_EQ(iface.get(), nullptr);
557         EXPECT_TRUE(endpoints.empty());
558     }
559     {
560         auto assocs = assocMaps.ifaces.find(defaultRevPath);
561         auto& iface = std::get<ifacePos>(assocs->second);
562         auto& endpoints = std::get<endpointsPos>(assocs->second);
563 
564         EXPECT_EQ(iface.get(), nullptr);
565         EXPECT_TRUE(endpoints.empty());
566     }
567 }
568