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 153*5d4bd2bdSEd 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 164*5d4bd2bdSEd Tanous // std::function<void(boost::system::error_code, dbus::message)> event_handler 165*5d4bd2bdSEd Tanous // = 166*5d4bd2bdSEd Tanous 167*5d4bd2bdSEd Tanous f.async_dispatch([&](boost::system::error_code ec, dbus::message s) { 16882a51ce2SEd Tanous std::string object_name; 169*5d4bd2bdSEd Tanous EXPECT_EQ(s.get_path(), 170*5d4bd2bdSEd Tanous "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp"); 171*5d4bd2bdSEd 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 177*5d4bd2bdSEd Tanous EXPECT_EQ(values.size(), 1); 17882a51ce2SEd Tanous auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42); 179*5d4bd2bdSEd Tanous EXPECT_EQ(values[0], expected); 18082a51ce2SEd Tanous 181b6e8327aSEd Tanous io.stop(); 182*5d4bd2bdSEd 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 } 207*5d4bd2bdSEd Tanous 208*5d4bd2bdSEd Tanous TEST(BOOST_DBUS, MultipleSensorChanged) { 209*5d4bd2bdSEd Tanous boost::asio::io_service io; 210*5d4bd2bdSEd Tanous dbus::connection system_bus(io, dbus::bus::system); 211*5d4bd2bdSEd Tanous 212*5d4bd2bdSEd Tanous dbus::match ma(system_bus, 213*5d4bd2bdSEd Tanous "type='signal',path_namespace='/xyz/openbmc_project/sensors'"); 214*5d4bd2bdSEd Tanous dbus::filter f(system_bus, [](dbus::message& m) { 215*5d4bd2bdSEd Tanous auto member = m.get_member(); 216*5d4bd2bdSEd Tanous return member == "PropertiesChanged"; 217*5d4bd2bdSEd Tanous }); 218*5d4bd2bdSEd Tanous 219*5d4bd2bdSEd Tanous int count = 0; 220*5d4bd2bdSEd Tanous f.async_dispatch([&](boost::system::error_code ec, dbus::message s) { 221*5d4bd2bdSEd Tanous std::string object_name; 222*5d4bd2bdSEd Tanous EXPECT_EQ(s.get_path(), 223*5d4bd2bdSEd Tanous "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp"); 224*5d4bd2bdSEd Tanous 225*5d4bd2bdSEd Tanous std::vector<std::pair<std::string, dbus::dbus_variant>> values; 226*5d4bd2bdSEd Tanous s.unpack(object_name).unpack(values); 227*5d4bd2bdSEd Tanous 228*5d4bd2bdSEd Tanous EXPECT_EQ(object_name, "xyz.openbmc_project.Sensor.Value"); 229*5d4bd2bdSEd Tanous 230*5d4bd2bdSEd Tanous EXPECT_EQ(values.size(), 1); 231*5d4bd2bdSEd Tanous auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42); 232*5d4bd2bdSEd Tanous EXPECT_EQ(values[0], expected); 233*5d4bd2bdSEd Tanous count++; 234*5d4bd2bdSEd Tanous if (count == 2) { 235*5d4bd2bdSEd Tanous io.stop(); 236*5d4bd2bdSEd Tanous } 237*5d4bd2bdSEd Tanous 238*5d4bd2bdSEd Tanous }); 239*5d4bd2bdSEd Tanous 240*5d4bd2bdSEd Tanous dbus::endpoint test_endpoint( 241*5d4bd2bdSEd Tanous "org.freedesktop.Avahi", 242*5d4bd2bdSEd Tanous "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp", 243*5d4bd2bdSEd Tanous "org.freedesktop.DBus.Properties"); 244*5d4bd2bdSEd Tanous 245*5d4bd2bdSEd Tanous auto signal_name = std::string("PropertiesChanged"); 246*5d4bd2bdSEd Tanous auto m = dbus::message::new_signal(test_endpoint, signal_name); 247*5d4bd2bdSEd Tanous 248*5d4bd2bdSEd Tanous m.pack("xyz.openbmc_project.Sensor.Value"); 249*5d4bd2bdSEd Tanous 250*5d4bd2bdSEd Tanous std::vector<std::pair<std::string, dbus::dbus_variant>> map2; 251*5d4bd2bdSEd Tanous 252*5d4bd2bdSEd Tanous map2.emplace_back("Value", 42); 253*5d4bd2bdSEd Tanous 254*5d4bd2bdSEd Tanous m.pack(map2); 255*5d4bd2bdSEd Tanous 256*5d4bd2bdSEd Tanous auto removed = std::vector<uint32_t>(); 257*5d4bd2bdSEd Tanous m.pack(removed); 258*5d4bd2bdSEd Tanous system_bus.async_send(m, 259*5d4bd2bdSEd Tanous [&](boost::system::error_code ec, dbus::message s) {}); 260*5d4bd2bdSEd Tanous system_bus.async_send(m, 261*5d4bd2bdSEd Tanous [&](boost::system::error_code ec, dbus::message s) {}); 262*5d4bd2bdSEd Tanous io.run(); 263*5d4bd2bdSEd Tanous }