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 "chromeos/dbus/modem_messaging_client.h"
6
7#include "base/bind.h"
8#include "base/message_loop/message_loop.h"
9#include "base/values.h"
10#include "dbus/message.h"
11#include "dbus/mock_bus.h"
12#include "dbus/mock_object_proxy.h"
13#include "dbus/object_path.h"
14#include "dbus/values_util.h"
15#include "testing/gmock/include/gmock/gmock.h"
16#include "testing/gtest/include/gtest/gtest.h"
17#include "third_party/cros_system_api/dbus/service_constants.h"
18
19using ::testing::_;
20using ::testing::Invoke;
21using ::testing::Return;
22
23namespace chromeos {
24
25namespace {
26
27// A mock SmsReceivedHandler.
28class MockSmsReceivedHandler {
29 public:
30  MOCK_METHOD2(Run, void(const dbus::ObjectPath &sms, bool complete));
31};
32
33// A mock DeleteCallback.
34class MockDeleteCallback {
35 public:
36  MOCK_METHOD0(Run, void());
37};
38
39// A mock ListCallback.
40class MockListCallback {
41 public:
42  MOCK_METHOD1(Run, void(const std::vector<dbus::ObjectPath>& result));
43};
44
45// D-Bus service name used by test.
46const char kServiceName[] = "service.name";
47// D-Bus object path used by test.
48const char kObjectPath[] = "/object/path";
49
50}  // namespace
51
52class ModemMessagingClientTest : public testing::Test {
53 public:
54  ModemMessagingClientTest() : response_(NULL),
55                               expected_result_(NULL) {}
56
57  virtual void SetUp() OVERRIDE {
58    // Create a mock bus.
59    dbus::Bus::Options options;
60    options.bus_type = dbus::Bus::SYSTEM;
61    mock_bus_ = new dbus::MockBus(options);
62
63    // Create a mock proxy.
64    mock_proxy_ = new dbus::MockObjectProxy(mock_bus_.get(),
65                                            kServiceName,
66                                            dbus::ObjectPath(kObjectPath));
67
68    // Set an expectation so mock_proxy's ConnectToSignal() will use
69    // OnConnectToSignal() to run the callback.
70    EXPECT_CALL(*mock_proxy_.get(),
71                ConnectToSignal(modemmanager::kModemManager1MessagingInterface,
72                                modemmanager::kSMSAddedSignal,
73                                _,
74                                _))
75        .WillRepeatedly(
76             Invoke(this, &ModemMessagingClientTest::OnConnectToSignal));
77
78    // Set an expectation so mock_bus's GetObjectProxy() for the given
79    // service name and the object path will return mock_proxy_.
80    EXPECT_CALL(*mock_bus_.get(),
81                GetObjectProxy(kServiceName, dbus::ObjectPath(kObjectPath)))
82        .WillOnce(Return(mock_proxy_.get()));
83
84    // ShutdownAndBlock() will be called in TearDown().
85    EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()).WillOnce(Return());
86
87    // Create a client with the mock bus.
88    client_.reset(ModemMessagingClient::Create());
89    client_->Init(mock_bus_.get());
90  }
91
92  virtual void TearDown() OVERRIDE {
93    mock_bus_->ShutdownAndBlock();
94  }
95
96  // Handles Delete method call.
97  void OnDelete(dbus::MethodCall* method_call,
98                int timeout_ms,
99                const dbus::ObjectProxy::ResponseCallback& callback) {
100    EXPECT_EQ(modemmanager::kModemManager1MessagingInterface,
101              method_call->GetInterface());
102    EXPECT_EQ(modemmanager::kSMSDeleteFunction, method_call->GetMember());
103    dbus::ObjectPath sms_path;
104    dbus::MessageReader reader(method_call);
105    EXPECT_TRUE(reader.PopObjectPath(&sms_path));
106    EXPECT_EQ(expected_sms_path_, sms_path);
107    EXPECT_FALSE(reader.HasMoreData());
108
109    message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_));
110  }
111
112  // Handles List method call.
113  void OnList(dbus::MethodCall* method_call,
114              int timeout_ms,
115              const dbus::ObjectProxy::ResponseCallback& callback) {
116    EXPECT_EQ(modemmanager::kModemManager1MessagingInterface,
117              method_call->GetInterface());
118    EXPECT_EQ(modemmanager::kSMSListFunction, method_call->GetMember());
119    dbus::MessageReader reader(method_call);
120    EXPECT_FALSE(reader.HasMoreData());
121
122    message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_));
123  }
124
125  // Checks the results of List.
126  void CheckResult(const std::vector<dbus::ObjectPath>& result) {
127    EXPECT_EQ(result, *expected_result_);
128  }
129
130 protected:
131  // The client to be tested.
132  scoped_ptr<ModemMessagingClient> client_;
133  // A message loop to emulate asynchronous behavior.
134  base::MessageLoop message_loop_;
135  // The mock bus.
136  scoped_refptr<dbus::MockBus> mock_bus_;
137  // The mock object proxy.
138  scoped_refptr<dbus::MockObjectProxy> mock_proxy_;
139  // The SmsReceived signal handler given by the tested client.
140  dbus::ObjectProxy::SignalCallback sms_received_callback_;
141  // Expected argument for Delete method.
142  dbus::ObjectPath expected_sms_path_;
143  // Response returned by mock methods.
144  dbus::Response* response_;
145  // Expected result of List method.
146  std::vector<dbus::ObjectPath>* expected_result_;
147
148 private:
149  // Used to implement the mock proxy.
150  void OnConnectToSignal(
151      const std::string& interface_name,
152      const std::string& signal_name,
153      const dbus::ObjectProxy::SignalCallback& signal_callback,
154      const dbus::ObjectProxy::OnConnectedCallback& on_connected_callback) {
155    sms_received_callback_ = signal_callback;
156    const bool success = true;
157    message_loop_.PostTask(FROM_HERE, base::Bind(on_connected_callback,
158                                                 interface_name,
159                                                 signal_name,
160                                                 success));
161  }
162};
163
164TEST_F(ModemMessagingClientTest, SmsReceived) {
165  // Set expectations.
166  const dbus::ObjectPath kSmsPath("/SMS/0");
167  const bool kComplete = true;
168  MockSmsReceivedHandler handler;
169  EXPECT_CALL(handler, Run(kSmsPath, kComplete)).Times(1);
170  // Set handler.
171  client_->SetSmsReceivedHandler(kServiceName, dbus::ObjectPath(kObjectPath),
172                                 base::Bind(&MockSmsReceivedHandler::Run,
173                                            base::Unretained(&handler)));
174
175  // Run the message loop to run the signal connection result callback.
176  message_loop_.RunUntilIdle();
177
178  // Send signal.
179  dbus::Signal signal(modemmanager::kModemManager1MessagingInterface,
180                      modemmanager::kSMSAddedSignal);
181  dbus::MessageWriter writer(&signal);
182  writer.AppendObjectPath(kSmsPath);
183  writer.AppendBool(kComplete);
184  ASSERT_FALSE(sms_received_callback_.is_null());
185  sms_received_callback_.Run(&signal);
186  // Reset handler.
187  client_->ResetSmsReceivedHandler(kServiceName, dbus::ObjectPath(kObjectPath));
188  // Send signal again.
189  sms_received_callback_.Run(&signal);
190}
191
192TEST_F(ModemMessagingClientTest, Delete) {
193  // Set expectations.
194  const dbus::ObjectPath kSmsPath("/SMS/0");
195  expected_sms_path_ = kSmsPath;
196  EXPECT_CALL(*mock_proxy_.get(), CallMethod(_, _, _))
197      .WillOnce(Invoke(this, &ModemMessagingClientTest::OnDelete));
198  MockDeleteCallback callback;
199  EXPECT_CALL(callback, Run()).Times(1);
200  // Create response.
201  scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
202  response_ = response.get();
203  // Call Delete.
204  client_->Delete(kServiceName, dbus::ObjectPath(kObjectPath), kSmsPath,
205                  base::Bind(&MockDeleteCallback::Run,
206                             base::Unretained(&callback)));
207
208  // Run the message loop.
209  message_loop_.RunUntilIdle();
210}
211
212TEST_F(ModemMessagingClientTest, List) {
213  // Set expectations.
214  EXPECT_CALL(*mock_proxy_.get(), CallMethod(_, _, _))
215      .WillOnce(Invoke(this, &ModemMessagingClientTest::OnList));
216  MockListCallback callback;
217  EXPECT_CALL(callback, Run(_))
218      .WillOnce(Invoke(this, &ModemMessagingClientTest::CheckResult));
219  // Create response.
220  scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
221  dbus::ObjectPath path1("/SMS/1");
222  dbus::ObjectPath path2("/SMS/2");
223  std::vector<dbus::ObjectPath> expected_result;
224  expected_result.push_back(path1);
225  expected_result.push_back(path2);
226
227  dbus::MessageWriter writer(response.get());
228  writer.AppendArrayOfObjectPaths(expected_result);
229  response_ = response.get();
230
231  // Save expected result.
232  expected_result_ = &expected_result;
233  // Call List.
234  client_->List(kServiceName, dbus::ObjectPath(kObjectPath),
235                base::Bind(&MockListCallback::Run,
236                           base::Unretained(&callback)));
237
238  // Run the message loop.
239  message_loop_.RunUntilIdle();
240}
241
242}  // namespace chromeos
243