system: get LLDP neighbors from JSON output of networkctl

Old way of getting the LLDP neighbours list was through patched systemd.
We patched the systemd in a way that the functions working with LLDP
files in /run/systemd/netif/lldp were made public and thus we could use
them to parse the data [1]. That required to use patched systemd (for
br2-external and for CI test runs). This was not easily maintainable
with new systemd versions.

New attempt is parsing the output of `networkctl lldp --json=pretty`
which is available with the new patch [2].
This also asks for a redesign of tests as we currently have no way of
'injecting' LLDP neighbours into systemd-networkd unless we implement
our own varlink server providing the LLDP data (see the patch).

As we are parsing only the output of `networkctl lldp`, and we do not
rely on any systemd function (even for tests), there is no need to
compile patched systemd. That will also speedup the CI runs, yay.

[1] https://github.com/systemd/systemd/pull/16744
[2] https://github.com/systemd/systemd/pull/20333

Change-Id: Ib880fef50e8d44ca257b582e7d15027ffc5194c9
diff --git a/tests/system_lldp.cpp b/tests/system_lldp.cpp
index 2e01137..fde4de3 100644
--- a/tests/system_lldp.cpp
+++ b/tests/system_lldp.cpp
@@ -1,11 +1,10 @@
 #include "trompeloeil_doctest.h"
-#include <sdbus-c++/sdbus-c++.h>
-#include <unistd.h>
-#include "dbus-helpers/dbus_network1_server.h"
 #include "pretty_printers.h"
 #include "system/LLDP.h"
+#include "system_vars.h"
 #include "test_log_setup.h"
 #include "tests/configure.cmake.h"
+#include "utils/exec.h"
 
 using namespace std::literals;
 
@@ -20,52 +19,44 @@
 {
     TEST_INIT_LOGS;
 
-    const auto serverBus = "local.pid" + std::to_string(getpid()) + ".org.freedesktop.network1";
-    auto dbusServerConnection = sdbus::createSessionBusConnection(serverBus);
-    dbusServerConnection->enterEventLoopAsync();
-
-    std::vector<std::pair<int, std::string>> links;
-    std::string dataDir;
     std::vector<velia::system::NeighborEntry> expected;
+    std::string json;
 
     SECTION("LLDP active on a single link")
     {
-        links = {{1, "lo"}, {2, "enp0s25"}, {3, "wlp3s0"}, {4, "tun0"}, {5, "br-53662f640039"}, {6, "docker0"}, {7, "br-e78120c0adda"}, {8, "ve-image"}};
-        dataDir = "single-link";
+        json = R"({"ve-image": [{"neighbor": {"systemName": "image", "portId": "host0", "chassisId": "7062a9e41c924ac6942da39c56e6b820", "enabledCapabilities": "a"}}]})";
         expected = {
             {"ve-image", {
                              {"remoteSysName", "image"},
                              {"remotePortId", "host0"},
                              {"remoteChassisId", "7062a9e41c924ac6942da39c56e6b820"},
-                             {"systemCapabilitiesSupported", "bridge router station-only"},
                              {"systemCapabilitiesEnabled", "station-only"},
                          }}};
     }
 
     SECTION("No LLDP enabled")
     {
-        links = {{1, "lo"}, {2, "enp0s25"}, {3, "wlp3s0"}, {4, "tun0"}, {5, "br-53662f640039"}, {6, "docker0"}, {7, "br-e78120c0adda"}, {8, "ve-image"}};
-        dataDir = "no-link";
+        json = "{}";
         expected = {};
     }
 
     SECTION("Two LLDP links")
     {
-        links = {{1, "lo"}, {2, "enp0s25"}, {3, "enp0s31f6"}, {4, "ve-image"}};
-        dataDir = "two-links";
+        json = R"({
+"enp0s31f6": [{"neighbor": {"systemName": "sw-a1128-01.fit.cvut.cz", "portId": "Gi3/0/7", "chassisId": "00:b8:b3:e6:17:80", "enabledCapabilities": "b"}}],
+"ve-image":  [{"neighbor": {"systemName": "image", "portId": "host0", "chassisId": "8b90f96f448140fb9b5d9d68e86d052e", "enabledCapabilities": "a"}}]
+})";
         expected = {
             {"enp0s31f6", {
                               {"remoteSysName", "sw-a1128-01.fit.cvut.cz"},
                               {"remotePortId", "Gi3/0/7"},
                               {"remoteChassisId", "00:b8:b3:e6:17:80"},
-                              {"systemCapabilitiesSupported", "bridge router"},
                               {"systemCapabilitiesEnabled", "bridge"},
                           }},
             {"ve-image", {
                              {"remoteSysName", "image"},
                              {"remotePortId", "host0"},
                              {"remoteChassisId", "8b90f96f448140fb9b5d9d68e86d052e"},
-                             {"systemCapabilitiesSupported", "bridge router station-only"},
                              {"systemCapabilitiesEnabled", "station-only"},
                          }},
         };
@@ -73,32 +64,28 @@
 
     SECTION("Multiple neighbors on one interface")
     {
-        links = {{1, "host0"}};
-        dataDir = "multiple-neighbors";
+        json = R"({"host0": [
+{"neighbor": {"systemName": "image", "portId": "host0", "chassisId": "1631331c24bb499bb644fcdf7c9fd467", "enabledCapabilities": "a"}},
+{"neighbor": {"systemName": "enterprise", "portId": "vb-image2", "chassisId": "1efe5cecbfc248a09065ad6177a98b41", "enabledCapabilities": "a"}}
+]})";
+
         expected = {
             {"host0", {
                           {"remoteSysName", "image"},
                           {"remotePortId", "host0"},
                           {"remoteChassisId", "1631331c24bb499bb644fcdf7c9fd467"},
-                          {"systemCapabilitiesSupported", "bridge router station-only"},
                           {"systemCapabilitiesEnabled", "station-only"},
                       }},
             {"host0", {
                           {"remoteSysName", "enterprise"},
                           {"remotePortId", "vb-image2"},
                           {"remoteChassisId", "1efe5cecbfc248a09065ad6177a98b41"},
-                          {"systemCapabilitiesSupported", "bridge router station-only"},
                           {"systemCapabilitiesEnabled", "station-only"},
                       }},
         };
     }
 
-    auto dbusServer = DbusServer(*dbusServerConnection);
-    dbusServer.setLinks(links); // intentionally not mocking DbusMockServer::ListLinks but using explicit set/get pattern so I can avoid an unneccesary dependency on trompeloeil
-
-    auto dbusClient = sdbus::createSessionBusConnection();
-    auto lldp = std::make_shared<velia::system::LLDPDataProvider>(std::filesystem::path(CMAKE_CURRENT_SOURCE_DIR "/tests/lldp/"s) / dataDir, *dbusClient, serverBus);
-
+    auto lldp = std::make_shared<velia::system::LLDPDataProvider>([&]() { return json; });
     REQUIRE(lldp->getNeighbors() == expected);
 }
 
@@ -108,7 +95,7 @@
     TEST_INIT_LOGS;
 
     auto dbusConnection = sdbus::createSystemBusConnection();
-    auto lldp = std::make_shared<lldp::lldp::LLDPDataProvider>("/run/systemd/netif/lldp", *dbusConnection, "org.freedesktop.network1");
+    auto lldp = std::make_shared<velia::system::LLDPDataProvider>([]() { return velia::utils::execAndWait(spdlog::get("system"), NETWORKCTL_EXECUTABLE, {"lldp", "--json=short"}, ""); });
     [[maybe_unused]] auto x = lldp->getNeighbors();
 }
 #endif