15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
99ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/message.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/mock_bus.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/mock_exported_object.h"
139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "dbus/mock_object_proxy.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/object_path.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gmock/include/gmock/gmock.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ::testing::_;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ::testing::Invoke;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ::testing::Return;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ::testing::Unused;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)namespace dbus {
247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MockTest : public testing::Test {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockTest() {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void SetUp() {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Create a mock bus.
327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    Bus::Options options;
337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    options.bus_type = Bus::SYSTEM;
347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    mock_bus_ = new MockBus(options);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Create a mock proxy.
377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    mock_proxy_ = new MockObjectProxy(
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mock_bus_.get(),
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "org.chromium.TestService",
407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        ObjectPath("/org/chromium/TestObject"));
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Set an expectation so mock_proxy's CallMethodAndBlock() will use
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // CreateMockProxyResponse() to return responses.
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EXPECT_CALL(*mock_proxy_.get(), MockCallMethodAndBlock(_, _))
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        .WillRepeatedly(Invoke(this, &MockTest::CreateMockProxyResponse));
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Set an expectation so mock_proxy's CallMethod() will use
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // HandleMockProxyResponseWithMessageLoop() to return responses.
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EXPECT_CALL(*mock_proxy_.get(), CallMethod(_, _, _)).WillRepeatedly(
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        Invoke(this, &MockTest::HandleMockProxyResponseWithMessageLoop));
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Set an expectation so mock_bus's GetObjectProxy() for the given
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // service name and the object path will return mock_proxy_.
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EXPECT_CALL(*mock_bus_.get(),
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                GetObjectProxy("org.chromium.TestService",
567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                               ObjectPath("/org/chromium/TestObject")))
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        .WillOnce(Return(mock_proxy_.get()));
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ShutdownAndBlock() will be called in TearDown().
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()).WillOnce(Return());
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void TearDown() {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mock_bus_->ShutdownAndBlock();
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called when the response is received.
687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  void OnResponse(Response* response) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |response| will be deleted on exit of the function. Copy the
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // payload to |response_string_|.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (response) {
727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      MessageReader reader(response);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ASSERT_TRUE(reader.PopString(&response_string_));
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop_.Quit();
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string response_string_;
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoop message_loop_;
817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scoped_refptr<MockBus> mock_bus_;
827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scoped_refptr<MockObjectProxy> mock_proxy_;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns a response for the given method call. Used to implement
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CallMethodAndBlock() for |mock_proxy_|.
877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Response* CreateMockProxyResponse(MethodCall* method_call,
887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                    int timeout_ms) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (method_call->GetInterface() == "org.chromium.TestInterface" &&
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        method_call->GetMember() == "Echo") {
917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      MessageReader reader(method_call);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string text_message;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (reader.PopString(&text_message)) {
947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        scoped_ptr<Response> response = Response::CreateEmpty();
957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        MessageWriter writer(response.get());
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        writer.AppendString(text_message);
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return response.release();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unexpected method call: " << method_call->ToString();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates a response and runs the given response callback in the
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // message loop with the response. Used to implement for |mock_proxy_|.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void HandleMockProxyResponseWithMessageLoop(
1087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      MethodCall* method_call,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int timeout_ms,
1107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      ObjectProxy::ResponseCallback response_callback) {
1117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    Response* response = CreateMockProxyResponse(method_call, timeout_ms);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop_.PostTask(FROM_HERE,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           base::Bind(&MockTest::RunResponseCallback,
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      base::Unretained(this),
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      response_callback,
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      response));
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Runs the given response callback with the given response.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RunResponseCallback(
1217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      ObjectProxy::ResponseCallback response_callback,
1227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      Response* response) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    response_callback.Run(response);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete response;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This test demonstrates how to mock a synchronos method call using the
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// mock classes.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(MockTest, CallMethodAndBlock) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char kHello[] = "Hello";
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get an object proxy from the mock bus.
1337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  ObjectProxy* proxy = mock_bus_->GetObjectProxy(
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "org.chromium.TestService",
1357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      ObjectPath("/org/chromium/TestObject"));
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a method call.
1387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  MethodCall method_call("org.chromium.TestInterface", "Echo");
1397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  MessageWriter writer(&method_call);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  writer.AppendString(kHello);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Call the method.
1437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scoped_ptr<Response> response(
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proxy->CallMethodAndBlock(&method_call,
1457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                ObjectProxy::TIMEOUT_USE_DEFAULT));
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check the response.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(response.get());
1497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  MessageReader reader(response.get());
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string text_message;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(reader.PopString(&text_message));
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The text message should be echo'ed back.
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(kHello, text_message);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This test demonstrates how to mock an asynchronos method call using the
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// mock classes.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(MockTest, CallMethod) {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char kHello[] = "hello";
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get an object proxy from the mock bus.
1627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  ObjectProxy* proxy = mock_bus_->GetObjectProxy(
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "org.chromium.TestService",
1647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      ObjectPath("/org/chromium/TestObject"));
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a method call.
1677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  MethodCall method_call("org.chromium.TestInterface", "Echo");
1687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  MessageWriter writer(&method_call);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  writer.AppendString(kHello);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Call the method.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  proxy->CallMethod(&method_call,
1737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                    ObjectProxy::TIMEOUT_USE_DEFAULT,
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    base::Bind(&MockTest::OnResponse,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               base::Unretained(this)));
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run the message loop to let OnResponse be called.
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_.Run();
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(kHello, response_string_);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}  // namespace dbus
183