d4eb1decd39740d30ee59c88ef22109d66fd7358
[platform/core/security/vasum.git] / tests / unit_tests / dbus / ut-connection.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
5  *
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
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
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
17  */
18
19 /**
20  * @file
21  * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
22  * @brief   Dbus connection unit tests
23  */
24
25 #include "config.hpp"
26 #include "ut.hpp"
27 #include "dbus/test-server.hpp"
28 #include "dbus/test-client.hpp"
29 #include "dbus/test-common.hpp"
30 #include "utils/scoped-daemon.hpp"
31
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"
39
40 #include <boost/filesystem.hpp>
41 #include <thread>
42 #include <mutex>
43 #include <condition_variable>
44
45
46 BOOST_AUTO_TEST_SUITE(DbusSuite)
47
48 using namespace vasum;
49 using namespace vasum::utils;
50 using namespace dbus;
51
52 namespace {
53
54 const char* DBUS_DAEMON_PROC = "/usr/bin/dbus-daemon";
55 const char* const DBUS_DAEMON_ARGS[] = {
56     DBUS_DAEMON_PROC,
57     "--config-file=" VSM_TEST_CONFIG_INSTALL_DIR "/dbus/ut-connection/ut-dbus.conf",
58     "--nofork",
59     NULL
60 };
61 const int DBUS_DAEMON_TIMEOUT = 1000;
62 const int EVENT_TIMEOUT = 1000;
63
64 class ScopedDbusDaemon {
65 public:
66     ScopedDbusDaemon()
67     {
68         boost::filesystem::remove("/tmp/zone_socket");
69         mDaemon.start(DBUS_DAEMON_PROC, DBUS_DAEMON_ARGS);
70         waitForFile(DBUS_SOCKET_FILE, DBUS_DAEMON_TIMEOUT);
71     }
72     void stop()
73     {
74         mDaemon.stop();
75     }
76 private:
77     ScopedDaemon mDaemon;
78 };
79
80 std::string getInterfaceFromIntrospectionXML(const std::string& xml, const std::string& name)
81 {
82     std::string ret;
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());
85     if (iface) {
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);
90     }
91     g_dbus_node_info_unref(nodeInfo);
92     return ret;
93 }
94
95 } // namespace
96
97 BOOST_AUTO_TEST_CASE(GlibLoopTest)
98 {
99     ScopedGlibLoop loop;
100 }
101
102 BOOST_AUTO_TEST_CASE(DbusDaemonTest)
103 {
104     ScopedDbusDaemon daemon;
105 }
106
107 BOOST_AUTO_TEST_CASE(NoDbusTest)
108 {
109     ScopedGlibLoop loop;
110     BOOST_CHECK_THROW(DbusConnection::create(DBUS_ADDRESS), DbusIOException);
111 }
112
113 BOOST_AUTO_TEST_CASE(ConnectionTest)
114 {
115     ScopedGlibLoop loop;
116     DbusConnection::Pointer connSystem = DbusConnection::createSystem();
117 }
118
119 BOOST_AUTO_TEST_CASE(SimpleTest)
120 {
121     ScopedDbusDaemon daemon;
122     ScopedGlibLoop loop;
123     Latch nameAcquired, nameLost;
124
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());
133 }
134
135 BOOST_AUTO_TEST_CASE(ConnectionLostTest)
136 {
137     ScopedDbusDaemon daemon;
138     ScopedGlibLoop loop;
139     Latch nameAcquired, nameLost;
140
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());
147
148     // close dbus socket
149     daemon.stop();
150     BOOST_CHECK(nameLost.wait(EVENT_TIMEOUT));
151 }
152
153 BOOST_AUTO_TEST_CASE(NameOwnerTest)
154 {
155     ScopedDbusDaemon daemon;
156     ScopedGlibLoop loop;
157     Latch nameAcquired1, nameLost1;
158     Latch nameAcquired2, nameLost2;
159
160     DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
161     DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
162
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());
169
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());
176
177     // close conn1
178     conn1.reset();
179     // depending on dbus implementation conn2 can automatically acquire the name
180     //BOOST_CHECK(nameAcquired2.wait(EVENT_TIMEOUT));
181 }
182
183 BOOST_AUTO_TEST_CASE(GenericSignalTest)
184 {
185     ScopedDbusDaemon daemon;
186     ScopedGlibLoop loop;
187     Latch signalEmitted;
188
189     DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
190     DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
191
192     const std::string OBJECT_PATH = "/a/b/c";
193     const std::string INTERFACE = "a.b.c";
194     const std::string SIGNAL_NAME = "Foo";
195
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)) {
205             signalEmitted.set();
206         }
207     };
208     conn2->signalSubscribe(handler, std::string());
209
210     conn1->emitSignal(OBJECT_PATH, INTERFACE, SIGNAL_NAME, NULL);
211     BOOST_CHECK(signalEmitted.wait(EVENT_TIMEOUT));
212 }
213
214 BOOST_AUTO_TEST_CASE(FilteredSignalTest)
215 {
216     ScopedDbusDaemon daemon;
217     ScopedGlibLoop loop;
218     Latch goodSignalEmitted;
219     Latch wrongSignalEmitted;
220     Latch nameAcquired;
221
222     DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
223     DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
224
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)"))) {
234
235             const gchar* msg = NULL;
236             g_variant_get(parameters, "(&s)", &msg);
237             if (msg == std::string("jipii")) {
238                 goodSignalEmitted.set();
239             } else {
240                 wrongSignalEmitted.set();
241             }
242         }
243     };
244     conn2->signalSubscribe(handler, TESTAPI_BUS_NAME);
245
246     conn1->emitSignal(TESTAPI_OBJECT_PATH,
247                       TESTAPI_INTERFACE,
248                       TESTAPI_SIGNAL_NOTIFY,
249                       g_variant_new("(s)", "boo"));
250
251     conn1->setName(TESTAPI_BUS_NAME,
252                    [&] {nameAcquired.set();},
253                    [] {});
254     BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT));
255
256     conn1->emitSignal(TESTAPI_OBJECT_PATH,
257                       TESTAPI_INTERFACE,
258                       TESTAPI_SIGNAL_NOTIFY,
259                       g_variant_new("(s)", "jipii"));
260
261     BOOST_CHECK(goodSignalEmitted.wait(EVENT_TIMEOUT));
262     BOOST_CHECK(wrongSignalEmitted.empty());
263 }
264
265 BOOST_AUTO_TEST_CASE(RegisterObjectTest)
266 {
267     ScopedDbusDaemon daemon;
268     ScopedGlibLoop loop;
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));
278 }
279
280 BOOST_AUTO_TEST_CASE(IntrospectSystemTest)
281 {
282     ScopedGlibLoop loop;
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());
287 }
288
289 BOOST_AUTO_TEST_CASE(IntrospectTest)
290 {
291     ScopedDbusDaemon daemon;
292     ScopedGlibLoop loop;
293     Latch nameAcquired;
294
295     DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
296     DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
297
298     conn1->setName(TESTAPI_BUS_NAME,
299                    [&] {nameAcquired.set();},
300                    [] {});
301     BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT));
302     conn1->registerObject(TESTAPI_OBJECT_PATH,
303                           TESTAPI_DEFINITION,
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));
313 }
314
315 BOOST_AUTO_TEST_CASE(MethodCallTest)
316 {
317     ScopedDbusDaemon daemon;
318     ScopedGlibLoop loop;
319     Latch nameAcquired;
320
321     DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
322     DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
323
324     conn1->setName(TESTAPI_BUS_NAME,
325                    [&] {nameAcquired.set();},
326                    [] {});
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) {
334             return;
335         }
336         if (methodName == TESTAPI_METHOD_NOOP) {
337             result->setVoid();
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) {
344             int arg = 0;
345             g_variant_get(parameters, "(i)", &arg);
346             result->setError("org.tizen.vasum.Error.Test", "msg: " + std::to_string(arg));
347         }
348     };
349     conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler);
350
351     GVariantPtr result1 = conn2->callMethod(TESTAPI_BUS_NAME,
352                                             TESTAPI_OBJECT_PATH,
353                                             TESTAPI_INTERFACE,
354                                             TESTAPI_METHOD_NOOP,
355                                             NULL,
356                                             "()");
357     BOOST_CHECK(g_variant_is_of_type(result1.get(), G_VARIANT_TYPE_UNIT));
358
359     GVariantPtr result2 = conn2->callMethod(TESTAPI_BUS_NAME,
360                                             TESTAPI_OBJECT_PATH,
361                                             TESTAPI_INTERFACE,
362                                             TESTAPI_METHOD_PROCESS,
363                                             g_variant_new("(s)", "arg"),
364                                             "(s)");
365     const gchar* ret2 = NULL;
366     g_variant_get(result2.get(), "(&s)", &ret2);
367     BOOST_CHECK_EQUAL("resp: arg", ret2);
368
369     BOOST_CHECK_THROW(conn2->callMethod(TESTAPI_BUS_NAME,
370                                         TESTAPI_OBJECT_PATH,
371                                         TESTAPI_INTERFACE,
372                                         TESTAPI_METHOD_THROW,
373                                         g_variant_new("(i)", 7),
374                                         "()"),
375                       DbusCustomException);
376 }
377
378 BOOST_AUTO_TEST_CASE(MethodAsyncCallTest)
379 {
380     ScopedDbusDaemon daemon;
381     ScopedGlibLoop loop;
382     Latch nameAcquired;
383     Latch callDone;
384
385     DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
386     DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
387
388     conn1->setName(TESTAPI_BUS_NAME,
389                    [&] {nameAcquired.set();},
390                    [] {});
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) {
398             return;
399         }
400         if (methodName == TESTAPI_METHOD_NOOP) {
401             result->setVoid();
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) {
408             int arg = 0;
409             g_variant_get(parameters, "(i)", &arg);
410             result->setError("org.tizen.vasum.Error.Test", "msg: " + std::to_string(arg));
411         }
412     };
413     conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler);
414
415     auto asyncResult1 = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) {
416         BOOST_CHECK(g_variant_is_of_type(asyncMethodCallResult.get(), G_VARIANT_TYPE_UNIT));
417         callDone.set();
418     };
419     conn2->callMethodAsync(TESTAPI_BUS_NAME,
420                            TESTAPI_OBJECT_PATH,
421                            TESTAPI_INTERFACE,
422                            TESTAPI_METHOD_NOOP,
423                            NULL,
424                            "()",
425                            asyncResult1);
426     BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
427
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);
432         callDone.set();
433     };
434     conn2->callMethodAsync(TESTAPI_BUS_NAME,
435                            TESTAPI_OBJECT_PATH,
436                            TESTAPI_INTERFACE,
437                            TESTAPI_METHOD_PROCESS,
438                            g_variant_new("(s)", "arg"),
439                            "(s)",
440                            asyncResult2);
441     BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
442
443     auto asyncResult3 = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) {
444         BOOST_CHECK_THROW(asyncMethodCallResult.get(), DbusCustomException);
445         callDone.set();
446     };
447     conn2->callMethodAsync(TESTAPI_BUS_NAME,
448                            TESTAPI_OBJECT_PATH,
449                            TESTAPI_INTERFACE,
450                            TESTAPI_METHOD_THROW,
451                            g_variant_new("(i)", 7),
452                            "()",
453                            asyncResult3);
454     BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
455 }
456
457 BOOST_AUTO_TEST_CASE(MethodAsyncCallAsyncHandlerTest)
458 {
459     ScopedDbusDaemon daemon;
460     ScopedGlibLoop loop;
461     Latch nameAcquired;
462     Latch handlerDone;
463     Latch callDone;
464
465     DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
466     DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
467
468     conn1->setName(TESTAPI_BUS_NAME,
469                    [&] {nameAcquired.set();},
470                    [] {});
471     BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT));
472
473     std::string strResult;
474     MethodResultBuilder::Pointer deferredResult;
475
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) {
482             return;
483         }
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;
489             handlerDone.set();
490         }
491     };
492     conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler);
493
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);
498         callDone.set();
499     };
500     conn2->callMethodAsync(TESTAPI_BUS_NAME,
501                            TESTAPI_OBJECT_PATH,
502                            TESTAPI_INTERFACE,
503                            TESTAPI_METHOD_PROCESS,
504                            g_variant_new("(s)", "arg"),
505                            "(s)",
506                            asyncResult);
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));
511 }
512
513 BOOST_AUTO_TEST_CASE(MethodCallExceptionTest)
514 {
515     ScopedDbusDaemon daemon;
516     ScopedGlibLoop loop;
517     Latch nameAcquired;
518
519     DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS);
520     DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS);
521
522     conn1->setName(TESTAPI_BUS_NAME,
523                    [&] {nameAcquired.set();},
524                    [] {});
525     BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT));
526     conn1->registerObject(TESTAPI_OBJECT_PATH,
527                           TESTAPI_DEFINITION,
528                           DbusConnection::MethodCallCallback());
529     BOOST_CHECK_THROW(conn2->callMethod(TESTAPI_BUS_NAME,
530                                         TESTAPI_OBJECT_PATH,
531                                         TESTAPI_INTERFACE,
532                                         TESTAPI_METHOD_NOOP,
533                                         NULL,
534                                         "()"),
535                       DbusOperationException);
536     BOOST_CHECK_THROW(conn2->callMethod(TESTAPI_BUS_NAME,
537                                         TESTAPI_OBJECT_PATH,
538                                         TESTAPI_INTERFACE,
539                                         "Foo",
540                                         NULL,
541                                         "()"),
542                       DbusOperationException);
543     BOOST_CHECK_THROW(conn2->callMethod(TESTAPI_BUS_NAME,
544                                         TESTAPI_OBJECT_PATH,
545                                         TESTAPI_INTERFACE + ".foo",
546                                         TESTAPI_METHOD_NOOP,
547                                         NULL,
548                                         "()"),
549                       DbusOperationException);
550     BOOST_CHECK_THROW(conn2->callMethod(TESTAPI_BUS_NAME,
551                                         TESTAPI_OBJECT_PATH + "/foo",
552                                         TESTAPI_INTERFACE,
553                                         TESTAPI_METHOD_NOOP,
554                                         NULL,
555                                         "()"),
556                       DbusOperationException);
557 }
558
559 BOOST_AUTO_TEST_CASE(DbusApiTest)
560 {
561     ScopedDbusDaemon daemon;
562     ScopedGlibLoop loop;
563     DbusTestServer server;
564     DbusTestClient client;
565
566     BOOST_CHECK_NO_THROW(client.noop());
567     BOOST_CHECK_EQUAL("Processed: arg", client.process("arg"));
568     BOOST_CHECK_NO_THROW(client.throwException(0));
569
570     auto checkException = [](const DbusCustomException& e) {
571         return e.what() == std::string("Argument: 666");
572     };
573     BOOST_CHECK_EXCEPTION(client.throwException(666), DbusCustomException, checkException);
574 }
575
576 BOOST_AUTO_TEST_CASE(DbusApiNotifyTest)
577 {
578     ScopedDbusDaemon daemon;
579     ScopedGlibLoop loop;
580     Latch notified;
581
582     DbusTestServer server;
583     DbusTestClient client;
584
585     auto onNotify = [&](const std::string& message) {
586         BOOST_CHECK_EQUAL("notification", message);
587         notified.set();
588     };
589     client.setNotifyCallback(onNotify);
590     server.notifyClients("notification");
591     BOOST_CHECK(notified.wait(EVENT_TIMEOUT));
592 }
593
594 BOOST_AUTO_TEST_CASE(DbusApiNameAcquiredTest)
595 {
596     ScopedDbusDaemon daemon;
597     ScopedGlibLoop loop;
598
599     DbusTestServer server;
600     DbusTestClient client;
601
602     BOOST_CHECK_THROW(DbusTestServer(), DbusOperationException);
603     BOOST_CHECK_NO_THROW(client.noop());
604 }
605
606 BOOST_AUTO_TEST_CASE(DbusApiConnectionLost1Test)
607 {
608     ScopedDbusDaemon daemon;
609     ScopedGlibLoop loop;
610     Latch disconnected;
611
612     DbusTestServer server;
613     server.setDisconnectCallback([&] {disconnected.set();});
614     DbusTestClient client;
615
616     BOOST_CHECK_NO_THROW(client.noop());
617     daemon.stop();
618     BOOST_CHECK(disconnected.wait(EVENT_TIMEOUT));
619     BOOST_CHECK_THROW(client.noop(), DbusIOException);
620 }
621
622 BOOST_AUTO_TEST_CASE(DbusApiConnectionLost2Test)
623 {
624     ScopedDbusDaemon daemon;
625     ScopedGlibLoop loop;
626     Latch disconnected;
627
628     DbusTestServer server;
629     DbusTestClient client;
630
631     BOOST_CHECK_NO_THROW(client.noop());
632     daemon.stop();
633     BOOST_CHECK_THROW(client.noop(), DbusIOException);
634
635     server.setDisconnectCallback([&] {disconnected.set();});
636     BOOST_CHECK(disconnected.wait(EVENT_TIMEOUT));
637 }
638
639 BOOST_AUTO_TEST_SUITE_END()