summaryrefslogtreecommitdiff
path: root/cras/src/tests/dbus_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'cras/src/tests/dbus_test.cc')
-rw-r--r--cras/src/tests/dbus_test.cc734
1 files changed, 0 insertions, 734 deletions
diff --git a/cras/src/tests/dbus_test.cc b/cras/src/tests/dbus_test.cc
deleted file mode 100644
index b435825d..00000000
--- a/cras/src/tests/dbus_test.cc
+++ /dev/null
@@ -1,734 +0,0 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "dbus_test.h"
-
-#include <stdlib.h>
-#include <sys/select.h>
-#include <unistd.h>
-
-#include <algorithm>
-
-namespace {
-
-const char kServerAddress[] = "unix:abstract=/org/chromium/DBusTest";
-
-} // namespace
-
-DBusMatch::DBusMatch()
- : message_type_(DBUS_MESSAGE_TYPE_INVALID),
- as_property_dictionary_(false),
- send_reply_(false),
- send_error_(false),
- expect_serial_(false),
- matched_(false) {}
-
-DBusMatch& DBusMatch::WithString(std::string value) {
- Arg arg;
- arg.type = DBUS_TYPE_STRING;
- arg.array = false;
- arg.string_value = value;
-
- if (send_reply_)
- reply_args_.push_back(arg);
- else
- args_.push_back(arg);
- return *this;
-}
-
-DBusMatch& DBusMatch::WithUnixFd(int value) {
- Arg arg;
- arg.type = DBUS_TYPE_UNIX_FD;
- arg.array = false;
- arg.int_value = value;
-
- if (send_reply_)
- reply_args_.push_back(arg);
- else
- args_.push_back(arg);
- return *this;
-}
-
-DBusMatch& DBusMatch::WithObjectPath(std::string value) {
- Arg arg;
- arg.type = DBUS_TYPE_OBJECT_PATH;
- arg.array = false;
- arg.string_value = value;
-
- if (send_reply_)
- reply_args_.push_back(arg);
- else
- args_.push_back(arg);
- return *this;
-}
-
-DBusMatch& DBusMatch::WithArrayOfStrings(std::vector<std::string> values) {
- Arg arg;
- arg.type = DBUS_TYPE_STRING;
- arg.array = true;
- arg.string_values = values;
-
- if (send_reply_)
- reply_args_.push_back(arg);
- else
- args_.push_back(arg);
- return *this;
-}
-
-DBusMatch& DBusMatch::WithArrayOfObjectPaths(std::vector<std::string> values) {
- Arg arg;
- arg.type = DBUS_TYPE_OBJECT_PATH;
- arg.array = true;
- arg.string_values = values;
-
- if (send_reply_)
- reply_args_.push_back(arg);
- else
- args_.push_back(arg);
- return *this;
-}
-
-DBusMatch& DBusMatch::WithNoMoreArgs() {
- Arg arg;
- arg.type = DBUS_TYPE_INVALID;
-
- args_.push_back(arg);
- return *this;
-}
-
-DBusMatch& DBusMatch::AsPropertyDictionary() {
- as_property_dictionary_ = true;
- return *this;
-}
-
-DBusMatch& DBusMatch::SendReply() {
- send_reply_ = true;
- expect_serial_ = true;
- return *this;
-}
-
-DBusMatch& DBusMatch::SendError(std::string error_name,
- std::string error_message) {
- send_error_ = true;
- error_name_ = error_name;
- error_message_ = error_message;
- expect_serial_ = true;
- return *this;
-}
-
-DBusMatch& DBusMatch::SendReplyNoWait() {
- send_reply_ = true;
- expect_serial_ = false;
- return *this;
-}
-
-DBusMatch& DBusMatch::Send() {
- DBusMessage* message;
- if (message_type_ == DBUS_MESSAGE_TYPE_SIGNAL)
- message = dbus_message_new_signal(path_.c_str(), interface_.c_str(),
- member_.c_str());
- else if (message_type_ == DBUS_MESSAGE_TYPE_METHOD_CALL)
- message = dbus_message_new_method_call(NULL, path_.c_str(),
- interface_.c_str(), member_.c_str());
- else
- return *this;
-
- AppendArgsToMessage(message, &args_);
- SendMessage(conn_, message);
-
- dbus_message_unref(message);
-
- return *this;
-}
-
-void DBusMatch::ExpectMethodCall(std::string path,
- std::string interface,
- std::string method) {
- message_type_ = DBUS_MESSAGE_TYPE_METHOD_CALL;
- path_ = path;
- interface_ = interface;
- member_ = method;
-}
-
-void DBusMatch::CreateSignal(DBusConnection* conn,
- std::string path,
- std::string interface,
- std::string signal_name) {
- message_type_ = DBUS_MESSAGE_TYPE_SIGNAL;
- path_ = path;
- interface_ = interface;
- member_ = signal_name;
-
- conn_ = conn;
- expect_serial_ = true;
- matched_ = true;
-}
-
-void DBusMatch::CreateMessageCall(DBusConnection* conn,
- std::string path,
- std::string interface,
- std::string method_name) {
- message_type_ = DBUS_MESSAGE_TYPE_METHOD_CALL;
- path_ = path;
- interface_ = interface;
- member_ = method_name;
-
- conn_ = conn;
- expect_serial_ = true;
- matched_ = true;
-}
-
-bool DBusMatch::MatchMessageArgs(DBusMessage* message, std::vector<Arg>* args) {
- DBusMessageIter iter;
- dbus_message_iter_init(message, &iter);
- for (std::vector<Arg>::iterator it = args->begin(); it != args->end(); ++it) {
- Arg& arg = *it;
-
- int type = dbus_message_iter_get_arg_type(&iter);
- if (type != arg.type)
- return false;
-
- if (arg.type == DBUS_TYPE_STRING || arg.type == DBUS_TYPE_OBJECT_PATH) {
- const char* str_value;
- dbus_message_iter_get_basic(&iter, &str_value);
- if (strcmp(str_value, arg.string_value.c_str()) != 0)
- return false;
- }
- // TODO(keybuk): additional argument types
-
- dbus_message_iter_next(&iter);
- }
-
- return true;
-}
-
-void DBusMatch::AppendArgsToMessage(DBusMessage* message,
- std::vector<Arg>* args) {
- DBusMessageIter message_iter;
- DBusMessageIter dict_array_iter;
- DBusMessageIter struct_iter;
- DBusMessageIter iter;
-
- if (as_property_dictionary_) {
- dbus_message_iter_init_append(message, &message_iter);
- dbus_message_iter_open_container(&message_iter, DBUS_TYPE_ARRAY, "{sv}",
- &dict_array_iter);
- } else {
- dbus_message_iter_init_append(message, &iter);
- }
-
- for (std::vector<Arg>::iterator it = args->begin(); it != args->end(); ++it) {
- Arg& arg = *it;
-
- if (as_property_dictionary_) {
- dbus_message_iter_open_container(&dict_array_iter, DBUS_TYPE_DICT_ENTRY,
- NULL, &struct_iter);
-
- const char* str_value = arg.string_value.c_str();
- dbus_message_iter_append_basic(&struct_iter, arg.type, &str_value);
-
- arg = *(++it);
- }
-
- const char *array_type, *element_type;
- switch (arg.type) {
- case DBUS_TYPE_STRING:
- array_type = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
- element_type = DBUS_TYPE_STRING_AS_STRING;
- break;
- case DBUS_TYPE_OBJECT_PATH:
- array_type = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING;
- element_type = DBUS_TYPE_OBJECT_PATH_AS_STRING;
- break;
- case DBUS_TYPE_UNIX_FD:
- array_type = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UNIX_FD_AS_STRING;
- element_type = DBUS_TYPE_UNIX_FD_AS_STRING;
- break;
- default:
- abort();
- // TODO(keybuk): additional argument types
- }
-
- if (as_property_dictionary_) {
- dbus_message_iter_open_container(&struct_iter, DBUS_TYPE_VARIANT,
- arg.array ? array_type : element_type,
- &iter);
- }
-
- DBusMessageIter array_iter;
- if (arg.array) {
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, element_type,
- &array_iter);
-
- if (arg.type == DBUS_TYPE_STRING || arg.type == DBUS_TYPE_OBJECT_PATH) {
- for (std::vector<std::string>::const_iterator vit =
- arg.string_values.begin();
- vit != arg.string_values.end(); ++vit) {
- const char* str_value = vit->c_str();
- dbus_message_iter_append_basic(&array_iter, arg.type, &str_value);
- }
- }
- // TODO(keybuk): additional element types
-
- dbus_message_iter_close_container(&iter, &array_iter);
- } else {
- if (arg.type == DBUS_TYPE_STRING || arg.type == DBUS_TYPE_OBJECT_PATH) {
- const char* str_value = arg.string_value.c_str();
- dbus_message_iter_append_basic(&iter, arg.type, &str_value);
- } else if (arg.type == DBUS_TYPE_UNIX_FD) {
- dbus_message_iter_append_basic(&iter, arg.type, &arg.int_value);
- }
- // TODO(keybuk): additional argument types
- }
-
- if (as_property_dictionary_) {
- dbus_message_iter_close_container(&struct_iter, &iter);
- dbus_message_iter_close_container(&dict_array_iter, &struct_iter);
- }
- }
-
- if (as_property_dictionary_)
- dbus_message_iter_close_container(&message_iter, &dict_array_iter);
-}
-
-void DBusMatch::SendMessage(DBusConnection* conn, DBusMessage* message) {
- dbus_bool_t success;
- dbus_uint32_t serial;
- success = dbus_connection_send(conn, message, &serial);
-
- if (success && expect_serial_)
- expected_serials_.push_back(serial);
-}
-
-bool DBusMatch::HandleServerMessage(DBusConnection* conn,
- DBusMessage* message) {
- // Make sure we're expecting a method call or signal of this name
- if (message_type_ == DBUS_MESSAGE_TYPE_METHOD_CALL &&
- !dbus_message_is_method_call(message, interface_.c_str(),
- member_.c_str()))
- return false;
- else if (message_type_ == DBUS_MESSAGE_TYPE_SIGNAL &&
- !dbus_message_is_signal(message, interface_.c_str(),
- member_.c_str()))
- return false;
-
- // Make sure the path is what we expected.
- if (path_.length() &&
- strcmp(path_.c_str(), dbus_message_get_path(message)) != 0)
- return false;
-
- // And the arguments.
- if (!MatchMessageArgs(message, &args_))
- return false;
-
- // Handle any actions.
- matched_ = true;
- if (send_reply_ || send_error_) {
- // Send out the reply
- DBusMessage* reply = NULL;
- if (send_reply_)
- reply = dbus_message_new_method_return(message);
- else if (send_error_)
- reply = dbus_message_new_error(message, error_name_.c_str(),
- error_message_.c_str());
-
- AppendArgsToMessage(reply, &reply_args_);
- SendMessage(conn, reply);
-
- dbus_message_unref(reply);
- }
-
- return true;
-}
-
-bool DBusMatch::HandleClientMessage(DBusConnection* conn,
- DBusMessage* message) {
- // From the client side we check whether the message has a serial number
- // we generated on our server side, and if so, remove it from the list of
- // those we're expecting to see.
- for (std::vector<dbus_uint32_t>::iterator it = expected_serials_.begin();
- it != expected_serials_.end(); ++it) {
- if (*it == dbus_message_get_serial(message)) {
- expected_serials_.erase(it);
- return true;
- }
- }
-
- return false;
-}
-
-bool DBusMatch::Complete() {
- return matched_ && expected_serials_.size() == 0;
-}
-
-DBusTest::DBusTest()
- : conn_(NULL), server_(NULL), server_conn_(NULL), dispatch_(false) {}
-
-DBusTest::~DBusTest() {}
-
-DBusMatch& DBusTest::ExpectMethodCall(std::string path,
- std::string interface,
- std::string method) {
- DBusMatch match;
- match.ExpectMethodCall(path, interface, method);
- pthread_mutex_lock(&mutex_);
- matches_.push_back(match);
- DBusMatch& ref = matches_.back();
- pthread_mutex_unlock(&mutex_);
- return ref;
-}
-
-DBusMatch& DBusTest::CreateSignal(std::string path,
- std::string interface,
- std::string signal_name) {
- DBusMatch match;
- match.CreateSignal(server_conn_, path, interface, signal_name);
- pthread_mutex_lock(&mutex_);
- matches_.push_back(match);
- DBusMatch& ref = matches_.back();
- pthread_mutex_unlock(&mutex_);
- return ref;
-}
-
-DBusMatch& DBusTest::CreateMessageCall(std::string path,
- std::string interface,
- std::string signal_name) {
- DBusMatch match;
- match.CreateMessageCall(server_conn_, path, interface, signal_name);
- pthread_mutex_lock(&mutex_);
- matches_.push_back(match);
- DBusMatch& ref = matches_.back();
- pthread_mutex_unlock(&mutex_);
- return ref;
-}
-
-void DBusTest::WaitForMatches() {
- for (;;) {
- pthread_mutex_lock(&mutex_);
- size_t incomplete_matches = 0;
- for (std::vector<DBusMatch>::iterator it = matches_.begin();
- it != matches_.end(); ++it) {
- DBusMatch& match = *it;
- if (!match.Complete())
- ++incomplete_matches;
- }
- pthread_mutex_unlock(&mutex_);
-
- if (!incomplete_matches)
- break;
-
- // Fish a message from the queue.
- DBusMessage* message;
- while ((message = dbus_connection_borrow_message(conn_)) == NULL)
- dbus_connection_read_write(conn_, -1);
-
- // Allow matches to verify the serial of the message.
- pthread_mutex_lock(&mutex_);
- for (std::vector<DBusMatch>::iterator it = matches_.begin();
- it != matches_.end(); ++it) {
- DBusMatch& match = *it;
-
- if (match.HandleClientMessage(conn_, message))
- break;
- }
- pthread_mutex_unlock(&mutex_);
-
- // Throw it back and dispatch.
- dbus_connection_return_message(conn_, message);
- dbus_connection_dispatch(conn_);
- }
-
- pthread_mutex_lock(&mutex_);
- matches_.erase(matches_.begin(), matches_.end());
- pthread_mutex_unlock(&mutex_);
-}
-
-void DBusTest::SetUp() {
- dbus_threads_init_default();
-
- // Create the D-Bus server that will accept a connection for us, since
- // there's no "just give me a socketpair" option in libdbus.
- server_ = dbus_server_listen(kServerAddress, NULL);
- ASSERT_TRUE(server_ != NULL);
-
- dbus_server_set_new_connection_function(server_, NewConnectionThunk, this,
- NULL);
-
- dbus_bool_t success;
- success = dbus_server_set_watch_functions(
- server_, AddWatchThunk, RemoveWatchThunk, WatchToggledThunk, this, NULL);
- ASSERT_TRUE(success);
-
- success = dbus_server_set_timeout_functions(server_, AddTimeoutThunk,
- RemoveTimeoutThunk,
- TimeoutToggledThunk, this, NULL);
- ASSERT_TRUE(success);
-
- // Open a connection to our server, this returns the "client" side of the
- // connection.
- conn_ = dbus_connection_open_private(kServerAddress, NULL);
- ASSERT_TRUE(conn_ != NULL);
-
- // The "server" side of the connection comes from the NewConnection method
- // we set above. Dispatch until we have it.
- while (!server_conn_)
- DispatchOnce();
-
- // Now we set off "main loop" in the background to dispatch until the
- // client is disconnected by the TearDown method.
- int r;
- r = pthread_mutex_init(&mutex_, NULL);
- ASSERT_EQ(0, r);
-
- dispatch_ = true;
- r = pthread_create(&thread_id_, NULL, DispatchLoopThunk, this);
- ASSERT_EQ(0, r);
-}
-
-void DBusTest::TearDown() {
- WaitForMatches();
-
- // Close the client end of the connection, this will result in a signal
- // within the dispatch loop of the server.
- if (conn_) {
- dbus_connection_flush(conn_);
- dbus_connection_close(conn_);
- dbus_connection_unref(conn_);
- conn_ = NULL;
- }
-
- // Join the thread and wait for it to finish dispatch.
- if (dispatch_)
- pthread_join(thread_id_, NULL);
- pthread_mutex_destroy(&mutex_);
-
- // Clean up the server end of the connection and the server itself.
- if (server_conn_) {
- dbus_connection_flush(server_conn_);
- dbus_connection_close(server_conn_);
- dbus_connection_unref(server_conn_);
- server_conn_ = NULL;
- }
-
- dbus_server_disconnect(server_);
- dbus_server_unref(server_);
- server_ = NULL;
-
- dbus_shutdown();
-}
-
-void DBusTest::NewConnectionThunk(DBusServer* server,
- DBusConnection* conn,
- void* data) {
- DBusTest* test = static_cast<DBusTest*>(data);
- test->NewConnection(server, conn);
-}
-
-void DBusTest::NewConnection(DBusServer* server, DBusConnection* conn) {
- ASSERT_TRUE(server_conn_ == NULL);
-
- dbus_bool_t success;
- success = dbus_connection_set_watch_functions(
- conn, AddWatchThunk, RemoveWatchThunk, WatchToggledThunk, this, NULL);
- ASSERT_TRUE(success);
-
- success = dbus_connection_set_timeout_functions(
- conn, AddTimeoutThunk, RemoveTimeoutThunk, TimeoutToggledThunk, this,
- NULL);
- ASSERT_TRUE(success);
-
- success = dbus_connection_add_filter(conn, HandleMessageThunk, this, NULL);
- ASSERT_TRUE(success);
-
- server_conn_ = conn;
- dbus_connection_ref(server_conn_);
-}
-
-dbus_bool_t DBusTest::AddWatchThunk(DBusWatch* watch, void* data) {
- DBusTest* test = static_cast<DBusTest*>(data);
- return test->AddWatch(watch);
-}
-
-dbus_bool_t DBusTest::AddWatch(DBusWatch* watch) {
- watches_.push_back(watch);
- return TRUE;
-}
-
-void DBusTest::RemoveWatchThunk(DBusWatch* watch, void* data) {
- DBusTest* test = static_cast<DBusTest*>(data);
- test->RemoveWatch(watch);
-}
-
-void DBusTest::RemoveWatch(DBusWatch* watch) {
- std::vector<DBusWatch*>::iterator it =
- find(watches_.begin(), watches_.end(), watch);
- if (it != watches_.end())
- watches_.erase(it);
-}
-
-void DBusTest::WatchToggledThunk(DBusWatch* watch, void* data) {
- DBusTest* test = static_cast<DBusTest*>(data);
- test->WatchToggled(watch);
-}
-
-void DBusTest::WatchToggled(DBusWatch* watch) {}
-
-dbus_bool_t DBusTest::AddTimeoutThunk(DBusTimeout* timeout, void* data) {
- DBusTest* test = static_cast<DBusTest*>(data);
- return test->AddTimeout(timeout);
-}
-
-dbus_bool_t DBusTest::AddTimeout(DBusTimeout* timeout) {
- timeouts_.push_back(timeout);
- return TRUE;
-}
-
-void DBusTest::RemoveTimeoutThunk(DBusTimeout* timeout, void* data) {
- DBusTest* test = static_cast<DBusTest*>(data);
- test->RemoveTimeout(timeout);
-}
-
-void DBusTest::RemoveTimeout(DBusTimeout* timeout) {
- std::vector<DBusTimeout*>::iterator it =
- find(timeouts_.begin(), timeouts_.end(), timeout);
- if (it != timeouts_.end())
- timeouts_.erase(it);
-}
-
-void DBusTest::TimeoutToggledThunk(DBusTimeout* timeout, void* data) {
- DBusTest* test = static_cast<DBusTest*>(data);
- test->TimeoutToggled(timeout);
-}
-
-void DBusTest::TimeoutToggled(DBusTimeout* timeout) {}
-
-DBusHandlerResult DBusTest::HandleMessageThunk(DBusConnection* conn,
- DBusMessage* message,
- void* data) {
- DBusTest* test = static_cast<DBusTest*>(data);
- return test->HandleMessage(conn, message);
-}
-
-DBusHandlerResult DBusTest::HandleMessage(DBusConnection* conn,
- DBusMessage* message) {
- if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
- dispatch_ = false;
- return DBUS_HANDLER_RESULT_HANDLED;
- }
-
- pthread_mutex_lock(&mutex_);
- for (std::vector<DBusMatch>::iterator it = matches_.begin();
- it != matches_.end(); ++it) {
- DBusMatch& match = *it;
-
- if (match.HandleServerMessage(conn, message)) {
- pthread_mutex_unlock(&mutex_);
- return DBUS_HANDLER_RESULT_HANDLED;
- }
- }
- pthread_mutex_unlock(&mutex_);
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-void* DBusTest::DispatchLoopThunk(void* ptr) {
- DBusTest* test = static_cast<DBusTest*>(ptr);
- return test->DispatchLoop();
-}
-
-void* DBusTest::DispatchLoop() {
- while (dispatch_)
- DispatchOnce();
-
- return NULL;
-}
-
-void DBusTest::DispatchOnce() {
- fd_set readfds, writefds;
- int nfds = 0;
- int r;
-
- // Ideally we'd just use dbus_connection_read_write_dispatch() here, but
- // we have to deal with both the server itself and its connection, so we
- // have to do it all by hand.
- FD_ZERO(&readfds);
- FD_ZERO(&writefds);
-
- for (std::vector<DBusWatch*>::iterator it = watches_.begin();
- it != watches_.end(); ++it) {
- DBusWatch* watch = *it;
-
- if (!dbus_watch_get_enabled(watch))
- continue;
-
- int fd = dbus_watch_get_unix_fd(watch);
- if (fd + 1 > nfds)
- nfds = fd + 1;
-
- unsigned int flags = dbus_watch_get_flags(watch);
- if (flags & DBUS_WATCH_READABLE)
- FD_SET(fd, &readfds);
- if (flags & DBUS_WATCH_WRITABLE)
- FD_SET(fd, &writefds);
- }
-
- // Only block in select for the interval of the smallest timeout; this
- // isn't quite right according to the D-Bus spec, since the interval is
- // supposed to be since the time the timeout was added or toggled, but
- // it's good enough for the purposes of testing.
- DBusTimeout* earliest_timeout = NULL;
- struct timeval timeval;
-
- for (std::vector<DBusTimeout*>::iterator it = timeouts_.begin();
- it != timeouts_.end(); ++it) {
- DBusTimeout* timeout = *it;
-
- if (!dbus_timeout_get_enabled(timeout))
- continue;
-
- if (!earliest_timeout || (dbus_timeout_get_interval(timeout) <
- dbus_timeout_get_interval(earliest_timeout)))
- earliest_timeout = timeout;
- }
-
- if (earliest_timeout) {
- int interval = dbus_timeout_get_interval(earliest_timeout);
- timeval.tv_sec = interval / 1000;
- timeval.tv_usec = (interval % 1000) * 1000;
-
- r = select(nfds, &readfds, &writefds, NULL, &timeval);
- } else {
- r = select(nfds, &readfds, &writefds, NULL, NULL);
- }
-
- ASSERT_LE(0, r);
-
- // Handle the timeout if we didn't poll for anything else.
- if (r == 0 && earliest_timeout)
- dbus_timeout_handle(earliest_timeout);
-
- // Handle the watches, use a copy of the vector since a watch handler
- // might remove other watches in the vector.
- std::vector<DBusWatch*> immutable_watches = watches_;
- for (std::vector<DBusWatch*>::iterator it = immutable_watches.begin();
- it != immutable_watches.end(); ++it) {
- DBusWatch* watch = *it;
-
- int fd = dbus_watch_get_unix_fd(watch);
- unsigned int flags = 0;
-
- if (FD_ISSET(fd, &readfds))
- flags |= DBUS_WATCH_READABLE;
- if (FD_ISSET(fd, &writefds))
- flags |= DBUS_WATCH_WRITABLE;
-
- if (flags)
- dbus_watch_handle(watch, flags);
- }
-
- // Dispatch data on the server-side of the connection.
- while (server_conn_ &&
- dbus_connection_dispatch(server_conn_) == DBUS_DISPATCH_DATA_REMAINS)
- ;
-}