blob: 5d020e94c0b8d64abbdc2190f505efc6bb29ae45 [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 "config.h"
Patrick Venturea680d1e2018-10-14 13:34:26 -070017
18#include "manager.hpp"
Brad Bishopa6fcd562017-02-03 11:00:27 -050019#include "xyz/openbmc_project/Example/Iface1/server.hpp"
20#include "xyz/openbmc_project/Example/Iface2/server.hpp"
Brad Bishop49aefb32016-10-19 11:54:14 -040021
Patrick Venturea680d1e2018-10-14 13:34:26 -070022#include <algorithm>
23#include <cassert>
24#include <chrono>
25#include <iostream>
26#include <thread>
27
Brad Bishop8f868502017-01-23 13:13:58 -050028using namespace std::literals::chrono_literals;
29using namespace std::literals::string_literals;
30
Brad Bishop03f4cd92017-02-03 15:17:21 -050031using Object = phosphor::inventory::manager::Object;
32using ObjectMap = std::map<sdbusplus::message::object_path, Object>;
33
Brad Bishop8f868502017-01-23 13:13:58 -050034constexpr auto MGR_SERVICE = "phosphor.inventory.test.mgr";
35constexpr auto MGR_INTERFACE = IFACE;
36constexpr auto MGR_ROOT = "/testing/inventory";
37constexpr auto EXAMPLE_SERVICE = "phosphor.inventory.test.example";
38constexpr auto EXAMPLE_ROOT = "/testing";
39
Brad Bishop615b2a82018-03-29 10:32:41 -040040const auto trigger1 =
41 sdbusplus::message::object_path(EXAMPLE_ROOT + "/trigger1"s);
42const auto trigger2 =
43 sdbusplus::message::object_path(EXAMPLE_ROOT + "/trigger2"s);
44const auto trigger3 =
45 sdbusplus::message::object_path(EXAMPLE_ROOT + "/trigger3"s);
46const auto trigger4 =
47 sdbusplus::message::object_path(EXAMPLE_ROOT + "/trigger4"s);
48const auto trigger5 =
49 sdbusplus::message::object_path(EXAMPLE_ROOT + "/trigger5"s);
Brad Bishopfb083c22017-01-19 09:22:04 -050050
51const sdbusplus::message::object_path relDeleteMeOne{"/deleteme1"};
52const sdbusplus::message::object_path relDeleteMeTwo{"/deleteme2"};
53const sdbusplus::message::object_path relDeleteMeThree{"/deleteme3"};
54
55const std::string root{MGR_ROOT};
56const std::string deleteMeOne{root + relDeleteMeOne.str};
57const std::string deleteMeTwo{root + relDeleteMeTwo.str};
58const std::string deleteMeThree{root + relDeleteMeThree.str};
Brad Bishop8f868502017-01-23 13:13:58 -050059
60using ExampleIface1 = sdbusplus::xyz::openbmc_project::Example::server::Iface1;
61using ExampleIface2 = sdbusplus::xyz::openbmc_project::Example::server::Iface2;
62
63/** @class ExampleService
64 * @brief Host an object for triggering events.
65 */
66struct ExampleService
67{
68 ~ExampleService() = default;
69 ExampleService() :
Brad Bishop615b2a82018-03-29 10:32:41 -040070 shutdown(false), bus(sdbusplus::bus::new_default()),
Brad Bishop8f868502017-01-23 13:13:58 -050071 objmgr(sdbusplus::server::manager::manager(bus, MGR_ROOT))
72 {
73 bus.request_name(EXAMPLE_SERVICE);
74 }
75
76 void run()
77 {
Brad Bishop615b2a82018-03-29 10:32:41 -040078 sdbusplus::server::object::object<ExampleIface1, ExampleIface2> t1(
79 bus, trigger1.str.c_str());
80 sdbusplus::server::object::object<ExampleIface1, ExampleIface2> t2(
81 bus, trigger2.str.c_str());
82 sdbusplus::server::object::object<ExampleIface1, ExampleIface2> t3(
83 bus, trigger3.str.c_str());
84 sdbusplus::server::object::object<ExampleIface1, ExampleIface2> t4(
85 bus, trigger4.str.c_str());
86 sdbusplus::server::object::object<ExampleIface1, ExampleIface2> t5(
87 bus, trigger5.str.c_str());
Brad Bishop8f868502017-01-23 13:13:58 -050088
89 while (!shutdown)
90 {
91 bus.process_discard();
92 bus.wait((5000000us).count());
93 }
94 }
95
96 volatile bool shutdown;
97 sdbusplus::bus::bus bus;
98 sdbusplus::server::manager::manager objmgr;
99};
Brad Bishop49aefb32016-10-19 11:54:14 -0400100
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500101/** @class SignalQueue
102 * @brief Store DBus signals in a queue.
103 */
104class SignalQueue
105{
Brad Bishop615b2a82018-03-29 10:32:41 -0400106 public:
107 ~SignalQueue() = default;
108 SignalQueue() = delete;
109 SignalQueue(const SignalQueue&) = delete;
110 SignalQueue(SignalQueue&&) = default;
111 SignalQueue& operator=(const SignalQueue&) = delete;
112 SignalQueue& operator=(SignalQueue&&) = default;
113 explicit SignalQueue(const std::string& match) :
114 _bus(sdbusplus::bus::new_default()),
115 _match(_bus, match.c_str(), &callback, this), _next(nullptr)
Brad Bishopa83db302020-12-06 14:51:23 -0500116 {}
Brad Bishop7b337772017-01-12 16:11:24 -0500117
Brad Bishop615b2a82018-03-29 10:32:41 -0400118 auto&& pop(unsigned timeout = 1000000)
119 {
120 while (timeout > 0 && !_next)
Brad Bishop7b337772017-01-12 16:11:24 -0500121 {
Brad Bishop615b2a82018-03-29 10:32:41 -0400122 _bus.process_discard();
123 _bus.wait(50000);
124 timeout -= 50000;
Brad Bishop7b337772017-01-12 16:11:24 -0500125 }
Brad Bishop615b2a82018-03-29 10:32:41 -0400126 return std::move(_next);
127 }
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500128
Brad Bishop615b2a82018-03-29 10:32:41 -0400129 private:
130 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 Bishop615b2a82018-03-29 10:32:41 -0400139 sdbusplus::bus::bus _bus;
140 sdbusplus::bus::match_t _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 Bishop615b2a82018-03-29 10:32:41 -0400148 std::set_difference(r.cbegin(), r.cend(), l.cbegin(), l.cend(),
149 std::inserter(result, result.end()));
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500150 return result.empty();
151}
152
Brad Bishop432e3522016-12-01 00:24:14 -0500153/**@brief Check an object for one or more interfaces. */
Brad Bishop1157af12017-01-22 01:03:02 -0500154auto hasInterfaces(const std::vector<std::string>& l, const Object& r)
Brad Bishop432e3522016-12-01 00:24:14 -0500155{
156 std::vector<std::string> stripped, interfaces;
Brad Bishop615b2a82018-03-29 10:32:41 -0400157 std::transform(r.cbegin(), r.cend(), std::back_inserter(stripped),
158 [](auto& p) { return p.first; });
159 std::set_difference(stripped.cbegin(), stripped.cend(), l.cbegin(),
160 l.cend(), std::back_inserter(interfaces));
Brad Bishop432e3522016-12-01 00:24:14 -0500161 return interfaces.empty();
162}
163
Brad Bishop8f868502017-01-23 13:13:58 -0500164void runTests()
Brad Bishop49aefb32016-10-19 11:54:14 -0400165{
Brad Bishop8f868502017-01-23 13:13:58 -0500166 const std::string exampleRoot{EXAMPLE_ROOT};
Brad Bishop49aefb32016-10-19 11:54:14 -0400167 auto b = sdbusplus::bus::new_default();
Brad Bishop8f868502017-01-23 13:13:58 -0500168
Brad Bishop615b2a82018-03-29 10:32:41 -0400169 auto notify = [&]() {
170 return b.new_method_call(MGR_SERVICE, MGR_ROOT, MGR_INTERFACE,
171 "Notify");
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500172 };
Brad Bishop615b2a82018-03-29 10:32:41 -0400173 auto set = [&](const std::string& path) {
174 return b.new_method_call(EXAMPLE_SERVICE, path.c_str(),
175 "org.freedesktop.DBus.Properties", "Set");
Brad Bishop432e3522016-12-01 00:24:14 -0500176 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400177
Brad Bishop615b2a82018-03-29 10:32:41 -0400178 Object obj{
179 {"xyz.openbmc_project.Example.Iface1",
180 {{"ExampleProperty1", "test1"s}}},
181 {"xyz.openbmc_project.Example.Iface2",
182 {{"ExampleProperty2", "test2"s},
183 {"ExampleProperty3", static_cast<int64_t>(0ll)}}},
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500184 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400185
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500186 // Validate startup events occurred.
187 {
188 sdbusplus::message::object_path relCreateMe3{"/createme3"};
189 std::string createMe3{root + relCreateMe3.str};
190
Brad Bishop615b2a82018-03-29 10:32:41 -0400191 auto get =
192 b.new_method_call(MGR_SERVICE, createMe3.c_str(),
193 "org.freedesktop.DBus.Properties", "GetAll");
Brad Bishop3e4a19a2017-01-21 22:17:09 -0500194 get.append("xyz.openbmc_project.Example.Iface1");
195 auto resp = b.call(get);
196
197 Object::mapped_type properties;
198 assert(!resp.is_method_error());
199 resp.read(properties);
200 }
201
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500202 // Make sure the notify method works.
203 {
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500204 sdbusplus::message::object_path relPath{"/foo"};
205 std::string path(root + relPath.str);
Brad Bishop49aefb32016-10-19 11:54:14 -0400206
Brad Bishop615b2a82018-03-29 10:32:41 -0400207 SignalQueue queue("path='" + root + "',member='InterfacesAdded'");
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500208
209 auto m = notify();
Brad Bishop03f4cd92017-02-03 15:17:21 -0500210 m.append(ObjectMap({{relPath, obj}}));
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500211 b.call(m);
212
213 auto sig{queue.pop()};
Brad Bishop6211a432018-02-21 13:24:41 -0500214 assert(static_cast<bool>(sig));
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500215 sdbusplus::message::object_path signalPath;
Brad Bishop1157af12017-01-22 01:03:02 -0500216 Object signalObjectType;
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500217 sig.read(signalPath);
Brad Bishope07a1642017-01-24 14:37:33 -0500218 assert(path == signalPath.str);
Brad Bishop1157af12017-01-22 01:03:02 -0500219 sig.read(signalObjectType);
220 assert(hasProperties(signalObjectType, obj));
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500221 auto moreSignals{queue.pop()};
222 assert(!moreSignals);
Brad Bishop49aefb32016-10-19 11:54:14 -0400223 }
224
Brad Bishopfa51da72017-01-19 11:06:51 -0500225 // Validate the propertyIs filter.
Brad Bishop615b2a82018-03-29 10:32:41 -0400226 {// Create an object to be deleted.
227 {auto m = notify();
228 m.append(ObjectMap({{relDeleteMeThree, obj}}));
229 b.call(m);
230}
231
232// Validate that the action does not run if the property doesn't match.
233{
234 SignalQueue queue("path='" + root + "',member='InterfacesRemoved'");
235 auto m = set(trigger4.str);
236 m.append("xyz.openbmc_project.Example.Iface2");
237 m.append("ExampleProperty2");
Patrick Williams55f9eae2020-05-13 17:57:04 -0500238 m.append(std::variant<std::string>("123"));
Brad Bishop615b2a82018-03-29 10:32:41 -0400239 b.call(m);
240 auto sig{queue.pop()};
241 assert(!sig);
242}
243
244// Validate that the action does run if the property matches.
245{
246 // Set ExampleProperty2 to something else to the 123 filter
247 // matches.
248 SignalQueue queue("path='" + root + "',member='InterfacesRemoved'");
249 auto m = set(trigger4.str);
250 m.append("xyz.openbmc_project.Example.Iface2");
251 m.append("ExampleProperty2");
Patrick Williams55f9eae2020-05-13 17:57:04 -0500252 m.append(std::variant<std::string>("xyz"));
Brad Bishop615b2a82018-03-29 10:32:41 -0400253 b.call(m);
254 auto sig{queue.pop()};
255 assert(!sig);
256}
257{
258 // Set ExampleProperty3 to 99.
259 SignalQueue queue("path='" + root + "',member='InterfacesRemoved'");
260 auto m = set(trigger4.str);
261 m.append("xyz.openbmc_project.Example.Iface2");
262 m.append("ExampleProperty3");
Patrick Williams55f9eae2020-05-13 17:57:04 -0500263 m.append(std::variant<int64_t>(99));
Brad Bishop615b2a82018-03-29 10:32:41 -0400264 b.call(m);
265 auto sig{queue.pop()};
266 assert(!sig);
267}
268{
269 SignalQueue queue("path='" + root + "',member='InterfacesRemoved'");
270 auto m = set(trigger4.str);
271 m.append("xyz.openbmc_project.Example.Iface2");
272 m.append("ExampleProperty2");
Patrick Williams55f9eae2020-05-13 17:57:04 -0500273 m.append(std::variant<std::string>("123"));
Brad Bishop615b2a82018-03-29 10:32:41 -0400274 b.call(m);
275
276 sdbusplus::message::object_path sigpath;
277 std::vector<std::string> interfaces;
Brad Bishopfa51da72017-01-19 11:06:51 -0500278 {
Brad Bishop615b2a82018-03-29 10:32:41 -0400279 std::vector<std::string> interfaces;
280 auto sig{queue.pop()};
281 assert(static_cast<bool>(sig));
282 sig.read(sigpath);
283 assert(sigpath == deleteMeThree);
284 sig.read(interfaces);
285 std::sort(interfaces.begin(), interfaces.end());
286 assert(hasInterfaces(interfaces, obj));
287 }
288}
289}
Brad Bishopfa51da72017-01-19 11:06:51 -0500290
Brad Bishop615b2a82018-03-29 10:32:41 -0400291// Make sure DBus signals are handled.
292{// Create some objects to be deleted by an action.
293 {auto m = notify();
294m.append(ObjectMap({{relDeleteMeOne, obj}}));
295b.call(m);
296}
297{
298 auto m = notify();
299 m.append(ObjectMap({{relDeleteMeTwo, obj}}));
300 b.call(m);
301}
302{
303 auto m = notify();
304 m.append(ObjectMap({{relDeleteMeThree, obj}}));
305 b.call(m);
306}
Brad Bishopfa51da72017-01-19 11:06:51 -0500307
Brad Bishop615b2a82018-03-29 10:32:41 -0400308// Set some properties that should not trigger due to a filter.
309{
310 SignalQueue queue("path='" + root + "',member='InterfacesRemoved'");
311 auto m = set(trigger1.str);
312 m.append("xyz.openbmc_project.Example.Iface2");
313 m.append("ExampleProperty2");
Patrick Williams55f9eae2020-05-13 17:57:04 -0500314 m.append(std::variant<std::string>("abc123"));
Brad Bishop615b2a82018-03-29 10:32:41 -0400315 b.call(m);
316 auto sig{queue.pop()};
317 assert(!sig);
318}
319{
320 SignalQueue queue("path='" + root + "',member='InterfacesRemoved'");
321 auto m = set(trigger3.str);
322 m.append("xyz.openbmc_project.Example.Iface2");
323 m.append("ExampleProperty3");
Patrick Williams55f9eae2020-05-13 17:57:04 -0500324 m.append(std::variant<int64_t>(11));
Brad Bishop615b2a82018-03-29 10:32:41 -0400325 b.call(m);
326 auto sig{queue.pop()};
327 assert(!sig);
328}
Brad Bishopfa51da72017-01-19 11:06:51 -0500329
Brad Bishop615b2a82018-03-29 10:32:41 -0400330// Set some properties that should trigger.
331{
332 SignalQueue queue("path='" + root + "',member='InterfacesRemoved'");
333
334 auto m = set(trigger1.str);
335 m.append("xyz.openbmc_project.Example.Iface2");
336 m.append("ExampleProperty2");
Patrick Williams55f9eae2020-05-13 17:57:04 -0500337 m.append(std::variant<std::string>("xxxyyy"));
Brad Bishop615b2a82018-03-29 10:32:41 -0400338 b.call(m);
339
340 sdbusplus::message::object_path sigpath;
341 std::vector<std::string> interfaces;
342 {
343 std::vector<std::string> interfaces;
344 auto sig{queue.pop()};
345 assert(static_cast<bool>(sig));
346 sig.read(sigpath);
347 assert(sigpath == deleteMeOne);
348 sig.read(interfaces);
349 std::sort(interfaces.begin(), interfaces.end());
350 assert(hasInterfaces(interfaces, obj));
351 }
352 {
353 std::vector<std::string> interfaces;
354 auto sig{queue.pop()};
355 assert(static_cast<bool>(sig));
356 sig.read(sigpath);
357 assert(sigpath == deleteMeTwo);
358 sig.read(interfaces);
359 std::sort(interfaces.begin(), interfaces.end());
360 assert(hasInterfaces(interfaces, obj));
361 }
362 {
363 // Make sure there were only two signals.
364 auto sig{queue.pop()};
365 assert(!sig);
366 }
367}
368{
369 SignalQueue queue("path='" + root + "',member='InterfacesRemoved'");
370
371 auto m = set(trigger3.str);
372 m.append("xyz.openbmc_project.Example.Iface2");
373 m.append("ExampleProperty3");
Patrick Williams55f9eae2020-05-13 17:57:04 -0500374 m.append(std::variant<int64_t>(10));
Brad Bishop615b2a82018-03-29 10:32:41 -0400375 b.call(m);
376
377 sdbusplus::message::object_path sigpath;
378 std::vector<std::string> interfaces;
379 {
380 std::vector<std::string> interfaces;
381 auto sig{queue.pop()};
382 assert(static_cast<bool>(sig));
383 sig.read(sigpath);
384 assert(sigpath == deleteMeThree);
385 sig.read(interfaces);
386 std::sort(interfaces.begin(), interfaces.end());
387 assert(hasInterfaces(interfaces, obj));
388 }
389 {
390 // Make sure there was only one signal.
391 auto sig{queue.pop()};
392 assert(!sig);
393 }
394}
395}
396
397// Validate the set property action.
398{
399 sdbusplus::message::object_path relChangeMe{"/changeme"};
400 std::string changeMe{root + relChangeMe.str};
401
402 // Create an object to be updated by the set property action.
403 {
404 auto m = notify();
405 m.append(ObjectMap({{relChangeMe, obj}}));
406 b.call(m);
407 }
408
409 // Trigger and validate the change.
410 {
411 SignalQueue queue("path='" + changeMe + "',member='PropertiesChanged'");
412 auto m = set(trigger2.str);
413 m.append("xyz.openbmc_project.Example.Iface2");
414 m.append("ExampleProperty2");
Patrick Williams55f9eae2020-05-13 17:57:04 -0500415 m.append(std::variant<std::string>("yyyxxx"));
Brad Bishop615b2a82018-03-29 10:32:41 -0400416 b.call(m);
417
418 std::string sigInterface;
Patrick Williams55f9eae2020-05-13 17:57:04 -0500419 std::map<std::string, std::variant<std::string>> sigProperties;
Brad Bishop615b2a82018-03-29 10:32:41 -0400420 {
Brad Bishopfa51da72017-01-19 11:06:51 -0500421 std::vector<std::string> interfaces;
Brad Bishop432e3522016-12-01 00:24:14 -0500422 auto sig{queue.pop()};
Brad Bishop615b2a82018-03-29 10:32:41 -0400423 sig.read(sigInterface);
424 assert(sigInterface == "xyz.openbmc_project.Example.Iface1");
425 sig.read(sigProperties);
Patrick Williams26f86682020-05-13 11:36:19 -0500426 assert(std::get<std::string>(sigProperties["ExampleProperty1"]) ==
427 "changed");
Brad Bishop432e3522016-12-01 00:24:14 -0500428 }
Brad Bishop615b2a82018-03-29 10:32:41 -0400429 }
430}
431
432// Validate the create object action.
433{
434 sdbusplus::message::object_path relCreateMe1{"/createme1"};
435 sdbusplus::message::object_path relCreateMe2{"/createme2"};
436 std::string createMe1{root + relCreateMe1.str};
437 std::string createMe2{root + relCreateMe2.str};
438
439 // Trigger the action.
440 {
441 sdbusplus::message::object_path signalPath;
442 Object signalObject;
443
444 SignalQueue queue("path='" + root + "',member='InterfacesAdded'");
445
446 auto m = set(trigger5.str);
447 m.append("xyz.openbmc_project.Example.Iface2");
448 m.append("ExampleProperty2");
Patrick Williams55f9eae2020-05-13 17:57:04 -0500449 m.append(std::variant<std::string>("abc123"));
Brad Bishop615b2a82018-03-29 10:32:41 -0400450 b.call(m);
Brad Bishopfb083c22017-01-19 09:22:04 -0500451 {
Brad Bishopfb083c22017-01-19 09:22:04 -0500452 auto sig{queue.pop()};
Brad Bishop615b2a82018-03-29 10:32:41 -0400453 assert(static_cast<bool>(sig));
454 sig.read(signalPath);
455 assert(createMe1 == signalPath.str);
456 sig.read(signalObject);
Brad Bishop432e3522016-12-01 00:24:14 -0500457 }
Brad Bishopfb083c22017-01-19 09:22:04 -0500458 {
Brad Bishop615b2a82018-03-29 10:32:41 -0400459 auto sig{queue.pop()};
460 assert(static_cast<bool>(sig));
461 sig.read(signalPath);
462 assert(createMe2 == signalPath.str);
463 sig.read(signalObject);
Brad Bishopfb083c22017-01-19 09:22:04 -0500464 }
Brad Bishop615b2a82018-03-29 10:32:41 -0400465
466 auto moreSignals{queue.pop()};
467 assert(!moreSignals);
Brad Bishop432e3522016-12-01 00:24:14 -0500468 }
Brad Bishop615b2a82018-03-29 10:32:41 -0400469}
Brad Bishop49aefb32016-10-19 11:54:14 -0400470}
471
472int main()
473{
Brad Bishopacaaab62020-12-06 20:17:09 -0500474 phosphor::inventory::manager::Manager mgr(sdbusplus::bus::new_default(),
Brad Bishop20c94352020-12-06 20:23:56 -0500475 MGR_ROOT);
Brad Bishop8f868502017-01-23 13:13:58 -0500476 ExampleService d;
Brad Bishop49aefb32016-10-19 11:54:14 -0400477
Brad Bishop20c94352020-12-06 20:23:56 -0500478 auto f1 = [](auto mgr) { mgr->run(MGR_SERVICE); };
Brad Bishop615b2a82018-03-29 10:32:41 -0400479 auto f2 = [](auto d) { d->run(); };
Brad Bishop49aefb32016-10-19 11:54:14 -0400480
Brad Bishop8f868502017-01-23 13:13:58 -0500481 auto t1 = std::thread(f1, &mgr);
482 auto t2 = std::thread(f2, &d);
483
484 runTests();
485
486 mgr.shutdown();
487 d.shutdown = true;
488
489 // Wait for server threads to exit.
490 t1.join();
491 t2.join();
492 std::cout << "Success! Waiting for threads to exit..." << std::endl;
Brad Bishop49aefb32016-10-19 11:54:14 -0400493
494 return 0;
495}
496
497// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4