blob: 6ffad515ff848cdf36d78f2ac97d827779b4d635 [file] [log] [blame]
Brad Bishop49aefb32016-10-19 11:54:14 -04001/**
2 * Copyright © 2016 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brad Bishopa6fcd562017-02-03 11:00:27 -050016#include "manager.hpp"
17#include "config.h"
Brad Bishop49aefb32016-10-19 11:54:14 -040018#include <cassert>
Brad Bishopabb2a1a2016-11-30 22:02:28 -050019#include <iostream>
20#include <algorithm>
Brad Bishop21621432017-01-13 16:35:53 -050021#include <thread>
Brad Bishop8f868502017-01-23 13:13:58 -050022#include <chrono>
Brad Bishopa6fcd562017-02-03 11:00:27 -050023#include "xyz/openbmc_project/Example/Iface1/server.hpp"
24#include "xyz/openbmc_project/Example/Iface2/server.hpp"
Brad Bishop49aefb32016-10-19 11:54:14 -040025
Brad Bishop8f868502017-01-23 13:13:58 -050026using namespace std::literals::chrono_literals;
27using namespace std::literals::string_literals;
28
29constexpr auto MGR_SERVICE = "phosphor.inventory.test.mgr";
30constexpr auto MGR_INTERFACE = IFACE;
31constexpr auto MGR_ROOT = "/testing/inventory";
32constexpr auto EXAMPLE_SERVICE = "phosphor.inventory.test.example";
33constexpr auto EXAMPLE_ROOT = "/testing";
34
35const auto trigger1 = sdbusplus::message::object_path(EXAMPLE_ROOT +
36 "/trigger1"s);
37const auto trigger2 = sdbusplus::message::object_path(EXAMPLE_ROOT +
38 "/trigger2"s);
Brad Bishopfb083c22017-01-19 09:22:04 -050039const auto trigger3 = sdbusplus::message::object_path(EXAMPLE_ROOT +
40 "/trigger3"s);
Brad Bishopfa51da72017-01-19 11:06:51 -050041const auto trigger4 = sdbusplus::message::object_path(EXAMPLE_ROOT +
42 "/trigger4"s);
Brad Bishopeb68a682017-01-22 00:58:54 -050043const auto trigger5 = sdbusplus::message::object_path(EXAMPLE_ROOT +
44 "/trigger5"s);
Brad Bishopfb083c22017-01-19 09:22:04 -050045
46const sdbusplus::message::object_path relDeleteMeOne{"/deleteme1"};
47const sdbusplus::message::object_path relDeleteMeTwo{"/deleteme2"};
48const sdbusplus::message::object_path relDeleteMeThree{"/deleteme3"};
49
50const std::string root{MGR_ROOT};
51const std::string deleteMeOne{root + relDeleteMeOne.str};
52const std::string deleteMeTwo{root + relDeleteMeTwo.str};
53const std::string deleteMeThree{root + relDeleteMeThree.str};
Brad Bishop8f868502017-01-23 13:13:58 -050054
55using ExampleIface1 = sdbusplus::xyz::openbmc_project::Example::server::Iface1;
56using ExampleIface2 = sdbusplus::xyz::openbmc_project::Example::server::Iface2;
57
58/** @class ExampleService
59 * @brief Host an object for triggering events.
60 */
61struct ExampleService
62{
63 ~ExampleService() = default;
64 ExampleService() :
65 shutdown(false),
66 bus(sdbusplus::bus::new_default()),
67 objmgr(sdbusplus::server::manager::manager(bus, MGR_ROOT))
68 {
69 bus.request_name(EXAMPLE_SERVICE);
70 }
71
72 void run()
73 {
74 sdbusplus::server::object::object <
75 ExampleIface1, ExampleIface2 > t1(bus, trigger1.str.c_str());
76 sdbusplus::server::object::object <
77 ExampleIface1, ExampleIface2 > t2(bus, trigger2.str.c_str());
Brad Bishopfb083c22017-01-19 09:22:04 -050078 sdbusplus::server::object::object <
79 ExampleIface1, ExampleIface2 > t3(bus, trigger3.str.c_str());
Brad Bishopfa51da72017-01-19 11:06:51 -050080 sdbusplus::server::object::object <
81 ExampleIface1, ExampleIface2 > t4(bus, trigger4.str.c_str());
Brad Bishopeb68a682017-01-22 00:58:54 -050082 sdbusplus::server::object::object <
83 ExampleIface1, ExampleIface2 > t5(bus, trigger5.str.c_str());
Brad Bishop8f868502017-01-23 13:13:58 -050084
85 while (!shutdown)
86 {
87 bus.process_discard();
88 bus.wait((5000000us).count());
89 }
90 }
91
92 volatile bool shutdown;
93 sdbusplus::bus::bus bus;
94 sdbusplus::server::manager::manager objmgr;
95};
Brad Bishop49aefb32016-10-19 11:54:14 -040096
Brad Bishop1157af12017-01-22 01:03:02 -050097using Object = phosphor::inventory::manager::Object;
98
Brad Bishopabb2a1a2016-11-30 22:02:28 -050099/** @class SignalQueue
100 * @brief Store DBus signals in a queue.
101 */
102class SignalQueue
103{
104 public:
Brad Bishop7b337772017-01-12 16:11:24 -0500105 ~SignalQueue() = default;
106 SignalQueue() = delete;
107 SignalQueue(const SignalQueue&) = delete;
108 SignalQueue(SignalQueue&&) = default;
109 SignalQueue& operator=(const SignalQueue&) = delete;
110 SignalQueue& operator=(SignalQueue&&) = default;
111 explicit SignalQueue(const std::string& match) :
112 _bus(sdbusplus::bus::new_default()),
113 _match(_bus, match.c_str(), &callback, this),
114 _next(nullptr)
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500115 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500116 }
Brad Bishop7b337772017-01-12 16:11:24 -0500117
118 auto&& pop(unsigned timeout = 1000000)
119 {
120 while (timeout > 0 && !_next)
121 {
122 _bus.process_discard();
123 _bus.wait(50000);
124 timeout -= 50000;
125 }
126 return std::move(_next);
127 }
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500128
129 private:
Brad Bishop7b337772017-01-12 16:11:24 -0500130 static int callback(sd_bus_message* m, void* context, sd_bus_error*)
131 {
132 auto* me = static_cast<SignalQueue*>(context);
133 sd_bus_message_ref(m);
134 sdbusplus::message::message msg{m};
135 me->_next = std::move(msg);
136 return 0;
137 }
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500138
Brad Bishop7b337772017-01-12 16:11:24 -0500139 sdbusplus::bus::bus _bus;
140 sdbusplus::server::match::match _match;
141 sdbusplus::message::message _next;
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500142};
143
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500144/**@brief Find a subset of interfaces and properties in an object. */
Brad Bishop1157af12017-01-22 01:03:02 -0500145auto hasProperties(const Object& l, const Object& r)
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500146{
Brad Bishop1157af12017-01-22 01:03:02 -0500147 Object result;
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500148 std::set_difference(
Brad Bishop7b337772017-01-12 16:11:24 -0500149 r.cbegin(),
150 r.cend(),
151 l.cbegin(),
152 l.cend(),
153 std::inserter(result, result.end()));
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500154 return result.empty();
155}
156
Brad Bishop432e3522016-12-01 00:24:14 -0500157/**@brief Check an object for one or more interfaces. */
Brad Bishop1157af12017-01-22 01:03:02 -0500158auto hasInterfaces(const std::vector<std::string>& l, const Object& r)
Brad Bishop432e3522016-12-01 00:24:14 -0500159{
160 std::vector<std::string> stripped, interfaces;
161 std::transform(
Brad Bishop7b337772017-01-12 16:11:24 -0500162 r.cbegin(),
163 r.cend(),
164 std::back_inserter(stripped),
165 [](auto & p)
166 {
167 return p.first;
168 });
Brad Bishop432e3522016-12-01 00:24:14 -0500169 std::set_difference(
Brad Bishop7b337772017-01-12 16:11:24 -0500170 stripped.cbegin(),
171 stripped.cend(),
172 l.cbegin(),
173 l.cend(),
174 std::back_inserter(interfaces));
Brad Bishop432e3522016-12-01 00:24:14 -0500175 return interfaces.empty();
176}
177
Brad Bishop8f868502017-01-23 13:13:58 -0500178void runTests()
Brad Bishop49aefb32016-10-19 11:54:14 -0400179{
Brad Bishop8f868502017-01-23 13:13:58 -0500180 const std::string exampleRoot{EXAMPLE_ROOT};
Brad Bishop49aefb32016-10-19 11:54:14 -0400181 auto b = sdbusplus::bus::new_default();
Brad Bishop8f868502017-01-23 13:13:58 -0500182
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500183 auto notify = [&]()
Brad Bishop49aefb32016-10-19 11:54:14 -0400184 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500185 return b.new_method_call(
Brad Bishop8f868502017-01-23 13:13:58 -0500186 MGR_SERVICE,
187 MGR_ROOT,
188 MGR_INTERFACE,
Brad Bishop7b337772017-01-12 16:11:24 -0500189 "Notify");
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500190 };
Brad Bishop7b337772017-01-12 16:11:24 -0500191 auto set = [&](const std::string & path)
Brad Bishop432e3522016-12-01 00:24:14 -0500192 {
193 return b.new_method_call(
Brad Bishop8f868502017-01-23 13:13:58 -0500194 EXAMPLE_SERVICE,
Brad Bishop7b337772017-01-12 16:11:24 -0500195 path.c_str(),
196 "org.freedesktop.DBus.Properties",
197 "Set");
Brad Bishop432e3522016-12-01 00:24:14 -0500198 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400199
Brad Bishop1157af12017-01-22 01:03:02 -0500200 Object obj
Brad Bishop7b337772017-01-12 16:11:24 -0500201 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500202 {
203 "xyz.openbmc_project.Example.Iface1",
204 {{"ExampleProperty1", "test1"}}
205 },
206 {
207 "xyz.openbmc_project.Example.Iface2",
208 {{"ExampleProperty2", "test2"}}
209 },
210 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400211
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500212 // Validate startup events occurred.
213 {
214 sdbusplus::message::object_path relCreateMe3{"/createme3"};
215 std::string createMe3{root + relCreateMe3.str};
216
217 auto get = b.new_method_call(
218 MGR_SERVICE,
219 createMe3.c_str(),
220 "org.freedesktop.DBus.Properties",
221 "GetAll");
222 get.append("xyz.openbmc_project.Example.Iface1");
223 auto resp = b.call(get);
224
225 Object::mapped_type properties;
226 assert(!resp.is_method_error());
227 resp.read(properties);
228 }
229
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500230 // Make sure the notify method works.
231 {
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500232 sdbusplus::message::object_path relPath{"/foo"};
233 std::string path(root + relPath.str);
Brad Bishop49aefb32016-10-19 11:54:14 -0400234
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500235 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500236 "path='" + root + "',member='InterfacesAdded'");
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500237
238 auto m = notify();
239 m.append(relPath);
240 m.append(obj);
241 b.call(m);
242
243 auto sig{queue.pop()};
244 assert(sig);
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500245 sdbusplus::message::object_path signalPath;
Brad Bishop1157af12017-01-22 01:03:02 -0500246 Object signalObjectType;
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500247 sig.read(signalPath);
Brad Bishope07a1642017-01-24 14:37:33 -0500248 assert(path == signalPath.str);
Brad Bishop1157af12017-01-22 01:03:02 -0500249 sig.read(signalObjectType);
250 assert(hasProperties(signalObjectType, obj));
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500251 auto moreSignals{queue.pop()};
252 assert(!moreSignals);
Brad Bishop49aefb32016-10-19 11:54:14 -0400253 }
254
Brad Bishopfa51da72017-01-19 11:06:51 -0500255 // Validate the propertyIs filter.
256 {
257 // Create an object to be deleted.
258 {
259 auto m = notify();
260 m.append(relDeleteMeThree);
261 m.append(obj);
262 b.call(m);
263 }
264
265 // Validate that the action does not run if the property doesn't match.
266 {
267 SignalQueue queue(
268 "path='" + root + "',member='InterfacesRemoved'");
269 auto m = set(trigger4.str);
270 m.append("xyz.openbmc_project.Example.Iface2");
271 m.append("ExampleProperty2");
272 m.append(sdbusplus::message::variant<std::string>("123"));
273 b.call(m);
274 auto sig{queue.pop()};
275 assert(!sig);
276 }
277
278 // Validate that the action does run if the property matches.
279 {
280 // Set ExampleProperty2 to something else to the 123 filter
281 // matches.
282 SignalQueue queue(
283 "path='" + root + "',member='InterfacesRemoved'");
284 auto m = set(trigger4.str);
285 m.append("xyz.openbmc_project.Example.Iface2");
286 m.append("ExampleProperty2");
287 m.append(sdbusplus::message::variant<std::string>("xyz"));
288 b.call(m);
289 auto sig{queue.pop()};
290 assert(!sig);
291 }
292 {
293 // Set ExampleProperty3 to 99.
294 SignalQueue queue(
295 "path='" + root + "',member='InterfacesRemoved'");
296 auto m = set(trigger4.str);
297 m.append("xyz.openbmc_project.Example.Iface2");
298 m.append("ExampleProperty3");
299 m.append(sdbusplus::message::variant<int64_t>(99));
300 b.call(m);
301 auto sig{queue.pop()};
302 assert(!sig);
303 }
304 {
305 SignalQueue queue(
306 "path='" + root + "',member='InterfacesRemoved'");
307 auto m = set(trigger4.str);
308 m.append("xyz.openbmc_project.Example.Iface2");
309 m.append("ExampleProperty2");
310 m.append(sdbusplus::message::variant<std::string>("123"));
311 b.call(m);
312
313 sdbusplus::message::object_path sigpath;
314 std::vector<std::string> interfaces;
315 {
316 std::vector<std::string> interfaces;
317 auto sig{queue.pop()};
318 assert(sig);
319 sig.read(sigpath);
320 assert(sigpath == deleteMeThree);
321 sig.read(interfaces);
322 std::sort(interfaces.begin(), interfaces.end());
323 assert(hasInterfaces(interfaces, obj));
324 }
325 }
326 }
327
Brad Bishop432e3522016-12-01 00:24:14 -0500328 // Make sure DBus signals are handled.
329 {
Brad Bishop432e3522016-12-01 00:24:14 -0500330 // Create some objects to be deleted by an action.
331 {
332 auto m = notify();
333 m.append(relDeleteMeOne);
334 m.append(obj);
335 b.call(m);
336 }
337 {
338 auto m = notify();
339 m.append(relDeleteMeTwo);
340 m.append(obj);
341 b.call(m);
342 }
Brad Bishopfb083c22017-01-19 09:22:04 -0500343 {
344 auto m = notify();
345 m.append(relDeleteMeThree);
346 m.append(obj);
347 b.call(m);
348 }
Brad Bishop432e3522016-12-01 00:24:14 -0500349
Brad Bishopfb083c22017-01-19 09:22:04 -0500350 // Set some properties that should not trigger due to a filter.
Brad Bishop432e3522016-12-01 00:24:14 -0500351 {
352 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500353 "path='" + root + "',member='InterfacesRemoved'");
Brad Bishop8f868502017-01-23 13:13:58 -0500354 auto m = set(trigger1.str);
Brad Bishop432e3522016-12-01 00:24:14 -0500355 m.append("xyz.openbmc_project.Example.Iface2");
356 m.append("ExampleProperty2");
357 m.append(sdbusplus::message::variant<std::string>("abc123"));
358 b.call(m);
359 auto sig{queue.pop()};
360 assert(!sig);
361 }
Brad Bishopfb083c22017-01-19 09:22:04 -0500362 {
363 SignalQueue queue(
364 "path='" + root + "',member='InterfacesRemoved'");
365 auto m = set(trigger3.str);
366 m.append("xyz.openbmc_project.Example.Iface2");
367 m.append("ExampleProperty3");
368 m.append(sdbusplus::message::variant<int64_t>(11));
369 b.call(m);
370 auto sig{queue.pop()};
371 assert(!sig);
372 }
Brad Bishop432e3522016-12-01 00:24:14 -0500373
Brad Bishopfb083c22017-01-19 09:22:04 -0500374 // Set some properties that should trigger.
Brad Bishop432e3522016-12-01 00:24:14 -0500375 {
376 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500377 "path='" + root + "',member='InterfacesRemoved'");
Brad Bishop432e3522016-12-01 00:24:14 -0500378
Brad Bishop8f868502017-01-23 13:13:58 -0500379 auto m = set(trigger1.str);
Brad Bishop432e3522016-12-01 00:24:14 -0500380 m.append("xyz.openbmc_project.Example.Iface2");
381 m.append("ExampleProperty2");
382 m.append(sdbusplus::message::variant<std::string>("xxxyyy"));
383 b.call(m);
384
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500385 sdbusplus::message::object_path sigpath;
Brad Bishop432e3522016-12-01 00:24:14 -0500386 std::vector<std::string> interfaces;
387 {
388 std::vector<std::string> interfaces;
389 auto sig{queue.pop()};
390 assert(sig);
391 sig.read(sigpath);
392 assert(sigpath == deleteMeOne);
393 sig.read(interfaces);
394 std::sort(interfaces.begin(), interfaces.end());
395 assert(hasInterfaces(interfaces, obj));
396 }
397 {
398 std::vector<std::string> interfaces;
399 auto sig{queue.pop()};
400 assert(sig);
401 sig.read(sigpath);
402 assert(sigpath == deleteMeTwo);
403 sig.read(interfaces);
404 std::sort(interfaces.begin(), interfaces.end());
405 assert(hasInterfaces(interfaces, obj));
406 }
407 {
408 // Make sure there were only two signals.
409 auto sig{queue.pop()};
410 assert(!sig);
411 }
412 }
Brad Bishopfb083c22017-01-19 09:22:04 -0500413 {
414 SignalQueue queue(
415 "path='" + root + "',member='InterfacesRemoved'");
416
417 auto m = set(trigger3.str);
418 m.append("xyz.openbmc_project.Example.Iface2");
419 m.append("ExampleProperty3");
420 m.append(sdbusplus::message::variant<int64_t>(10));
421 b.call(m);
422
423 sdbusplus::message::object_path sigpath;
424 std::vector<std::string> interfaces;
425 {
426 std::vector<std::string> interfaces;
427 auto sig{queue.pop()};
428 assert(sig);
429 sig.read(sigpath);
430 assert(sigpath == deleteMeThree);
431 sig.read(interfaces);
432 std::sort(interfaces.begin(), interfaces.end());
433 assert(hasInterfaces(interfaces, obj));
434 }
435 {
436 // Make sure there was only one signal.
437 auto sig{queue.pop()};
438 assert(!sig);
439 }
440 }
Brad Bishop432e3522016-12-01 00:24:14 -0500441 }
442
Brad Bishop22ecacc2016-12-01 08:38:06 -0500443 // Validate the set property action.
444 {
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500445 sdbusplus::message::object_path relChangeMe{"/changeme"};
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500446 std::string changeMe{root + relChangeMe.str};
Brad Bishop22ecacc2016-12-01 08:38:06 -0500447
448 // Create an object to be updated by the set property action.
449 {
450 auto m = notify();
451 m.append(relChangeMe);
452 m.append(obj);
453 b.call(m);
454 }
455
Brad Bishop22ecacc2016-12-01 08:38:06 -0500456 // Trigger and validate the change.
457 {
458 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500459 "path='" + changeMe + "',member='PropertiesChanged'");
Brad Bishop8f868502017-01-23 13:13:58 -0500460 auto m = set(trigger2.str);
Brad Bishop22ecacc2016-12-01 08:38:06 -0500461 m.append("xyz.openbmc_project.Example.Iface2");
462 m.append("ExampleProperty2");
463 m.append(sdbusplus::message::variant<std::string>("yyyxxx"));
464 b.call(m);
465
466 std::string sigInterface;
Brad Bishop7b337772017-01-12 16:11:24 -0500467 std::map <
468 std::string,
469 sdbusplus::message::variant<std::string >> sigProperties;
Brad Bishop22ecacc2016-12-01 08:38:06 -0500470 {
471 std::vector<std::string> interfaces;
472 auto sig{queue.pop()};
473 sig.read(sigInterface);
474 assert(sigInterface == "xyz.openbmc_project.Example.Iface1");
475 sig.read(sigProperties);
476 assert(sigProperties["ExampleProperty1"] == "changed");
477 }
478 }
479 }
Brad Bishopeb68a682017-01-22 00:58:54 -0500480
481 // Validate the create object action.
482 {
483 sdbusplus::message::object_path relCreateMe1{"/createme1"};
484 sdbusplus::message::object_path relCreateMe2{"/createme2"};
485 std::string createMe1{root + relCreateMe1.str};
486 std::string createMe2{root + relCreateMe2.str};
487
488 // Trigger the action.
489 {
490 sdbusplus::message::object_path signalPath;
491 Object signalObject;
492
493 SignalQueue queue(
494 "path='" + root + "',member='InterfacesAdded'");
495
496 auto m = set(trigger5.str);
497 m.append("xyz.openbmc_project.Example.Iface2");
498 m.append("ExampleProperty2");
499 m.append(sdbusplus::message::variant<std::string>("abc123"));
500 b.call(m);
501 {
502 auto sig{queue.pop()};
503 assert(sig);
504 sig.read(signalPath);
505 assert(createMe1 == signalPath.str);
506 sig.read(signalObject);
507 }
508 {
509 auto sig{queue.pop()};
510 assert(sig);
511 sig.read(signalPath);
512 assert(createMe2 == signalPath.str);
513 sig.read(signalObject);
514 }
515
516 auto moreSignals{queue.pop()};
517 assert(!moreSignals);
518 }
519 }
Brad Bishop49aefb32016-10-19 11:54:14 -0400520}
521
522int main()
523{
Brad Bishop65247582017-01-15 19:48:41 -0500524 phosphor::inventory::manager::Manager mgr(
525 sdbusplus::bus::new_default(),
Brad Bishop8f868502017-01-23 13:13:58 -0500526 MGR_SERVICE, MGR_ROOT, MGR_INTERFACE);
527 ExampleService d;
Brad Bishop49aefb32016-10-19 11:54:14 -0400528
Brad Bishop8f868502017-01-23 13:13:58 -0500529 auto f1 = [](auto mgr)
Brad Bishop49aefb32016-10-19 11:54:14 -0400530 {
Brad Bishop21621432017-01-13 16:35:53 -0500531 mgr->run();
532 };
Brad Bishop8f868502017-01-23 13:13:58 -0500533 auto f2 = [](auto d)
534 {
535 d->run();
536 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400537
Brad Bishop8f868502017-01-23 13:13:58 -0500538 auto t1 = std::thread(f1, &mgr);
539 auto t2 = std::thread(f2, &d);
540
541 runTests();
542
543 mgr.shutdown();
544 d.shutdown = true;
545
546 // Wait for server threads to exit.
547 t1.join();
548 t2.join();
549 std::cout << "Success! Waiting for threads to exit..." << std::endl;
Brad Bishop49aefb32016-10-19 11:54:14 -0400550
551 return 0;
552}
553
554// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4