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
TEST(AvahiTest,GetHostName)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
TEST(AvahiTest,ServiceBrowser)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
TEST(BOOST_DBUS,ListServices)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
TEST(BOOST_DBUS,SingleSensorChanged)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(), std::size_t{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 std::vector<std::pair<std::string, dbus::dbus_variant>> map2;
159
160 map2.emplace_back("Value", 42);
161
162 auto removed = std::vector<std::string>();
163 EXPECT_EQ(m.pack("xyz.openbmc_project.Sensor.Value", map2, removed), true);
164
165 system_bus->async_send(m,
166 [&](boost::system::error_code ec, dbus::message s) {});
167
168 io.run();
169 }
170
TEST(BOOST_DBUS,MultipleSensorChanged)171 TEST(BOOST_DBUS, MultipleSensorChanged) {
172 boost::asio::io_service io;
173 auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
174
175 dbus::match ma(system_bus,
176 "type='signal',path_namespace='/xyz/openbmc_project/sensors'");
177 dbus::filter f(system_bus, [](dbus::message& m) {
178 auto member = m.get_member();
179 return member == "PropertiesChanged";
180 });
181
182 int count = 0;
183 std::function<void(boost::system::error_code, dbus::message)> callback = [&](
184 boost::system::error_code ec, dbus::message s) {
185 std::string object_name;
186 EXPECT_EQ(s.get_path(),
187 "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp");
188
189 std::vector<std::pair<std::string, dbus::dbus_variant>> values;
190 s.unpack(object_name, values);
191 EXPECT_EQ(object_name, "xyz.openbmc_project.Sensor.Value");
192
193 EXPECT_EQ(values.size(), std::size_t{1});
194 auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42);
195 EXPECT_EQ(values[0], expected);
196 count++;
197 if (count == 2) {
198 io.stop();
199 } else {
200 f.async_dispatch(callback);
201 }
202 s.unpack(object_name, values);
203
204 };
205 f.async_dispatch(callback);
206
207 dbus::endpoint test_endpoint(
208 "org.freedesktop.Avahi",
209 "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
210 "org.freedesktop.DBus.Properties");
211
212 auto signal_name = std::string("PropertiesChanged");
213
214 std::vector<std::pair<std::string, dbus::dbus_variant>> map2;
215
216 map2.emplace_back("Value", 42);
217
218 static auto removed = std::vector<uint32_t>();
219
220 auto m = dbus::message::new_signal(test_endpoint, signal_name);
221 m.pack("xyz.openbmc_project.Sensor.Value", map2, removed);
222
223 system_bus->send(m, std::chrono::seconds(0));
224 system_bus->send(m, std::chrono::seconds(0));
225
226 io.run();
227 }
228
TEST(BOOST_DBUS,MethodCallEx)229 TEST(BOOST_DBUS, MethodCallEx) {
230 boost::asio::io_service io;
231 // Expiration timer to stop tests if they fail
232 boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
233 t.async_wait([&](const boost::system::error_code&) {
234 io.stop();
235 FAIL() << "Callback was never called\n";
236 });
237
238 auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::session);
239 std::string requested_name = system_bus->get_unique_name();
240
241 dbus::filter f(system_bus, [requested_name](dbus::message& m) {
242 return m.get_sender() == requested_name;
243 });
244
245 std::function<void(boost::system::error_code, dbus::message)> method_handler =
246 [&](boost::system::error_code ec, dbus::message s) {
247 if (ec) {
248 FAIL() << ec;
249 } else {
250 std::string intf_name, prop_name;
251 EXPECT_EQ(s.get_signature(), "ss");
252 EXPECT_EQ(s.get_member(), "Get");
253 EXPECT_EQ(s.get_interface(), "org.freedesktop.DBus.Properties");
254 s.unpack(intf_name, prop_name);
255
256 EXPECT_EQ(intf_name, "xyz.openbmc_project.fwupdate1");
257 EXPECT_EQ(prop_name, "State");
258
259 // send a reply
260 auto r = system_bus->reply(s);
261 r.pack("IDLE");
262 system_bus->async_send(
263 r, [&](boost::system::error_code ec, dbus::message s) {});
264 io.stop();
265 }
266 };
267 f.async_dispatch(method_handler);
268
269 dbus::endpoint test_endpoint(requested_name, "/xyz/openbmc_project/fwupdate1",
270 "org.freedesktop.DBus.Properties", "Get");
271 system_bus->async_method_call(
272 [&](const boost::system::error_code ec,
273 const dbus::dbus_variant& status) {
274 if (ec) {
275 FAIL();
276 } else {
277 EXPECT_EQ(boost::get<std::string>(status), "IDLE");
278 }
279 },
280 test_endpoint, "xyz.openbmc_project.fwupdate1", "State");
281
282 io.run();
283 }
284
TEST(BOOST_DBUS,MethodCall)285 TEST(BOOST_DBUS, MethodCall) {
286 boost::asio::io_service io;
287
288 boost::asio::deadline_timer t(io, boost::posix_time::seconds(2));
289 t.async_wait([&](const boost::system::error_code&) {
290 io.stop();
291 FAIL() << "Callback was never called\n";
292 });
293
294 auto bus = std::make_shared<dbus::connection>(io, dbus::bus::session);
295 std::string requested_name = bus->get_unique_name();
296
297 dbus::filter f(bus, [](dbus::message& m) {
298 return (m.get_member() == "Get" &&
299 m.get_interface() == "org.freedesktop.DBus.Properties" &&
300 m.get_signature() == "ss");
301 });
302
303 std::function<void(boost::system::error_code, dbus::message)> method_handler =
304 [&](boost::system::error_code ec, dbus::message s) {
305 if (ec) {
306 FAIL() << ec;
307 } else {
308 std::string intf_name, prop_name;
309 s.unpack(intf_name, prop_name);
310
311 EXPECT_EQ(intf_name, "xyz.openbmc_project.fwupdate1");
312 EXPECT_EQ(prop_name, "State");
313
314 // send a reply so dbus doesn't get angry?
315 auto r = bus->reply(s);
316 r.pack("IDLE");
317 bus->async_send(
318 r, [&](boost::system::error_code ec, dbus::message s) {});
319 io.stop();
320 }
321 };
322 f.async_dispatch(method_handler);
323
324 dbus::endpoint test_endpoint(requested_name, "/xyz/openbmc_project/fwupdate1",
325 "org.freedesktop.DBus.Properties");
326
327 auto method_name = std::string("Get");
328 auto m = dbus::message::new_call(test_endpoint, method_name);
329
330 m.pack("xyz.openbmc_project.fwupdate1", "State");
331 bus->async_send(m, [&](boost::system::error_code ec, dbus::message s) {
332 std::cerr << "received s: " << s << std::endl;
333 });
334
335 // system_bus->send(m, std::chrono::seconds(0));
336
337 io.run();
338 }
339