unit-test: Move associationChanged()

Make it easier to unit test and continue reduction of main.cpp

Change-Id: Ic549e096343e7a2fb11985f1c48879ed4486e40b
Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
diff --git a/src/associations.cpp b/src/associations.cpp
index 352db9b..6982b52 100644
--- a/src/associations.cpp
+++ b/src/associations.cpp
@@ -1,5 +1,7 @@
 #include "associations.hpp"
 
+#include <iostream>
+
 void removeAssociation(const std::string& sourcePath, const std::string& owner,
                        sdbusplus::asio::object_server& server,
                        AssociationOwnersType& assocOwners,
@@ -138,3 +140,93 @@
         }
     }
 }
+
+void associationChanged(sdbusplus::asio::object_server& objectServer,
+                        const std::vector<Association>& associations,
+                        const std::string& path, const std::string& owner,
+                        AssociationOwnersType& assocOwners,
+                        AssociationInterfaces& assocInterfaces)
+{
+    AssociationPaths objects;
+
+    for (const Association& association : associations)
+    {
+        std::string forward;
+        std::string reverse;
+        std::string endpoint;
+        std::tie(forward, reverse, endpoint) = association;
+
+        if (forward.size())
+        {
+            objects[path + "/" + forward].emplace(endpoint);
+        }
+        if (reverse.size())
+        {
+            if (endpoint.empty())
+            {
+                std::cerr << "Found invalid association on path " << path
+                          << "\n";
+                continue;
+            }
+            objects[endpoint + "/" + reverse].emplace(path);
+        }
+    }
+    for (const auto& object : objects)
+    {
+        // the mapper exposes the new association interface but intakes
+        // the old
+
+        auto& iface = assocInterfaces[object.first];
+        auto& i = std::get<ifacePos>(iface);
+        auto& endpoints = std::get<endpointsPos>(iface);
+
+        // Only add new endpoints
+        for (auto& e : object.second)
+        {
+            if (std::find(endpoints.begin(), endpoints.end(), e) ==
+                endpoints.end())
+            {
+                endpoints.push_back(e);
+            }
+        }
+
+        // If the interface already exists, only need to update
+        // the property value, otherwise create it
+        if (i)
+        {
+            i->set_property("endpoints", endpoints);
+        }
+        else
+        {
+            i = objectServer.add_interface(object.first,
+                                           XYZ_ASSOCIATION_INTERFACE);
+            i->register_property("endpoints", endpoints);
+            i->initialize();
+        }
+    }
+
+    // Check for endpoints being removed instead of added
+    checkAssociationEndpointRemoves(path, owner, objects, objectServer,
+                                    assocOwners, assocInterfaces);
+
+    // Update associationOwners with the latest info
+    auto a = assocOwners.find(path);
+    if (a != assocOwners.end())
+    {
+        auto o = a->second.find(owner);
+        if (o != a->second.end())
+        {
+            o->second = std::move(objects);
+        }
+        else
+        {
+            a->second.emplace(owner, std::move(objects));
+        }
+    }
+    else
+    {
+        boost::container::flat_map<std::string, AssociationPaths> owners;
+        owners.emplace(owner, std::move(objects));
+        assocOwners.emplace(path, owners);
+    }
+}