1// Copyright 2014 The Chromium OS 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 <brillo/dbus/dbus_signal_handler.h>
6
7#include <string>
8
9#include <brillo/bind_lambda.h>
10#include <brillo/dbus/dbus_param_writer.h>
11#include <dbus/mock_bus.h>
12#include <dbus/mock_object_proxy.h>
13#include <gmock/gmock.h>
14#include <gtest/gtest.h>
15
16using testing::AnyNumber;
17using testing::Return;
18using testing::SaveArg;
19using testing::_;
20
21namespace brillo {
22namespace dbus_utils {
23
24const char kTestPath[] = "/test/path";
25const char kTestServiceName[] = "org.test.Object";
26const char kInterface[] = "org.test.Object.TestInterface";
27const char kSignal[] = "TestSignal";
28
29class DBusSignalHandlerTest : public testing::Test {
30 public:
31  void SetUp() override {
32    dbus::Bus::Options options;
33    options.bus_type = dbus::Bus::SYSTEM;
34    bus_ = new dbus::MockBus(options);
35    // By default, don't worry about threading assertions.
36    EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
37    EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
38    // Use a mock object proxy.
39    mock_object_proxy_ = new dbus::MockObjectProxy(
40        bus_.get(), kTestServiceName, dbus::ObjectPath(kTestPath));
41    EXPECT_CALL(*bus_,
42                GetObjectProxy(kTestServiceName, dbus::ObjectPath(kTestPath)))
43        .WillRepeatedly(Return(mock_object_proxy_.get()));
44  }
45
46  void TearDown() override { bus_ = nullptr; }
47
48 protected:
49  template<typename SignalHandlerSink, typename... Args>
50  void CallSignal(SignalHandlerSink* sink, Args... args) {
51    dbus::ObjectProxy::SignalCallback signal_callback;
52    EXPECT_CALL(*mock_object_proxy_, ConnectToSignal(kInterface, kSignal, _, _))
53        .WillOnce(SaveArg<2>(&signal_callback));
54
55    brillo::dbus_utils::ConnectToSignal(
56        mock_object_proxy_.get(),
57        kInterface,
58        kSignal,
59        base::Bind(&SignalHandlerSink::Handler, base::Unretained(sink)),
60        {});
61
62    dbus::Signal signal(kInterface, kSignal);
63    dbus::MessageWriter writer(&signal);
64    DBusParamWriter::Append(&writer, args...);
65    signal_callback.Run(&signal);
66  }
67
68  scoped_refptr<dbus::MockBus> bus_;
69  scoped_refptr<dbus::MockObjectProxy> mock_object_proxy_;
70};
71
72TEST_F(DBusSignalHandlerTest, ConnectToSignal) {
73  EXPECT_CALL(*mock_object_proxy_, ConnectToSignal(kInterface, kSignal, _, _))
74      .Times(1);
75
76  brillo::dbus_utils::ConnectToSignal(
77      mock_object_proxy_.get(), kInterface, kSignal, base::Closure{}, {});
78}
79
80TEST_F(DBusSignalHandlerTest, CallSignal_3Args) {
81  class SignalHandlerSink {
82   public:
83    MOCK_METHOD3(Handler, void(int, int, double));
84  } sink;
85
86  EXPECT_CALL(sink, Handler(10, 20, 30.5)).Times(1);
87  CallSignal(&sink, 10, 20, 30.5);
88}
89
90TEST_F(DBusSignalHandlerTest, CallSignal_2Args) {
91  class SignalHandlerSink {
92   public:
93    // Take string both by reference and by value to make sure this works too.
94    MOCK_METHOD2(Handler, void(const std::string&, std::string));
95  } sink;
96
97  EXPECT_CALL(sink, Handler(std::string{"foo"}, std::string{"bar"})).Times(1);
98  CallSignal(&sink, std::string{"foo"}, std::string{"bar"});
99}
100
101TEST_F(DBusSignalHandlerTest, CallSignal_NoArgs) {
102  class SignalHandlerSink {
103   public:
104    MOCK_METHOD0(Handler, void());
105  } sink;
106
107  EXPECT_CALL(sink, Handler()).Times(1);
108  CallSignal(&sink);
109}
110
111TEST_F(DBusSignalHandlerTest, CallSignal_Error_TooManyArgs) {
112  class SignalHandlerSink {
113   public:
114    MOCK_METHOD0(Handler, void());
115  } sink;
116
117  // Handler() expects no args, but we send an int.
118  EXPECT_CALL(sink, Handler()).Times(0);
119  CallSignal(&sink, 5);
120}
121
122TEST_F(DBusSignalHandlerTest, CallSignal_Error_TooFewArgs) {
123  class SignalHandlerSink {
124   public:
125    MOCK_METHOD2(Handler, void(std::string, bool));
126  } sink;
127
128  // Handler() expects 2 args while we send it just one.
129  EXPECT_CALL(sink, Handler(_, _)).Times(0);
130  CallSignal(&sink, std::string{"bar"});
131}
132
133TEST_F(DBusSignalHandlerTest, CallSignal_Error_TypeMismatchArgs) {
134  class SignalHandlerSink {
135   public:
136    MOCK_METHOD2(Handler, void(std::string, bool));
137  } sink;
138
139  // Handler() expects "sb" while we send it "ii".
140  EXPECT_CALL(sink, Handler(_, _)).Times(0);
141  CallSignal(&sink, 1, 2);
142}
143
144}  // namespace dbus_utils
145}  // namespace brillo
146