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> 11*b6e8327aSEd Tanous #include <dbus/utility.hpp> 12da3eeb6aSEd Tanous #include <functional> 13b2c2467dSBenjamin Kietzman 14a83e5951SBenjamin Kietzman #include <unistd.h> 15*b6e8327aSEd 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 } 96*b6e8327aSEd Tanous 97*b6e8327aSEd Tanous TEST(BOOST_DBUS, ListServices) { 98*b6e8327aSEd Tanous boost::asio::io_service io; 99*b6e8327aSEd Tanous boost::asio::deadline_timer t(io, boost::posix_time::seconds(10)); 100*b6e8327aSEd Tanous t.async_wait([&](const boost::system::error_code& /*e*/) { 101*b6e8327aSEd Tanous io.stop(); 102*b6e8327aSEd Tanous FAIL() << "Callback was never called\n"; 103*b6e8327aSEd Tanous }); 104*b6e8327aSEd Tanous 105*b6e8327aSEd Tanous dbus::connection system_bus(io, dbus::bus::system); 106*b6e8327aSEd Tanous 107*b6e8327aSEd Tanous dbus::endpoint test_daemon("org.freedesktop.DBus", "/", 108*b6e8327aSEd Tanous "org.freedesktop.DBus"); 109*b6e8327aSEd Tanous // create new service browser 110*b6e8327aSEd Tanous dbus::message m = dbus::message::new_call(test_daemon, "ListNames"); 111*b6e8327aSEd Tanous system_bus.async_send( 112*b6e8327aSEd Tanous m, [&](const boost::system::error_code ec, dbus::message r) { 113*b6e8327aSEd Tanous io.stop(); 114*b6e8327aSEd Tanous std::vector<std::string> services; 115*b6e8327aSEd Tanous r.unpack(services); 116*b6e8327aSEd Tanous // Test a couple things that should always be present.... adapt if 117*b6e8327aSEd Tanous // neccesary 118*b6e8327aSEd Tanous EXPECT_THAT(services, testing::Contains("org.freedesktop.DBus")); 119*b6e8327aSEd Tanous EXPECT_THAT(services, testing::Contains("org.freedesktop.Accounts")); 120*b6e8327aSEd Tanous 121*b6e8327aSEd Tanous }); 122*b6e8327aSEd Tanous 123*b6e8327aSEd Tanous io.run(); 124*b6e8327aSEd Tanous } 125*b6e8327aSEd Tanous 126*b6e8327aSEd Tanous TEST(BOOST_DBUS, ListObjects) { 127*b6e8327aSEd Tanous boost::asio::io_service io; 128*b6e8327aSEd Tanous dbus::connection system_bus(io, dbus::bus::system); 129*b6e8327aSEd Tanous 130*b6e8327aSEd Tanous dbus::endpoint test_daemon("org.freedesktop.DBus", "/", 131*b6e8327aSEd Tanous "org.freedesktop.DBus"); 132*b6e8327aSEd Tanous 133*b6e8327aSEd Tanous // create new service browser 134*b6e8327aSEd Tanous dbus::message m = dbus::message::new_call(test_daemon, "ListNames"); 135*b6e8327aSEd Tanous system_bus.async_send(m, [&](const boost::system::error_code ec, 136*b6e8327aSEd Tanous dbus::message r) { 137*b6e8327aSEd Tanous static std::vector<std::string> services; 138*b6e8327aSEd Tanous r.unpack(services); 139*b6e8327aSEd Tanous // todo(ed) find out why this needs to be atomic 140*b6e8327aSEd Tanous static std::atomic<int> dbus_count(0); 141*b6e8327aSEd Tanous std::cout << dbus_count << " Callers\n"; 142*b6e8327aSEd Tanous auto names = std::make_shared<std::vector<std::string>>(); 143*b6e8327aSEd Tanous for (auto& service : services) { 144*b6e8327aSEd Tanous dbus::endpoint service_daemon(service, "/", 145*b6e8327aSEd Tanous "org.freedesktop.DBus.Introspectable"); 146*b6e8327aSEd Tanous dbus::message m = dbus::message::new_call(service_daemon, "Introspect"); 147*b6e8327aSEd Tanous dbus_count++; 148*b6e8327aSEd Tanous std::cout << dbus_count << " Callers\n"; 149*b6e8327aSEd Tanous 150*b6e8327aSEd Tanous system_bus.async_send(m, [&io, &service, names]( 151*b6e8327aSEd Tanous const boost::system::error_code ec, 152*b6e8327aSEd Tanous dbus::message r) { 153*b6e8327aSEd Tanous dbus_count--; 154*b6e8327aSEd Tanous std::cout << service << "\n"; 155*b6e8327aSEd Tanous // Todo(ed) figure out why we're occassionally getting access denied 156*b6e8327aSEd Tanous // errors 157*b6e8327aSEd Tanous // EXPECT_EQ(ec, boost::system::errc::success); 158*b6e8327aSEd Tanous if (ec) { 159*b6e8327aSEd Tanous std::cout << "Error:" << ec << " reading service " << service << "\n"; 160*b6e8327aSEd Tanous } else { 161*b6e8327aSEd Tanous std::string xml; 162*b6e8327aSEd Tanous r.unpack(xml); 163*b6e8327aSEd Tanous size_t old_size = names->size(); 164*b6e8327aSEd Tanous // TODO(ed) names needs lock for multithreaded access 165*b6e8327aSEd Tanous dbus::read_dbus_xml_names(xml, *names); 166*b6e8327aSEd Tanous // loop over the newly added items 167*b6e8327aSEd Tanous for (size_t name_index = old_size; name_index < names->size(); 168*b6e8327aSEd Tanous name_index++) { 169*b6e8327aSEd Tanous // auto& name = names[name_index]; 170*b6e8327aSEd Tanous } 171*b6e8327aSEd Tanous } 172*b6e8327aSEd Tanous // if we're the last one, print the list and cancel the io_service 173*b6e8327aSEd Tanous if (dbus_count == 0) { 174*b6e8327aSEd Tanous for (auto& name : *names) { 175*b6e8327aSEd Tanous std::cout << name << "\n"; 176*b6e8327aSEd Tanous } 177*b6e8327aSEd Tanous io.stop(); 178*b6e8327aSEd Tanous } 179*b6e8327aSEd Tanous }); 180*b6e8327aSEd Tanous 181*b6e8327aSEd Tanous std::function<void(const boost::system::error_code ec, dbus::message r)> 182*b6e8327aSEd Tanous event_handler = 183*b6e8327aSEd Tanous [&](const boost::system::error_code ec, dbus::message r) {}; 184*b6e8327aSEd Tanous system_bus.async_send(m, event_handler); 185*b6e8327aSEd Tanous } 186*b6e8327aSEd Tanous 187*b6e8327aSEd Tanous }); 188*b6e8327aSEd Tanous 189*b6e8327aSEd Tanous io.run(); 190*b6e8327aSEd Tanous } 191