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 <dbus/utility.hpp> 12 #include <functional> 13 14 #include <unistd.h> 15 #include <gmock/gmock.h> 16 #include <gtest/gtest.h> 17 18 TEST(AvahiTest, GetHostName) { 19 dbus::endpoint test_daemon("org.freedesktop.Avahi", "/", 20 "org.freedesktop.Avahi.Server"); 21 boost::asio::io_service io; 22 dbus::connection system_bus(io, dbus::bus::system); 23 24 dbus::message m = dbus::message::new_call(test_daemon, "GetHostName"); 25 26 system_bus.async_send( 27 m, [&](const boost::system::error_code ec, dbus::message r) { 28 29 std::string avahi_hostname; 30 std::string hostname; 31 32 // get hostname from a system call 33 char c[1024]; 34 gethostname(c, 1024); 35 hostname = c; 36 37 r.unpack(avahi_hostname); 38 39 // Get only the host name, not the fqdn 40 auto unix_hostname = hostname.substr(0, hostname.find(".")); 41 EXPECT_EQ(unix_hostname, avahi_hostname); 42 43 io.stop(); 44 }); 45 boost::asio::deadline_timer t(io, boost::posix_time::seconds(10)); 46 t.async_wait([&](const boost::system::error_code& /*e*/) { 47 io.stop(); 48 FAIL() << "Callback was never called\n"; 49 }); 50 io.run(); 51 } 52 53 TEST(AvahiTest, ServiceBrowser) { 54 boost::asio::io_service io; 55 dbus::connection system_bus(io, dbus::bus::system); 56 57 dbus::endpoint test_daemon("org.freedesktop.Avahi", "/", 58 "org.freedesktop.Avahi.Server"); 59 // create new service browser 60 dbus::message m1 = dbus::message::new_call(test_daemon, "ServiceBrowserNew"); 61 m1.pack<int32_t>(-1) 62 .pack<int32_t>(-1) 63 .pack<std::string>("_http._tcp") 64 .pack<std::string>("local") 65 .pack<uint32_t>(0); 66 67 dbus::message r = system_bus.send(m1); 68 std::string browser_path; 69 r.unpack(browser_path); 70 testing::Test::RecordProperty("browserPath", browser_path); 71 72 dbus::match ma(system_bus, "type='signal',path='" + browser_path + "'"); 73 dbus::filter f(system_bus, [](dbus::message& m) { 74 auto member = m.get_member(); 75 return member == "NameAcquired"; 76 }); 77 78 std::function<void(boost::system::error_code, dbus::message)> event_handler = 79 [&](boost::system::error_code ec, dbus::message s) { 80 testing::Test::RecordProperty("firstSignal", s.get_member()); 81 std::string a = s.get_member(); 82 std::string dude; 83 s.unpack(dude); 84 f.async_dispatch(event_handler); 85 io.stop(); 86 }; 87 f.async_dispatch(event_handler); 88 89 boost::asio::deadline_timer t(io, boost::posix_time::seconds(10)); 90 t.async_wait([&](const boost::system::error_code& /*e*/) { 91 io.stop(); 92 FAIL() << "Callback was never called\n"; 93 }); 94 io.run(); 95 } 96 97 TEST(BOOST_DBUS, ListServices) { 98 boost::asio::io_service io; 99 boost::asio::deadline_timer t(io, boost::posix_time::seconds(10)); 100 t.async_wait([&](const boost::system::error_code& /*e*/) { 101 io.stop(); 102 FAIL() << "Callback was never called\n"; 103 }); 104 105 dbus::connection system_bus(io, dbus::bus::system); 106 107 dbus::endpoint test_daemon("org.freedesktop.DBus", "/", 108 "org.freedesktop.DBus"); 109 // create new service browser 110 dbus::message m = dbus::message::new_call(test_daemon, "ListNames"); 111 system_bus.async_send( 112 m, [&](const boost::system::error_code ec, dbus::message r) { 113 io.stop(); 114 std::vector<std::string> services; 115 r.unpack(services); 116 // Test a couple things that should always be present.... adapt if 117 // neccesary 118 EXPECT_THAT(services, testing::Contains("org.freedesktop.DBus")); 119 EXPECT_THAT(services, testing::Contains("org.freedesktop.Accounts")); 120 121 }); 122 123 io.run(); 124 } 125 126 TEST(BOOST_DBUS, ListObjects) { 127 boost::asio::io_service io; 128 dbus::connection system_bus(io, dbus::bus::system); 129 130 dbus::endpoint test_daemon("org.freedesktop.DBus", "/", 131 "org.freedesktop.DBus"); 132 133 // create new service browser 134 dbus::message m = dbus::message::new_call(test_daemon, "ListNames"); 135 system_bus.async_send(m, [&](const boost::system::error_code ec, 136 dbus::message r) { 137 static std::vector<std::string> services; 138 r.unpack(services); 139 // todo(ed) find out why this needs to be atomic 140 static std::atomic<int> dbus_count(0); 141 std::cout << dbus_count << " Callers\n"; 142 auto names = std::make_shared<std::vector<std::string>>(); 143 for (auto& service : services) { 144 dbus::endpoint service_daemon(service, "/", 145 "org.freedesktop.DBus.Introspectable"); 146 dbus::message m = dbus::message::new_call(service_daemon, "Introspect"); 147 dbus_count++; 148 std::cout << dbus_count << " Callers\n"; 149 150 system_bus.async_send(m, [&io, &service, names]( 151 const boost::system::error_code ec, 152 dbus::message r) { 153 dbus_count--; 154 std::cout << service << "\n"; 155 // Todo(ed) figure out why we're occassionally getting access denied 156 // errors 157 // EXPECT_EQ(ec, boost::system::errc::success); 158 if (ec) { 159 std::cout << "Error:" << ec << " reading service " << service << "\n"; 160 } else { 161 std::string xml; 162 r.unpack(xml); 163 size_t old_size = names->size(); 164 // TODO(ed) names needs lock for multithreaded access 165 dbus::read_dbus_xml_names(xml, *names); 166 // loop over the newly added items 167 for (size_t name_index = old_size; name_index < names->size(); 168 name_index++) { 169 // auto& name = names[name_index]; 170 } 171 } 172 // if we're the last one, print the list and cancel the io_service 173 if (dbus_count == 0) { 174 for (auto& name : *names) { 175 std::cout << name << "\n"; 176 } 177 io.stop(); 178 } 179 }); 180 181 std::function<void(const boost::system::error_code ec, dbus::message r)> 182 event_handler = 183 [&](const boost::system::error_code ec, dbus::message r) {}; 184 system_bus.async_send(m, event_handler); 185 } 186 187 }); 188 189 io.run(); 190 } 191