blob: 5d2deb805c278e786ada24782b409bf5bf24fc96 [file] [log] [blame]
// Copyright (c) Benjamin Kietzman (github.com/bkietz)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <dbus/connection.hpp>
#include <dbus/endpoint.hpp>
#include <dbus/filter.hpp>
#include <dbus/match.hpp>
#include <dbus/message.hpp>
#include <dbus/utility.hpp>
#include <functional>
#include <unistd.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
TEST(AvahiTest, GetHostName) {
dbus::endpoint test_daemon("org.freedesktop.Avahi", "/",
"org.freedesktop.Avahi.Server");
boost::asio::io_service io;
auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
dbus::message m = dbus::message::new_call(test_daemon, "GetHostName");
system_bus->async_send(
m, [&](const boost::system::error_code ec, dbus::message r) {
std::string avahi_hostname;
std::string hostname;
// get hostname from a system call
char c[1024];
gethostname(c, 1024);
hostname = c;
r.unpack(avahi_hostname);
// Get only the host name, not the fqdn
auto unix_hostname = hostname.substr(0, hostname.find("."));
EXPECT_EQ(unix_hostname, avahi_hostname);
io.stop();
});
boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
t.async_wait([&](const boost::system::error_code& /*e*/) {
io.stop();
FAIL() << "Callback was never called\n";
});
io.run();
}
TEST(AvahiTest, ServiceBrowser) {
boost::asio::io_service io;
auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
dbus::endpoint test_daemon("org.freedesktop.Avahi", "/",
"org.freedesktop.Avahi.Server");
// create new service browser
dbus::message m1 = dbus::message::new_call(test_daemon, "ServiceBrowserNew");
m1.pack<int32_t>(-1)
.pack<int32_t>(-1)
.pack<std::string>("_http._tcp")
.pack<std::string>("local")
.pack<uint32_t>(0);
dbus::message r = system_bus->send(m1);
std::string browser_path;
r.unpack(browser_path);
testing::Test::RecordProperty("browserPath", browser_path);
dbus::match ma(system_bus, "type='signal',path='" + browser_path + "'");
dbus::filter f(system_bus, [](dbus::message& m) {
auto member = m.get_member();
return member == "NameAcquired";
});
std::function<void(boost::system::error_code, dbus::message)> event_handler =
[&](boost::system::error_code ec, dbus::message s) {
testing::Test::RecordProperty("firstSignal", s.get_member());
std::string a = s.get_member();
std::string dude;
s.unpack(dude);
f.async_dispatch(event_handler);
io.stop();
};
f.async_dispatch(event_handler);
boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
t.async_wait([&](const boost::system::error_code& /*e*/) {
io.stop();
FAIL() << "Callback was never called\n";
});
io.run();
}
TEST(BOOST_DBUS, ListServices) {
boost::asio::io_service io;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
t.async_wait([&](const boost::system::error_code& /*e*/) {
io.stop();
FAIL() << "Callback was never called\n";
});
auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
dbus::endpoint test_daemon("org.freedesktop.DBus", "/",
"org.freedesktop.DBus");
// create new service browser
dbus::message m = dbus::message::new_call(test_daemon, "ListNames");
system_bus->async_send(
m, [&](const boost::system::error_code ec, dbus::message r) {
io.stop();
std::vector<std::string> services;
r.unpack(services);
// Test a couple things that should always be present.... adapt if
// neccesary
EXPECT_THAT(services, testing::Contains("org.freedesktop.DBus"));
EXPECT_THAT(services, testing::Contains("org.freedesktop.Accounts"));
});
io.run();
}
void query_interfaces(dbus::connection_ptr system_bus,
std::string& service_name, std::string& object_name) {
dbus::endpoint service_daemon(service_name, object_name,
"org.freedestop.DBus.Introspectable");
dbus::message m = dbus::message::new_call(service_daemon, "Introspect");
try {
auto r = system_bus->send(m);
std::vector<std::string> names;
// Todo(ed) figure out why we're occassionally getting access
// denied errors
// EXPECT_EQ(ec, boost::system::errc::success);
std::string xml;
r.unpack(xml);
// TODO(ed) names needs lock for multithreaded access
dbus::read_dbus_xml_names(xml, names);
// loop over the newly added items
for (auto name : names) {
std::cout << name << "\n";
auto new_service_string = object_name + "/" + name;
query_interfaces(system_bus, service_name, new_service_string);
}
} catch (boost::system::error_code e) {
std::cout << e;
}
}
TEST(BOOST_DBUS, SingleSensorChanged) {
boost::asio::io_service io;
auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
dbus::match ma(system_bus,
"type='signal',path_namespace='/xyz/openbmc_project/sensors'");
dbus::filter f(system_bus, [](dbus::message& m) {
auto member = m.get_member();
return member == "PropertiesChanged";
});
// std::function<void(boost::system::error_code, dbus::message)> event_handler
// =
f.async_dispatch([&](boost::system::error_code ec, dbus::message s) {
std::string object_name;
EXPECT_EQ(s.get_path(),
"/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp");
std::vector<std::pair<std::string, dbus::dbus_variant>> values;
s.unpack(object_name).unpack(values);
EXPECT_EQ(object_name, "xyz.openbmc_project.Sensor.Value");
EXPECT_EQ(values.size(), 1);
auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42);
EXPECT_EQ(values[0], expected);
io.stop();
});
dbus::endpoint test_endpoint(
"org.freedesktop.Avahi",
"/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
"org.freedesktop.DBus.Properties");
auto signal_name = std::string("PropertiesChanged");
auto m = dbus::message::new_signal(test_endpoint, signal_name);
m.pack("xyz.openbmc_project.Sensor.Value");
std::vector<std::pair<std::string, dbus::dbus_variant>> map2;
map2.emplace_back("Value", 42);
m.pack(map2);
auto removed = std::vector<uint32_t>();
m.pack(removed);
system_bus->async_send(m,
[&](boost::system::error_code ec, dbus::message s) {});
io.run();
}
TEST(BOOST_DBUS, MultipleSensorChanged) {
boost::asio::io_service io;
auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
dbus::match ma(system_bus,
"type='signal',path_namespace='/xyz/openbmc_project/sensors'");
dbus::filter f(system_bus, [](dbus::message& m) {
auto member = m.get_member();
return member == "PropertiesChanged";
});
int count = 0;
std::function<void(boost::system::error_code, dbus::message)> callback = [&](
boost::system::error_code ec, dbus::message s) {
std::string object_name;
EXPECT_EQ(s.get_path(),
"/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp");
std::vector<std::pair<std::string, dbus::dbus_variant>> values;
s.unpack(object_name).unpack(values);
EXPECT_EQ(object_name, "xyz.openbmc_project.Sensor.Value");
EXPECT_EQ(values.size(), 1);
auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42);
EXPECT_EQ(values[0], expected);
count++;
if (count == 2) {
io.stop();
} else {
f.async_dispatch(callback);
}
};
f.async_dispatch(callback);
dbus::endpoint test_endpoint(
"org.freedesktop.Avahi",
"/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
"org.freedesktop.DBus.Properties");
auto signal_name = std::string("PropertiesChanged");
auto m = dbus::message::new_signal(test_endpoint, signal_name);
m.pack("xyz.openbmc_project.Sensor.Value");
std::vector<std::pair<std::string, dbus::dbus_variant>> map2;
map2.emplace_back("Value", 42);
m.pack(map2);
auto removed = std::vector<uint32_t>();
m.pack(removed);
system_bus->async_send(m,
[&](boost::system::error_code ec, dbus::message s) {});
system_bus->async_send(m,
[&](boost::system::error_code ec, dbus::message s) {});
io.run();
}
TEST(BOOST_DBUS, MethodCall) {
boost::asio::io_service io;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(30));
t.async_wait([&](const boost::system::error_code& /*e*/) {
io.stop();
FAIL() << "Callback was never called\n";
});
std::string requested_name = "xyz.openbmc_project.fwupdate1.server";
auto system_bus = std::make_shared<dbus::connection>(io, dbus::bus::system);
//system_bus->request_name(requested_name);
/* not sure we even need to add a match for method calls,
* but this is how you might do it .... */
dbus::match ma(
system_bus,
"type='method_call',path_namespace='/xyz/openbmc_project/fwupdate1'");
dbus::filter f(system_bus, [](dbus::message& m) {
// std::cerr << "filter called: " << m << std::endl;
return (m.get_member() == "Get" &&
m.get_interface() == "org.freedesktop.DBus.Properties" &&
m.get_signature() == "ss");
});
std::function<void(boost::system::error_code, dbus::message)> method_handler =
[&](boost::system::error_code ec, dbus::message s) {
if (ec) {
FAIL() << ec;
} else {
std::string intf_name, prop_name;
s.unpack(intf_name).unpack(prop_name);
EXPECT_EQ(intf_name, "xyz.openbmc_project.fwupdate1");
EXPECT_EQ(prop_name, "State");
// send a reply so dbus doesn't get angry?
auto r = system_bus->reply(s);
r.pack("IDLE");
system_bus->async_send(
r, [&](boost::system::error_code ec, dbus::message s) {});
io.stop();
}
};
f.async_dispatch(method_handler);
dbus::endpoint test_endpoint(requested_name, "/xyz/openbmc_project/fwupdate1",
"org.freedesktop.DBus.Properties");
auto method_name = std::string("Get");
auto m = dbus::message::new_call(test_endpoint, method_name);
m.pack("xyz.openbmc_project.fwupdate1");
m.pack("State");
system_bus->async_send(m, [&](boost::system::error_code ec, dbus::message s) {
std::cerr << "received s: " << s << std::endl;
});
io.run();
}