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/gsm_sms_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 19 using ::testing::_; 20 using ::testing::Invoke; 21 using ::testing::Return; 22 23 namespace chromeos { 24 25 namespace { 26 27 // A mock SmsReceivedHandler. 28 class MockSmsReceivedHandler { 29 public: 30 MOCK_METHOD2(Run, void(uint32 index, bool complete)); 31 }; 32 33 // A mock DeleteCallback. 34 class MockDeleteCallback { 35 public: 36 MOCK_METHOD0(Run, void()); 37 }; 38 39 // A mock GetCallback. 40 class MockGetCallback { 41 public: 42 MOCK_METHOD1(Run, void(const base::DictionaryValue& sms)); 43 }; 44 45 // A mock ListCallback. 46 class MockListCallback { 47 public: 48 MOCK_METHOD1(Run, void(const base::ListValue& result)); 49 }; 50 51 // D-Bus service name used by test. 52 const char kServiceName[] = "service.name"; 53 // D-Bus object path used by test. 54 const char kObjectPath[] = "/object/path"; 55 56 // Keys of SMS dictionary. 57 const char kNumberKey[] = "number"; 58 const char kTextKey[] = "text"; 59 60 // Example values of SMS dictionary. 61 const char kExampleNumber[] = "00012345678"; 62 const char kExampleText[] = "Hello."; 63 64 } // namespace 65 66 class GsmSMSClientTest : public testing::Test { 67 public: 68 GsmSMSClientTest() : expected_index_(0), 69 response_(NULL), 70 expected_result_(NULL) {} 71 72 virtual void SetUp() OVERRIDE { 73 // Create a mock bus. 74 dbus::Bus::Options options; 75 options.bus_type = dbus::Bus::SYSTEM; 76 mock_bus_ = new dbus::MockBus(options); 77 78 // Create a mock proxy. 79 mock_proxy_ = new dbus::MockObjectProxy(mock_bus_.get(), 80 kServiceName, 81 dbus::ObjectPath(kObjectPath)); 82 83 // Set an expectation so mock_proxy's ConnectToSignal() will use 84 // OnConnectToSignal() to run the callback. 85 EXPECT_CALL(*mock_proxy_.get(), 86 ConnectToSignal(modemmanager::kModemManagerSMSInterface, 87 modemmanager::kSMSReceivedSignal, 88 _, 89 _)) 90 .WillRepeatedly(Invoke(this, &GsmSMSClientTest::OnConnectToSignal)); 91 92 // Set an expectation so mock_bus's GetObjectProxy() for the given 93 // service name and the object path will return mock_proxy_. 94 EXPECT_CALL(*mock_bus_.get(), 95 GetObjectProxy(kServiceName, dbus::ObjectPath(kObjectPath))) 96 .WillOnce(Return(mock_proxy_.get())); 97 98 // ShutdownAndBlock() will be called in TearDown(). 99 EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()).WillOnce(Return()); 100 101 // Create a client with the mock bus. 102 client_.reset(GsmSMSClient::Create()); 103 client_->Init(mock_bus_.get()); 104 } 105 106 virtual void TearDown() OVERRIDE { 107 mock_bus_->ShutdownAndBlock(); 108 } 109 110 // Handles Delete method call. 111 void OnDelete(dbus::MethodCall* method_call, 112 int timeout_ms, 113 const dbus::ObjectProxy::ResponseCallback& callback) { 114 EXPECT_EQ(modemmanager::kModemManagerSMSInterface, 115 method_call->GetInterface()); 116 EXPECT_EQ(modemmanager::kSMSDeleteFunction, method_call->GetMember()); 117 uint32 index = 0; 118 dbus::MessageReader reader(method_call); 119 EXPECT_TRUE(reader.PopUint32(&index)); 120 EXPECT_EQ(expected_index_, index); 121 EXPECT_FALSE(reader.HasMoreData()); 122 123 message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_)); 124 } 125 126 // Handles Get method call. 127 void OnGet(dbus::MethodCall* method_call, 128 int timeout_ms, 129 const dbus::ObjectProxy::ResponseCallback& callback) { 130 EXPECT_EQ(modemmanager::kModemManagerSMSInterface, 131 method_call->GetInterface()); 132 EXPECT_EQ(modemmanager::kSMSGetFunction, method_call->GetMember()); 133 uint32 index = 0; 134 dbus::MessageReader reader(method_call); 135 EXPECT_TRUE(reader.PopUint32(&index)); 136 EXPECT_EQ(expected_index_, index); 137 EXPECT_FALSE(reader.HasMoreData()); 138 139 message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_)); 140 } 141 142 // Handles List method call. 143 void OnList(dbus::MethodCall* method_call, 144 int timeout_ms, 145 const dbus::ObjectProxy::ResponseCallback& callback) { 146 EXPECT_EQ(modemmanager::kModemManagerSMSInterface, 147 method_call->GetInterface()); 148 EXPECT_EQ(modemmanager::kSMSListFunction, method_call->GetMember()); 149 dbus::MessageReader reader(method_call); 150 EXPECT_FALSE(reader.HasMoreData()); 151 152 message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_)); 153 } 154 155 // Checks the results of Get and List. 156 void CheckResult(const base::Value& result) { 157 EXPECT_TRUE(result.Equals(expected_result_)); 158 } 159 160 protected: 161 // The client to be tested. 162 scoped_ptr<GsmSMSClient> client_; 163 // A message loop to emulate asynchronous behavior. 164 base::MessageLoop message_loop_; 165 // The mock bus. 166 scoped_refptr<dbus::MockBus> mock_bus_; 167 // The mock object proxy. 168 scoped_refptr<dbus::MockObjectProxy> mock_proxy_; 169 // The SmsReceived signal handler given by the tested client. 170 dbus::ObjectProxy::SignalCallback sms_received_callback_; 171 // Expected argument for Delete and Get methods. 172 uint32 expected_index_; 173 // Response returned by mock methods. 174 dbus::Response* response_; 175 // Expected result of Get and List methods. 176 base::Value* expected_result_; 177 178 private: 179 // Used to implement the mock proxy. 180 void OnConnectToSignal( 181 const std::string& interface_name, 182 const std::string& signal_name, 183 const dbus::ObjectProxy::SignalCallback& signal_callback, 184 const dbus::ObjectProxy::OnConnectedCallback& on_connected_callback) { 185 sms_received_callback_ = signal_callback; 186 const bool success = true; 187 message_loop_.PostTask(FROM_HERE, base::Bind(on_connected_callback, 188 interface_name, 189 signal_name, 190 success)); 191 } 192 }; 193 194 TEST_F(GsmSMSClientTest, SmsReceived) { 195 // Set expectations. 196 const uint32 kIndex = 42; 197 const bool kComplete = true; 198 MockSmsReceivedHandler handler; 199 EXPECT_CALL(handler, Run(kIndex, kComplete)).Times(1); 200 // Set handler. 201 client_->SetSmsReceivedHandler(kServiceName, dbus::ObjectPath(kObjectPath), 202 base::Bind(&MockSmsReceivedHandler::Run, 203 base::Unretained(&handler))); 204 205 // Run the message loop to run the signal connection result callback. 206 message_loop_.RunUntilIdle(); 207 208 // Send signal. 209 dbus::Signal signal(modemmanager::kModemManagerSMSInterface, 210 modemmanager::kSMSReceivedSignal); 211 dbus::MessageWriter writer(&signal); 212 writer.AppendUint32(kIndex); 213 writer.AppendBool(kComplete); 214 ASSERT_FALSE(sms_received_callback_.is_null()); 215 sms_received_callback_.Run(&signal); 216 // Reset handler. 217 client_->ResetSmsReceivedHandler(kServiceName, dbus::ObjectPath(kObjectPath)); 218 // Send signal again. 219 sms_received_callback_.Run(&signal); 220 } 221 222 TEST_F(GsmSMSClientTest, Delete) { 223 // Set expectations. 224 const uint32 kIndex = 42; 225 expected_index_ = kIndex; 226 EXPECT_CALL(*mock_proxy_.get(), CallMethod(_, _, _)) 227 .WillOnce(Invoke(this, &GsmSMSClientTest::OnDelete)); 228 MockDeleteCallback callback; 229 EXPECT_CALL(callback, Run()).Times(1); 230 // Create response. 231 scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); 232 response_ = response.get(); 233 // Call Delete. 234 client_->Delete(kServiceName, dbus::ObjectPath(kObjectPath), kIndex, 235 base::Bind(&MockDeleteCallback::Run, 236 base::Unretained(&callback))); 237 238 // Run the message loop. 239 message_loop_.RunUntilIdle(); 240 } 241 242 TEST_F(GsmSMSClientTest, Get) { 243 // Set expectations. 244 const uint32 kIndex = 42; 245 expected_index_ = kIndex; 246 EXPECT_CALL(*mock_proxy_.get(), CallMethod(_, _, _)) 247 .WillOnce(Invoke(this, &GsmSMSClientTest::OnGet)); 248 MockGetCallback callback; 249 EXPECT_CALL(callback, Run(_)) 250 .WillOnce(Invoke(this, &GsmSMSClientTest::CheckResult)); 251 // Create response. 252 scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); 253 dbus::MessageWriter writer(response.get()); 254 dbus::MessageWriter array_writer(NULL); 255 writer.OpenArray("{sv}", &array_writer); 256 dbus::MessageWriter entry_writer(NULL); 257 array_writer.OpenDictEntry(&entry_writer); 258 entry_writer.AppendString(kNumberKey); 259 entry_writer.AppendVariantOfString(kExampleNumber); 260 array_writer.CloseContainer(&entry_writer); 261 array_writer.OpenDictEntry(&entry_writer); 262 entry_writer.AppendString(kTextKey); 263 entry_writer.AppendVariantOfString(kExampleText); 264 array_writer.CloseContainer(&entry_writer); 265 writer.CloseContainer(&array_writer); 266 response_ = response.get(); 267 // Create expected result. 268 base::DictionaryValue expected_result; 269 expected_result.SetWithoutPathExpansion( 270 kNumberKey, base::Value::CreateStringValue(kExampleNumber)); 271 expected_result.SetWithoutPathExpansion( 272 kTextKey, base::Value::CreateStringValue(kExampleText)); 273 expected_result_ = &expected_result; 274 // Call Delete. 275 client_->Get(kServiceName, dbus::ObjectPath(kObjectPath), kIndex, 276 base::Bind(&MockGetCallback::Run, base::Unretained(&callback))); 277 278 // Run the message loop. 279 message_loop_.RunUntilIdle(); 280 } 281 282 TEST_F(GsmSMSClientTest, List) { 283 // Set expectations. 284 EXPECT_CALL(*mock_proxy_.get(), CallMethod(_, _, _)) 285 .WillOnce(Invoke(this, &GsmSMSClientTest::OnList)); 286 MockListCallback callback; 287 EXPECT_CALL(callback, Run(_)) 288 .WillOnce(Invoke(this, &GsmSMSClientTest::CheckResult)); 289 // Create response. 290 scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); 291 dbus::MessageWriter writer(response.get()); 292 dbus::MessageWriter array_writer(NULL); 293 writer.OpenArray("a{sv}", &array_writer); 294 dbus::MessageWriter sub_array_writer(NULL); 295 array_writer.OpenArray("{sv}", &sub_array_writer); 296 dbus::MessageWriter entry_writer(NULL); 297 sub_array_writer.OpenDictEntry(&entry_writer); 298 entry_writer.AppendString(kNumberKey); 299 entry_writer.AppendVariantOfString(kExampleNumber); 300 sub_array_writer.CloseContainer(&entry_writer); 301 sub_array_writer.OpenDictEntry(&entry_writer); 302 entry_writer.AppendString(kTextKey); 303 entry_writer.AppendVariantOfString(kExampleText); 304 sub_array_writer.CloseContainer(&entry_writer); 305 array_writer.CloseContainer(&sub_array_writer); 306 writer.CloseContainer(&array_writer); 307 response_ = response.get(); 308 // Create expected result. 309 base::ListValue expected_result; 310 base::DictionaryValue* sms = new base::DictionaryValue; 311 sms->SetWithoutPathExpansion( 312 kNumberKey, base::Value::CreateStringValue(kExampleNumber)); 313 sms->SetWithoutPathExpansion( 314 kTextKey, base::Value::CreateStringValue(kExampleText)); 315 expected_result.Append(sms); 316 expected_result_ = &expected_result; 317 // Call List. 318 client_->List(kServiceName, dbus::ObjectPath(kObjectPath), 319 base::Bind(&MockListCallback::Run, 320 base::Unretained(&callback))); 321 322 // Run the message loop. 323 message_loop_.RunUntilIdle(); 324 } 325 326 } // namespace chromeos 327