Enhance notify testcase
Validate signal content rather than doing explicit property
lookups. This avoids race conditions and additionally validates
that a signal is sent with the correct values.
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
Change-Id: Iaf13b1dfd68eeaf8ab7e8dc3bf045f824c3c803a
diff --git a/test/test.cpp b/test/test.cpp
index f089fcd..669879d 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -16,6 +16,8 @@
#include "../manager.hpp"
#include "../config.h"
#include <cassert>
+#include <iostream>
+#include <algorithm>
constexpr auto SERVICE = "phosphor.inventory.test";
constexpr auto INTERFACE = IFACE;
@@ -30,46 +32,142 @@
return static_cast<void *>(nullptr);
}
+/** @class SignalQueue
+ * @brief Store DBus signals in a queue.
+ */
+class SignalQueue
+{
+ public:
+ ~SignalQueue() = default;
+ SignalQueue() = delete;
+ SignalQueue(const SignalQueue &) = delete;
+ SignalQueue(SignalQueue &&) = default;
+ SignalQueue& operator=(const SignalQueue &) = delete;
+ SignalQueue& operator=(SignalQueue &&) = default;
+ explicit SignalQueue(const std::string &match) :
+ _bus(sdbusplus::bus::new_default()),
+ _match(_bus, match.c_str(), &callback, this),
+ _next(nullptr)
+ {
+ }
+
+ auto &&pop(unsigned timeout=1000000)
+ {
+ while(timeout > 0 && !_next)
+ {
+ _bus.process_discard();
+ _bus.wait(50000);
+ timeout -= 50000;
+ }
+ return std::move(_next);
+ }
+
+ private:
+ static int callback(sd_bus_message *m, void *context, sd_bus_error *)
+ {
+ auto *me = static_cast<SignalQueue *>(context);
+ sd_bus_message_ref(m);
+ sdbusplus::message::message msg{m};
+ me->_next = std::move(msg);
+ return 0;
+ }
+
+ sdbusplus::bus::bus _bus;
+ sdbusplus::server::match::match _match;
+ sdbusplus::message::message _next;
+};
+
+template <typename ...T>
+using Object = std::map<
+ std::string,
+ std::map<
+ std::string,
+ sdbusplus::message::variant<T...>>>;
+
+using ObjectPath = std::string;
+
+/**@brief Find a subset of interfaces and properties in an object. */
+template <typename ...T>
+auto hasProperties(const Object<T...> &l, const Object<T...> &r)
+{
+ Object<T...> result;
+ std::set_difference(
+ r.cbegin(),
+ r.cend(),
+ l.cbegin(),
+ l.cend(),
+ std::inserter(result, result.end()));
+ return result.empty();
+}
+
void runTests(phosphor::inventory::manager::Manager &mgr)
{
+ const std::string root{ROOT};
auto b = sdbusplus::bus::new_default();
-
- // make sure the notify method works
+ auto notify = [&]()
{
- auto m = b.new_method_call(SERVICE, ROOT, INTERFACE, "Notify");
- m.append("/foo");
+ return b.new_method_call(
+ SERVICE,
+ ROOT,
+ INTERFACE,
+ "Notify");
+ };
- using var = sdbusplus::message::variant<std::string>;
- using inner = std::map<std::string, var>;
- using outer = std::map<std::string, inner>;
+ Object<std::string> obj{
+ {
+ "xyz.openbmc_project.Example.Iface1",
+ {{"ExampleProperty1", "test1"}}
+ },
+ {
+ "xyz.openbmc_project.Example.Iface2",
+ {{"ExampleProperty2", "test2"}}
+ },
+ };
- inner i = {{"ExampleProperty1", "test"}};
- outer o = {{"xyz.openbmc_project.Example.Iface1", i}};
+ // Make sure the notify method works.
+ {
+ ObjectPath relPath{"/foo"};
+ ObjectPath path{root + relPath};
- m.append(o);
- auto reply = b.call(m);
- auto cleanup = sdbusplus::message::message(reply);
- assert(sd_bus_message_get_errno(reply) == 0);
+ SignalQueue queue(
+ "path='" + root + "',member='InterfacesAdded'");
+
+ auto m = notify();
+ m.append(relPath);
+ m.append(obj);
+ b.call(m);
+
+ auto sig{queue.pop()};
+ assert(sig);
+ ObjectPath signalPath;
+ Object<std::string> signalObject;
+ sig.read(signalPath);
+ assert(path == signalPath);
+ sig.read(signalObject);
+ assert(hasProperties(signalObject, obj));
+ auto moreSignals{queue.pop()};
+ assert(!moreSignals);
}
mgr.shutdown();
+ std::cout << "Success!" << std::endl;
}
int main()
{
auto mgr = phosphor::inventory::manager::Manager(
- sdbusplus::bus::new_system(),
+ sdbusplus::bus::new_default(),
SERVICE, ROOT, INTERFACE);
pthread_t t;
{
- pthread_create(&t, NULL, server_thread, &mgr);
+ pthread_create(&t, nullptr, server_thread, &mgr);
}
runTests(mgr);
// Wait for server thread to exit.
- pthread_join(t, NULL);
+ pthread_join(t, nullptr);
return 0;
}