xref: /openbmc/boost-dbus/test/avahi.cpp (revision 458a9c100019778114a58efc1ec29ce6e7375b2c)
1a83e5951SBenjamin Kietzman // Copyright (c) Benjamin Kietzman (github.com/bkietz)
2a83e5951SBenjamin Kietzman //
3a83e5951SBenjamin Kietzman // Distributed under the Boost Software License, Version 1.0. (See accompanying
4a83e5951SBenjamin Kietzman // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5a83e5951SBenjamin Kietzman 
6a83e5951SBenjamin Kietzman #include <dbus/connection.hpp>
716d80fe9SBenjamin Kietzman #include <dbus/endpoint.hpp>
8a83e5951SBenjamin Kietzman #include <dbus/filter.hpp>
9a83e5951SBenjamin Kietzman #include <dbus/match.hpp>
10da3eeb6aSEd Tanous #include <dbus/message.hpp>
11b6e8327aSEd Tanous #include <dbus/utility.hpp>
12da3eeb6aSEd Tanous #include <functional>
13b2c2467dSBenjamin Kietzman 
14a83e5951SBenjamin Kietzman #include <unistd.h>
15b6e8327aSEd Tanous #include <gmock/gmock.h>
16da3eeb6aSEd Tanous #include <gtest/gtest.h>
17b2c2467dSBenjamin Kietzman 
18da3eeb6aSEd Tanous TEST(AvahiTest, GetHostName) {
19da3eeb6aSEd Tanous   dbus::endpoint test_daemon("org.freedesktop.Avahi", "/",
2016d80fe9SBenjamin Kietzman                              "org.freedesktop.Avahi.Server");
21da3eeb6aSEd Tanous   boost::asio::io_service io;
22da3eeb6aSEd Tanous   dbus::connection system_bus(io, dbus::bus::system);
23a83e5951SBenjamin Kietzman 
24da3eeb6aSEd Tanous   dbus::message m = dbus::message::new_call(test_daemon, "GetHostName");
25a83e5951SBenjamin Kietzman 
26da3eeb6aSEd Tanous   system_bus.async_send(
27da3eeb6aSEd Tanous       m, [&](const boost::system::error_code ec, dbus::message r) {
28a83e5951SBenjamin Kietzman 
29da3eeb6aSEd Tanous         std::string avahi_hostname;
30da3eeb6aSEd Tanous         std::string hostname;
31da3eeb6aSEd Tanous 
32a83e5951SBenjamin Kietzman         // get hostname from a system call
33a83e5951SBenjamin Kietzman         char c[1024];
34a83e5951SBenjamin Kietzman         gethostname(c, 1024);
35da3eeb6aSEd Tanous         hostname = c;
36a83e5951SBenjamin Kietzman 
37b2c2467dSBenjamin Kietzman         r.unpack(avahi_hostname);
38b2c2467dSBenjamin Kietzman 
39da3eeb6aSEd Tanous         // Get only the host name, not the fqdn
40da3eeb6aSEd Tanous         auto unix_hostname = hostname.substr(0, hostname.find("."));
41b2c2467dSBenjamin Kietzman         EXPECT_EQ(unix_hostname, avahi_hostname);
42b2c2467dSBenjamin Kietzman 
43b2c2467dSBenjamin Kietzman         io.stop();
44da3eeb6aSEd Tanous       });
45da3eeb6aSEd Tanous   boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
46da3eeb6aSEd Tanous   t.async_wait([&](const boost::system::error_code& /*e*/) {
47b2c2467dSBenjamin Kietzman     io.stop();
48da3eeb6aSEd Tanous     FAIL() << "Callback was never called\n";
49da3eeb6aSEd Tanous   });
50a83e5951SBenjamin Kietzman   io.run();
51a83e5951SBenjamin Kietzman }
52a83e5951SBenjamin Kietzman 
53da3eeb6aSEd Tanous TEST(AvahiTest, ServiceBrowser) {
54da3eeb6aSEd Tanous   boost::asio::io_service io;
55da3eeb6aSEd Tanous   dbus::connection system_bus(io, dbus::bus::system);
56a83e5951SBenjamin Kietzman 
57da3eeb6aSEd Tanous   dbus::endpoint test_daemon("org.freedesktop.Avahi", "/",
58da3eeb6aSEd Tanous                              "org.freedesktop.Avahi.Server");
59a83e5951SBenjamin Kietzman   // create new service browser
60da3eeb6aSEd Tanous   dbus::message m1 = dbus::message::new_call(test_daemon, "ServiceBrowserNew");
61da3eeb6aSEd Tanous   m1.pack<int32_t>(-1)
62da3eeb6aSEd Tanous       .pack<int32_t>(-1)
63da3eeb6aSEd Tanous       .pack<std::string>("_http._tcp")
64da3eeb6aSEd Tanous       .pack<std::string>("local")
65da3eeb6aSEd Tanous       .pack<uint32_t>(0);
66a83e5951SBenjamin Kietzman 
67da3eeb6aSEd Tanous   dbus::message r = system_bus.send(m1);
68da3eeb6aSEd Tanous   std::string browser_path;
69a83e5951SBenjamin Kietzman   r.unpack(browser_path);
70da3eeb6aSEd Tanous   testing::Test::RecordProperty("browserPath", browser_path);
71a83e5951SBenjamin Kietzman 
72da3eeb6aSEd Tanous   dbus::match ma(system_bus, "type='signal',path='" + browser_path + "'");
73da3eeb6aSEd Tanous   dbus::filter f(system_bus, [](dbus::message& m) {
74da3eeb6aSEd Tanous     auto member = m.get_member();
75da3eeb6aSEd Tanous     return member == "NameAcquired";
76da3eeb6aSEd Tanous   });
77a83e5951SBenjamin Kietzman 
78da3eeb6aSEd Tanous   std::function<void(boost::system::error_code, dbus::message)> event_handler =
79da3eeb6aSEd Tanous       [&](boost::system::error_code ec, dbus::message s) {
80da3eeb6aSEd Tanous         testing::Test::RecordProperty("firstSignal", s.get_member());
81da3eeb6aSEd Tanous         std::string a = s.get_member();
82da3eeb6aSEd Tanous         std::string dude;
83da3eeb6aSEd Tanous         s.unpack(dude);
84da3eeb6aSEd Tanous         f.async_dispatch(event_handler);
85da3eeb6aSEd Tanous         io.stop();
86da3eeb6aSEd Tanous       };
87da3eeb6aSEd Tanous   f.async_dispatch(event_handler);
88b2c2467dSBenjamin Kietzman 
89da3eeb6aSEd Tanous   boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
90da3eeb6aSEd Tanous   t.async_wait([&](const boost::system::error_code& /*e*/) {
91da3eeb6aSEd Tanous     io.stop();
92da3eeb6aSEd Tanous     FAIL() << "Callback was never called\n";
93da3eeb6aSEd Tanous   });
94a83e5951SBenjamin Kietzman   io.run();
95a83e5951SBenjamin Kietzman }
96b6e8327aSEd Tanous 
97b6e8327aSEd Tanous TEST(BOOST_DBUS, ListServices) {
98b6e8327aSEd Tanous   boost::asio::io_service io;
99b6e8327aSEd Tanous   boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
100b6e8327aSEd Tanous   t.async_wait([&](const boost::system::error_code& /*e*/) {
101b6e8327aSEd Tanous     io.stop();
102b6e8327aSEd Tanous     FAIL() << "Callback was never called\n";
103b6e8327aSEd Tanous   });
104b6e8327aSEd Tanous 
105b6e8327aSEd Tanous   dbus::connection system_bus(io, dbus::bus::system);
106b6e8327aSEd Tanous 
107b6e8327aSEd Tanous   dbus::endpoint test_daemon("org.freedesktop.DBus", "/",
108b6e8327aSEd Tanous                              "org.freedesktop.DBus");
109b6e8327aSEd Tanous   // create new service browser
110b6e8327aSEd Tanous   dbus::message m = dbus::message::new_call(test_daemon, "ListNames");
111b6e8327aSEd Tanous   system_bus.async_send(
112b6e8327aSEd Tanous       m, [&](const boost::system::error_code ec, dbus::message r) {
113b6e8327aSEd Tanous         io.stop();
114b6e8327aSEd Tanous         std::vector<std::string> services;
115b6e8327aSEd Tanous         r.unpack(services);
116b6e8327aSEd Tanous         // Test a couple things that should always be present.... adapt if
117b6e8327aSEd Tanous         // neccesary
118b6e8327aSEd Tanous         EXPECT_THAT(services, testing::Contains("org.freedesktop.DBus"));
119b6e8327aSEd Tanous         EXPECT_THAT(services, testing::Contains("org.freedesktop.Accounts"));
120b6e8327aSEd Tanous 
121b6e8327aSEd Tanous       });
122b6e8327aSEd Tanous 
123b6e8327aSEd Tanous   io.run();
124b6e8327aSEd Tanous }
125b6e8327aSEd Tanous 
12682a51ce2SEd Tanous void query_interfaces(dbus::connection& system_bus, std::string& service_name,
12782a51ce2SEd Tanous                       std::string& object_name) {
12882a51ce2SEd Tanous   dbus::endpoint service_daemon(service_name, object_name,
12982a51ce2SEd Tanous                                 "org.freedestop.DBus.Introspectable");
13082a51ce2SEd Tanous   dbus::message m = dbus::message::new_call(service_daemon, "Introspect");
13182a51ce2SEd Tanous   try {
13282a51ce2SEd Tanous     auto r = system_bus.send(m);
13382a51ce2SEd Tanous     std::vector<std::string> names;
13482a51ce2SEd Tanous     // Todo(ed) figure out why we're occassionally getting access
13582a51ce2SEd Tanous     // denied errors
13682a51ce2SEd Tanous     // EXPECT_EQ(ec, boost::system::errc::success);
13782a51ce2SEd Tanous 
13882a51ce2SEd Tanous     std::string xml;
13982a51ce2SEd Tanous     r.unpack(xml);
14082a51ce2SEd Tanous     // TODO(ed) names needs lock for multithreaded access
14182a51ce2SEd Tanous     dbus::read_dbus_xml_names(xml, names);
14282a51ce2SEd Tanous     // loop over the newly added items
14382a51ce2SEd Tanous     for (auto name : names) {
14482a51ce2SEd Tanous       std::cout << name << "\n";
14582a51ce2SEd Tanous       auto new_service_string = object_name + "/" + name;
14682a51ce2SEd Tanous       query_interfaces(system_bus, service_name, new_service_string);
14782a51ce2SEd Tanous     }
14882a51ce2SEd Tanous   } catch (boost::system::error_code e) {
14982a51ce2SEd Tanous     std::cout << e;
15082a51ce2SEd Tanous   }
15182a51ce2SEd Tanous }
15282a51ce2SEd Tanous 
1535d4bd2bdSEd Tanous TEST(BOOST_DBUS, SingleSensorChanged) {
154b6e8327aSEd Tanous   boost::asio::io_service io;
155b6e8327aSEd Tanous   dbus::connection system_bus(io, dbus::bus::system);
156b6e8327aSEd Tanous 
15782a51ce2SEd Tanous   dbus::match ma(system_bus,
15882a51ce2SEd Tanous                  "type='signal',path_namespace='/xyz/openbmc_project/sensors'");
15982a51ce2SEd Tanous   dbus::filter f(system_bus, [](dbus::message& m) {
16082a51ce2SEd Tanous     auto member = m.get_member();
16182a51ce2SEd Tanous     return member == "PropertiesChanged";
16282a51ce2SEd Tanous   });
163b6e8327aSEd Tanous 
1645d4bd2bdSEd Tanous   // std::function<void(boost::system::error_code, dbus::message)> event_handler
1655d4bd2bdSEd Tanous   // =
1665d4bd2bdSEd Tanous 
1675d4bd2bdSEd Tanous   f.async_dispatch([&](boost::system::error_code ec, dbus::message s) {
16882a51ce2SEd Tanous     std::string object_name;
1695d4bd2bdSEd Tanous     EXPECT_EQ(s.get_path(),
1705d4bd2bdSEd Tanous               "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp");
1715d4bd2bdSEd Tanous 
17282a51ce2SEd Tanous     std::vector<std::pair<std::string, dbus::dbus_variant>> values;
17382a51ce2SEd Tanous     s.unpack(object_name).unpack(values);
174b6e8327aSEd Tanous 
17582a51ce2SEd Tanous     EXPECT_EQ(object_name, "xyz.openbmc_project.Sensor.Value");
17682a51ce2SEd Tanous 
1775d4bd2bdSEd Tanous     EXPECT_EQ(values.size(), 1);
17882a51ce2SEd Tanous     auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42);
1795d4bd2bdSEd Tanous     EXPECT_EQ(values[0], expected);
18082a51ce2SEd Tanous 
181b6e8327aSEd Tanous     io.stop();
1825d4bd2bdSEd Tanous   });
183b6e8327aSEd Tanous 
18482a51ce2SEd Tanous   dbus::endpoint test_endpoint(
18582a51ce2SEd Tanous       "org.freedesktop.Avahi",
18682a51ce2SEd Tanous       "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
18782a51ce2SEd Tanous       "org.freedesktop.DBus.Properties");
188b6e8327aSEd Tanous 
18982a51ce2SEd Tanous   auto signal_name = std::string("PropertiesChanged");
19082a51ce2SEd Tanous   auto m = dbus::message::new_signal(test_endpoint, signal_name);
19182a51ce2SEd Tanous 
19282a51ce2SEd Tanous   m.pack("xyz.openbmc_project.Sensor.Value");
19382a51ce2SEd Tanous 
19482a51ce2SEd Tanous   std::vector<std::pair<std::string, dbus::dbus_variant>> map2;
19582a51ce2SEd Tanous 
19682a51ce2SEd Tanous   map2.emplace_back("Value", 42);
19782a51ce2SEd Tanous 
19882a51ce2SEd Tanous   m.pack(map2);
19982a51ce2SEd Tanous 
20082a51ce2SEd Tanous   auto removed = std::vector<uint32_t>();
20182a51ce2SEd Tanous   m.pack(removed);
20282a51ce2SEd Tanous   system_bus.async_send(m,
20382a51ce2SEd Tanous                         [&](boost::system::error_code ec, dbus::message s) {});
204b6e8327aSEd Tanous 
205b6e8327aSEd Tanous   io.run();
206b6e8327aSEd Tanous }
2075d4bd2bdSEd Tanous 
2085d4bd2bdSEd Tanous TEST(BOOST_DBUS, MultipleSensorChanged) {
2095d4bd2bdSEd Tanous   boost::asio::io_service io;
2105d4bd2bdSEd Tanous   dbus::connection system_bus(io, dbus::bus::system);
2115d4bd2bdSEd Tanous 
2125d4bd2bdSEd Tanous   dbus::match ma(system_bus,
2135d4bd2bdSEd Tanous                  "type='signal',path_namespace='/xyz/openbmc_project/sensors'");
2145d4bd2bdSEd Tanous   dbus::filter f(system_bus, [](dbus::message& m) {
2155d4bd2bdSEd Tanous     auto member = m.get_member();
2165d4bd2bdSEd Tanous     return member == "PropertiesChanged";
2175d4bd2bdSEd Tanous   });
2185d4bd2bdSEd Tanous 
2195d4bd2bdSEd Tanous   int count = 0;
2205d4bd2bdSEd Tanous   f.async_dispatch([&](boost::system::error_code ec, dbus::message s) {
2215d4bd2bdSEd Tanous     std::string object_name;
2225d4bd2bdSEd Tanous     EXPECT_EQ(s.get_path(),
2235d4bd2bdSEd Tanous               "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp");
2245d4bd2bdSEd Tanous 
2255d4bd2bdSEd Tanous     std::vector<std::pair<std::string, dbus::dbus_variant>> values;
2265d4bd2bdSEd Tanous     s.unpack(object_name).unpack(values);
2275d4bd2bdSEd Tanous 
2285d4bd2bdSEd Tanous     EXPECT_EQ(object_name, "xyz.openbmc_project.Sensor.Value");
2295d4bd2bdSEd Tanous 
2305d4bd2bdSEd Tanous     EXPECT_EQ(values.size(), 1);
2315d4bd2bdSEd Tanous     auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42);
2325d4bd2bdSEd Tanous     EXPECT_EQ(values[0], expected);
2335d4bd2bdSEd Tanous     count++;
2345d4bd2bdSEd Tanous     if (count == 2) {
2355d4bd2bdSEd Tanous       io.stop();
2365d4bd2bdSEd Tanous     }
2375d4bd2bdSEd Tanous 
2385d4bd2bdSEd Tanous   });
2395d4bd2bdSEd Tanous 
2405d4bd2bdSEd Tanous   dbus::endpoint test_endpoint(
2415d4bd2bdSEd Tanous       "org.freedesktop.Avahi",
2425d4bd2bdSEd Tanous       "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
2435d4bd2bdSEd Tanous       "org.freedesktop.DBus.Properties");
2445d4bd2bdSEd Tanous 
2455d4bd2bdSEd Tanous   auto signal_name = std::string("PropertiesChanged");
2465d4bd2bdSEd Tanous   auto m = dbus::message::new_signal(test_endpoint, signal_name);
2475d4bd2bdSEd Tanous 
2485d4bd2bdSEd Tanous   m.pack("xyz.openbmc_project.Sensor.Value");
2495d4bd2bdSEd Tanous 
2505d4bd2bdSEd Tanous   std::vector<std::pair<std::string, dbus::dbus_variant>> map2;
2515d4bd2bdSEd Tanous 
2525d4bd2bdSEd Tanous   map2.emplace_back("Value", 42);
2535d4bd2bdSEd Tanous 
2545d4bd2bdSEd Tanous   m.pack(map2);
2555d4bd2bdSEd Tanous 
2565d4bd2bdSEd Tanous   auto removed = std::vector<uint32_t>();
2575d4bd2bdSEd Tanous   m.pack(removed);
2585d4bd2bdSEd Tanous   system_bus.async_send(m,
2595d4bd2bdSEd Tanous                         [&](boost::system::error_code ec, dbus::message s) {});
2605d4bd2bdSEd Tanous   system_bus.async_send(m,
2615d4bd2bdSEd Tanous                         [&](boost::system::error_code ec, dbus::message s) {});
2625d4bd2bdSEd Tanous   io.run();
2635d4bd2bdSEd Tanous }
264*458a9c10SVernon Mauery 
265*458a9c10SVernon Mauery TEST(BOOST_DBUS, MethodCall) {
266*458a9c10SVernon Mauery   boost::asio::io_service io;
267*458a9c10SVernon Mauery   boost::asio::deadline_timer t(io, boost::posix_time::seconds(30));
268*458a9c10SVernon Mauery   t.async_wait([&](const boost::system::error_code& /*e*/) {
269*458a9c10SVernon Mauery     io.stop();
270*458a9c10SVernon Mauery     FAIL() << "Callback was never called\n";
271*458a9c10SVernon Mauery   });
272*458a9c10SVernon Mauery   std::string requested_name = "xyz.openbmc_project.fwupdate1.server";
273*458a9c10SVernon Mauery   dbus::connection system_bus(io, dbus::bus::system);
274*458a9c10SVernon Mauery   system_bus.request_name(requested_name);
275*458a9c10SVernon Mauery 
276*458a9c10SVernon Mauery   /* not sure we even need to add a match for method calls,
277*458a9c10SVernon Mauery    * but this is how you might do it .... */
278*458a9c10SVernon Mauery   dbus::match ma(system_bus,
279*458a9c10SVernon Mauery                  "type='method_call',path_namespace='/xyz/openbmc_project/fwupdate1'");
280*458a9c10SVernon Mauery 
281*458a9c10SVernon Mauery   dbus::filter f(system_bus, [](dbus::message& m) {
282*458a9c10SVernon Mauery     // std::cerr << "filter called: " << m << std::endl;
283*458a9c10SVernon Mauery     return (m.get_member() == "Get" &&
284*458a9c10SVernon Mauery             m.get_interface() == "org.freedesktop.DBus.Properties" &&
285*458a9c10SVernon Mauery             m.get_signature() == "ss");
286*458a9c10SVernon Mauery   });
287*458a9c10SVernon Mauery 
288*458a9c10SVernon Mauery   std::function<void(boost::system::error_code, dbus::message)> method_handler =
289*458a9c10SVernon Mauery       [&](boost::system::error_code ec, dbus::message s) {
290*458a9c10SVernon Mauery         std::string intf_name, prop_name;
291*458a9c10SVernon Mauery         s.unpack(intf_name).unpack(prop_name);
292*458a9c10SVernon Mauery 
293*458a9c10SVernon Mauery         EXPECT_EQ(intf_name, "xyz.openbmc_project.fwupdate1");
294*458a9c10SVernon Mauery         EXPECT_EQ(prop_name, "State");
295*458a9c10SVernon Mauery 
296*458a9c10SVernon Mauery         // send a reply so dbus doesn't get angry?
297*458a9c10SVernon Mauery         auto r = system_bus.reply(s);
298*458a9c10SVernon Mauery         r.pack("IDLE");
299*458a9c10SVernon Mauery         system_bus.async_send(r,
300*458a9c10SVernon Mauery                 [&](boost::system::error_code ec, dbus::message s) {} );
301*458a9c10SVernon Mauery         io.stop();
302*458a9c10SVernon Mauery       };
303*458a9c10SVernon Mauery   f.async_dispatch(method_handler);
304*458a9c10SVernon Mauery 
305*458a9c10SVernon Mauery   dbus::endpoint test_endpoint(
306*458a9c10SVernon Mauery       requested_name,
307*458a9c10SVernon Mauery       "/xyz/openbmc_project/fwupdate1",
308*458a9c10SVernon Mauery       "org.freedesktop.DBus.Properties");
309*458a9c10SVernon Mauery 
310*458a9c10SVernon Mauery   auto method_name = std::string("Get");
311*458a9c10SVernon Mauery   auto m = dbus::message::new_call(test_endpoint, method_name);
312*458a9c10SVernon Mauery 
313*458a9c10SVernon Mauery   m.pack("xyz.openbmc_project.fwupdate1");
314*458a9c10SVernon Mauery   m.pack("State");
315*458a9c10SVernon Mauery 
316*458a9c10SVernon Mauery   system_bus.async_send(m,
317*458a9c10SVernon Mauery                         [&](boost::system::error_code ec, dbus::message s) {
318*458a9c10SVernon Mauery                         std::cerr <<"received s: " << s << std::endl;
319*458a9c10SVernon Mauery                         });
320*458a9c10SVernon Mauery 
321*458a9c10SVernon Mauery   io.run();
322*458a9c10SVernon Mauery }
323