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_object.h>
6 
7 #include <memory>
8 
9 #include <base/bind.h>
10 #include <brillo/dbus/dbus_object_test_helpers.h>
11 #include <brillo/dbus/mock_exported_object_manager.h>
12 #include <dbus/message.h>
13 #include <dbus/property.h>
14 #include <dbus/object_path.h>
15 #include <dbus/mock_bus.h>
16 #include <dbus/mock_exported_object.h>
17 
18 using ::testing::AnyNumber;
19 using ::testing::Return;
20 using ::testing::Invoke;
21 using ::testing::Mock;
22 using ::testing::_;
23 
24 namespace brillo {
25 namespace dbus_utils {
26 
27 namespace {
28 
29 const char kMethodsExportedOn[] = "/export";
30 
31 const char kTestInterface1[] = "org.chromium.Test.MathInterface";
32 const char kTestMethod_Add[] = "Add";
33 const char kTestMethod_Negate[] = "Negate";
34 const char kTestMethod_Positive[] = "Positive";
35 const char kTestMethod_AddSubtract[] = "AddSubtract";
36 
37 const char kTestInterface2[] = "org.chromium.Test.StringInterface";
38 const char kTestMethod_StrLen[] = "StrLen";
39 const char kTestMethod_CheckNonEmpty[] = "CheckNonEmpty";
40 
41 const char kTestInterface3[] = "org.chromium.Test.NoOpInterface";
42 const char kTestMethod_NoOp[] = "NoOp";
43 const char kTestMethod_WithMessage[] = "TestWithMessage";
44 const char kTestMethod_WithMessageAsync[] = "TestWithMessageAsync";
45 
46 struct Calc {
Addbrillo::dbus_utils::__anon531d6bc20111::Calc47   int Add(int x, int y) { return x + y; }
Negatebrillo::dbus_utils::__anon531d6bc20111::Calc48   int Negate(int x) { return -x; }
Positivebrillo::dbus_utils::__anon531d6bc20111::Calc49   void Positive(std::unique_ptr<DBusMethodResponse<double>> response,
50                 double x) {
51     if (x >= 0.0) {
52       response->Return(x);
53       return;
54     }
55     ErrorPtr error;
56     Error::AddTo(&error, FROM_HERE, "test", "not_positive",
57                  "Negative value passed in");
58     response->ReplyWithError(error.get());
59   }
AddSubtractbrillo::dbus_utils::__anon531d6bc20111::Calc60   void AddSubtract(int x, int y, int* sum, int* diff) {
61     *sum = x + y;
62     *diff = x - y;
63   }
64 };
65 
StrLen(const std::string & str)66 int StrLen(const std::string& str) {
67   return str.size();
68 }
69 
CheckNonEmpty(ErrorPtr * error,const std::string & str)70 bool CheckNonEmpty(ErrorPtr* error, const std::string& str) {
71   if (!str.empty())
72     return true;
73   Error::AddTo(error, FROM_HERE, "test", "string_empty", "String is empty");
74   return false;
75 }
76 
NoOp()77 void NoOp() {}
78 
TestWithMessage(ErrorPtr *,dbus::Message * message,std::string * str)79 bool TestWithMessage(ErrorPtr* /* error */,
80                      dbus::Message* message,
81                      std::string* str) {
82   *str = message->GetSender();
83   return true;
84 }
85 
TestWithMessageAsync(std::unique_ptr<DBusMethodResponse<std::string>> response,dbus::Message * message)86 void TestWithMessageAsync(
87     std::unique_ptr<DBusMethodResponse<std::string>> response,
88     dbus::Message* message) {
89   response->Return(message->GetSender());
90 }
91 
92 }  // namespace
93 
94 class DBusObjectTest : public ::testing::Test {
95  public:
SetUp()96   virtual void SetUp() {
97     dbus::Bus::Options options;
98     options.bus_type = dbus::Bus::SYSTEM;
99     bus_ = new dbus::MockBus(options);
100     // By default, don't worry about threading assertions.
101     EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
102     EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
103     // Use a mock exported object.
104     const dbus::ObjectPath kMethodsExportedOnPath{
105         std::string{kMethodsExportedOn}};
106     mock_exported_object_ =
107         new dbus::MockExportedObject(bus_.get(), kMethodsExportedOnPath);
108     EXPECT_CALL(*bus_, GetExportedObject(kMethodsExportedOnPath))
109         .Times(AnyNumber())
110         .WillRepeatedly(Return(mock_exported_object_.get()));
111     EXPECT_CALL(*mock_exported_object_, ExportMethod(_, _, _, _))
112         .Times(AnyNumber());
113     EXPECT_CALL(*mock_exported_object_, Unregister()).Times(1);
114 
115     dbus_object_ = std::unique_ptr<DBusObject>(
116         new DBusObject(nullptr, bus_, kMethodsExportedOnPath));
117 
118     DBusInterface* itf1 = dbus_object_->AddOrGetInterface(kTestInterface1);
119     itf1->AddSimpleMethodHandler(
120         kTestMethod_Add, base::Unretained(&calc_), &Calc::Add);
121     itf1->AddSimpleMethodHandler(
122         kTestMethod_Negate, base::Unretained(&calc_), &Calc::Negate);
123     itf1->AddMethodHandler(
124         kTestMethod_Positive, base::Unretained(&calc_), &Calc::Positive);
125     itf1->AddSimpleMethodHandler(
126         kTestMethod_AddSubtract, base::Unretained(&calc_), &Calc::AddSubtract);
127     DBusInterface* itf2 = dbus_object_->AddOrGetInterface(kTestInterface2);
128     itf2->AddSimpleMethodHandler(kTestMethod_StrLen, StrLen);
129     itf2->AddSimpleMethodHandlerWithError(kTestMethod_CheckNonEmpty,
130                                           CheckNonEmpty);
131     DBusInterface* itf3 = dbus_object_->AddOrGetInterface(kTestInterface3);
132     base::Callback<void()> noop_callback = base::Bind(NoOp);
133     itf3->AddSimpleMethodHandler(kTestMethod_NoOp, noop_callback);
134     itf3->AddSimpleMethodHandlerWithErrorAndMessage(
135         kTestMethod_WithMessage, base::Bind(&TestWithMessage));
136     itf3->AddMethodHandlerWithMessage(kTestMethod_WithMessageAsync,
137                                       base::Bind(&TestWithMessageAsync));
138 
139     dbus_object_->RegisterAsync(
140         AsyncEventSequencer::GetDefaultCompletionAction());
141   }
142 
ExpectError(dbus::Response * response,const std::string & expected_code)143   void ExpectError(dbus::Response* response, const std::string& expected_code) {
144     EXPECT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
145     EXPECT_EQ(expected_code, response->GetErrorName());
146   }
147 
148   scoped_refptr<dbus::MockBus> bus_;
149   scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
150   std::unique_ptr<DBusObject> dbus_object_;
151   Calc calc_;
152 };
153 
TEST_F(DBusObjectTest,Add)154 TEST_F(DBusObjectTest, Add) {
155   dbus::MethodCall method_call(kTestInterface1, kTestMethod_Add);
156   method_call.SetSerial(123);
157   dbus::MessageWriter writer(&method_call);
158   writer.AppendInt32(2);
159   writer.AppendInt32(3);
160   auto response = testing::CallMethod(*dbus_object_, &method_call);
161   dbus::MessageReader reader(response.get());
162   int result;
163   ASSERT_TRUE(reader.PopInt32(&result));
164   ASSERT_FALSE(reader.HasMoreData());
165   ASSERT_EQ(5, result);
166 }
167 
TEST_F(DBusObjectTest,Negate)168 TEST_F(DBusObjectTest, Negate) {
169   dbus::MethodCall method_call(kTestInterface1, kTestMethod_Negate);
170   method_call.SetSerial(123);
171   dbus::MessageWriter writer(&method_call);
172   writer.AppendInt32(98765);
173   auto response = testing::CallMethod(*dbus_object_, &method_call);
174   dbus::MessageReader reader(response.get());
175   int result;
176   ASSERT_TRUE(reader.PopInt32(&result));
177   ASSERT_FALSE(reader.HasMoreData());
178   ASSERT_EQ(-98765, result);
179 }
180 
TEST_F(DBusObjectTest,PositiveSuccess)181 TEST_F(DBusObjectTest, PositiveSuccess) {
182   dbus::MethodCall method_call(kTestInterface1, kTestMethod_Positive);
183   method_call.SetSerial(123);
184   dbus::MessageWriter writer(&method_call);
185   writer.AppendDouble(17.5);
186   auto response = testing::CallMethod(*dbus_object_, &method_call);
187   dbus::MessageReader reader(response.get());
188   double result;
189   ASSERT_TRUE(reader.PopDouble(&result));
190   ASSERT_FALSE(reader.HasMoreData());
191   ASSERT_DOUBLE_EQ(17.5, result);
192 }
193 
TEST_F(DBusObjectTest,PositiveFailure)194 TEST_F(DBusObjectTest, PositiveFailure) {
195   dbus::MethodCall method_call(kTestInterface1, kTestMethod_Positive);
196   method_call.SetSerial(123);
197   dbus::MessageWriter writer(&method_call);
198   writer.AppendDouble(-23.2);
199   auto response = testing::CallMethod(*dbus_object_, &method_call);
200   ExpectError(response.get(), DBUS_ERROR_FAILED);
201 }
202 
TEST_F(DBusObjectTest,AddSubtract)203 TEST_F(DBusObjectTest, AddSubtract) {
204   dbus::MethodCall method_call(kTestInterface1, kTestMethod_AddSubtract);
205   method_call.SetSerial(123);
206   dbus::MessageWriter writer(&method_call);
207   writer.AppendInt32(2);
208   writer.AppendInt32(3);
209   auto response = testing::CallMethod(*dbus_object_, &method_call);
210   dbus::MessageReader reader(response.get());
211   int sum = 0, diff = 0;
212   ASSERT_TRUE(reader.PopInt32(&sum));
213   ASSERT_TRUE(reader.PopInt32(&diff));
214   ASSERT_FALSE(reader.HasMoreData());
215   EXPECT_EQ(5, sum);
216   EXPECT_EQ(-1, diff);
217 }
218 
TEST_F(DBusObjectTest,StrLen0)219 TEST_F(DBusObjectTest, StrLen0) {
220   dbus::MethodCall method_call(kTestInterface2, kTestMethod_StrLen);
221   method_call.SetSerial(123);
222   dbus::MessageWriter writer(&method_call);
223   writer.AppendString("");
224   auto response = testing::CallMethod(*dbus_object_, &method_call);
225   dbus::MessageReader reader(response.get());
226   int result;
227   ASSERT_TRUE(reader.PopInt32(&result));
228   ASSERT_FALSE(reader.HasMoreData());
229   ASSERT_EQ(0, result);
230 }
231 
TEST_F(DBusObjectTest,StrLen4)232 TEST_F(DBusObjectTest, StrLen4) {
233   dbus::MethodCall method_call(kTestInterface2, kTestMethod_StrLen);
234   method_call.SetSerial(123);
235   dbus::MessageWriter writer(&method_call);
236   writer.AppendString("test");
237   auto response = testing::CallMethod(*dbus_object_, &method_call);
238   dbus::MessageReader reader(response.get());
239   int result;
240   ASSERT_TRUE(reader.PopInt32(&result));
241   ASSERT_FALSE(reader.HasMoreData());
242   ASSERT_EQ(4, result);
243 }
244 
TEST_F(DBusObjectTest,CheckNonEmpty_Success)245 TEST_F(DBusObjectTest, CheckNonEmpty_Success) {
246   dbus::MethodCall method_call(kTestInterface2, kTestMethod_CheckNonEmpty);
247   method_call.SetSerial(123);
248   dbus::MessageWriter writer(&method_call);
249   writer.AppendString("test");
250   auto response = testing::CallMethod(*dbus_object_, &method_call);
251   ASSERT_EQ(dbus::Message::MESSAGE_METHOD_RETURN, response->GetMessageType());
252   dbus::MessageReader reader(response.get());
253   EXPECT_FALSE(reader.HasMoreData());
254 }
255 
TEST_F(DBusObjectTest,CheckNonEmpty_Failure)256 TEST_F(DBusObjectTest, CheckNonEmpty_Failure) {
257   dbus::MethodCall method_call(kTestInterface2, kTestMethod_CheckNonEmpty);
258   method_call.SetSerial(123);
259   dbus::MessageWriter writer(&method_call);
260   writer.AppendString("");
261   auto response = testing::CallMethod(*dbus_object_, &method_call);
262   ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
263   ErrorPtr error;
264   ExtractMethodCallResults(response.get(), &error);
265   ASSERT_NE(nullptr, error.get());
266   EXPECT_EQ("test", error->GetDomain());
267   EXPECT_EQ("string_empty", error->GetCode());
268   EXPECT_EQ("String is empty", error->GetMessage());
269 }
270 
TEST_F(DBusObjectTest,CheckNonEmpty_MissingParams)271 TEST_F(DBusObjectTest, CheckNonEmpty_MissingParams) {
272   dbus::MethodCall method_call(kTestInterface2, kTestMethod_CheckNonEmpty);
273   method_call.SetSerial(123);
274   auto response = testing::CallMethod(*dbus_object_, &method_call);
275   ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
276   dbus::MessageReader reader(response.get());
277   std::string message;
278   ASSERT_TRUE(reader.PopString(&message));
279   EXPECT_EQ(DBUS_ERROR_INVALID_ARGS, response->GetErrorName());
280   EXPECT_EQ("Too few parameters in a method call", message);
281   EXPECT_FALSE(reader.HasMoreData());
282 }
283 
TEST_F(DBusObjectTest,NoOp)284 TEST_F(DBusObjectTest, NoOp) {
285   dbus::MethodCall method_call(kTestInterface3, kTestMethod_NoOp);
286   method_call.SetSerial(123);
287   auto response = testing::CallMethod(*dbus_object_, &method_call);
288   dbus::MessageReader reader(response.get());
289   ASSERT_FALSE(reader.HasMoreData());
290 }
291 
TEST_F(DBusObjectTest,TestWithMessage)292 TEST_F(DBusObjectTest, TestWithMessage) {
293   const std::string sender{":1.2345"};
294   dbus::MethodCall method_call(kTestInterface3, kTestMethod_WithMessage);
295   method_call.SetSerial(123);
296   method_call.SetSender(sender);
297   auto response = testing::CallMethod(*dbus_object_, &method_call);
298   dbus::MessageReader reader(response.get());
299   std::string message;
300   ASSERT_TRUE(reader.PopString(&message));
301   ASSERT_FALSE(reader.HasMoreData());
302   EXPECT_EQ(sender, message);
303 }
304 
TEST_F(DBusObjectTest,TestWithMessageAsync)305 TEST_F(DBusObjectTest, TestWithMessageAsync) {
306   const std::string sender{":6.7890"};
307   dbus::MethodCall method_call(kTestInterface3, kTestMethod_WithMessageAsync);
308   method_call.SetSerial(123);
309   method_call.SetSender(sender);
310   auto response = testing::CallMethod(*dbus_object_, &method_call);
311   dbus::MessageReader reader(response.get());
312   std::string message;
313   ASSERT_TRUE(reader.PopString(&message));
314   ASSERT_FALSE(reader.HasMoreData());
315   EXPECT_EQ(sender, message);
316 }
317 
TEST_F(DBusObjectTest,TooFewParams)318 TEST_F(DBusObjectTest, TooFewParams) {
319   dbus::MethodCall method_call(kTestInterface1, kTestMethod_Add);
320   method_call.SetSerial(123);
321   dbus::MessageWriter writer(&method_call);
322   writer.AppendInt32(2);
323   auto response = testing::CallMethod(*dbus_object_, &method_call);
324   ExpectError(response.get(), DBUS_ERROR_INVALID_ARGS);
325 }
326 
TEST_F(DBusObjectTest,TooManyParams)327 TEST_F(DBusObjectTest, TooManyParams) {
328   dbus::MethodCall method_call(kTestInterface1, kTestMethod_Add);
329   method_call.SetSerial(123);
330   dbus::MessageWriter writer(&method_call);
331   writer.AppendInt32(1);
332   writer.AppendInt32(2);
333   writer.AppendInt32(3);
334   auto response = testing::CallMethod(*dbus_object_, &method_call);
335   ExpectError(response.get(), DBUS_ERROR_INVALID_ARGS);
336 }
337 
TEST_F(DBusObjectTest,ParamTypeMismatch)338 TEST_F(DBusObjectTest, ParamTypeMismatch) {
339   dbus::MethodCall method_call(kTestInterface1, kTestMethod_Add);
340   method_call.SetSerial(123);
341   dbus::MessageWriter writer(&method_call);
342   writer.AppendInt32(1);
343   writer.AppendBool(false);
344   auto response = testing::CallMethod(*dbus_object_, &method_call);
345   ExpectError(response.get(), DBUS_ERROR_INVALID_ARGS);
346 }
347 
TEST_F(DBusObjectTest,ParamAsVariant)348 TEST_F(DBusObjectTest, ParamAsVariant) {
349   dbus::MethodCall method_call(kTestInterface1, kTestMethod_Add);
350   method_call.SetSerial(123);
351   dbus::MessageWriter writer(&method_call);
352   writer.AppendVariantOfInt32(10);
353   writer.AppendVariantOfInt32(3);
354   auto response = testing::CallMethod(*dbus_object_, &method_call);
355   dbus::MessageReader reader(response.get());
356   int result;
357   ASSERT_TRUE(reader.PopInt32(&result));
358   ASSERT_FALSE(reader.HasMoreData());
359   ASSERT_EQ(13, result);
360 }
361 
TEST_F(DBusObjectTest,UnknownMethod)362 TEST_F(DBusObjectTest, UnknownMethod) {
363   dbus::MethodCall method_call(kTestInterface2, kTestMethod_Add);
364   method_call.SetSerial(123);
365   dbus::MessageWriter writer(&method_call);
366   writer.AppendInt32(1);
367   writer.AppendBool(false);
368   auto response = testing::CallMethod(*dbus_object_, &method_call);
369   ExpectError(response.get(), DBUS_ERROR_UNKNOWN_METHOD);
370 }
371 
TEST_F(DBusObjectTest,ShouldReleaseOnlyClaimedInterfaces)372 TEST_F(DBusObjectTest, ShouldReleaseOnlyClaimedInterfaces) {
373   const dbus::ObjectPath kObjectManagerPath{std::string{"/"}};
374   const dbus::ObjectPath kMethodsExportedOnPath{
375       std::string{kMethodsExportedOn}};
376   MockExportedObjectManager mock_object_manager{bus_, kObjectManagerPath};
377   dbus_object_ = std::unique_ptr<DBusObject>(
378       new DBusObject(&mock_object_manager, bus_, kMethodsExportedOnPath));
379   EXPECT_CALL(mock_object_manager, ClaimInterface(_, _, _)).Times(0);
380   EXPECT_CALL(mock_object_manager, ReleaseInterface(_, _)).Times(0);
381   DBusInterface* itf1 = dbus_object_->AddOrGetInterface(kTestInterface1);
382   itf1->AddSimpleMethodHandler(
383       kTestMethod_Add, base::Unretained(&calc_), &Calc::Add);
384   // When we tear down our DBusObject, it should release only interfaces it has
385   // previously claimed.  This prevents a check failing inside the
386   // ExportedObjectManager.  Since no interfaces have finished exporting
387   // handlers, nothing should be released.
388   dbus_object_.reset();
389 }
390 
391 }  // namespace dbus_utils
392 }  // namespace brillo
393