remove pending associations by owner Changes: Match with the service while removing the pending association for an object. Only the pending association introduced by the service which removes the object/interface will be erased. If Service A has an association on Object X with Object Y (which comes from Service C), and Service B also has an association definition for Object X, there is a scenario where the X-Y association will not be created, even though both objects are present in the D-Bus tree. Steps to Reproduce: 1. Service A starts and creates Object X. It creates a pending association Y-X. 2. Service B starts, registers properties for Object X, and creates other associations. 3. Service B drops Object X and its associated definitions. As a result, all pending associations for Object X are wiped out (including X-Y which is from A). 4. Service B creates Object X again along with other associations related to Service B (but not the ones from Service A). 5. Service C finally starts and creates Object Y, but no pending association is processed to complete the X-Y link. Tested: Unit tested. Also testing on a machine with the above steps and all the associations were still created. Patch Tracking Bug: b/491287006 Upstream info / review: https://gerrit.openbmc.org/c/openbmc/phosphor-objmgr/+/88131 Upstream-Status: Accepted Justification: Bugfix - b/488925115 Google-Bug-Id: 488925115 Change-Id: I86788e115c4431e2103fb8fc0692f8188f48ac1b Signed-off-by: Munawar Hussain <munawarhussain@google.com> Signed-off-by: Jane Kramer <jkrm@google.com> Google-Bug-Id: 572860608
diff --git a/src/associations.cpp b/src/associations.cpp index db911f9..1eceddd 100644 --- a/src/associations.cpp +++ b/src/associations.cpp
@@ -129,7 +129,7 @@ // If we were still waiting on the other side of this association to // show up, cancel that wait. - removeFromPendingAssociations(sourcePath, assocMaps); + removeFromPendingAssociations(sourcePath, owner, assocMaps); } void removeAssociationEndpoints( @@ -345,6 +345,7 @@ } void removeFromPendingAssociations(const std::string& endpointPath, + const std::string& owner, AssociationMaps& assocMaps) { auto assoc = assocMaps.pending.begin(); @@ -354,7 +355,8 @@ while (endpoint != assoc->second.end()) { auto& e = std::get<assocPos>(*endpoint); - if (std::get<reversePathPos>(e) == endpointPath) + if (std::get<reversePathPos>(e) == endpointPath && + std::get<ownerPos>(*endpoint) == owner) { endpoint = assoc->second.erase(endpoint); continue;
diff --git a/src/associations.hpp b/src/associations.hpp index 1d7b778..d9bdbb1 100644 --- a/src/associations.hpp +++ b/src/associations.hpp
@@ -126,9 +126,11 @@ * If the last endpoint is removed, removes the whole entry * * @param[in] endpointPath - the endpoint path to remove + * @param[in] owner - The service name that owns the association * @param[in,out] assocMaps - The association maps */ void removeFromPendingAssociations(const std::string& endpointPath, + const std::string& owner, AssociationMaps& assocMaps); /** @brief Adds a single association D-Bus object (<path>/<type>)
diff --git a/src/test/associations.cpp b/src/test/associations.cpp index fe0a826..cfd7de9 100644 --- a/src/test/associations.cpp +++ b/src/test/associations.cpp
@@ -433,7 +433,8 @@ EXPECT_EQ(assocMaps.pending.size(), 1); - removeFromPendingAssociations("some/other/endpoint", assocMaps); + removeFromPendingAssociations("some/other/endpoint", defaultDbusSvc, + assocMaps); // Still 1 pending entry, but down to 1 endpoint EXPECT_EQ(assocMaps.pending.size(), 1); @@ -444,10 +445,34 @@ EXPECT_EQ(endpoints.size(), 1); // Now nothing pending - removeFromPendingAssociations(defaultEndpoint, assocMaps); + removeFromPendingAssociations(defaultEndpoint, defaultDbusSvc, assocMaps); EXPECT_EQ(assocMaps.pending.size(), 0); } +// Test removing pending associations by multiple owners +TEST_F(TestAssociations, testRemoveFromPendingAssociationsMultipleOwners) +{ + AssociationMaps assocMaps; + + addPendingAssociation(defaultSourcePath, "inventory", defaultEndpoint, + "error", "serviceA", assocMaps); + + addPendingAssociation(defaultSourcePath, "inventory", defaultEndpoint, + "error", "serviceB", assocMaps); + + EXPECT_EQ(assocMaps.pending.size(), 1); + + removeFromPendingAssociations(defaultEndpoint, "serviceB", assocMaps); + + EXPECT_EQ(assocMaps.pending.size(), 1); + + auto assoc = assocMaps.pending.find(defaultSourcePath); + EXPECT_NE(assoc, assocMaps.pending.end()); + auto& endpoints = assoc->second; + EXPECT_EQ(endpoints.size(), 1); + EXPECT_EQ(std::get<ownerPos>(endpoints[0]), "serviceA"); +} + // Test moving a pending association to a real one TEST_F(TestAssociations, checkIfPending) {