16cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko// Copyright 2014 The Chromium OS Authors. All rights reserved.
26cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko// Use of this source code is governed by a BSD-style license that can be
36cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko// found in the LICENSE file.
46cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
59ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/dbus/dbus_method_invoker.h>
66cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
76cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko#include <string>
86cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
99ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/bind_lambda.h>
106cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko#include <dbus/mock_bus.h>
116cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko#include <dbus/mock_object_proxy.h>
12cabc46f5811343594b4b25a4a5ba976b9792d020Alex Vakulenko#include <dbus/scoped_dbus_error.h>
136cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko#include <gmock/gmock.h>
146cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko#include <gtest/gtest.h>
156cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
162df11639dd1dcfd9adca54235255d14249fe51fdAlex Vakulenko#include "brillo/dbus/test.pb.h"
17d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko
186cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenkousing testing::AnyNumber;
196cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenkousing testing::InSequence;
206cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenkousing testing::Invoke;
216cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenkousing testing::Return;
226cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenkousing testing::_;
236cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
246cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenkousing dbus::MessageReader;
256cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenkousing dbus::MessageWriter;
266cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenkousing dbus::Response;
276cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
289ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkonamespace brillo {
296cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenkonamespace dbus_utils {
306cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
316cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenkoconst char kTestPath[] = "/test/path";
326cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenkoconst char kTestServiceName[] = "org.test.Object";
336cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenkoconst char kTestInterface[] = "org.test.Object.TestInterface";
346cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenkoconst char kTestMethod1[] = "TestMethod1";
356cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenkoconst char kTestMethod2[] = "TestMethod2";
36d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenkoconst char kTestMethod3[] = "TestMethod3";
372d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenkoconst char kTestMethod4[] = "TestMethod4";
386cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
3905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenkoclass DBusMethodInvokerTest : public testing::Test {
406cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko public:
416cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko  void SetUp() override {
426cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    dbus::Bus::Options options;
436cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    options.bus_type = dbus::Bus::SYSTEM;
446cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    bus_ = new dbus::MockBus(options);
456cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    // By default, don't worry about threading assertions.
466cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
476cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
486cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    // Use a mock exported object.
496cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    mock_object_proxy_ = new dbus::MockObjectProxy(
506cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko        bus_.get(), kTestServiceName, dbus::ObjectPath(kTestPath));
5105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    EXPECT_CALL(*bus_,
5205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                GetObjectProxy(kTestServiceName, dbus::ObjectPath(kTestPath)))
536cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko        .WillRepeatedly(Return(mock_object_proxy_.get()));
546cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    int def_timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT;
55cabc46f5811343594b4b25a4a5ba976b9792d020Alex Vakulenko    EXPECT_CALL(*mock_object_proxy_,
56cabc46f5811343594b4b25a4a5ba976b9792d020Alex Vakulenko                MockCallMethodAndBlockWithErrorDetails(_, def_timeout_ms, _))
576cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko        .WillRepeatedly(Invoke(this, &DBusMethodInvokerTest::CreateResponse));
586cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko  }
596cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
6005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  void TearDown() override { bus_ = nullptr; }
616cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
62cabc46f5811343594b4b25a4a5ba976b9792d020Alex Vakulenko  Response* CreateResponse(dbus::MethodCall* method_call,
632fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley                           int /* timeout_ms */,
64cabc46f5811343594b4b25a4a5ba976b9792d020Alex Vakulenko                           dbus::ScopedDBusError* dbus_error) {
656cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    if (method_call->GetInterface() == kTestInterface) {
666cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko      if (method_call->GetMember() == kTestMethod1) {
676cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko        MessageReader reader(method_call);
686cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko        int v1, v2;
696cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko        // Input: two ints.
706cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko        // Output: sum of the ints converted to string.
716cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko        if (reader.PopInt32(&v1) && reader.PopInt32(&v2)) {
726cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko          auto response = Response::CreateEmpty();
736cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko          MessageWriter writer(response.get());
746cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko          writer.AppendString(std::to_string(v1 + v2));
756cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko          return response.release();
766cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko        }
776cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko      } else if (method_call->GetMember() == kTestMethod2) {
786cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko        method_call->SetSerial(123);
79cabc46f5811343594b4b25a4a5ba976b9792d020Alex Vakulenko        dbus_set_error(dbus_error->get(), "org.MyError", "My error message");
80cabc46f5811343594b4b25a4a5ba976b9792d020Alex Vakulenko        return nullptr;
81d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko      } else if (method_call->GetMember() == kTestMethod3) {
82d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko        MessageReader reader(method_call);
83d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko        dbus_utils_test::TestMessage msg;
84d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko        if (PopValueFromReader(&reader, &msg)) {
85d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko          auto response = Response::CreateEmpty();
86d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko          MessageWriter writer(response.get());
87d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko          AppendValueToWriter(&writer, msg);
88d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko          return response.release();
89d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko        }
902d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko      } else if (method_call->GetMember() == kTestMethod4) {
912d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko        method_call->SetSerial(123);
922d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko        MessageReader reader(method_call);
932d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko        dbus::FileDescriptor fd;
942d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko        if (reader.PopFileDescriptor(&fd)) {
952d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko          auto response = Response::CreateEmpty();
962d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko          MessageWriter writer(response.get());
972d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko          fd.CheckValidity();
982d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko          writer.AppendFileDescriptor(fd);
992d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko          return response.release();
1002d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko        }
1016cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko      }
1026cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    }
1036cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
1046cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    LOG(ERROR) << "Unexpected method call: " << method_call->ToString();
1056cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    return nullptr;
1066cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko  }
1076cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
1086cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko  std::string CallTestMethod(int v1, int v2) {
1096cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    std::unique_ptr<dbus::Response> response =
1109ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko        brillo::dbus_utils::CallMethodAndBlock(mock_object_proxy_.get(),
1119ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko                                               kTestInterface, kTestMethod1,
1129ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko                                               nullptr, v1, v2);
1136cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    EXPECT_NE(nullptr, response.get());
1146cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    std::string result;
1159ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    using brillo::dbus_utils::ExtractMethodCallResults;
1166cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    EXPECT_TRUE(ExtractMethodCallResults(response.get(), nullptr, &result));
1176cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko    return result;
1186cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko  }
1196cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
120d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko  dbus_utils_test::TestMessage CallProtobufTestMethod(
121d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko      const dbus_utils_test::TestMessage& message) {
122d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko    std::unique_ptr<dbus::Response> response =
1239ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko        brillo::dbus_utils::CallMethodAndBlock(mock_object_proxy_.get(),
1249ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko                                               kTestInterface, kTestMethod3,
1259ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko                                               nullptr, message);
126d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko    EXPECT_NE(nullptr, response.get());
127d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko    dbus_utils_test::TestMessage result;
1289ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    using brillo::dbus_utils::ExtractMethodCallResults;
129d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko    EXPECT_TRUE(ExtractMethodCallResults(response.get(), nullptr, &result));
130d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko    return result;
131d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko  }
132d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko
1332d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  // Sends a file descriptor received over D-Bus back to the caller.
1342d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  dbus::FileDescriptor EchoFD(const dbus::FileDescriptor& fd_in) {
1352d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko    std::unique_ptr<dbus::Response> response =
1369ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko        brillo::dbus_utils::CallMethodAndBlock(mock_object_proxy_.get(),
1379ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko                                               kTestInterface, kTestMethod4,
1389ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko                                               nullptr, fd_in);
1392d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko    EXPECT_NE(nullptr, response.get());
1402d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko    dbus::FileDescriptor fd_out;
1419ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    using brillo::dbus_utils::ExtractMethodCallResults;
1422d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko    EXPECT_TRUE(ExtractMethodCallResults(response.get(), nullptr, &fd_out));
14380b7ee94e36e2d25a97a262d3b558bbf130c2a01Alex Vakulenko    return fd_out;
1442d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  }
1452d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko
1466cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko  scoped_refptr<dbus::MockBus> bus_;
1476cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko  scoped_refptr<dbus::MockObjectProxy> mock_object_proxy_;
1486cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko};
1496cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
1506cd7f815cb865ac1a82429c5088147283595c3feAlex VakulenkoTEST_F(DBusMethodInvokerTest, TestSuccess) {
1516cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko  EXPECT_EQ("4", CallTestMethod(2, 2));
1526cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko  EXPECT_EQ("10", CallTestMethod(3, 7));
1536cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko  EXPECT_EQ("-4", CallTestMethod(13, -17));
1546cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko}
1556cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
156cabc46f5811343594b4b25a4a5ba976b9792d020Alex VakulenkoTEST_F(DBusMethodInvokerTest, TestFailure) {
1579ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  brillo::ErrorPtr error;
158cabc46f5811343594b4b25a4a5ba976b9792d020Alex Vakulenko  std::unique_ptr<dbus::Response> response =
1599ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko      brillo::dbus_utils::CallMethodAndBlock(
16005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko          mock_object_proxy_.get(), kTestInterface, kTestMethod2, &error);
161cabc46f5811343594b4b25a4a5ba976b9792d020Alex Vakulenko  EXPECT_EQ(nullptr, response.get());
1629ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  EXPECT_EQ(brillo::errors::dbus::kDomain, error->GetDomain());
163cabc46f5811343594b4b25a4a5ba976b9792d020Alex Vakulenko  EXPECT_EQ("org.MyError", error->GetCode());
164cabc46f5811343594b4b25a4a5ba976b9792d020Alex Vakulenko  EXPECT_EQ("My error message", error->GetMessage());
165cabc46f5811343594b4b25a4a5ba976b9792d020Alex Vakulenko}
1666cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko
167d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex VakulenkoTEST_F(DBusMethodInvokerTest, TestProtobuf) {
168d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko  dbus_utils_test::TestMessage test_message;
169d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko  test_message.set_foo(123);
170d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko  test_message.set_bar("bar");
171d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko
172d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko  dbus_utils_test::TestMessage resp = CallProtobufTestMethod(test_message);
173d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko
174d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko  EXPECT_EQ(123, resp.foo());
175d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko  EXPECT_EQ("bar", resp.bar());
176d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko}
177d0b4d8d45a727b082fa2948971c9b7ae31d4737fAlex Vakulenko
1782d33ad53c0207bab34e53a88d94ca949922d527bAlex VakulenkoTEST_F(DBusMethodInvokerTest, TestFileDescriptors) {
1792d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  // Passing a file descriptor over D-Bus would effectively duplicate the fd.
1802d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  // So the resulting file descriptor value would be different but it still
1812d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  // should be valid.
1822d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  dbus::FileDescriptor fd_stdin(0);
1832d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  fd_stdin.CheckValidity();
1842d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  EXPECT_NE(fd_stdin.value(), EchoFD(fd_stdin).value());
1852d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  dbus::FileDescriptor fd_stdout(1);
1862d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  fd_stdout.CheckValidity();
1872d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  EXPECT_NE(fd_stdout.value(), EchoFD(fd_stdout).value());
1882d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  dbus::FileDescriptor fd_stderr(2);
1892d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  fd_stderr.CheckValidity();
1902d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko  EXPECT_NE(fd_stderr.value(), EchoFD(fd_stderr).value());
1912d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko}
1922d33ad53c0207bab34e53a88d94ca949922d527bAlex Vakulenko
193973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko//////////////////////////////////////////////////////////////////////////////
194973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko// Asynchronous method invocation support
195973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
19605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenkoclass AsyncDBusMethodInvokerTest : public testing::Test {
197973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko public:
198973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  void SetUp() override {
199973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    dbus::Bus::Options options;
200973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    options.bus_type = dbus::Bus::SYSTEM;
201973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    bus_ = new dbus::MockBus(options);
202973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    // By default, don't worry about threading assertions.
203973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
204973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
205973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    // Use a mock exported object.
206973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    mock_object_proxy_ = new dbus::MockObjectProxy(
207973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko        bus_.get(), kTestServiceName, dbus::ObjectPath(kTestPath));
20805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    EXPECT_CALL(*bus_,
20905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                GetObjectProxy(kTestServiceName, dbus::ObjectPath(kTestPath)))
210973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko        .WillRepeatedly(Return(mock_object_proxy_.get()));
211973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    int def_timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT;
212973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    EXPECT_CALL(*mock_object_proxy_,
213973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko                CallMethodWithErrorCallback(_, def_timeout_ms, _, _))
21405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko        .WillRepeatedly(Invoke(this, &AsyncDBusMethodInvokerTest::HandleCall));
215973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  }
216973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
21705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  void TearDown() override { bus_ = nullptr; }
218973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
219973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  void HandleCall(dbus::MethodCall* method_call,
2202fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley                  int /* timeout_ms */,
221973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko                  dbus::ObjectProxy::ResponseCallback success_callback,
222973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko                  dbus::ObjectProxy::ErrorCallback error_callback) {
223973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    if (method_call->GetInterface() == kTestInterface) {
224973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      if (method_call->GetMember() == kTestMethod1) {
225973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko        MessageReader reader(method_call);
226973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko        int v1, v2;
227973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko        // Input: two ints.
228973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko        // Output: sum of the ints converted to string.
229973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko        if (reader.PopInt32(&v1) && reader.PopInt32(&v2)) {
230973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko          auto response = Response::CreateEmpty();
231973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko          MessageWriter writer(response.get());
232973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko          writer.AppendString(std::to_string(v1 + v2));
233973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko          success_callback.Run(response.get());
234973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko        }
235973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko        return;
236973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      } else if (method_call->GetMember() == kTestMethod2) {
237973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko        method_call->SetSerial(123);
238973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko        auto error_response = dbus::ErrorResponse::FromMethodCall(
239973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko            method_call, "org.MyError", "My error message");
240973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko        error_callback.Run(error_response.get());
241973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko        return;
242973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      }
243973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    }
244973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
245973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    LOG(FATAL) << "Unexpected method call: " << method_call->ToString();
246973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  }
247973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
248973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  struct SuccessCallback {
24905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    SuccessCallback(const std::string& in_result, int* in_counter)
25005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko        : result(in_result), counter(in_counter) {}
251973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
252973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    explicit SuccessCallback(int* in_counter) : counter(in_counter) {}
253973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
254973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    void operator()(const std::string& actual_result) {
255973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      (*counter)++;
256973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      EXPECT_EQ(result, actual_result);
257973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    }
258973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    std::string result;
259973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    int* counter;
260973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  };
261973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
262973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  struct ErrorCallback {
263973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    ErrorCallback(const std::string& in_domain,
264973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko                  const std::string& in_code,
265973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko                  const std::string& in_message,
266973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko                  int* in_counter)
267973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko        : domain(in_domain),
268973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko          code(in_code),
269973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko          message(in_message),
270973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko          counter(in_counter) {}
271973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
272973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    explicit ErrorCallback(int* in_counter) : counter(in_counter) {}
273973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
2749ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    void operator()(brillo::Error* error) {
275973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      (*counter)++;
276973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      EXPECT_NE(nullptr, error);
277973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      EXPECT_EQ(domain, error->GetDomain());
278973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      EXPECT_EQ(code, error->GetCode());
279973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      EXPECT_EQ(message, error->GetMessage());
280973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    }
281973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
282973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    std::string domain;
283973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    std::string code;
284973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    std::string message;
285973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko    int* counter;
286973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  };
287973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
288973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  scoped_refptr<dbus::MockBus> bus_;
289973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  scoped_refptr<dbus::MockObjectProxy> mock_object_proxy_;
290973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko};
291973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
292973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex VakulenkoTEST_F(AsyncDBusMethodInvokerTest, TestSuccess) {
293973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  int error_count = 0;
294973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  int success_count = 0;
2959ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  brillo::dbus_utils::CallMethod(
296973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      mock_object_proxy_.get(),
297973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      kTestInterface,
298973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      kTestMethod1,
299973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      base::Bind(SuccessCallback{"4", &success_count}),
300973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      base::Bind(ErrorCallback{&error_count}),
301973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      2, 2);
3029ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  brillo::dbus_utils::CallMethod(
303973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      mock_object_proxy_.get(),
304973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      kTestInterface,
305973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      kTestMethod1,
306973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      base::Bind(SuccessCallback{"10", &success_count}),
307973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      base::Bind(ErrorCallback{&error_count}),
308973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      3, 7);
3099ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  brillo::dbus_utils::CallMethod(
310973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      mock_object_proxy_.get(),
311973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      kTestInterface,
312973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      kTestMethod1,
313973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      base::Bind(SuccessCallback{"-4", &success_count}),
314973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      base::Bind(ErrorCallback{&error_count}),
315973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      13, -17);
316973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  EXPECT_EQ(0, error_count);
317973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  EXPECT_EQ(3, success_count);
318973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko}
319973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
320973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex VakulenkoTEST_F(AsyncDBusMethodInvokerTest, TestFailure) {
321973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  int error_count = 0;
322973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  int success_count = 0;
3239ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  brillo::dbus_utils::CallMethod(
324973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      mock_object_proxy_.get(),
325973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      kTestInterface,
326973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      kTestMethod2,
327973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      base::Bind(SuccessCallback{&success_count}),
3289ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko      base::Bind(ErrorCallback{brillo::errors::dbus::kDomain,
329973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko                               "org.MyError",
330973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko                               "My error message",
331973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko                               &error_count}),
332973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko      2, 2);
333973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  EXPECT_EQ(1, error_count);
334973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko  EXPECT_EQ(0, success_count);
335973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko}
336973ba0a0bbe2edd7a9a43f59f0a3343bf7d30e1cAlex Vakulenko
3376cd7f815cb865ac1a82429c5088147283595c3feAlex Vakulenko}  // namespace dbus_utils
3389ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko}  // namespace brillo
339