blob: bd75dbba743e7405847120be17cc31a094edd3ba [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 Bishope30dd772016-11-12 21:39:28 -050016#include "../manager.hpp"
Brad Bishop49aefb32016-10-19 11:54:14 -040017#include "../config.h"
18#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>
23#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);
41
42const sdbusplus::message::object_path relDeleteMeOne{"/deleteme1"};
43const sdbusplus::message::object_path relDeleteMeTwo{"/deleteme2"};
44const sdbusplus::message::object_path relDeleteMeThree{"/deleteme3"};
45
46const std::string root{MGR_ROOT};
47const std::string deleteMeOne{root + relDeleteMeOne.str};
48const std::string deleteMeTwo{root + relDeleteMeTwo.str};
49const std::string deleteMeThree{root + relDeleteMeThree.str};
Brad Bishop8f868502017-01-23 13:13:58 -050050
51using ExampleIface1 = sdbusplus::xyz::openbmc_project::Example::server::Iface1;
52using ExampleIface2 = sdbusplus::xyz::openbmc_project::Example::server::Iface2;
53
54/** @class ExampleService
55 * @brief Host an object for triggering events.
56 */
57struct ExampleService
58{
59 ~ExampleService() = default;
60 ExampleService() :
61 shutdown(false),
62 bus(sdbusplus::bus::new_default()),
63 objmgr(sdbusplus::server::manager::manager(bus, MGR_ROOT))
64 {
65 bus.request_name(EXAMPLE_SERVICE);
66 }
67
68 void run()
69 {
70 sdbusplus::server::object::object <
71 ExampleIface1, ExampleIface2 > t1(bus, trigger1.str.c_str());
72 sdbusplus::server::object::object <
73 ExampleIface1, ExampleIface2 > t2(bus, trigger2.str.c_str());
Brad Bishopfb083c22017-01-19 09:22:04 -050074 sdbusplus::server::object::object <
75 ExampleIface1, ExampleIface2 > t3(bus, trigger3.str.c_str());
Brad Bishop8f868502017-01-23 13:13:58 -050076
77 while (!shutdown)
78 {
79 bus.process_discard();
80 bus.wait((5000000us).count());
81 }
82 }
83
84 volatile bool shutdown;
85 sdbusplus::bus::bus bus;
86 sdbusplus::server::manager::manager objmgr;
87};
Brad Bishop49aefb32016-10-19 11:54:14 -040088
Brad Bishopabb2a1a2016-11-30 22:02:28 -050089/** @class SignalQueue
90 * @brief Store DBus signals in a queue.
91 */
92class SignalQueue
93{
94 public:
Brad Bishop7b337772017-01-12 16:11:24 -050095 ~SignalQueue() = default;
96 SignalQueue() = delete;
97 SignalQueue(const SignalQueue&) = delete;
98 SignalQueue(SignalQueue&&) = default;
99 SignalQueue& operator=(const SignalQueue&) = delete;
100 SignalQueue& operator=(SignalQueue&&) = default;
101 explicit SignalQueue(const std::string& match) :
102 _bus(sdbusplus::bus::new_default()),
103 _match(_bus, match.c_str(), &callback, this),
104 _next(nullptr)
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500105 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500106 }
Brad Bishop7b337772017-01-12 16:11:24 -0500107
108 auto&& pop(unsigned timeout = 1000000)
109 {
110 while (timeout > 0 && !_next)
111 {
112 _bus.process_discard();
113 _bus.wait(50000);
114 timeout -= 50000;
115 }
116 return std::move(_next);
117 }
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500118
119 private:
Brad Bishop7b337772017-01-12 16:11:24 -0500120 static int callback(sd_bus_message* m, void* context, sd_bus_error*)
121 {
122 auto* me = static_cast<SignalQueue*>(context);
123 sd_bus_message_ref(m);
124 sdbusplus::message::message msg{m};
125 me->_next = std::move(msg);
126 return 0;
127 }
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500128
Brad Bishop7b337772017-01-12 16:11:24 -0500129 sdbusplus::bus::bus _bus;
130 sdbusplus::server::match::match _match;
131 sdbusplus::message::message _next;
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500132};
133
134template <typename ...T>
Brad Bishop7b337772017-01-12 16:11:24 -0500135using Object = std::map <
136 std::string,
137 std::map <
138 std::string,
139 sdbusplus::message::variant<T... >>>;
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500140
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500141/**@brief Find a subset of interfaces and properties in an object. */
142template <typename ...T>
Brad Bishop7b337772017-01-12 16:11:24 -0500143auto hasProperties(const Object<T...>& l, const Object<T...>& r)
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500144{
145 Object<T...> result;
146 std::set_difference(
Brad Bishop7b337772017-01-12 16:11:24 -0500147 r.cbegin(),
148 r.cend(),
149 l.cbegin(),
150 l.cend(),
151 std::inserter(result, result.end()));
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500152 return result.empty();
153}
154
Brad Bishop432e3522016-12-01 00:24:14 -0500155/**@brief Check an object for one or more interfaces. */
156template <typename ...T>
Brad Bishop7b337772017-01-12 16:11:24 -0500157auto hasInterfaces(const std::vector<std::string>& l, const Object<T...>& r)
Brad Bishop432e3522016-12-01 00:24:14 -0500158{
159 std::vector<std::string> stripped, interfaces;
160 std::transform(
Brad Bishop7b337772017-01-12 16:11:24 -0500161 r.cbegin(),
162 r.cend(),
163 std::back_inserter(stripped),
164 [](auto & p)
165 {
166 return p.first;
167 });
Brad Bishop432e3522016-12-01 00:24:14 -0500168 std::set_difference(
Brad Bishop7b337772017-01-12 16:11:24 -0500169 stripped.cbegin(),
170 stripped.cend(),
171 l.cbegin(),
172 l.cend(),
173 std::back_inserter(interfaces));
Brad Bishop432e3522016-12-01 00:24:14 -0500174 return interfaces.empty();
175}
176
Brad Bishop8f868502017-01-23 13:13:58 -0500177void runTests()
Brad Bishop49aefb32016-10-19 11:54:14 -0400178{
Brad Bishop8f868502017-01-23 13:13:58 -0500179 const std::string exampleRoot{EXAMPLE_ROOT};
Brad Bishop49aefb32016-10-19 11:54:14 -0400180 auto b = sdbusplus::bus::new_default();
Brad Bishop8f868502017-01-23 13:13:58 -0500181
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500182 auto notify = [&]()
Brad Bishop49aefb32016-10-19 11:54:14 -0400183 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500184 return b.new_method_call(
Brad Bishop8f868502017-01-23 13:13:58 -0500185 MGR_SERVICE,
186 MGR_ROOT,
187 MGR_INTERFACE,
Brad Bishop7b337772017-01-12 16:11:24 -0500188 "Notify");
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500189 };
Brad Bishop7b337772017-01-12 16:11:24 -0500190 auto set = [&](const std::string & path)
Brad Bishop432e3522016-12-01 00:24:14 -0500191 {
192 return b.new_method_call(
Brad Bishop8f868502017-01-23 13:13:58 -0500193 EXAMPLE_SERVICE,
Brad Bishop7b337772017-01-12 16:11:24 -0500194 path.c_str(),
195 "org.freedesktop.DBus.Properties",
196 "Set");
Brad Bishop432e3522016-12-01 00:24:14 -0500197 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400198
Brad Bishop7b337772017-01-12 16:11:24 -0500199 Object<std::string> obj
200 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500201 {
202 "xyz.openbmc_project.Example.Iface1",
203 {{"ExampleProperty1", "test1"}}
204 },
205 {
206 "xyz.openbmc_project.Example.Iface2",
207 {{"ExampleProperty2", "test2"}}
208 },
209 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400210
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500211 // Make sure the notify method works.
212 {
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500213 sdbusplus::message::object_path relPath{"/foo"};
214 std::string path(root + relPath.str);
Brad Bishop49aefb32016-10-19 11:54:14 -0400215
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500216 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500217 "path='" + root + "',member='InterfacesAdded'");
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500218
219 auto m = notify();
220 m.append(relPath);
221 m.append(obj);
222 b.call(m);
223
224 auto sig{queue.pop()};
225 assert(sig);
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500226 sdbusplus::message::object_path signalPath;
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500227 Object<std::string> signalObject;
228 sig.read(signalPath);
Brad Bishope07a1642017-01-24 14:37:33 -0500229 assert(path == signalPath.str);
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500230 sig.read(signalObject);
231 assert(hasProperties(signalObject, obj));
232 auto moreSignals{queue.pop()};
233 assert(!moreSignals);
Brad Bishop49aefb32016-10-19 11:54:14 -0400234 }
235
Brad Bishop432e3522016-12-01 00:24:14 -0500236 // Make sure DBus signals are handled.
237 {
Brad Bishop432e3522016-12-01 00:24:14 -0500238 // Create some objects to be deleted by an action.
239 {
240 auto m = notify();
241 m.append(relDeleteMeOne);
242 m.append(obj);
243 b.call(m);
244 }
245 {
246 auto m = notify();
247 m.append(relDeleteMeTwo);
248 m.append(obj);
249 b.call(m);
250 }
Brad Bishopfb083c22017-01-19 09:22:04 -0500251 {
252 auto m = notify();
253 m.append(relDeleteMeThree);
254 m.append(obj);
255 b.call(m);
256 }
Brad Bishop432e3522016-12-01 00:24:14 -0500257
Brad Bishopfb083c22017-01-19 09:22:04 -0500258 // Set some properties that should not trigger due to a filter.
Brad Bishop432e3522016-12-01 00:24:14 -0500259 {
260 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500261 "path='" + root + "',member='InterfacesRemoved'");
Brad Bishop8f868502017-01-23 13:13:58 -0500262 auto m = set(trigger1.str);
Brad Bishop432e3522016-12-01 00:24:14 -0500263 m.append("xyz.openbmc_project.Example.Iface2");
264 m.append("ExampleProperty2");
265 m.append(sdbusplus::message::variant<std::string>("abc123"));
266 b.call(m);
267 auto sig{queue.pop()};
268 assert(!sig);
269 }
Brad Bishopfb083c22017-01-19 09:22:04 -0500270 {
271 SignalQueue queue(
272 "path='" + root + "',member='InterfacesRemoved'");
273 auto m = set(trigger3.str);
274 m.append("xyz.openbmc_project.Example.Iface2");
275 m.append("ExampleProperty3");
276 m.append(sdbusplus::message::variant<int64_t>(11));
277 b.call(m);
278 auto sig{queue.pop()};
279 assert(!sig);
280 }
Brad Bishop432e3522016-12-01 00:24:14 -0500281
Brad Bishopfb083c22017-01-19 09:22:04 -0500282 // Set some properties that should trigger.
Brad Bishop432e3522016-12-01 00:24:14 -0500283 {
284 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500285 "path='" + root + "',member='InterfacesRemoved'");
Brad Bishop432e3522016-12-01 00:24:14 -0500286
Brad Bishop8f868502017-01-23 13:13:58 -0500287 auto m = set(trigger1.str);
Brad Bishop432e3522016-12-01 00:24:14 -0500288 m.append("xyz.openbmc_project.Example.Iface2");
289 m.append("ExampleProperty2");
290 m.append(sdbusplus::message::variant<std::string>("xxxyyy"));
291 b.call(m);
292
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500293 sdbusplus::message::object_path sigpath;
Brad Bishop432e3522016-12-01 00:24:14 -0500294 std::vector<std::string> interfaces;
295 {
296 std::vector<std::string> interfaces;
297 auto sig{queue.pop()};
298 assert(sig);
299 sig.read(sigpath);
300 assert(sigpath == deleteMeOne);
301 sig.read(interfaces);
302 std::sort(interfaces.begin(), interfaces.end());
303 assert(hasInterfaces(interfaces, obj));
304 }
305 {
306 std::vector<std::string> interfaces;
307 auto sig{queue.pop()};
308 assert(sig);
309 sig.read(sigpath);
310 assert(sigpath == deleteMeTwo);
311 sig.read(interfaces);
312 std::sort(interfaces.begin(), interfaces.end());
313 assert(hasInterfaces(interfaces, obj));
314 }
315 {
316 // Make sure there were only two signals.
317 auto sig{queue.pop()};
318 assert(!sig);
319 }
320 }
Brad Bishopfb083c22017-01-19 09:22:04 -0500321 {
322 SignalQueue queue(
323 "path='" + root + "',member='InterfacesRemoved'");
324
325 auto m = set(trigger3.str);
326 m.append("xyz.openbmc_project.Example.Iface2");
327 m.append("ExampleProperty3");
328 m.append(sdbusplus::message::variant<int64_t>(10));
329 b.call(m);
330
331 sdbusplus::message::object_path sigpath;
332 std::vector<std::string> interfaces;
333 {
334 std::vector<std::string> interfaces;
335 auto sig{queue.pop()};
336 assert(sig);
337 sig.read(sigpath);
338 assert(sigpath == deleteMeThree);
339 sig.read(interfaces);
340 std::sort(interfaces.begin(), interfaces.end());
341 assert(hasInterfaces(interfaces, obj));
342 }
343 {
344 // Make sure there was only one signal.
345 auto sig{queue.pop()};
346 assert(!sig);
347 }
348 }
Brad Bishop432e3522016-12-01 00:24:14 -0500349 }
350
Brad Bishop22ecacc2016-12-01 08:38:06 -0500351 // Validate the set property action.
352 {
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500353 sdbusplus::message::object_path relChangeMe{"/changeme"};
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500354 std::string changeMe{root + relChangeMe.str};
Brad Bishop22ecacc2016-12-01 08:38:06 -0500355
356 // Create an object to be updated by the set property action.
357 {
358 auto m = notify();
359 m.append(relChangeMe);
360 m.append(obj);
361 b.call(m);
362 }
363
Brad Bishop22ecacc2016-12-01 08:38:06 -0500364 // Trigger and validate the change.
365 {
366 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500367 "path='" + changeMe + "',member='PropertiesChanged'");
Brad Bishop8f868502017-01-23 13:13:58 -0500368 auto m = set(trigger2.str);
Brad Bishop22ecacc2016-12-01 08:38:06 -0500369 m.append("xyz.openbmc_project.Example.Iface2");
370 m.append("ExampleProperty2");
371 m.append(sdbusplus::message::variant<std::string>("yyyxxx"));
372 b.call(m);
373
374 std::string sigInterface;
Brad Bishop7b337772017-01-12 16:11:24 -0500375 std::map <
376 std::string,
377 sdbusplus::message::variant<std::string >> sigProperties;
Brad Bishop22ecacc2016-12-01 08:38:06 -0500378 {
379 std::vector<std::string> interfaces;
380 auto sig{queue.pop()};
381 sig.read(sigInterface);
382 assert(sigInterface == "xyz.openbmc_project.Example.Iface1");
383 sig.read(sigProperties);
384 assert(sigProperties["ExampleProperty1"] == "changed");
385 }
386 }
387 }
Brad Bishop49aefb32016-10-19 11:54:14 -0400388}
389
390int main()
391{
Brad Bishop65247582017-01-15 19:48:41 -0500392 phosphor::inventory::manager::Manager mgr(
393 sdbusplus::bus::new_default(),
Brad Bishop8f868502017-01-23 13:13:58 -0500394 MGR_SERVICE, MGR_ROOT, MGR_INTERFACE);
395 ExampleService d;
Brad Bishop49aefb32016-10-19 11:54:14 -0400396
Brad Bishop8f868502017-01-23 13:13:58 -0500397 auto f1 = [](auto mgr)
Brad Bishop49aefb32016-10-19 11:54:14 -0400398 {
Brad Bishop21621432017-01-13 16:35:53 -0500399 mgr->run();
400 };
Brad Bishop8f868502017-01-23 13:13:58 -0500401 auto f2 = [](auto d)
402 {
403 d->run();
404 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400405
Brad Bishop8f868502017-01-23 13:13:58 -0500406 auto t1 = std::thread(f1, &mgr);
407 auto t2 = std::thread(f2, &d);
408
409 runTests();
410
411 mgr.shutdown();
412 d.shutdown = true;
413
414 // Wait for server threads to exit.
415 t1.join();
416 t2.join();
417 std::cout << "Success! Waiting for threads to exit..." << std::endl;
Brad Bishop49aefb32016-10-19 11:54:14 -0400418
419 return 0;
420}
421
422// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4