1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/bind.h" 6 #include "base/logging.h" 7 #include "base/memory/ref_counted.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/message_loop/message_loop.h" 10 #include "dbus/message.h" 11 #include "dbus/mock_bus.h" 12 #include "dbus/mock_exported_object.h" 13 #include "dbus/mock_object_proxy.h" 14 #include "dbus/object_path.h" 15 #include "testing/gmock/include/gmock/gmock.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 using ::testing::_; 19 using ::testing::Invoke; 20 using ::testing::Return; 21 using ::testing::Unused; 22 23 namespace dbus { 24 25 class MockTest : public testing::Test { 26 public: 27 MockTest() { 28 } 29 30 virtual void SetUp() { 31 // Create a mock bus. 32 Bus::Options options; 33 options.bus_type = Bus::SYSTEM; 34 mock_bus_ = new MockBus(options); 35 36 // Create a mock proxy. 37 mock_proxy_ = new MockObjectProxy( 38 mock_bus_.get(), 39 "org.chromium.TestService", 40 ObjectPath("/org/chromium/TestObject")); 41 42 // Set an expectation so mock_proxy's CallMethodAndBlock() will use 43 // CreateMockProxyResponse() to return responses. 44 EXPECT_CALL(*mock_proxy_.get(), MockCallMethodAndBlock(_, _)) 45 .WillRepeatedly(Invoke(this, &MockTest::CreateMockProxyResponse)); 46 47 // Set an expectation so mock_proxy's CallMethod() will use 48 // HandleMockProxyResponseWithMessageLoop() to return responses. 49 EXPECT_CALL(*mock_proxy_.get(), CallMethod(_, _, _)).WillRepeatedly( 50 Invoke(this, &MockTest::HandleMockProxyResponseWithMessageLoop)); 51 52 // Set an expectation so mock_bus's GetObjectProxy() for the given 53 // service name and the object path will return mock_proxy_. 54 EXPECT_CALL(*mock_bus_.get(), 55 GetObjectProxy("org.chromium.TestService", 56 ObjectPath("/org/chromium/TestObject"))) 57 .WillOnce(Return(mock_proxy_.get())); 58 59 // ShutdownAndBlock() will be called in TearDown(). 60 EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()).WillOnce(Return()); 61 } 62 63 virtual void TearDown() { 64 mock_bus_->ShutdownAndBlock(); 65 } 66 67 // Called when the response is received. 68 void OnResponse(Response* response) { 69 // |response| will be deleted on exit of the function. Copy the 70 // payload to |response_string_|. 71 if (response) { 72 MessageReader reader(response); 73 ASSERT_TRUE(reader.PopString(&response_string_)); 74 } 75 message_loop_.Quit(); 76 }; 77 78 protected: 79 std::string response_string_; 80 base::MessageLoop message_loop_; 81 scoped_refptr<MockBus> mock_bus_; 82 scoped_refptr<MockObjectProxy> mock_proxy_; 83 84 private: 85 // Returns a response for the given method call. Used to implement 86 // CallMethodAndBlock() for |mock_proxy_|. 87 Response* CreateMockProxyResponse(MethodCall* method_call, 88 int timeout_ms) { 89 if (method_call->GetInterface() == "org.chromium.TestInterface" && 90 method_call->GetMember() == "Echo") { 91 MessageReader reader(method_call); 92 std::string text_message; 93 if (reader.PopString(&text_message)) { 94 scoped_ptr<Response> response = Response::CreateEmpty(); 95 MessageWriter writer(response.get()); 96 writer.AppendString(text_message); 97 return response.release(); 98 } 99 } 100 101 LOG(ERROR) << "Unexpected method call: " << method_call->ToString(); 102 return NULL; 103 } 104 105 // Creates a response and runs the given response callback in the 106 // message loop with the response. Used to implement for |mock_proxy_|. 107 void HandleMockProxyResponseWithMessageLoop( 108 MethodCall* method_call, 109 int timeout_ms, 110 ObjectProxy::ResponseCallback response_callback) { 111 Response* response = CreateMockProxyResponse(method_call, timeout_ms); 112 message_loop_.PostTask(FROM_HERE, 113 base::Bind(&MockTest::RunResponseCallback, 114 base::Unretained(this), 115 response_callback, 116 response)); 117 } 118 119 // Runs the given response callback with the given response. 120 void RunResponseCallback( 121 ObjectProxy::ResponseCallback response_callback, 122 Response* response) { 123 response_callback.Run(response); 124 delete response; 125 } 126 }; 127 128 // This test demonstrates how to mock a synchronos method call using the 129 // mock classes. 130 TEST_F(MockTest, CallMethodAndBlock) { 131 const char kHello[] = "Hello"; 132 // Get an object proxy from the mock bus. 133 ObjectProxy* proxy = mock_bus_->GetObjectProxy( 134 "org.chromium.TestService", 135 ObjectPath("/org/chromium/TestObject")); 136 137 // Create a method call. 138 MethodCall method_call("org.chromium.TestInterface", "Echo"); 139 MessageWriter writer(&method_call); 140 writer.AppendString(kHello); 141 142 // Call the method. 143 scoped_ptr<Response> response( 144 proxy->CallMethodAndBlock(&method_call, 145 ObjectProxy::TIMEOUT_USE_DEFAULT)); 146 147 // Check the response. 148 ASSERT_TRUE(response.get()); 149 MessageReader reader(response.get()); 150 std::string text_message; 151 ASSERT_TRUE(reader.PopString(&text_message)); 152 // The text message should be echo'ed back. 153 EXPECT_EQ(kHello, text_message); 154 } 155 156 // This test demonstrates how to mock an asynchronos method call using the 157 // mock classes. 158 TEST_F(MockTest, CallMethod) { 159 const char kHello[] = "hello"; 160 161 // Get an object proxy from the mock bus. 162 ObjectProxy* proxy = mock_bus_->GetObjectProxy( 163 "org.chromium.TestService", 164 ObjectPath("/org/chromium/TestObject")); 165 166 // Create a method call. 167 MethodCall method_call("org.chromium.TestInterface", "Echo"); 168 MessageWriter writer(&method_call); 169 writer.AppendString(kHello); 170 171 // Call the method. 172 proxy->CallMethod(&method_call, 173 ObjectProxy::TIMEOUT_USE_DEFAULT, 174 base::Bind(&MockTest::OnResponse, 175 base::Unretained(this))); 176 // Run the message loop to let OnResponse be called. 177 message_loop_.Run(); 178 179 EXPECT_EQ(kHello, response_string_); 180 } 181 182 } // namespace dbus 183