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>
11da3eeb6aSEd Tanous #include <functional>
12b2c2467dSBenjamin Kietzman
13a83e5951SBenjamin Kietzman #include <unistd.h>
14b6e8327aSEd Tanous #include <gmock/gmock.h>
15da3eeb6aSEd Tanous #include <gtest/gtest.h>
16b2c2467dSBenjamin Kietzman
TEST(AvahiTest,GetHostName)17da3eeb6aSEd Tanous TEST(AvahiTest, GetHostName) {
18da3eeb6aSEd Tanous dbus::endpoint test_daemon("org.freedesktop.Avahi", "/",
1916d80fe9SBenjamin Kietzman "org.freedesktop.Avahi.Server");
20da3eeb6aSEd Tanous boost::asio::io_service io;
21b573e22eSEd Tanous auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
22a83e5951SBenjamin Kietzman
23da3eeb6aSEd Tanous dbus::message m = dbus::message::new_call(test_daemon, "GetHostName");
24a83e5951SBenjamin Kietzman
25b573e22eSEd Tanous system_bus->async_send(
26da3eeb6aSEd Tanous m, [&](const boost::system::error_code ec, dbus::message r) {
27a83e5951SBenjamin Kietzman
28da3eeb6aSEd Tanous std::string avahi_hostname;
29da3eeb6aSEd Tanous std::string hostname;
30da3eeb6aSEd Tanous
31a83e5951SBenjamin Kietzman // get hostname from a system call
32a83e5951SBenjamin Kietzman char c[1024];
33a83e5951SBenjamin Kietzman gethostname(c, 1024);
34da3eeb6aSEd Tanous hostname = c;
35a83e5951SBenjamin Kietzman
36b2c2467dSBenjamin Kietzman r.unpack(avahi_hostname);
37b2c2467dSBenjamin Kietzman
38da3eeb6aSEd Tanous // Get only the host name, not the fqdn
39da3eeb6aSEd Tanous auto unix_hostname = hostname.substr(0, hostname.find("."));
40b2c2467dSBenjamin Kietzman EXPECT_EQ(unix_hostname, avahi_hostname);
41b2c2467dSBenjamin Kietzman
42b2c2467dSBenjamin Kietzman io.stop();
43da3eeb6aSEd Tanous });
44da3eeb6aSEd Tanous boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
45da3eeb6aSEd Tanous t.async_wait([&](const boost::system::error_code& /*e*/) {
46b2c2467dSBenjamin Kietzman io.stop();
47da3eeb6aSEd Tanous FAIL() << "Callback was never called\n";
48da3eeb6aSEd Tanous });
49a83e5951SBenjamin Kietzman io.run();
50a83e5951SBenjamin Kietzman }
51a83e5951SBenjamin Kietzman
TEST(AvahiTest,ServiceBrowser)52da3eeb6aSEd Tanous TEST(AvahiTest, ServiceBrowser) {
53da3eeb6aSEd Tanous boost::asio::io_service io;
54b573e22eSEd Tanous auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
55a83e5951SBenjamin Kietzman
56da3eeb6aSEd Tanous dbus::endpoint test_daemon("org.freedesktop.Avahi", "/",
57da3eeb6aSEd Tanous "org.freedesktop.Avahi.Server");
58a83e5951SBenjamin Kietzman // create new service browser
59da3eeb6aSEd Tanous dbus::message m1 = dbus::message::new_call(test_daemon, "ServiceBrowserNew");
60a04118e8SEd Tanous m1.pack((int32_t)-1, (int32_t)-1, "_http._tcp", "local", (uint32_t)(0));
61a83e5951SBenjamin Kietzman
62b573e22eSEd Tanous dbus::message r = system_bus->send(m1);
63a04118e8SEd Tanous dbus::object_path browser_path;
64a04118e8SEd Tanous EXPECT_TRUE(r.unpack(browser_path));
65a04118e8SEd Tanous testing::Test::RecordProperty("browserPath", browser_path.value);
66a83e5951SBenjamin Kietzman
67a04118e8SEd Tanous dbus::match ma(system_bus, "type='signal',path='" + browser_path.value + "'");
68da3eeb6aSEd Tanous dbus::filter f(system_bus, [](dbus::message& m) {
69da3eeb6aSEd Tanous auto member = m.get_member();
70da3eeb6aSEd Tanous return member == "NameAcquired";
71da3eeb6aSEd Tanous });
72a83e5951SBenjamin Kietzman
73da3eeb6aSEd Tanous std::function<void(boost::system::error_code, dbus::message)> event_handler =
74da3eeb6aSEd Tanous [&](boost::system::error_code ec, dbus::message s) {
75da3eeb6aSEd Tanous testing::Test::RecordProperty("firstSignal", s.get_member());
76da3eeb6aSEd Tanous std::string a = s.get_member();
77da3eeb6aSEd Tanous std::string dude;
78da3eeb6aSEd Tanous s.unpack(dude);
79da3eeb6aSEd Tanous f.async_dispatch(event_handler);
80da3eeb6aSEd Tanous io.stop();
81da3eeb6aSEd Tanous };
82da3eeb6aSEd Tanous f.async_dispatch(event_handler);
83b2c2467dSBenjamin Kietzman
84da3eeb6aSEd Tanous boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
85da3eeb6aSEd Tanous t.async_wait([&](const boost::system::error_code& /*e*/) {
86da3eeb6aSEd Tanous io.stop();
87da3eeb6aSEd Tanous FAIL() << "Callback was never called\n";
88da3eeb6aSEd Tanous });
89a83e5951SBenjamin Kietzman io.run();
90a83e5951SBenjamin Kietzman }
91b6e8327aSEd Tanous
TEST(BOOST_DBUS,ListServices)92b6e8327aSEd Tanous TEST(BOOST_DBUS, ListServices) {
93b6e8327aSEd Tanous boost::asio::io_service io;
94b6e8327aSEd Tanous boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
95b6e8327aSEd Tanous t.async_wait([&](const boost::system::error_code& /*e*/) {
96b6e8327aSEd Tanous io.stop();
97b6e8327aSEd Tanous FAIL() << "Callback was never called\n";
98b6e8327aSEd Tanous });
99b6e8327aSEd Tanous
100b573e22eSEd Tanous auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
101b6e8327aSEd Tanous
102b6e8327aSEd Tanous dbus::endpoint test_daemon("org.freedesktop.DBus", "/",
103b6e8327aSEd Tanous "org.freedesktop.DBus");
104b6e8327aSEd Tanous // create new service browser
105b6e8327aSEd Tanous dbus::message m = dbus::message::new_call(test_daemon, "ListNames");
106b573e22eSEd Tanous system_bus->async_send(
107b6e8327aSEd Tanous m, [&](const boost::system::error_code ec, dbus::message r) {
108b6e8327aSEd Tanous io.stop();
109b6e8327aSEd Tanous std::vector<std::string> services;
110b6e8327aSEd Tanous r.unpack(services);
111b6e8327aSEd Tanous // Test a couple things that should always be present.... adapt if
112b6e8327aSEd Tanous // neccesary
113b6e8327aSEd Tanous EXPECT_THAT(services, testing::Contains("org.freedesktop.DBus"));
114b6e8327aSEd Tanous EXPECT_THAT(services, testing::Contains("org.freedesktop.Accounts"));
115b6e8327aSEd Tanous
116b6e8327aSEd Tanous });
117b6e8327aSEd Tanous
118b6e8327aSEd Tanous io.run();
119b6e8327aSEd Tanous }
120b6e8327aSEd Tanous
TEST(BOOST_DBUS,SingleSensorChanged)1215d4bd2bdSEd Tanous TEST(BOOST_DBUS, SingleSensorChanged) {
122b6e8327aSEd Tanous boost::asio::io_service io;
123b6e8327aSEd Tanous
124b573e22eSEd Tanous auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
125b573e22eSEd Tanous
12677e62c83SEd Tanous dbus::match ma(system_bus,
12777e62c83SEd Tanous "type='signal',path_namespace='/xyz/openbmc_project/sensors'");
128b573e22eSEd Tanous
12982a51ce2SEd Tanous dbus::filter f(system_bus, [](dbus::message& m) {
13082a51ce2SEd Tanous auto member = m.get_member();
13182a51ce2SEd Tanous return member == "PropertiesChanged";
13282a51ce2SEd Tanous });
133b6e8327aSEd Tanous
1345d4bd2bdSEd Tanous f.async_dispatch([&](boost::system::error_code ec, dbus::message s) {
13582a51ce2SEd Tanous std::string object_name;
1365d4bd2bdSEd Tanous EXPECT_EQ(s.get_path(),
1375d4bd2bdSEd Tanous "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp");
1385d4bd2bdSEd Tanous
13982a51ce2SEd Tanous std::vector<std::pair<std::string, dbus::dbus_variant>> values;
1400d6f56d2SEd Tanous s.unpack(object_name, values);
14182a51ce2SEd Tanous EXPECT_EQ(object_name, "xyz.openbmc_project.Sensor.Value");
14282a51ce2SEd Tanous
143*a8b4eac4SEd Tanous EXPECT_EQ(values.size(), std::size_t{1});
14482a51ce2SEd Tanous auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42);
1455d4bd2bdSEd Tanous EXPECT_EQ(values[0], expected);
14682a51ce2SEd Tanous
147b6e8327aSEd Tanous io.stop();
1485d4bd2bdSEd Tanous });
149b6e8327aSEd Tanous
15082a51ce2SEd Tanous dbus::endpoint test_endpoint(
15182a51ce2SEd Tanous "org.freedesktop.Avahi",
15282a51ce2SEd Tanous "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
15382a51ce2SEd Tanous "org.freedesktop.DBus.Properties");
154b6e8327aSEd Tanous
15582a51ce2SEd Tanous auto signal_name = std::string("PropertiesChanged");
15682a51ce2SEd Tanous auto m = dbus::message::new_signal(test_endpoint, signal_name);
15782a51ce2SEd Tanous
15882a51ce2SEd Tanous std::vector<std::pair<std::string, dbus::dbus_variant>> map2;
15982a51ce2SEd Tanous
16082a51ce2SEd Tanous map2.emplace_back("Value", 42);
16182a51ce2SEd Tanous
162*a8b4eac4SEd Tanous auto removed = std::vector<std::string>();
163*a8b4eac4SEd Tanous EXPECT_EQ(m.pack("xyz.openbmc_project.Sensor.Value", map2, removed), true);
16482a51ce2SEd Tanous
165b573e22eSEd Tanous system_bus->async_send(m,
16682a51ce2SEd Tanous [&](boost::system::error_code ec, dbus::message s) {});
167b6e8327aSEd Tanous
168b6e8327aSEd Tanous io.run();
169b6e8327aSEd Tanous }
1705d4bd2bdSEd Tanous
TEST(BOOST_DBUS,MultipleSensorChanged)1715d4bd2bdSEd Tanous TEST(BOOST_DBUS, MultipleSensorChanged) {
1725d4bd2bdSEd Tanous boost::asio::io_service io;
173b573e22eSEd Tanous auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
1745d4bd2bdSEd Tanous
1755d4bd2bdSEd Tanous dbus::match ma(system_bus,
1765d4bd2bdSEd Tanous "type='signal',path_namespace='/xyz/openbmc_project/sensors'");
1775d4bd2bdSEd Tanous dbus::filter f(system_bus, [](dbus::message& m) {
1785d4bd2bdSEd Tanous auto member = m.get_member();
1795d4bd2bdSEd Tanous return member == "PropertiesChanged";
1805d4bd2bdSEd Tanous });
1815d4bd2bdSEd Tanous
1825d4bd2bdSEd Tanous int count = 0;
183b573e22eSEd Tanous std::function<void(boost::system::error_code, dbus::message)> callback = [&](
184b573e22eSEd Tanous boost::system::error_code ec, dbus::message s) {
1855d4bd2bdSEd Tanous std::string object_name;
1865d4bd2bdSEd Tanous EXPECT_EQ(s.get_path(),
1875d4bd2bdSEd Tanous "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp");
1885d4bd2bdSEd Tanous
1895d4bd2bdSEd Tanous std::vector<std::pair<std::string, dbus::dbus_variant>> values;
1900d6f56d2SEd Tanous s.unpack(object_name, values);
1915d4bd2bdSEd Tanous EXPECT_EQ(object_name, "xyz.openbmc_project.Sensor.Value");
1925d4bd2bdSEd Tanous
193*a8b4eac4SEd Tanous EXPECT_EQ(values.size(), std::size_t{1});
1945d4bd2bdSEd Tanous auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42);
1955d4bd2bdSEd Tanous EXPECT_EQ(values[0], expected);
1965d4bd2bdSEd Tanous count++;
1975d4bd2bdSEd Tanous if (count == 2) {
1985d4bd2bdSEd Tanous io.stop();
199b573e22eSEd Tanous } else {
200b573e22eSEd Tanous f.async_dispatch(callback);
2015d4bd2bdSEd Tanous }
2020d6f56d2SEd Tanous s.unpack(object_name, values);
2035d4bd2bdSEd Tanous
204b573e22eSEd Tanous };
205b573e22eSEd Tanous f.async_dispatch(callback);
2065d4bd2bdSEd Tanous
2075d4bd2bdSEd Tanous dbus::endpoint test_endpoint(
2085d4bd2bdSEd Tanous "org.freedesktop.Avahi",
2095d4bd2bdSEd Tanous "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
2105d4bd2bdSEd Tanous "org.freedesktop.DBus.Properties");
2115d4bd2bdSEd Tanous
2125d4bd2bdSEd Tanous auto signal_name = std::string("PropertiesChanged");
2135d4bd2bdSEd Tanous
2145d4bd2bdSEd Tanous std::vector<std::pair<std::string, dbus::dbus_variant>> map2;
2155d4bd2bdSEd Tanous
2165d4bd2bdSEd Tanous map2.emplace_back("Value", 42);
2175d4bd2bdSEd Tanous
21877e62c83SEd Tanous static auto removed = std::vector<uint32_t>();
2195d4bd2bdSEd Tanous
22077e62c83SEd Tanous auto m = dbus::message::new_signal(test_endpoint, signal_name);
22177e62c83SEd Tanous m.pack("xyz.openbmc_project.Sensor.Value", map2, removed);
22277e62c83SEd Tanous
22377e62c83SEd Tanous system_bus->send(m, std::chrono::seconds(0));
22477e62c83SEd Tanous system_bus->send(m, std::chrono::seconds(0));
22577e62c83SEd Tanous
2265d4bd2bdSEd Tanous io.run();
2275d4bd2bdSEd Tanous }
228458a9c10SVernon Mauery
TEST(BOOST_DBUS,MethodCallEx)229e62be329SEd Tanous TEST(BOOST_DBUS, MethodCallEx) {
230e62be329SEd Tanous boost::asio::io_service io;
231e62be329SEd Tanous // Expiration timer to stop tests if they fail
232e62be329SEd Tanous boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
233e62be329SEd Tanous t.async_wait([&](const boost::system::error_code&) {
234e62be329SEd Tanous io.stop();
235e62be329SEd Tanous FAIL() << "Callback was never called\n";
236e62be329SEd Tanous });
237e62be329SEd Tanous
238e62be329SEd Tanous auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::session);
239e62be329SEd Tanous std::string requested_name = system_bus->get_unique_name();
240e62be329SEd Tanous
241e62be329SEd Tanous dbus::filter f(system_bus, [requested_name](dbus::message& m) {
242e62be329SEd Tanous return m.get_sender() == requested_name;
243e62be329SEd Tanous });
244e62be329SEd Tanous
245e62be329SEd Tanous std::function<void(boost::system::error_code, dbus::message)> method_handler =
246e62be329SEd Tanous [&](boost::system::error_code ec, dbus::message s) {
247e62be329SEd Tanous if (ec) {
248e62be329SEd Tanous FAIL() << ec;
249e62be329SEd Tanous } else {
250e62be329SEd Tanous std::string intf_name, prop_name;
251e62be329SEd Tanous EXPECT_EQ(s.get_signature(), "ss");
252e62be329SEd Tanous EXPECT_EQ(s.get_member(), "Get");
253e62be329SEd Tanous EXPECT_EQ(s.get_interface(), "org.freedesktop.DBus.Properties");
254e62be329SEd Tanous s.unpack(intf_name, prop_name);
255e62be329SEd Tanous
256e62be329SEd Tanous EXPECT_EQ(intf_name, "xyz.openbmc_project.fwupdate1");
257e62be329SEd Tanous EXPECT_EQ(prop_name, "State");
258e62be329SEd Tanous
259e62be329SEd Tanous // send a reply
260e62be329SEd Tanous auto r = system_bus->reply(s);
261e62be329SEd Tanous r.pack("IDLE");
262e62be329SEd Tanous system_bus->async_send(
263e62be329SEd Tanous r, [&](boost::system::error_code ec, dbus::message s) {});
264e62be329SEd Tanous io.stop();
265e62be329SEd Tanous }
266e62be329SEd Tanous };
267e62be329SEd Tanous f.async_dispatch(method_handler);
268e62be329SEd Tanous
269e62be329SEd Tanous dbus::endpoint test_endpoint(requested_name, "/xyz/openbmc_project/fwupdate1",
270e62be329SEd Tanous "org.freedesktop.DBus.Properties", "Get");
271e62be329SEd Tanous system_bus->async_method_call(
272e62be329SEd Tanous [&](const boost::system::error_code ec,
273e62be329SEd Tanous const dbus::dbus_variant& status) {
274e62be329SEd Tanous if (ec) {
275e62be329SEd Tanous FAIL();
276e62be329SEd Tanous } else {
277e62be329SEd Tanous EXPECT_EQ(boost::get<std::string>(status), "IDLE");
278e62be329SEd Tanous }
279e62be329SEd Tanous },
280e62be329SEd Tanous test_endpoint, "xyz.openbmc_project.fwupdate1", "State");
281e62be329SEd Tanous
282e62be329SEd Tanous io.run();
283e62be329SEd Tanous }
284e62be329SEd Tanous
TEST(BOOST_DBUS,MethodCall)285458a9c10SVernon Mauery TEST(BOOST_DBUS, MethodCall) {
286458a9c10SVernon Mauery boost::asio::io_service io;
28777e62c83SEd Tanous
28877e62c83SEd Tanous boost::asio::deadline_timer t(io, boost::posix_time::seconds(2));
28977e62c83SEd Tanous t.async_wait([&](const boost::system::error_code&) {
290458a9c10SVernon Mauery io.stop();
291458a9c10SVernon Mauery FAIL() << "Callback was never called\n";
292458a9c10SVernon Mauery });
293458a9c10SVernon Mauery
294cae80d1cSEd Tanous auto bus = std::make_shared<dbus::connection>(io, dbus::bus::session);
295cae80d1cSEd Tanous std::string requested_name = bus->get_unique_name();
296458a9c10SVernon Mauery
297cae80d1cSEd Tanous dbus::filter f(bus, [](dbus::message& m) {
298458a9c10SVernon Mauery return (m.get_member() == "Get" &&
299458a9c10SVernon Mauery m.get_interface() == "org.freedesktop.DBus.Properties" &&
300458a9c10SVernon Mauery m.get_signature() == "ss");
301458a9c10SVernon Mauery });
302458a9c10SVernon Mauery
303458a9c10SVernon Mauery std::function<void(boost::system::error_code, dbus::message)> method_handler =
304458a9c10SVernon Mauery [&](boost::system::error_code ec, dbus::message s) {
3050d6f56d2SEd Tanous if (ec) {
3060d6f56d2SEd Tanous FAIL() << ec;
3070d6f56d2SEd Tanous } else {
308458a9c10SVernon Mauery std::string intf_name, prop_name;
3090d6f56d2SEd Tanous s.unpack(intf_name, prop_name);
310458a9c10SVernon Mauery
311458a9c10SVernon Mauery EXPECT_EQ(intf_name, "xyz.openbmc_project.fwupdate1");
312458a9c10SVernon Mauery EXPECT_EQ(prop_name, "State");
313458a9c10SVernon Mauery
314458a9c10SVernon Mauery // send a reply so dbus doesn't get angry?
315cae80d1cSEd Tanous auto r = bus->reply(s);
316458a9c10SVernon Mauery r.pack("IDLE");
317cae80d1cSEd Tanous bus->async_send(
31877e62c83SEd Tanous r, [&](boost::system::error_code ec, dbus::message s) {});
319458a9c10SVernon Mauery io.stop();
3200d6f56d2SEd Tanous }
321458a9c10SVernon Mauery };
322458a9c10SVernon Mauery f.async_dispatch(method_handler);
323458a9c10SVernon Mauery
32477e62c83SEd Tanous dbus::endpoint test_endpoint(requested_name, "/xyz/openbmc_project/fwupdate1",
325458a9c10SVernon Mauery "org.freedesktop.DBus.Properties");
326458a9c10SVernon Mauery
327458a9c10SVernon Mauery auto method_name = std::string("Get");
328458a9c10SVernon Mauery auto m = dbus::message::new_call(test_endpoint, method_name);
329458a9c10SVernon Mauery
3300d6f56d2SEd Tanous m.pack("xyz.openbmc_project.fwupdate1", "State");
331cae80d1cSEd Tanous bus->async_send(m, [&](boost::system::error_code ec, dbus::message s) {
332458a9c10SVernon Mauery std::cerr << "received s: " << s << std::endl;
333458a9c10SVernon Mauery });
334458a9c10SVernon Mauery
33577e62c83SEd Tanous // system_bus->send(m, std::chrono::seconds(0));
33677e62c83SEd Tanous
337458a9c10SVernon Mauery io.run();
338458a9c10SVernon Mauery }
339