xref: /openbmc/boost-dbus/test/avahi.cpp (revision e62be329)
1 // Copyright (c) Benjamin Kietzman (github.com/bkietz)
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #include <dbus/connection.hpp>
7 #include <dbus/endpoint.hpp>
8 #include <dbus/filter.hpp>
9 #include <dbus/match.hpp>
10 #include <dbus/message.hpp>
11 #include <functional>
12 
13 #include <unistd.h>
14 #include <gmock/gmock.h>
15 #include <gtest/gtest.h>
16 
17 TEST(AvahiTest, GetHostName) {
18   dbus::endpoint test_daemon("org.freedesktop.Avahi", "/",
19                              "org.freedesktop.Avahi.Server");
20   boost::asio::io_service io;
21   auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
22 
23   dbus::message m = dbus::message::new_call(test_daemon, "GetHostName");
24 
25   system_bus->async_send(
26       m, [&](const boost::system::error_code ec, dbus::message r) {
27 
28         std::string avahi_hostname;
29         std::string hostname;
30 
31         // get hostname from a system call
32         char c[1024];
33         gethostname(c, 1024);
34         hostname = c;
35 
36         r.unpack(avahi_hostname);
37 
38         // Get only the host name, not the fqdn
39         auto unix_hostname = hostname.substr(0, hostname.find("."));
40         EXPECT_EQ(unix_hostname, avahi_hostname);
41 
42         io.stop();
43       });
44   boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
45   t.async_wait([&](const boost::system::error_code& /*e*/) {
46     io.stop();
47     FAIL() << "Callback was never called\n";
48   });
49   io.run();
50 }
51 
52 TEST(AvahiTest, ServiceBrowser) {
53   boost::asio::io_service io;
54   auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
55 
56   dbus::endpoint test_daemon("org.freedesktop.Avahi", "/",
57                              "org.freedesktop.Avahi.Server");
58   // create new service browser
59   dbus::message m1 = dbus::message::new_call(test_daemon, "ServiceBrowserNew");
60   m1.pack((int32_t)-1, (int32_t)-1, "_http._tcp", "local", (uint32_t)(0));
61 
62   dbus::message r = system_bus->send(m1);
63   dbus::object_path browser_path;
64   EXPECT_TRUE(r.unpack(browser_path));
65   testing::Test::RecordProperty("browserPath", browser_path.value);
66 
67   dbus::match ma(system_bus, "type='signal',path='" + browser_path.value + "'");
68   dbus::filter f(system_bus, [](dbus::message& m) {
69     auto member = m.get_member();
70     return member == "NameAcquired";
71   });
72 
73   std::function<void(boost::system::error_code, dbus::message)> event_handler =
74       [&](boost::system::error_code ec, dbus::message s) {
75         testing::Test::RecordProperty("firstSignal", s.get_member());
76         std::string a = s.get_member();
77         std::string dude;
78         s.unpack(dude);
79         f.async_dispatch(event_handler);
80         io.stop();
81       };
82   f.async_dispatch(event_handler);
83 
84   boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
85   t.async_wait([&](const boost::system::error_code& /*e*/) {
86     io.stop();
87     FAIL() << "Callback was never called\n";
88   });
89   io.run();
90 }
91 
92 TEST(BOOST_DBUS, ListServices) {
93   boost::asio::io_service io;
94   boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
95   t.async_wait([&](const boost::system::error_code& /*e*/) {
96     io.stop();
97     FAIL() << "Callback was never called\n";
98   });
99 
100   auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
101 
102   dbus::endpoint test_daemon("org.freedesktop.DBus", "/",
103                              "org.freedesktop.DBus");
104   // create new service browser
105   dbus::message m = dbus::message::new_call(test_daemon, "ListNames");
106   system_bus->async_send(
107       m, [&](const boost::system::error_code ec, dbus::message r) {
108         io.stop();
109         std::vector<std::string> services;
110         r.unpack(services);
111         // Test a couple things that should always be present.... adapt if
112         // neccesary
113         EXPECT_THAT(services, testing::Contains("org.freedesktop.DBus"));
114         EXPECT_THAT(services, testing::Contains("org.freedesktop.Accounts"));
115 
116       });
117 
118   io.run();
119 }
120 
121 TEST(BOOST_DBUS, SingleSensorChanged) {
122   boost::asio::io_service io;
123 
124   auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
125 
126   dbus::match ma(system_bus,
127                  "type='signal',path_namespace='/xyz/openbmc_project/sensors'");
128 
129   dbus::filter f(system_bus, [](dbus::message& m) {
130     auto member = m.get_member();
131     return member == "PropertiesChanged";
132   });
133 
134   f.async_dispatch([&](boost::system::error_code ec, dbus::message s) {
135     std::string object_name;
136     EXPECT_EQ(s.get_path(),
137               "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp");
138 
139     std::vector<std::pair<std::string, dbus::dbus_variant>> values;
140     s.unpack(object_name, values);
141     EXPECT_EQ(object_name, "xyz.openbmc_project.Sensor.Value");
142 
143     EXPECT_EQ(values.size(), 1);
144     auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42);
145     EXPECT_EQ(values[0], expected);
146 
147     io.stop();
148   });
149 
150   dbus::endpoint test_endpoint(
151       "org.freedesktop.Avahi",
152       "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
153       "org.freedesktop.DBus.Properties");
154 
155   auto signal_name = std::string("PropertiesChanged");
156   auto m = dbus::message::new_signal(test_endpoint, signal_name);
157 
158   m.pack("xyz.openbmc_project.Sensor.Value");
159 
160   std::vector<std::pair<std::string, dbus::dbus_variant>> map2;
161 
162   map2.emplace_back("Value", 42);
163 
164   m.pack(map2);
165 
166   auto removed = std::vector<uint32_t>();
167   m.pack(removed);
168   system_bus->async_send(m,
169                          [&](boost::system::error_code ec, dbus::message s) {});
170 
171   io.run();
172 }
173 
174 TEST(BOOST_DBUS, MultipleSensorChanged) {
175   boost::asio::io_service io;
176   auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
177 
178   dbus::match ma(system_bus,
179                  "type='signal',path_namespace='/xyz/openbmc_project/sensors'");
180   dbus::filter f(system_bus, [](dbus::message& m) {
181     auto member = m.get_member();
182     return member == "PropertiesChanged";
183   });
184 
185   int count = 0;
186   std::function<void(boost::system::error_code, dbus::message)> callback = [&](
187       boost::system::error_code ec, dbus::message s) {
188     std::string object_name;
189     EXPECT_EQ(s.get_path(),
190               "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp");
191 
192     std::vector<std::pair<std::string, dbus::dbus_variant>> values;
193     s.unpack(object_name, values);
194     EXPECT_EQ(object_name, "xyz.openbmc_project.Sensor.Value");
195 
196     EXPECT_EQ(values.size(), 1);
197     auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42);
198     EXPECT_EQ(values[0], expected);
199     count++;
200     if (count == 2) {
201       io.stop();
202     } else {
203       f.async_dispatch(callback);
204     }
205     s.unpack(object_name, values);
206 
207   };
208   f.async_dispatch(callback);
209 
210   dbus::endpoint test_endpoint(
211       "org.freedesktop.Avahi",
212       "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
213       "org.freedesktop.DBus.Properties");
214 
215   auto signal_name = std::string("PropertiesChanged");
216 
217   std::vector<std::pair<std::string, dbus::dbus_variant>> map2;
218 
219   map2.emplace_back("Value", 42);
220 
221   static auto removed = std::vector<uint32_t>();
222 
223   auto m = dbus::message::new_signal(test_endpoint, signal_name);
224   m.pack("xyz.openbmc_project.Sensor.Value", map2, removed);
225 
226   system_bus->send(m, std::chrono::seconds(0));
227   system_bus->send(m, std::chrono::seconds(0));
228 
229   io.run();
230 }
231 
232 TEST(BOOST_DBUS, MethodCallEx) {
233   boost::asio::io_service io;
234   // Expiration timer to stop tests if they fail
235   boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
236   t.async_wait([&](const boost::system::error_code&) {
237     io.stop();
238     FAIL() << "Callback was never called\n";
239   });
240 
241   auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::session);
242   std::string requested_name = system_bus->get_unique_name();
243 
244   dbus::filter f(system_bus, [requested_name](dbus::message& m) {
245     return m.get_sender() == requested_name;
246   });
247 
248   std::function<void(boost::system::error_code, dbus::message)> method_handler =
249       [&](boost::system::error_code ec, dbus::message s) {
250         if (ec) {
251           FAIL() << ec;
252         } else {
253           std::string intf_name, prop_name;
254           EXPECT_EQ(s.get_signature(), "ss");
255           EXPECT_EQ(s.get_member(), "Get");
256           EXPECT_EQ(s.get_interface(), "org.freedesktop.DBus.Properties");
257           s.unpack(intf_name, prop_name);
258 
259           EXPECT_EQ(intf_name, "xyz.openbmc_project.fwupdate1");
260           EXPECT_EQ(prop_name, "State");
261 
262           // send a reply
263           auto r = system_bus->reply(s);
264           r.pack("IDLE");
265           system_bus->async_send(
266               r, [&](boost::system::error_code ec, dbus::message s) {});
267           io.stop();
268         }
269       };
270   f.async_dispatch(method_handler);
271 
272   dbus::endpoint test_endpoint(requested_name, "/xyz/openbmc_project/fwupdate1",
273                                "org.freedesktop.DBus.Properties", "Get");
274   system_bus->async_method_call(
275       [&](const boost::system::error_code ec,
276           const dbus::dbus_variant& status) {
277         if (ec) {
278           FAIL();
279         } else {
280           EXPECT_EQ(boost::get<std::string>(status), "IDLE");
281         }
282       },
283       test_endpoint, "xyz.openbmc_project.fwupdate1", "State");
284 
285   io.run();
286 }
287 
288 TEST(BOOST_DBUS, MethodCall) {
289   boost::asio::io_service io;
290 
291   boost::asio::deadline_timer t(io, boost::posix_time::seconds(2));
292   t.async_wait([&](const boost::system::error_code&) {
293     io.stop();
294     FAIL() << "Callback was never called\n";
295   });
296 
297   auto bus = std::make_shared<dbus::connection>(io, dbus::bus::session);
298   std::string requested_name = bus->get_unique_name();
299 
300   dbus::filter f(bus, [](dbus::message& m) {
301     return (m.get_member() == "Get" &&
302             m.get_interface() == "org.freedesktop.DBus.Properties" &&
303             m.get_signature() == "ss");
304   });
305 
306   std::function<void(boost::system::error_code, dbus::message)> method_handler =
307       [&](boost::system::error_code ec, dbus::message s) {
308         if (ec) {
309           FAIL() << ec;
310         } else {
311           std::string intf_name, prop_name;
312           s.unpack(intf_name, prop_name);
313 
314           EXPECT_EQ(intf_name, "xyz.openbmc_project.fwupdate1");
315           EXPECT_EQ(prop_name, "State");
316 
317           // send a reply so dbus doesn't get angry?
318           auto r = bus->reply(s);
319           r.pack("IDLE");
320           bus->async_send(
321               r, [&](boost::system::error_code ec, dbus::message s) {});
322           io.stop();
323         }
324       };
325   f.async_dispatch(method_handler);
326 
327   dbus::endpoint test_endpoint(requested_name, "/xyz/openbmc_project/fwupdate1",
328                                "org.freedesktop.DBus.Properties");
329 
330   auto method_name = std::string("Get");
331   auto m = dbus::message::new_call(test_endpoint, method_name);
332 
333   m.pack("xyz.openbmc_project.fwupdate1", "State");
334   bus->async_send(m, [&](boost::system::error_code ec, dbus::message s) {
335     std::cerr << "received s: " << s << std::endl;
336   });
337 
338   // system_bus->send(m, std::chrono::seconds(0));
339 
340   io.run();
341 }
342