blob: 7f72721239ab0b1323cc63d6fb730cfe5a1e1748 [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 Bishop49aefb32016-10-19 11:54:14 -040022
23constexpr auto SERVICE = "phosphor.inventory.test";
24constexpr auto INTERFACE = IFACE;
25constexpr auto ROOT = "/testing/inventory";
26
Brad Bishopabb2a1a2016-11-30 22:02:28 -050027/** @class SignalQueue
28 * @brief Store DBus signals in a queue.
29 */
30class SignalQueue
31{
32 public:
Brad Bishop7b337772017-01-12 16:11:24 -050033 ~SignalQueue() = default;
34 SignalQueue() = delete;
35 SignalQueue(const SignalQueue&) = delete;
36 SignalQueue(SignalQueue&&) = default;
37 SignalQueue& operator=(const SignalQueue&) = delete;
38 SignalQueue& operator=(SignalQueue&&) = default;
39 explicit SignalQueue(const std::string& match) :
40 _bus(sdbusplus::bus::new_default()),
41 _match(_bus, match.c_str(), &callback, this),
42 _next(nullptr)
Brad Bishopabb2a1a2016-11-30 22:02:28 -050043 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -050044 }
Brad Bishop7b337772017-01-12 16:11:24 -050045
46 auto&& pop(unsigned timeout = 1000000)
47 {
48 while (timeout > 0 && !_next)
49 {
50 _bus.process_discard();
51 _bus.wait(50000);
52 timeout -= 50000;
53 }
54 return std::move(_next);
55 }
Brad Bishopabb2a1a2016-11-30 22:02:28 -050056
57 private:
Brad Bishop7b337772017-01-12 16:11:24 -050058 static int callback(sd_bus_message* m, void* context, sd_bus_error*)
59 {
60 auto* me = static_cast<SignalQueue*>(context);
61 sd_bus_message_ref(m);
62 sdbusplus::message::message msg{m};
63 me->_next = std::move(msg);
64 return 0;
65 }
Brad Bishopabb2a1a2016-11-30 22:02:28 -050066
Brad Bishop7b337772017-01-12 16:11:24 -050067 sdbusplus::bus::bus _bus;
68 sdbusplus::server::match::match _match;
69 sdbusplus::message::message _next;
Brad Bishopabb2a1a2016-11-30 22:02:28 -050070};
71
72template <typename ...T>
Brad Bishop7b337772017-01-12 16:11:24 -050073using Object = std::map <
74 std::string,
75 std::map <
76 std::string,
77 sdbusplus::message::variant<T... >>>;
Brad Bishopabb2a1a2016-11-30 22:02:28 -050078
79using ObjectPath = std::string;
80
81/**@brief Find a subset of interfaces and properties in an object. */
82template <typename ...T>
Brad Bishop7b337772017-01-12 16:11:24 -050083auto hasProperties(const Object<T...>& l, const Object<T...>& r)
Brad Bishopabb2a1a2016-11-30 22:02:28 -050084{
85 Object<T...> result;
86 std::set_difference(
Brad Bishop7b337772017-01-12 16:11:24 -050087 r.cbegin(),
88 r.cend(),
89 l.cbegin(),
90 l.cend(),
91 std::inserter(result, result.end()));
Brad Bishopabb2a1a2016-11-30 22:02:28 -050092 return result.empty();
93}
94
Brad Bishop432e3522016-12-01 00:24:14 -050095/**@brief Check an object for one or more interfaces. */
96template <typename ...T>
Brad Bishop7b337772017-01-12 16:11:24 -050097auto hasInterfaces(const std::vector<std::string>& l, const Object<T...>& r)
Brad Bishop432e3522016-12-01 00:24:14 -050098{
99 std::vector<std::string> stripped, interfaces;
100 std::transform(
Brad Bishop7b337772017-01-12 16:11:24 -0500101 r.cbegin(),
102 r.cend(),
103 std::back_inserter(stripped),
104 [](auto & p)
105 {
106 return p.first;
107 });
Brad Bishop432e3522016-12-01 00:24:14 -0500108 std::set_difference(
Brad Bishop7b337772017-01-12 16:11:24 -0500109 stripped.cbegin(),
110 stripped.cend(),
111 l.cbegin(),
112 l.cend(),
113 std::back_inserter(interfaces));
Brad Bishop432e3522016-12-01 00:24:14 -0500114 return interfaces.empty();
115}
116
Brad Bishop7b337772017-01-12 16:11:24 -0500117void runTests(phosphor::inventory::manager::Manager& mgr)
Brad Bishop49aefb32016-10-19 11:54:14 -0400118{
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500119 const std::string root{ROOT};
Brad Bishop49aefb32016-10-19 11:54:14 -0400120 auto b = sdbusplus::bus::new_default();
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500121 auto notify = [&]()
Brad Bishop49aefb32016-10-19 11:54:14 -0400122 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500123 return b.new_method_call(
Brad Bishop7b337772017-01-12 16:11:24 -0500124 SERVICE,
125 ROOT,
126 INTERFACE,
127 "Notify");
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500128 };
Brad Bishop7b337772017-01-12 16:11:24 -0500129 auto set = [&](const std::string & path)
Brad Bishop432e3522016-12-01 00:24:14 -0500130 {
131 return b.new_method_call(
Brad Bishop7b337772017-01-12 16:11:24 -0500132 SERVICE,
133 path.c_str(),
134 "org.freedesktop.DBus.Properties",
135 "Set");
Brad Bishop432e3522016-12-01 00:24:14 -0500136 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400137
Brad Bishop7b337772017-01-12 16:11:24 -0500138 Object<std::string> obj
139 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500140 {
141 "xyz.openbmc_project.Example.Iface1",
142 {{"ExampleProperty1", "test1"}}
143 },
144 {
145 "xyz.openbmc_project.Example.Iface2",
146 {{"ExampleProperty2", "test2"}}
147 },
148 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400149
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500150 // Make sure the notify method works.
151 {
152 ObjectPath relPath{"/foo"};
153 ObjectPath path{root + relPath};
Brad Bishop49aefb32016-10-19 11:54:14 -0400154
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500155 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500156 "path='" + root + "',member='InterfacesAdded'");
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500157
158 auto m = notify();
159 m.append(relPath);
160 m.append(obj);
161 b.call(m);
162
163 auto sig{queue.pop()};
164 assert(sig);
165 ObjectPath signalPath;
166 Object<std::string> signalObject;
167 sig.read(signalPath);
168 assert(path == signalPath);
169 sig.read(signalObject);
170 assert(hasProperties(signalObject, obj));
171 auto moreSignals{queue.pop()};
172 assert(!moreSignals);
Brad Bishop49aefb32016-10-19 11:54:14 -0400173 }
174
Brad Bishop432e3522016-12-01 00:24:14 -0500175 // Make sure DBus signals are handled.
176 {
177 ObjectPath relDeleteMeOne{"/deleteme1"};
178 ObjectPath relDeleteMeTwo{"/deleteme2"};
179 ObjectPath relTriggerOne{"/trigger1"};
180 ObjectPath deleteMeOne{root + relDeleteMeOne};
181 ObjectPath deleteMeTwo{root + relDeleteMeTwo};
182 ObjectPath triggerOne{root + relTriggerOne};
183
184 // Create some objects to be deleted by an action.
185 {
186 auto m = notify();
187 m.append(relDeleteMeOne);
188 m.append(obj);
189 b.call(m);
190 }
191 {
192 auto m = notify();
193 m.append(relDeleteMeTwo);
194 m.append(obj);
195 b.call(m);
196 }
197
198 // Create the triggering object.
199 {
200 auto m = notify();
201 m.append(relTriggerOne);
202 m.append(obj);
203 b.call(m);
204 }
205
206 // Set a property that should not trigger due to a filter.
207 {
208 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500209 "path='" + root + "',member='InterfacesRemoved'");
Brad Bishop432e3522016-12-01 00:24:14 -0500210 auto m = set(triggerOne);
211 m.append("xyz.openbmc_project.Example.Iface2");
212 m.append("ExampleProperty2");
213 m.append(sdbusplus::message::variant<std::string>("abc123"));
214 b.call(m);
215 auto sig{queue.pop()};
216 assert(!sig);
217 }
218
219 // Set a property that should trigger.
220 {
221 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500222 "path='" + root + "',member='InterfacesRemoved'");
Brad Bishop432e3522016-12-01 00:24:14 -0500223
224 auto m = set(triggerOne);
225 m.append("xyz.openbmc_project.Example.Iface2");
226 m.append("ExampleProperty2");
227 m.append(sdbusplus::message::variant<std::string>("xxxyyy"));
228 b.call(m);
229
230 ObjectPath sigpath;
231 std::vector<std::string> interfaces;
232 {
233 std::vector<std::string> interfaces;
234 auto sig{queue.pop()};
235 assert(sig);
236 sig.read(sigpath);
237 assert(sigpath == deleteMeOne);
238 sig.read(interfaces);
239 std::sort(interfaces.begin(), interfaces.end());
240 assert(hasInterfaces(interfaces, obj));
241 }
242 {
243 std::vector<std::string> interfaces;
244 auto sig{queue.pop()};
245 assert(sig);
246 sig.read(sigpath);
247 assert(sigpath == deleteMeTwo);
248 sig.read(interfaces);
249 std::sort(interfaces.begin(), interfaces.end());
250 assert(hasInterfaces(interfaces, obj));
251 }
252 {
253 // Make sure there were only two signals.
254 auto sig{queue.pop()};
255 assert(!sig);
256 }
257 }
258 }
259
Brad Bishop22ecacc2016-12-01 08:38:06 -0500260 // Validate the set property action.
261 {
262 ObjectPath relChangeMe{"/changeme"};
263 ObjectPath relTriggerTwo{"/trigger2"};
264 ObjectPath changeMe{root + relChangeMe};
265 ObjectPath triggerTwo{root + relTriggerTwo};
266
267 // Create an object to be updated by the set property action.
268 {
269 auto m = notify();
270 m.append(relChangeMe);
271 m.append(obj);
272 b.call(m);
273 }
274
275 // Create the triggering object.
276 {
277 auto m = notify();
278 m.append(relTriggerTwo);
279 m.append(obj);
280 b.call(m);
281 }
282
283 // Trigger and validate the change.
284 {
285 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500286 "path='" + changeMe + "',member='PropertiesChanged'");
Brad Bishop22ecacc2016-12-01 08:38:06 -0500287 auto m = set(triggerTwo);
288 m.append("xyz.openbmc_project.Example.Iface2");
289 m.append("ExampleProperty2");
290 m.append(sdbusplus::message::variant<std::string>("yyyxxx"));
291 b.call(m);
292
293 std::string sigInterface;
Brad Bishop7b337772017-01-12 16:11:24 -0500294 std::map <
295 std::string,
296 sdbusplus::message::variant<std::string >> sigProperties;
Brad Bishop22ecacc2016-12-01 08:38:06 -0500297 {
298 std::vector<std::string> interfaces;
299 auto sig{queue.pop()};
300 sig.read(sigInterface);
301 assert(sigInterface == "xyz.openbmc_project.Example.Iface1");
302 sig.read(sigProperties);
303 assert(sigProperties["ExampleProperty1"] == "changed");
304 }
305 }
306 }
307
Brad Bishop49aefb32016-10-19 11:54:14 -0400308 mgr.shutdown();
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500309 std::cout << "Success!" << std::endl;
Brad Bishop49aefb32016-10-19 11:54:14 -0400310}
311
312int main()
313{
Brad Bishop65247582017-01-15 19:48:41 -0500314 phosphor::inventory::manager::Manager mgr(
315 sdbusplus::bus::new_default(),
316 SERVICE, ROOT, INTERFACE);
Brad Bishop49aefb32016-10-19 11:54:14 -0400317
Brad Bishop21621432017-01-13 16:35:53 -0500318 auto f = [](auto mgr)
Brad Bishop49aefb32016-10-19 11:54:14 -0400319 {
Brad Bishop21621432017-01-13 16:35:53 -0500320 mgr->run();
321 };
322 auto t = std::thread(f, &mgr);
Brad Bishop49aefb32016-10-19 11:54:14 -0400323 runTests(mgr);
324
325 // Wait for server thread to exit.
Brad Bishop21621432017-01-13 16:35:53 -0500326 t.join();
Brad Bishop49aefb32016-10-19 11:54:14 -0400327
328 return 0;
329}
330
331// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4