blob: 21f89e240f385942c2556d1e68880508446c4651 [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);
Brad Bishopfa51da72017-01-19 11:06:51 -050041const auto trigger4 = sdbusplus::message::object_path(EXAMPLE_ROOT +
42 "/trigger4"s);
43
Brad Bishopfb083c22017-01-19 09:22:04 -050044
45const sdbusplus::message::object_path relDeleteMeOne{"/deleteme1"};
46const sdbusplus::message::object_path relDeleteMeTwo{"/deleteme2"};
47const sdbusplus::message::object_path relDeleteMeThree{"/deleteme3"};
48
49const std::string root{MGR_ROOT};
50const std::string deleteMeOne{root + relDeleteMeOne.str};
51const std::string deleteMeTwo{root + relDeleteMeTwo.str};
52const std::string deleteMeThree{root + relDeleteMeThree.str};
Brad Bishop8f868502017-01-23 13:13:58 -050053
54using ExampleIface1 = sdbusplus::xyz::openbmc_project::Example::server::Iface1;
55using ExampleIface2 = sdbusplus::xyz::openbmc_project::Example::server::Iface2;
56
57/** @class ExampleService
58 * @brief Host an object for triggering events.
59 */
60struct ExampleService
61{
62 ~ExampleService() = default;
63 ExampleService() :
64 shutdown(false),
65 bus(sdbusplus::bus::new_default()),
66 objmgr(sdbusplus::server::manager::manager(bus, MGR_ROOT))
67 {
68 bus.request_name(EXAMPLE_SERVICE);
69 }
70
71 void run()
72 {
73 sdbusplus::server::object::object <
74 ExampleIface1, ExampleIface2 > t1(bus, trigger1.str.c_str());
75 sdbusplus::server::object::object <
76 ExampleIface1, ExampleIface2 > t2(bus, trigger2.str.c_str());
Brad Bishopfb083c22017-01-19 09:22:04 -050077 sdbusplus::server::object::object <
78 ExampleIface1, ExampleIface2 > t3(bus, trigger3.str.c_str());
Brad Bishopfa51da72017-01-19 11:06:51 -050079 sdbusplus::server::object::object <
80 ExampleIface1, ExampleIface2 > t4(bus, trigger4.str.c_str());
Brad Bishop8f868502017-01-23 13:13:58 -050081
82 while (!shutdown)
83 {
84 bus.process_discard();
85 bus.wait((5000000us).count());
86 }
87 }
88
89 volatile bool shutdown;
90 sdbusplus::bus::bus bus;
91 sdbusplus::server::manager::manager objmgr;
92};
Brad Bishop49aefb32016-10-19 11:54:14 -040093
Brad Bishop1157af12017-01-22 01:03:02 -050094using Object = phosphor::inventory::manager::Object;
95
Brad Bishopabb2a1a2016-11-30 22:02:28 -050096/** @class SignalQueue
97 * @brief Store DBus signals in a queue.
98 */
99class SignalQueue
100{
101 public:
Brad Bishop7b337772017-01-12 16:11:24 -0500102 ~SignalQueue() = default;
103 SignalQueue() = delete;
104 SignalQueue(const SignalQueue&) = delete;
105 SignalQueue(SignalQueue&&) = default;
106 SignalQueue& operator=(const SignalQueue&) = delete;
107 SignalQueue& operator=(SignalQueue&&) = default;
108 explicit SignalQueue(const std::string& match) :
109 _bus(sdbusplus::bus::new_default()),
110 _match(_bus, match.c_str(), &callback, this),
111 _next(nullptr)
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500112 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500113 }
Brad Bishop7b337772017-01-12 16:11:24 -0500114
115 auto&& pop(unsigned timeout = 1000000)
116 {
117 while (timeout > 0 && !_next)
118 {
119 _bus.process_discard();
120 _bus.wait(50000);
121 timeout -= 50000;
122 }
123 return std::move(_next);
124 }
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500125
126 private:
Brad Bishop7b337772017-01-12 16:11:24 -0500127 static int callback(sd_bus_message* m, void* context, sd_bus_error*)
128 {
129 auto* me = static_cast<SignalQueue*>(context);
130 sd_bus_message_ref(m);
131 sdbusplus::message::message msg{m};
132 me->_next = std::move(msg);
133 return 0;
134 }
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500135
Brad Bishop7b337772017-01-12 16:11:24 -0500136 sdbusplus::bus::bus _bus;
137 sdbusplus::server::match::match _match;
138 sdbusplus::message::message _next;
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500139};
140
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500141/**@brief Find a subset of interfaces and properties in an object. */
Brad Bishop1157af12017-01-22 01:03:02 -0500142auto hasProperties(const Object& l, const Object& r)
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500143{
Brad Bishop1157af12017-01-22 01:03:02 -0500144 Object result;
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500145 std::set_difference(
Brad Bishop7b337772017-01-12 16:11:24 -0500146 r.cbegin(),
147 r.cend(),
148 l.cbegin(),
149 l.cend(),
150 std::inserter(result, result.end()));
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500151 return result.empty();
152}
153
Brad Bishop432e3522016-12-01 00:24:14 -0500154/**@brief Check an object for one or more interfaces. */
Brad Bishop1157af12017-01-22 01:03:02 -0500155auto hasInterfaces(const std::vector<std::string>& l, const Object& r)
Brad Bishop432e3522016-12-01 00:24:14 -0500156{
157 std::vector<std::string> stripped, interfaces;
158 std::transform(
Brad Bishop7b337772017-01-12 16:11:24 -0500159 r.cbegin(),
160 r.cend(),
161 std::back_inserter(stripped),
162 [](auto & p)
163 {
164 return p.first;
165 });
Brad Bishop432e3522016-12-01 00:24:14 -0500166 std::set_difference(
Brad Bishop7b337772017-01-12 16:11:24 -0500167 stripped.cbegin(),
168 stripped.cend(),
169 l.cbegin(),
170 l.cend(),
171 std::back_inserter(interfaces));
Brad Bishop432e3522016-12-01 00:24:14 -0500172 return interfaces.empty();
173}
174
Brad Bishop8f868502017-01-23 13:13:58 -0500175void runTests()
Brad Bishop49aefb32016-10-19 11:54:14 -0400176{
Brad Bishop8f868502017-01-23 13:13:58 -0500177 const std::string exampleRoot{EXAMPLE_ROOT};
Brad Bishop49aefb32016-10-19 11:54:14 -0400178 auto b = sdbusplus::bus::new_default();
Brad Bishop8f868502017-01-23 13:13:58 -0500179
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500180 auto notify = [&]()
Brad Bishop49aefb32016-10-19 11:54:14 -0400181 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500182 return b.new_method_call(
Brad Bishop8f868502017-01-23 13:13:58 -0500183 MGR_SERVICE,
184 MGR_ROOT,
185 MGR_INTERFACE,
Brad Bishop7b337772017-01-12 16:11:24 -0500186 "Notify");
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500187 };
Brad Bishop7b337772017-01-12 16:11:24 -0500188 auto set = [&](const std::string & path)
Brad Bishop432e3522016-12-01 00:24:14 -0500189 {
190 return b.new_method_call(
Brad Bishop8f868502017-01-23 13:13:58 -0500191 EXAMPLE_SERVICE,
Brad Bishop7b337772017-01-12 16:11:24 -0500192 path.c_str(),
193 "org.freedesktop.DBus.Properties",
194 "Set");
Brad Bishop432e3522016-12-01 00:24:14 -0500195 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400196
Brad Bishop1157af12017-01-22 01:03:02 -0500197 Object obj
Brad Bishop7b337772017-01-12 16:11:24 -0500198 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500199 {
200 "xyz.openbmc_project.Example.Iface1",
201 {{"ExampleProperty1", "test1"}}
202 },
203 {
204 "xyz.openbmc_project.Example.Iface2",
205 {{"ExampleProperty2", "test2"}}
206 },
207 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400208
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500209 // Make sure the notify method works.
210 {
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500211 sdbusplus::message::object_path relPath{"/foo"};
212 std::string path(root + relPath.str);
Brad Bishop49aefb32016-10-19 11:54:14 -0400213
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500214 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500215 "path='" + root + "',member='InterfacesAdded'");
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500216
217 auto m = notify();
218 m.append(relPath);
219 m.append(obj);
220 b.call(m);
221
222 auto sig{queue.pop()};
223 assert(sig);
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500224 sdbusplus::message::object_path signalPath;
Brad Bishop1157af12017-01-22 01:03:02 -0500225 Object signalObjectType;
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500226 sig.read(signalPath);
Brad Bishope07a1642017-01-24 14:37:33 -0500227 assert(path == signalPath.str);
Brad Bishop1157af12017-01-22 01:03:02 -0500228 sig.read(signalObjectType);
229 assert(hasProperties(signalObjectType, obj));
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500230 auto moreSignals{queue.pop()};
231 assert(!moreSignals);
Brad Bishop49aefb32016-10-19 11:54:14 -0400232 }
233
Brad Bishopfa51da72017-01-19 11:06:51 -0500234 // Validate the propertyIs filter.
235 {
236 // Create an object to be deleted.
237 {
238 auto m = notify();
239 m.append(relDeleteMeThree);
240 m.append(obj);
241 b.call(m);
242 }
243
244 // Validate that the action does not run if the property doesn't match.
245 {
246 SignalQueue queue(
247 "path='" + root + "',member='InterfacesRemoved'");
248 auto m = set(trigger4.str);
249 m.append("xyz.openbmc_project.Example.Iface2");
250 m.append("ExampleProperty2");
251 m.append(sdbusplus::message::variant<std::string>("123"));
252 b.call(m);
253 auto sig{queue.pop()};
254 assert(!sig);
255 }
256
257 // Validate that the action does run if the property matches.
258 {
259 // Set ExampleProperty2 to something else to the 123 filter
260 // matches.
261 SignalQueue queue(
262 "path='" + root + "',member='InterfacesRemoved'");
263 auto m = set(trigger4.str);
264 m.append("xyz.openbmc_project.Example.Iface2");
265 m.append("ExampleProperty2");
266 m.append(sdbusplus::message::variant<std::string>("xyz"));
267 b.call(m);
268 auto sig{queue.pop()};
269 assert(!sig);
270 }
271 {
272 // Set ExampleProperty3 to 99.
273 SignalQueue queue(
274 "path='" + root + "',member='InterfacesRemoved'");
275 auto m = set(trigger4.str);
276 m.append("xyz.openbmc_project.Example.Iface2");
277 m.append("ExampleProperty3");
278 m.append(sdbusplus::message::variant<int64_t>(99));
279 b.call(m);
280 auto sig{queue.pop()};
281 assert(!sig);
282 }
283 {
284 SignalQueue queue(
285 "path='" + root + "',member='InterfacesRemoved'");
286 auto m = set(trigger4.str);
287 m.append("xyz.openbmc_project.Example.Iface2");
288 m.append("ExampleProperty2");
289 m.append(sdbusplus::message::variant<std::string>("123"));
290 b.call(m);
291
292 sdbusplus::message::object_path sigpath;
293 std::vector<std::string> interfaces;
294 {
295 std::vector<std::string> interfaces;
296 auto sig{queue.pop()};
297 assert(sig);
298 sig.read(sigpath);
299 assert(sigpath == deleteMeThree);
300 sig.read(interfaces);
301 std::sort(interfaces.begin(), interfaces.end());
302 assert(hasInterfaces(interfaces, obj));
303 }
304 }
305 }
306
Brad Bishop432e3522016-12-01 00:24:14 -0500307 // Make sure DBus signals are handled.
308 {
Brad Bishop432e3522016-12-01 00:24:14 -0500309 // Create some objects to be deleted by an action.
310 {
311 auto m = notify();
312 m.append(relDeleteMeOne);
313 m.append(obj);
314 b.call(m);
315 }
316 {
317 auto m = notify();
318 m.append(relDeleteMeTwo);
319 m.append(obj);
320 b.call(m);
321 }
Brad Bishopfb083c22017-01-19 09:22:04 -0500322 {
323 auto m = notify();
324 m.append(relDeleteMeThree);
325 m.append(obj);
326 b.call(m);
327 }
Brad Bishop432e3522016-12-01 00:24:14 -0500328
Brad Bishopfb083c22017-01-19 09:22:04 -0500329 // Set some properties that should not trigger due to a filter.
Brad Bishop432e3522016-12-01 00:24:14 -0500330 {
331 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500332 "path='" + root + "',member='InterfacesRemoved'");
Brad Bishop8f868502017-01-23 13:13:58 -0500333 auto m = set(trigger1.str);
Brad Bishop432e3522016-12-01 00:24:14 -0500334 m.append("xyz.openbmc_project.Example.Iface2");
335 m.append("ExampleProperty2");
336 m.append(sdbusplus::message::variant<std::string>("abc123"));
337 b.call(m);
338 auto sig{queue.pop()};
339 assert(!sig);
340 }
Brad Bishopfb083c22017-01-19 09:22:04 -0500341 {
342 SignalQueue queue(
343 "path='" + root + "',member='InterfacesRemoved'");
344 auto m = set(trigger3.str);
345 m.append("xyz.openbmc_project.Example.Iface2");
346 m.append("ExampleProperty3");
347 m.append(sdbusplus::message::variant<int64_t>(11));
348 b.call(m);
349 auto sig{queue.pop()};
350 assert(!sig);
351 }
Brad Bishop432e3522016-12-01 00:24:14 -0500352
Brad Bishopfb083c22017-01-19 09:22:04 -0500353 // Set some properties that should trigger.
Brad Bishop432e3522016-12-01 00:24:14 -0500354 {
355 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500356 "path='" + root + "',member='InterfacesRemoved'");
Brad Bishop432e3522016-12-01 00:24:14 -0500357
Brad Bishop8f868502017-01-23 13:13:58 -0500358 auto m = set(trigger1.str);
Brad Bishop432e3522016-12-01 00:24:14 -0500359 m.append("xyz.openbmc_project.Example.Iface2");
360 m.append("ExampleProperty2");
361 m.append(sdbusplus::message::variant<std::string>("xxxyyy"));
362 b.call(m);
363
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500364 sdbusplus::message::object_path sigpath;
Brad Bishop432e3522016-12-01 00:24:14 -0500365 std::vector<std::string> interfaces;
366 {
367 std::vector<std::string> interfaces;
368 auto sig{queue.pop()};
369 assert(sig);
370 sig.read(sigpath);
371 assert(sigpath == deleteMeOne);
372 sig.read(interfaces);
373 std::sort(interfaces.begin(), interfaces.end());
374 assert(hasInterfaces(interfaces, obj));
375 }
376 {
377 std::vector<std::string> interfaces;
378 auto sig{queue.pop()};
379 assert(sig);
380 sig.read(sigpath);
381 assert(sigpath == deleteMeTwo);
382 sig.read(interfaces);
383 std::sort(interfaces.begin(), interfaces.end());
384 assert(hasInterfaces(interfaces, obj));
385 }
386 {
387 // Make sure there were only two signals.
388 auto sig{queue.pop()};
389 assert(!sig);
390 }
391 }
Brad Bishopfb083c22017-01-19 09:22:04 -0500392 {
393 SignalQueue queue(
394 "path='" + root + "',member='InterfacesRemoved'");
395
396 auto m = set(trigger3.str);
397 m.append("xyz.openbmc_project.Example.Iface2");
398 m.append("ExampleProperty3");
399 m.append(sdbusplus::message::variant<int64_t>(10));
400 b.call(m);
401
402 sdbusplus::message::object_path sigpath;
403 std::vector<std::string> interfaces;
404 {
405 std::vector<std::string> interfaces;
406 auto sig{queue.pop()};
407 assert(sig);
408 sig.read(sigpath);
409 assert(sigpath == deleteMeThree);
410 sig.read(interfaces);
411 std::sort(interfaces.begin(), interfaces.end());
412 assert(hasInterfaces(interfaces, obj));
413 }
414 {
415 // Make sure there was only one signal.
416 auto sig{queue.pop()};
417 assert(!sig);
418 }
419 }
Brad Bishop432e3522016-12-01 00:24:14 -0500420 }
421
Brad Bishop22ecacc2016-12-01 08:38:06 -0500422 // Validate the set property action.
423 {
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500424 sdbusplus::message::object_path relChangeMe{"/changeme"};
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500425 std::string changeMe{root + relChangeMe.str};
Brad Bishop22ecacc2016-12-01 08:38:06 -0500426
427 // Create an object to be updated by the set property action.
428 {
429 auto m = notify();
430 m.append(relChangeMe);
431 m.append(obj);
432 b.call(m);
433 }
434
Brad Bishop22ecacc2016-12-01 08:38:06 -0500435 // Trigger and validate the change.
436 {
437 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500438 "path='" + changeMe + "',member='PropertiesChanged'");
Brad Bishop8f868502017-01-23 13:13:58 -0500439 auto m = set(trigger2.str);
Brad Bishop22ecacc2016-12-01 08:38:06 -0500440 m.append("xyz.openbmc_project.Example.Iface2");
441 m.append("ExampleProperty2");
442 m.append(sdbusplus::message::variant<std::string>("yyyxxx"));
443 b.call(m);
444
445 std::string sigInterface;
Brad Bishop7b337772017-01-12 16:11:24 -0500446 std::map <
447 std::string,
448 sdbusplus::message::variant<std::string >> sigProperties;
Brad Bishop22ecacc2016-12-01 08:38:06 -0500449 {
450 std::vector<std::string> interfaces;
451 auto sig{queue.pop()};
452 sig.read(sigInterface);
453 assert(sigInterface == "xyz.openbmc_project.Example.Iface1");
454 sig.read(sigProperties);
455 assert(sigProperties["ExampleProperty1"] == "changed");
456 }
457 }
458 }
Brad Bishop49aefb32016-10-19 11:54:14 -0400459}
460
461int main()
462{
Brad Bishop65247582017-01-15 19:48:41 -0500463 phosphor::inventory::manager::Manager mgr(
464 sdbusplus::bus::new_default(),
Brad Bishop8f868502017-01-23 13:13:58 -0500465 MGR_SERVICE, MGR_ROOT, MGR_INTERFACE);
466 ExampleService d;
Brad Bishop49aefb32016-10-19 11:54:14 -0400467
Brad Bishop8f868502017-01-23 13:13:58 -0500468 auto f1 = [](auto mgr)
Brad Bishop49aefb32016-10-19 11:54:14 -0400469 {
Brad Bishop21621432017-01-13 16:35:53 -0500470 mgr->run();
471 };
Brad Bishop8f868502017-01-23 13:13:58 -0500472 auto f2 = [](auto d)
473 {
474 d->run();
475 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400476
Brad Bishop8f868502017-01-23 13:13:58 -0500477 auto t1 = std::thread(f1, &mgr);
478 auto t2 = std::thread(f2, &d);
479
480 runTests();
481
482 mgr.shutdown();
483 d.shutdown = true;
484
485 // Wait for server threads to exit.
486 t1.join();
487 t2.join();
488 std::cout << "Success! Waiting for threads to exit..." << std::endl;
Brad Bishop49aefb32016-10-19 11:54:14 -0400489
490 return 0;
491}
492
493// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4