2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
21 * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
22 * @brief Dbus connection unit tests
27 #include "dbus/test-server.hpp"
28 #include "dbus/test-client.hpp"
29 #include "dbus/test-common.hpp"
30 #include "utils/scoped-daemon.hpp"
32 #include "dbus/connection.hpp"
33 #include "dbus/exception.hpp"
34 #include "utils/glib-loop.hpp"
35 #include "utils/file-wait.hpp"
36 #include "utils/latch.hpp"
37 #include "utils/fs.hpp"
38 #include "logger/logger.hpp"
40 #include <boost/filesystem.hpp>
43 #include <condition_variable>
46 BOOST_AUTO_TEST_SUITE(DbusSuite)
48 using namespace vasum;
49 using namespace vasum::utils;
54 const char* DBUS_DAEMON_PROC = "/usr/bin/dbus-daemon";
55 const char* const DBUS_DAEMON_ARGS[] = {
57 "--config-file=" VSM_TEST_CONFIG_INSTALL_DIR "/dbus/ut-connection/ut-dbus.conf",
61 const int DBUS_DAEMON_TIMEOUT = 1000;
62 const int EVENT_TIMEOUT = 1000;
64 class ScopedDbusDaemon {
68 boost::filesystem::remove("/tmp/zone_socket");
69 mDaemon.start(DBUS_DAEMON_PROC, DBUS_DAEMON_ARGS);
70 waitForFile(DBUS_SOCKET_FILE, DBUS_DAEMON_TIMEOUT);
80 std::string getInterfaceFromIntrospectionXML(const std::string& xml, const std::string& name)
83 GDBusNodeInfo* nodeInfo = g_dbus_node_info_new_for_xml(xml.c_str(), NULL);
84 GDBusInterfaceInfo* iface = g_dbus_node_info_lookup_interface(nodeInfo, name.c_str());
86 GString* gret = g_string_new("");
87 g_dbus_interface_info_generate_xml(iface, 0, gret);
88 ret.assign(gret->str, gret->len);
89 g_string_free(gret, TRUE);
91 g_dbus_node_info_unref(nodeInfo);
97 BOOST_AUTO_TEST_CASE(GlibLoopTest)
102 BOOST_AUTO_TEST_CASE(DbusDaemonTest)
104 ScopedDbusDaemon daemon;
107 BOOST_AUTO_TEST_CASE(NoDbusTest)
110 BOOST_CHECK_THROW(DbusConnection::create(DBUS_ADDRESS), DbusIOException);
113 BOOST_AUTO_TEST_CASE(ConnectionTest)
116 DbusConnection::Pointer connSystem = DbusConnection::createSystem();
119 BOOST_AUTO_TEST_CASE(SimpleTest)
121 ScopedDbusDaemon daemon;
123 Latch nameAcquired, nameLost;
125 DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
126 DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
127 conn1->setName(TESTAPI_BUS_NAME,
128 [&] {nameAcquired.set();},
129 [&] {nameLost.set();});
130 DbusConnection::Pointer connSystem = DbusConnection::createSystem();
131 BOOST_CHECK(nameAcquired.wait(EVENT_TIMEOUT));
132 BOOST_CHECK(nameLost.empty());
135 BOOST_AUTO_TEST_CASE(ConnectionLostTest)
137 ScopedDbusDaemon daemon;
139 Latch nameAcquired, nameLost;
141 DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
142 conn1->setName(TESTAPI_BUS_NAME,
143 [&] {nameAcquired.set();},
144 [&] {nameLost.set();});
145 BOOST_CHECK(nameAcquired.wait(EVENT_TIMEOUT));
146 BOOST_CHECK(nameLost.empty());
150 BOOST_CHECK(nameLost.wait(EVENT_TIMEOUT));
153 BOOST_AUTO_TEST_CASE(NameOwnerTest)
155 ScopedDbusDaemon daemon;
157 Latch nameAcquired1, nameLost1;
158 Latch nameAcquired2, nameLost2;
160 DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
161 DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
163 // acquire name by conn1
164 conn1->setName(TESTAPI_BUS_NAME,
165 [&] {nameAcquired1.set();},
166 [&] {nameLost1.set();});
167 BOOST_CHECK(nameAcquired1.wait(EVENT_TIMEOUT));
168 BOOST_CHECK(nameLost1.empty());
170 // conn2 can't acquire name
171 conn2->setName(TESTAPI_BUS_NAME,
172 [&] {nameAcquired2.set();},
173 [&] {nameLost2.set();});
174 BOOST_CHECK(nameLost2.wait(EVENT_TIMEOUT));
175 BOOST_CHECK(nameAcquired2.empty());
179 // depending on dbus implementation conn2 can automatically acquire the name
180 //BOOST_CHECK(nameAcquired2.wait(EVENT_TIMEOUT));
183 BOOST_AUTO_TEST_CASE(GenericSignalTest)
185 ScopedDbusDaemon daemon;
189 DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
190 DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
192 const std::string OBJECT_PATH = "/a/b/c";
193 const std::string INTERFACE = "a.b.c";
194 const std::string SIGNAL_NAME = "Foo";
196 auto handler = [&](const std::string& /*senderBusName*/,
197 const std::string& objectPath,
198 const std::string& interface,
199 const std::string& signalName,
200 GVariant* parameters) {
201 if (objectPath == OBJECT_PATH &&
202 interface == INTERFACE &&
203 signalName == SIGNAL_NAME &&
204 g_variant_is_of_type(parameters, G_VARIANT_TYPE_UNIT)) {
208 conn2->signalSubscribe(handler, std::string());
210 conn1->emitSignal(OBJECT_PATH, INTERFACE, SIGNAL_NAME, NULL);
211 BOOST_CHECK(signalEmitted.wait(EVENT_TIMEOUT));
214 BOOST_AUTO_TEST_CASE(FilteredSignalTest)
216 ScopedDbusDaemon daemon;
218 Latch goodSignalEmitted;
219 Latch wrongSignalEmitted;
222 DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
223 DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
225 auto handler = [&](const std::string& /*senderBusName*/,
226 const std::string& objectPath,
227 const std::string& interface,
228 const std::string& signalName,
229 GVariant* parameters) {
230 if (objectPath == TESTAPI_OBJECT_PATH &&
231 interface == TESTAPI_INTERFACE &&
232 signalName == TESTAPI_SIGNAL_NOTIFY &&
233 g_variant_is_of_type(parameters, G_VARIANT_TYPE("(s)"))) {
235 const gchar* msg = NULL;
236 g_variant_get(parameters, "(&s)", &msg);
237 if (msg == std::string("jipii")) {
238 goodSignalEmitted.set();
240 wrongSignalEmitted.set();
244 conn2->signalSubscribe(handler, TESTAPI_BUS_NAME);
246 conn1->emitSignal(TESTAPI_OBJECT_PATH,
248 TESTAPI_SIGNAL_NOTIFY,
249 g_variant_new("(s)", "boo"));
251 conn1->setName(TESTAPI_BUS_NAME,
252 [&] {nameAcquired.set();},
254 BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT));
256 conn1->emitSignal(TESTAPI_OBJECT_PATH,
258 TESTAPI_SIGNAL_NOTIFY,
259 g_variant_new("(s)", "jipii"));
261 BOOST_CHECK(goodSignalEmitted.wait(EVENT_TIMEOUT));
262 BOOST_CHECK(wrongSignalEmitted.empty());
265 BOOST_AUTO_TEST_CASE(RegisterObjectTest)
267 ScopedDbusDaemon daemon;
269 DbusConnection::Pointer conn = DbusConnection::create(DBUS_ADDRESS);
270 DbusConnection::MethodCallCallback callback;
271 BOOST_CHECK_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, "<invalid", callback),
272 DbusInvalidArgumentException);
273 BOOST_CHECK_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, "", callback),
274 DbusInvalidArgumentException);
275 BOOST_CHECK_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, "<node></node>", callback),
276 DbusInvalidArgumentException);
277 BOOST_CHECK_NO_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, callback));
280 BOOST_AUTO_TEST_CASE(IntrospectSystemTest)
283 DbusConnection::Pointer conn = DbusConnection::createSystem();
284 std::string xml = conn->introspect("org.freedesktop.DBus", "/org/freedesktop/DBus");
285 std::string iface = getInterfaceFromIntrospectionXML(xml, "org.freedesktop.DBus");
286 BOOST_CHECK(!iface.empty());
289 BOOST_AUTO_TEST_CASE(IntrospectTest)
291 ScopedDbusDaemon daemon;
295 DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
296 DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
298 conn1->setName(TESTAPI_BUS_NAME,
299 [&] {nameAcquired.set();},
301 BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT));
302 conn1->registerObject(TESTAPI_OBJECT_PATH,
304 DbusConnection::MethodCallCallback());
305 std::string xml = conn2->introspect(TESTAPI_BUS_NAME, TESTAPI_OBJECT_PATH);
306 std::string iface = getInterfaceFromIntrospectionXML(xml, TESTAPI_INTERFACE);
307 BOOST_REQUIRE(!iface.empty());
308 BOOST_CHECK(std::string::npos != iface.find(TESTAPI_INTERFACE));
309 BOOST_CHECK(std::string::npos != iface.find(TESTAPI_METHOD_NOOP));
310 BOOST_CHECK(std::string::npos != iface.find(TESTAPI_METHOD_PROCESS));
311 BOOST_CHECK(std::string::npos != iface.find(TESTAPI_METHOD_THROW));
312 BOOST_CHECK(std::string::npos != iface.find(TESTAPI_SIGNAL_NOTIFY));
315 BOOST_AUTO_TEST_CASE(MethodCallTest)
317 ScopedDbusDaemon daemon;
321 DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
322 DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
324 conn1->setName(TESTAPI_BUS_NAME,
325 [&] {nameAcquired.set();},
327 BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT));
328 auto handler = [](const std::string& objectPath,
329 const std::string& interface,
330 const std::string& methodName,
331 GVariant* parameters,
332 MethodResultBuilder::Pointer result) {
333 if (objectPath != TESTAPI_OBJECT_PATH || interface != TESTAPI_INTERFACE) {
336 if (methodName == TESTAPI_METHOD_NOOP) {
338 } else if (methodName == TESTAPI_METHOD_PROCESS) {
339 const gchar* arg = NULL;
340 g_variant_get(parameters, "(&s)", &arg);
341 std::string str = std::string("resp: ") + arg;
342 result->set(g_variant_new("(s)", str.c_str()));
343 } else if (methodName == TESTAPI_METHOD_THROW) {
345 g_variant_get(parameters, "(i)", &arg);
346 result->setError("org.tizen.vasum.Error.Test", "msg: " + std::to_string(arg));
349 conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler);
351 GVariantPtr result1 = conn2->callMethod(TESTAPI_BUS_NAME,
357 BOOST_CHECK(g_variant_is_of_type(result1.get(), G_VARIANT_TYPE_UNIT));
359 GVariantPtr result2 = conn2->callMethod(TESTAPI_BUS_NAME,
362 TESTAPI_METHOD_PROCESS,
363 g_variant_new("(s)", "arg"),
365 const gchar* ret2 = NULL;
366 g_variant_get(result2.get(), "(&s)", &ret2);
367 BOOST_CHECK_EQUAL("resp: arg", ret2);
369 BOOST_CHECK_THROW(conn2->callMethod(TESTAPI_BUS_NAME,
372 TESTAPI_METHOD_THROW,
373 g_variant_new("(i)", 7),
375 DbusCustomException);
378 BOOST_AUTO_TEST_CASE(MethodAsyncCallTest)
380 ScopedDbusDaemon daemon;
385 DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
386 DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
388 conn1->setName(TESTAPI_BUS_NAME,
389 [&] {nameAcquired.set();},
391 BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT));
392 auto handler = [](const std::string& objectPath,
393 const std::string& interface,
394 const std::string& methodName,
395 GVariant* parameters,
396 MethodResultBuilder::Pointer result) {
397 if (objectPath != TESTAPI_OBJECT_PATH || interface != TESTAPI_INTERFACE) {
400 if (methodName == TESTAPI_METHOD_NOOP) {
402 } else if (methodName == TESTAPI_METHOD_PROCESS) {
403 const gchar* arg = NULL;
404 g_variant_get(parameters, "(&s)", &arg);
405 std::string str = std::string("resp: ") + arg;
406 result->set(g_variant_new("(s)", str.c_str()));
407 } else if (methodName == TESTAPI_METHOD_THROW) {
409 g_variant_get(parameters, "(i)", &arg);
410 result->setError("org.tizen.vasum.Error.Test", "msg: " + std::to_string(arg));
413 conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler);
415 auto asyncResult1 = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) {
416 BOOST_CHECK(g_variant_is_of_type(asyncMethodCallResult.get(), G_VARIANT_TYPE_UNIT));
419 conn2->callMethodAsync(TESTAPI_BUS_NAME,
426 BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
428 auto asyncResult2 = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) {
429 const gchar* ret = NULL;
430 g_variant_get(asyncMethodCallResult.get(), "(&s)", &ret);
431 BOOST_CHECK_EQUAL("resp: arg", ret);
434 conn2->callMethodAsync(TESTAPI_BUS_NAME,
437 TESTAPI_METHOD_PROCESS,
438 g_variant_new("(s)", "arg"),
441 BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
443 auto asyncResult3 = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) {
444 BOOST_CHECK_THROW(asyncMethodCallResult.get(), DbusCustomException);
447 conn2->callMethodAsync(TESTAPI_BUS_NAME,
450 TESTAPI_METHOD_THROW,
451 g_variant_new("(i)", 7),
454 BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
457 BOOST_AUTO_TEST_CASE(MethodAsyncCallAsyncHandlerTest)
459 ScopedDbusDaemon daemon;
465 DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
466 DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
468 conn1->setName(TESTAPI_BUS_NAME,
469 [&] {nameAcquired.set();},
471 BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT));
473 std::string strResult;
474 MethodResultBuilder::Pointer deferredResult;
476 auto handler = [&](const std::string& objectPath,
477 const std::string& interface,
478 const std::string& methodName,
479 GVariant* parameters,
480 MethodResultBuilder::Pointer result) {
481 if (objectPath != TESTAPI_OBJECT_PATH || interface != TESTAPI_INTERFACE) {
484 if (methodName == TESTAPI_METHOD_PROCESS) {
485 const gchar* arg = NULL;
486 g_variant_get(parameters, "(&s)", &arg);
487 strResult = std::string("resp: ") + arg;
488 deferredResult = result;
492 conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler);
494 auto asyncResult = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) {
495 const gchar* ret = NULL;
496 g_variant_get(asyncMethodCallResult.get(), "(&s)", &ret);
497 BOOST_CHECK_EQUAL("resp: arg", ret);
500 conn2->callMethodAsync(TESTAPI_BUS_NAME,
503 TESTAPI_METHOD_PROCESS,
504 g_variant_new("(s)", "arg"),
507 BOOST_REQUIRE(handlerDone.wait(EVENT_TIMEOUT));
508 BOOST_REQUIRE(callDone.empty());
509 deferredResult->set(g_variant_new("(s)", strResult.c_str()));
510 BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
513 BOOST_AUTO_TEST_CASE(MethodCallExceptionTest)
515 ScopedDbusDaemon daemon;
519 DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
520 DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
522 conn1->setName(TESTAPI_BUS_NAME,
523 [&] {nameAcquired.set();},
525 BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT));
526 conn1->registerObject(TESTAPI_OBJECT_PATH,
528 DbusConnection::MethodCallCallback());
529 BOOST_CHECK_THROW(conn2->callMethod(TESTAPI_BUS_NAME,
535 DbusOperationException);
536 BOOST_CHECK_THROW(conn2->callMethod(TESTAPI_BUS_NAME,
542 DbusOperationException);
543 BOOST_CHECK_THROW(conn2->callMethod(TESTAPI_BUS_NAME,
545 TESTAPI_INTERFACE + ".foo",
549 DbusOperationException);
550 BOOST_CHECK_THROW(conn2->callMethod(TESTAPI_BUS_NAME,
551 TESTAPI_OBJECT_PATH + "/foo",
556 DbusOperationException);
559 BOOST_AUTO_TEST_CASE(DbusApiTest)
561 ScopedDbusDaemon daemon;
563 DbusTestServer server;
564 DbusTestClient client;
566 BOOST_CHECK_NO_THROW(client.noop());
567 BOOST_CHECK_EQUAL("Processed: arg", client.process("arg"));
568 BOOST_CHECK_NO_THROW(client.throwException(0));
570 auto checkException = [](const DbusCustomException& e) {
571 return e.what() == std::string("Argument: 666");
573 BOOST_CHECK_EXCEPTION(client.throwException(666), DbusCustomException, checkException);
576 BOOST_AUTO_TEST_CASE(DbusApiNotifyTest)
578 ScopedDbusDaemon daemon;
582 DbusTestServer server;
583 DbusTestClient client;
585 auto onNotify = [&](const std::string& message) {
586 BOOST_CHECK_EQUAL("notification", message);
589 client.setNotifyCallback(onNotify);
590 server.notifyClients("notification");
591 BOOST_CHECK(notified.wait(EVENT_TIMEOUT));
594 BOOST_AUTO_TEST_CASE(DbusApiNameAcquiredTest)
596 ScopedDbusDaemon daemon;
599 DbusTestServer server;
600 DbusTestClient client;
602 BOOST_CHECK_THROW(DbusTestServer(), DbusOperationException);
603 BOOST_CHECK_NO_THROW(client.noop());
606 BOOST_AUTO_TEST_CASE(DbusApiConnectionLost1Test)
608 ScopedDbusDaemon daemon;
612 DbusTestServer server;
613 server.setDisconnectCallback([&] {disconnected.set();});
614 DbusTestClient client;
616 BOOST_CHECK_NO_THROW(client.noop());
618 BOOST_CHECK(disconnected.wait(EVENT_TIMEOUT));
619 BOOST_CHECK_THROW(client.noop(), DbusIOException);
622 BOOST_AUTO_TEST_CASE(DbusApiConnectionLost2Test)
624 ScopedDbusDaemon daemon;
628 DbusTestServer server;
629 DbusTestClient client;
631 BOOST_CHECK_NO_THROW(client.noop());
633 BOOST_CHECK_THROW(client.noop(), DbusIOException);
635 server.setDisconnectCallback([&] {disconnected.set();});
636 BOOST_CHECK(disconnected.wait(EVENT_TIMEOUT));
639 BOOST_AUTO_TEST_SUITE_END()