blob: 621860a78cf753c66d9095e11e847b0e7953b626 [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);
39
40using ExampleIface1 = sdbusplus::xyz::openbmc_project::Example::server::Iface1;
41using ExampleIface2 = sdbusplus::xyz::openbmc_project::Example::server::Iface2;
42
43/** @class ExampleService
44 * @brief Host an object for triggering events.
45 */
46struct ExampleService
47{
48 ~ExampleService() = default;
49 ExampleService() :
50 shutdown(false),
51 bus(sdbusplus::bus::new_default()),
52 objmgr(sdbusplus::server::manager::manager(bus, MGR_ROOT))
53 {
54 bus.request_name(EXAMPLE_SERVICE);
55 }
56
57 void run()
58 {
59 sdbusplus::server::object::object <
60 ExampleIface1, ExampleIface2 > t1(bus, trigger1.str.c_str());
61 sdbusplus::server::object::object <
62 ExampleIface1, ExampleIface2 > t2(bus, trigger2.str.c_str());
63
64 while (!shutdown)
65 {
66 bus.process_discard();
67 bus.wait((5000000us).count());
68 }
69 }
70
71 volatile bool shutdown;
72 sdbusplus::bus::bus bus;
73 sdbusplus::server::manager::manager objmgr;
74};
Brad Bishop49aefb32016-10-19 11:54:14 -040075
Brad Bishopabb2a1a2016-11-30 22:02:28 -050076/** @class SignalQueue
77 * @brief Store DBus signals in a queue.
78 */
79class SignalQueue
80{
81 public:
Brad Bishop7b337772017-01-12 16:11:24 -050082 ~SignalQueue() = default;
83 SignalQueue() = delete;
84 SignalQueue(const SignalQueue&) = delete;
85 SignalQueue(SignalQueue&&) = default;
86 SignalQueue& operator=(const SignalQueue&) = delete;
87 SignalQueue& operator=(SignalQueue&&) = default;
88 explicit SignalQueue(const std::string& match) :
89 _bus(sdbusplus::bus::new_default()),
90 _match(_bus, match.c_str(), &callback, this),
91 _next(nullptr)
Brad Bishopabb2a1a2016-11-30 22:02:28 -050092 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -050093 }
Brad Bishop7b337772017-01-12 16:11:24 -050094
95 auto&& pop(unsigned timeout = 1000000)
96 {
97 while (timeout > 0 && !_next)
98 {
99 _bus.process_discard();
100 _bus.wait(50000);
101 timeout -= 50000;
102 }
103 return std::move(_next);
104 }
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500105
106 private:
Brad Bishop7b337772017-01-12 16:11:24 -0500107 static int callback(sd_bus_message* m, void* context, sd_bus_error*)
108 {
109 auto* me = static_cast<SignalQueue*>(context);
110 sd_bus_message_ref(m);
111 sdbusplus::message::message msg{m};
112 me->_next = std::move(msg);
113 return 0;
114 }
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500115
Brad Bishop7b337772017-01-12 16:11:24 -0500116 sdbusplus::bus::bus _bus;
117 sdbusplus::server::match::match _match;
118 sdbusplus::message::message _next;
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500119};
120
121template <typename ...T>
Brad Bishop7b337772017-01-12 16:11:24 -0500122using Object = std::map <
123 std::string,
124 std::map <
125 std::string,
126 sdbusplus::message::variant<T... >>>;
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500127
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500128/**@brief Find a subset of interfaces and properties in an object. */
129template <typename ...T>
Brad Bishop7b337772017-01-12 16:11:24 -0500130auto hasProperties(const Object<T...>& l, const Object<T...>& r)
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500131{
132 Object<T...> result;
133 std::set_difference(
Brad Bishop7b337772017-01-12 16:11:24 -0500134 r.cbegin(),
135 r.cend(),
136 l.cbegin(),
137 l.cend(),
138 std::inserter(result, result.end()));
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500139 return result.empty();
140}
141
Brad Bishop432e3522016-12-01 00:24:14 -0500142/**@brief Check an object for one or more interfaces. */
143template <typename ...T>
Brad Bishop7b337772017-01-12 16:11:24 -0500144auto hasInterfaces(const std::vector<std::string>& l, const Object<T...>& r)
Brad Bishop432e3522016-12-01 00:24:14 -0500145{
146 std::vector<std::string> stripped, interfaces;
147 std::transform(
Brad Bishop7b337772017-01-12 16:11:24 -0500148 r.cbegin(),
149 r.cend(),
150 std::back_inserter(stripped),
151 [](auto & p)
152 {
153 return p.first;
154 });
Brad Bishop432e3522016-12-01 00:24:14 -0500155 std::set_difference(
Brad Bishop7b337772017-01-12 16:11:24 -0500156 stripped.cbegin(),
157 stripped.cend(),
158 l.cbegin(),
159 l.cend(),
160 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 root{MGR_ROOT};
167 const std::string exampleRoot{EXAMPLE_ROOT};
Brad Bishop49aefb32016-10-19 11:54:14 -0400168 auto b = sdbusplus::bus::new_default();
Brad Bishop8f868502017-01-23 13:13:58 -0500169
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500170 auto notify = [&]()
Brad Bishop49aefb32016-10-19 11:54:14 -0400171 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500172 return b.new_method_call(
Brad Bishop8f868502017-01-23 13:13:58 -0500173 MGR_SERVICE,
174 MGR_ROOT,
175 MGR_INTERFACE,
Brad Bishop7b337772017-01-12 16:11:24 -0500176 "Notify");
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500177 };
Brad Bishop7b337772017-01-12 16:11:24 -0500178 auto set = [&](const std::string & path)
Brad Bishop432e3522016-12-01 00:24:14 -0500179 {
180 return b.new_method_call(
Brad Bishop8f868502017-01-23 13:13:58 -0500181 EXAMPLE_SERVICE,
Brad Bishop7b337772017-01-12 16:11:24 -0500182 path.c_str(),
183 "org.freedesktop.DBus.Properties",
184 "Set");
Brad Bishop432e3522016-12-01 00:24:14 -0500185 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400186
Brad Bishop7b337772017-01-12 16:11:24 -0500187 Object<std::string> obj
188 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500189 {
190 "xyz.openbmc_project.Example.Iface1",
191 {{"ExampleProperty1", "test1"}}
192 },
193 {
194 "xyz.openbmc_project.Example.Iface2",
195 {{"ExampleProperty2", "test2"}}
196 },
197 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400198
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500199 // Make sure the notify method works.
200 {
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500201 sdbusplus::message::object_path relPath{"/foo"};
202 std::string path(root + relPath.str);
Brad Bishop49aefb32016-10-19 11:54:14 -0400203
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500204 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500205 "path='" + root + "',member='InterfacesAdded'");
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500206
207 auto m = notify();
208 m.append(relPath);
209 m.append(obj);
210 b.call(m);
211
212 auto sig{queue.pop()};
213 assert(sig);
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500214 sdbusplus::message::object_path signalPath;
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500215 Object<std::string> signalObject;
216 sig.read(signalPath);
Brad Bishope07a1642017-01-24 14:37:33 -0500217 assert(path == signalPath.str);
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500218 sig.read(signalObject);
219 assert(hasProperties(signalObject, obj));
220 auto moreSignals{queue.pop()};
221 assert(!moreSignals);
Brad Bishop49aefb32016-10-19 11:54:14 -0400222 }
223
Brad Bishop432e3522016-12-01 00:24:14 -0500224 // Make sure DBus signals are handled.
225 {
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500226 sdbusplus::message::object_path relDeleteMeOne{"/deleteme1"};
227 sdbusplus::message::object_path relDeleteMeTwo{"/deleteme2"};
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500228 std::string deleteMeOne{root + relDeleteMeOne.str};
229 std::string deleteMeTwo{root + relDeleteMeTwo.str};
Brad Bishop432e3522016-12-01 00:24:14 -0500230
231 // Create some objects to be deleted by an action.
232 {
233 auto m = notify();
234 m.append(relDeleteMeOne);
235 m.append(obj);
236 b.call(m);
237 }
238 {
239 auto m = notify();
240 m.append(relDeleteMeTwo);
241 m.append(obj);
242 b.call(m);
243 }
244
Brad Bishop432e3522016-12-01 00:24:14 -0500245 // Set a property that should not trigger due to a filter.
246 {
247 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500248 "path='" + root + "',member='InterfacesRemoved'");
Brad Bishop8f868502017-01-23 13:13:58 -0500249 auto m = set(trigger1.str);
Brad Bishop432e3522016-12-01 00:24:14 -0500250 m.append("xyz.openbmc_project.Example.Iface2");
251 m.append("ExampleProperty2");
252 m.append(sdbusplus::message::variant<std::string>("abc123"));
253 b.call(m);
254 auto sig{queue.pop()};
255 assert(!sig);
256 }
257
258 // Set a property that should trigger.
259 {
260 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500261 "path='" + root + "',member='InterfacesRemoved'");
Brad Bishop432e3522016-12-01 00:24:14 -0500262
Brad Bishop8f868502017-01-23 13:13:58 -0500263 auto m = set(trigger1.str);
Brad Bishop432e3522016-12-01 00:24:14 -0500264 m.append("xyz.openbmc_project.Example.Iface2");
265 m.append("ExampleProperty2");
266 m.append(sdbusplus::message::variant<std::string>("xxxyyy"));
267 b.call(m);
268
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500269 sdbusplus::message::object_path sigpath;
Brad Bishop432e3522016-12-01 00:24:14 -0500270 std::vector<std::string> interfaces;
271 {
272 std::vector<std::string> interfaces;
273 auto sig{queue.pop()};
274 assert(sig);
275 sig.read(sigpath);
276 assert(sigpath == deleteMeOne);
277 sig.read(interfaces);
278 std::sort(interfaces.begin(), interfaces.end());
279 assert(hasInterfaces(interfaces, obj));
280 }
281 {
282 std::vector<std::string> interfaces;
283 auto sig{queue.pop()};
284 assert(sig);
285 sig.read(sigpath);
286 assert(sigpath == deleteMeTwo);
287 sig.read(interfaces);
288 std::sort(interfaces.begin(), interfaces.end());
289 assert(hasInterfaces(interfaces, obj));
290 }
291 {
292 // Make sure there were only two signals.
293 auto sig{queue.pop()};
294 assert(!sig);
295 }
296 }
297 }
298
Brad Bishop22ecacc2016-12-01 08:38:06 -0500299 // Validate the set property action.
300 {
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500301 sdbusplus::message::object_path relChangeMe{"/changeme"};
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500302 std::string changeMe{root + relChangeMe.str};
Brad Bishop22ecacc2016-12-01 08:38:06 -0500303
304 // Create an object to be updated by the set property action.
305 {
306 auto m = notify();
307 m.append(relChangeMe);
308 m.append(obj);
309 b.call(m);
310 }
311
Brad Bishop22ecacc2016-12-01 08:38:06 -0500312 // Trigger and validate the change.
313 {
314 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500315 "path='" + changeMe + "',member='PropertiesChanged'");
Brad Bishop8f868502017-01-23 13:13:58 -0500316 auto m = set(trigger2.str);
Brad Bishop22ecacc2016-12-01 08:38:06 -0500317 m.append("xyz.openbmc_project.Example.Iface2");
318 m.append("ExampleProperty2");
319 m.append(sdbusplus::message::variant<std::string>("yyyxxx"));
320 b.call(m);
321
322 std::string sigInterface;
Brad Bishop7b337772017-01-12 16:11:24 -0500323 std::map <
324 std::string,
325 sdbusplus::message::variant<std::string >> sigProperties;
Brad Bishop22ecacc2016-12-01 08:38:06 -0500326 {
327 std::vector<std::string> interfaces;
328 auto sig{queue.pop()};
329 sig.read(sigInterface);
330 assert(sigInterface == "xyz.openbmc_project.Example.Iface1");
331 sig.read(sigProperties);
332 assert(sigProperties["ExampleProperty1"] == "changed");
333 }
334 }
335 }
Brad Bishop49aefb32016-10-19 11:54:14 -0400336}
337
338int main()
339{
Brad Bishop65247582017-01-15 19:48:41 -0500340 phosphor::inventory::manager::Manager mgr(
341 sdbusplus::bus::new_default(),
Brad Bishop8f868502017-01-23 13:13:58 -0500342 MGR_SERVICE, MGR_ROOT, MGR_INTERFACE);
343 ExampleService d;
Brad Bishop49aefb32016-10-19 11:54:14 -0400344
Brad Bishop8f868502017-01-23 13:13:58 -0500345 auto f1 = [](auto mgr)
Brad Bishop49aefb32016-10-19 11:54:14 -0400346 {
Brad Bishop21621432017-01-13 16:35:53 -0500347 mgr->run();
348 };
Brad Bishop8f868502017-01-23 13:13:58 -0500349 auto f2 = [](auto d)
350 {
351 d->run();
352 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400353
Brad Bishop8f868502017-01-23 13:13:58 -0500354 auto t1 = std::thread(f1, &mgr);
355 auto t2 = std::thread(f2, &d);
356
357 runTests();
358
359 mgr.shutdown();
360 d.shutdown = true;
361
362 // Wait for server threads to exit.
363 t1.join();
364 t2.join();
365 std::cout << "Success! Waiting for threads to exit..." << std::endl;
Brad Bishop49aefb32016-10-19 11:54:14 -0400366
367 return 0;
368}
369
370// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4