summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsatorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-25 05:18:29 +0000
committersatorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-25 05:18:29 +0000
commitb8ae051ea8edaefb9f787bdca704e2df1adfb89f (patch)
treef26c2509c5f31de44d9446d17be64666558bdfcc
parent2517cfa5066e63e6ed2642779ea57616ae49eb42 (diff)
downloadchromium_src-b8ae051ea8edaefb9f787bdca704e2df1adfb89f.zip
chromium_src-b8ae051ea8edaefb9f787bdca704e2df1adfb89f.tar.gz
chromium_src-b8ae051ea8edaefb9f787bdca704e2df1adfb89f.tar.bz2
Add mock classes for Bus, ObjectProxy, and ExportedObject.
Also add mock_unittest.cc that demonstrates how to mock synchronos and asynchronos D-Bus method calls. BUG=90036 TEST=dbus_unittests Review URL: http://codereview.chromium.org/7714030 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@98188 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--dbus/bus.h5
-rw-r--r--dbus/dbus.gyp31
-rw-r--r--dbus/exported_object.h5
-rw-r--r--dbus/mock_bus.cc15
-rw-r--r--dbus/mock_bus.h71
-rw-r--r--dbus/mock_exported_object.cc18
-rw-r--r--dbus/mock_exported_object.h39
-rw-r--r--dbus/mock_object_proxy.cc18
-rw-r--r--dbus/mock_object_proxy.h39
-rw-r--r--dbus/mock_unittest.cc171
-rw-r--r--dbus/object_proxy.h6
11 files changed, 411 insertions, 7 deletions
diff --git a/dbus/bus.h b/dbus/bus.h
index e632e9a..a11dd9b 100644
--- a/dbus/bus.h
+++ b/dbus/bus.h
@@ -368,9 +368,12 @@ class Bus : public base::RefCountedThreadSafe<Bus> {
// AssertOnOriginThread().
virtual void AssertOnDBusThread();
+ protected:
+ // This is protected, so we can define sub classes.
+ virtual ~Bus();
+
private:
friend class base::RefCountedThreadSafe<Bus>;
- virtual ~Bus();
// Helper function used for Shutdown().
void ShutdownInternal(OnShutdownCallback callback);
diff --git a/dbus/dbus.gyp b/dbus/dbus.gyp
index 143f672..c17aecf 100644
--- a/dbus/dbus.gyp
+++ b/dbus/dbus.gyp
@@ -17,8 +17,8 @@
'sources': [
'bus.cc',
'bus.h',
- 'exported_object.h',
'exported_object.cc',
+ 'exported_object.h',
'message.cc',
'message.h',
'object_proxy.cc',
@@ -27,20 +27,43 @@
],
},
{
+ # This target contains mocks that can be used to write unit tests
+ # without issuing actual D-Bus calls.
+ 'target_name': 'dbus_test_support',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../build/linux/system.gyp:dbus',
+ '../testing/gmock.gyp:gmock',
+ 'dbus',
+ ],
+ 'sources': [
+ 'mock_bus.cc',
+ 'mock_bus.h',
+ 'mock_object_proxy.cc',
+ 'mock_object_proxy.h',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ },
+ {
'target_name': 'dbus_unittests',
'type': 'executable',
'dependencies': [
- 'dbus',
'../base/base.gyp:test_support_base',
- '../testing/gtest.gyp:gtest',
'../build/linux/system.gyp:dbus',
+ '../testing/gmock.gyp:gmock',
+ '../testing/gtest.gyp:gtest',
+ 'dbus',
+ 'dbus_test_support',
],
'sources': [
'../base/test/run_all_unittests.cc',
'bus_unittest.cc',
- 'message_unittest.cc',
'end_to_end_async_unittest.cc',
'end_to_end_sync_unittest.cc',
+ 'message_unittest.cc',
+ 'mock_unittest.cc',
'test_service.cc',
'test_service.h',
],
diff --git a/dbus/exported_object.h b/dbus/exported_object.h
index 1351824..d9cda57 100644
--- a/dbus/exported_object.h
+++ b/dbus/exported_object.h
@@ -86,9 +86,12 @@ class ExportedObject : public base::RefCountedThreadSafe<ExportedObject> {
// BLOCKING CALL.
virtual void Unregister();
+ protected:
+ // This is protected, so we can define sub classes.
+ virtual ~ExportedObject();
+
private:
friend class base::RefCountedThreadSafe<ExportedObject>;
- virtual ~ExportedObject();
// Helper function for ExportMethod().
void ExportMethodInternal(const std::string& interface_name,
diff --git a/dbus/mock_bus.cc b/dbus/mock_bus.cc
new file mode 100644
index 0000000..e97cd71
--- /dev/null
+++ b/dbus/mock_bus.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2011 The Chromium 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/mock_bus.h"
+
+namespace dbus {
+
+MockBus::MockBus(Bus::Options& options) : Bus(options) {
+}
+
+MockBus::~MockBus() {
+}
+
+} // namespace dbus
diff --git a/dbus/mock_bus.h b/dbus/mock_bus.h
new file mode 100644
index 0000000..f1c5b4e
--- /dev/null
+++ b/dbus/mock_bus.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DBUS_MOCK_BUS_H_
+#define DBUS_MOCK_BUS_H_
+#pragma once
+
+#include "dbus/bus.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace dbus {
+
+// Mock for Bus class. Along with MockObjectProxy and MockExportedObject,
+// the mock classes can be used to write unit tests without issuing real
+// D-Bus calls.
+class MockBus : public Bus {
+ public:
+ MockBus(Bus::Options& options);
+ virtual ~MockBus();
+
+ MOCK_METHOD2(GetObjectProxy, ObjectProxy*(const std::string& service_name,
+ const std::string& object_path));
+ MOCK_METHOD2(GetExportedObject, ExportedObject*(
+ const std::string& service_name,
+ const std::string& object_path));
+ MOCK_METHOD0(ShutdownAndBlock, void());
+ MOCK_METHOD1(Shutdown, void(OnShutdownCallback callback));
+ MOCK_METHOD0(Connect, bool());
+ MOCK_METHOD1(RequestOwnership, bool(const std::string& service_name));
+ MOCK_METHOD1(ReleaseOwnership, bool(const std::string& service_name));
+ MOCK_METHOD0(SetUpAsyncOperations, bool());
+ MOCK_METHOD3(SendWithReplyAndBlock, DBusMessage*(DBusMessage* request,
+ int timeout_ms,
+ DBusError* error));
+ MOCK_METHOD3(SendWithReply, void(DBusMessage* request,
+ DBusPendingCall** pending_call,
+ int timeout_ms));
+ MOCK_METHOD2(Send, void(DBusMessage* request,
+ uint32* serial));
+ MOCK_METHOD2(AddFilter, void(DBusHandleMessageFunction handle_message,
+ void* user_data));
+ MOCK_METHOD2(RemoveFilter, void(DBusHandleMessageFunction handle_message,
+ void* user_data));
+ MOCK_METHOD2(AddMatch, void(const std::string& match_rule,
+ DBusError* error));
+ MOCK_METHOD2(RemoveMatch, void(const std::string& match_rule,
+ DBusError* error));
+ MOCK_METHOD4(TryRegisterObjectPath, bool(const std::string& object_path,
+ const DBusObjectPathVTable* vtable,
+ void* user_data,
+ DBusError* error));
+ MOCK_METHOD1(UnregisterObjectPath, void(const std::string& object_path));
+ MOCK_METHOD2(PostTaskToOriginThread, void(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task));
+ MOCK_METHOD2(PostTaskToDBusThread, void(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task));
+ MOCK_METHOD3(PostDelayedTaskToDBusThread, void(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ int delay_ms));
+ MOCK_METHOD0(HasDBusThread, bool());
+ MOCK_METHOD0(AssertOnOriginThread, void());
+ MOCK_METHOD0(AssertOnDBusThread, void());
+};
+
+} // namespace dbus
+
+#endif // DBUS_MOCK_BUS_H_
diff --git a/dbus/mock_exported_object.cc b/dbus/mock_exported_object.cc
new file mode 100644
index 0000000..0fd4f2e
--- /dev/null
+++ b/dbus/mock_exported_object.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2011 The Chromium 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/mock_exported_object.h"
+
+namespace dbus {
+
+MockExportedObject::MockExportedObject(Bus* bus,
+ const std::string& service_name,
+ const std::string& object_path)
+ : ExportedObject(bus, service_name, object_path) {
+}
+
+MockExportedObject::~MockExportedObject() {
+}
+
+} // namespace dbus
diff --git a/dbus/mock_exported_object.h b/dbus/mock_exported_object.h
new file mode 100644
index 0000000..17a36d0
--- /dev/null
+++ b/dbus/mock_exported_object.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DBUS_MOCK_EXPORTED_OBJECT_H_
+#define DBUS_MOCK_EXPORTED_OBJECT_H_
+#pragma once
+
+#include <string>
+
+#include "dbus/exported_object.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace dbus {
+
+// Mock for ExportedObject.
+class MockExportedObject : public ExportedObject {
+ public:
+ MockExportedObject(Bus* bus,
+ const std::string& service_name,
+ const std::string& object_path);
+ virtual ~MockExportedObject();
+
+ MOCK_METHOD3(ExportMethodAndBlock,
+ bool(const std::string& interface_name,
+ const std::string& method_name,
+ MethodCallCallback method_call_callback));
+ MOCK_METHOD4(ExportMethod,
+ void(const std::string& interface_name,
+ const std::string& method_name,
+ MethodCallCallback method_call_callback,
+ OnExportedCallback on_exported_callback));
+ MOCK_METHOD1(SendSignal, void(Signal* signal));
+ MOCK_METHOD0(Unregister, void());
+};
+
+} // namespace dbus
+
+#endif // DBUS_MOCK_EXPORTED_OBJECT_H_
diff --git a/dbus/mock_object_proxy.cc b/dbus/mock_object_proxy.cc
new file mode 100644
index 0000000..d58a604
--- /dev/null
+++ b/dbus/mock_object_proxy.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2011 The Chromium 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/mock_object_proxy.h"
+
+namespace dbus {
+
+MockObjectProxy::MockObjectProxy(Bus* bus,
+ const std::string& service_name,
+ const std::string& object_path)
+ : ObjectProxy(bus, service_name, object_path) {
+}
+
+MockObjectProxy::~MockObjectProxy() {
+}
+
+} // namespace dbus
diff --git a/dbus/mock_object_proxy.h b/dbus/mock_object_proxy.h
new file mode 100644
index 0000000..b5d4477
--- /dev/null
+++ b/dbus/mock_object_proxy.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DBUS_MOCK_OBJECT_PROXY_H_
+#define DBUS_MOCK_OBJECT_PROXY_H_
+#pragma once
+
+#include <string>
+
+#include "dbus/object_proxy.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace dbus {
+
+// Mock for ObjectProxy.
+class MockObjectProxy : public ObjectProxy {
+ public:
+ MockObjectProxy(Bus* bus,
+ const std::string& service_name,
+ const std::string& object_path);
+ virtual ~MockObjectProxy();
+
+ MOCK_METHOD2(CallMethodAndBlock, Response*(MethodCall* method_call,
+ int timeout_ms));
+ MOCK_METHOD3(CallMethod, void(MethodCall* method_call,
+ int timeout_ms,
+ ResponseCallback callback));
+ MOCK_METHOD4(ConnectToSignal,
+ void(const std::string& interface_name,
+ const std::string& signal_name,
+ SignalCallback signal_callback,
+ OnConnectedCallback on_connected_callback));
+ MOCK_METHOD0(Detach, void());
+};
+
+} // namespace dbus
+
+#endif // DBUS_MOCK_OBJECT_PROXY_H_
diff --git a/dbus/mock_unittest.cc b/dbus/mock_unittest.cc
new file mode 100644
index 0000000..f0289cf
--- /dev/null
+++ b/dbus/mock_unittest.cc
@@ -0,0 +1,171 @@
+// Copyright (c) 2011 The Chromium 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 "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "dbus/message.h"
+#include "dbus/mock_bus.h"
+#include "dbus/mock_object_proxy.h"
+#include "dbus/mock_exported_object.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::Unused;
+
+class MockTest : public testing::Test {
+ public:
+ MockTest() {
+ }
+
+ void SetUp() {
+ // Create a mock bus.
+ dbus::Bus::Options options;
+ options.bus_type = dbus::Bus::SYSTEM;
+ mock_bus_ = new dbus::MockBus(options);
+
+ // Create a mock proxy.
+ mock_proxy_ = new dbus::MockObjectProxy(mock_bus_.get(),
+ "org.chromium.TestService",
+ "/org/chromium/TestObject");
+
+ // Set an expectation so mock_proxy's CallMethodAndBlock() will use
+ // CreateMockProxyResponse() to return responses.
+ EXPECT_CALL(*mock_proxy_, CallMethodAndBlock(_, _))
+ .WillRepeatedly(Invoke(this, &MockTest::CreateMockProxyResponse));
+
+ // Set an expectation so mock_proxy's CallMethod() will use
+ // HandleMockProxyResponseWithMessageLoop() to return responses.
+ EXPECT_CALL(*mock_proxy_, CallMethod(_, _, _))
+ .WillRepeatedly(
+ Invoke(this,
+ &MockTest::HandleMockProxyResponseWithMessageLoop));
+
+ // Set an expectation so mock_bus's GetObjectProxy() for the given
+ // service name and the object path will return mock_proxy_.
+ EXPECT_CALL(*mock_bus_, GetObjectProxy("org.chromium.TestService",
+ "/org/chromium/TestObject"))
+ .WillOnce(Return(mock_proxy_.get()));
+ }
+
+ // Called when the response is received.
+ void OnResponse(dbus::Response* response) {
+ // |response| will be deleted on exit of the function. Copy the
+ // payload to |response_string_|.
+ if (response) {
+ dbus::MessageReader reader(response);
+ ASSERT_TRUE(reader.PopString(&response_string_));
+ }
+ message_loop_.Quit();
+ };
+
+ protected:
+ std::string response_string_;
+ MessageLoop message_loop_;
+ scoped_refptr<dbus::MockBus> mock_bus_;
+ scoped_refptr<dbus::MockObjectProxy> mock_proxy_;
+
+ private:
+ // Returns a response for the given method call. Used to implement
+ // CallMethodAndBlock() for |mock_proxy_|.
+ dbus::Response* CreateMockProxyResponse(dbus::MethodCall* method_call,
+ int timeout_ms) {
+ if (method_call->GetInterface() == "org.chromium.TestInterface" &&
+ method_call->GetMember() == "Echo") {
+ dbus::MessageReader reader(method_call);
+ std::string text_message;
+ if (reader.PopString(&text_message)) {
+ dbus::Response* response = dbus::Response::CreateEmpty();
+ dbus::MessageWriter writer(response);
+ writer.AppendString(text_message);
+ return response;
+ }
+ }
+
+ LOG(ERROR) << "Unexpected method call: " << method_call->ToString();
+ return NULL;
+ }
+
+ // Creates a response and runs the given response callback in the
+ // message loop with the response. Used to implement for |mock_proxy_|.
+ void HandleMockProxyResponseWithMessageLoop(
+ dbus::MethodCall* method_call,
+ int timeout_ms,
+ dbus::ObjectProxy::ResponseCallback response_callback) {
+ dbus::Response* response = CreateMockProxyResponse(method_call,
+ timeout_ms);
+ message_loop_.PostTask(FROM_HERE,
+ base::Bind(&MockTest::RunResponseCallback,
+ base::Unretained(this),
+ response_callback,
+ response));
+ }
+
+ // Runs the given response callback with the given response.
+ void RunResponseCallback(
+ dbus::ObjectProxy::ResponseCallback response_callback,
+ dbus::Response* response) {
+ response_callback.Run(response);
+ delete response;
+ }
+};
+
+// This test demonstrates how to mock a synchronos method call using the
+// mock classes.
+TEST_F(MockTest, CallMethodAndBlock) {
+ const char kHello[] = "Hello";
+ // Get an object proxy from the mock bus.
+ dbus::ObjectProxy* proxy = mock_bus_->GetObjectProxy(
+ "org.chromium.TestService",
+ "/org/chromium/TestObject");
+
+ // Create a method call.
+ dbus::MethodCall method_call("org.chromium.TestInterface", "Echo");
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(kHello);
+
+ // Call the method.
+ scoped_ptr<dbus::Response> response(
+ proxy->CallMethodAndBlock(&method_call,
+ dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
+
+ // Check the response.
+ ASSERT_TRUE(response.get());
+ dbus::MessageReader reader(response.get());
+ std::string text_message;
+ ASSERT_TRUE(reader.PopString(&text_message));
+ // The text message should be echo'ed back.
+ EXPECT_EQ(kHello, text_message);
+}
+
+// This test demonstrates how to mock an asynchronos method call using the
+// mock classes.
+TEST_F(MockTest, CallMethod) {
+ const char kHello[] = "hello";
+
+ // Get an object proxy from the mock bus.
+ dbus::ObjectProxy* proxy = mock_bus_->GetObjectProxy(
+ "org.chromium.TestService",
+ "/org/chromium/TestObject");
+
+ // Create a method call.
+ dbus::MethodCall method_call("org.chromium.TestInterface", "Echo");
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(kHello);
+
+ // Call the method.
+ proxy->CallMethod(&method_call,
+ dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&MockTest::OnResponse,
+ base::Unretained(this)));
+ // Run the message loop to let OnResponse be called.
+ message_loop_.Run();
+
+ EXPECT_EQ(kHello, response_string_);
+}
diff --git a/dbus/object_proxy.h b/dbus/object_proxy.h
index ae9bd9a3..f75e330 100644
--- a/dbus/object_proxy.h
+++ b/dbus/object_proxy.h
@@ -6,6 +6,7 @@
#define DBUS_OBJECT_PROXY_H_
#pragma once
+#include <map>
#include <string>
#include <vector>
#include <dbus/dbus.h>
@@ -104,9 +105,12 @@ class ObjectProxy : public base::RefCountedThreadSafe<ObjectProxy> {
// BLOCKING CALL.
virtual void Detach();
+ protected:
+ // This is protected, so we can define sub classes.
+ virtual ~ObjectProxy();
+
private:
friend class base::RefCountedThreadSafe<ObjectProxy>;
- virtual ~ObjectProxy();
// Struct of data we'll be passing from StartAsyncMethodCall() to
// OnPendingCallIsCompleteThunk().