blob: 89e46b9d312da252f8e57c8201beb216bb73024b [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
Brad Bishopabb2a1a2016-11-30 22:02:28 -050079/**@brief Find a subset of interfaces and properties in an object. */
80template <typename ...T>
Brad Bishop7b337772017-01-12 16:11:24 -050081auto hasProperties(const Object<T...>& l, const Object<T...>& r)
Brad Bishopabb2a1a2016-11-30 22:02:28 -050082{
83 Object<T...> result;
84 std::set_difference(
Brad Bishop7b337772017-01-12 16:11:24 -050085 r.cbegin(),
86 r.cend(),
87 l.cbegin(),
88 l.cend(),
89 std::inserter(result, result.end()));
Brad Bishopabb2a1a2016-11-30 22:02:28 -050090 return result.empty();
91}
92
Brad Bishop432e3522016-12-01 00:24:14 -050093/**@brief Check an object for one or more interfaces. */
94template <typename ...T>
Brad Bishop7b337772017-01-12 16:11:24 -050095auto hasInterfaces(const std::vector<std::string>& l, const Object<T...>& r)
Brad Bishop432e3522016-12-01 00:24:14 -050096{
97 std::vector<std::string> stripped, interfaces;
98 std::transform(
Brad Bishop7b337772017-01-12 16:11:24 -050099 r.cbegin(),
100 r.cend(),
101 std::back_inserter(stripped),
102 [](auto & p)
103 {
104 return p.first;
105 });
Brad Bishop432e3522016-12-01 00:24:14 -0500106 std::set_difference(
Brad Bishop7b337772017-01-12 16:11:24 -0500107 stripped.cbegin(),
108 stripped.cend(),
109 l.cbegin(),
110 l.cend(),
111 std::back_inserter(interfaces));
Brad Bishop432e3522016-12-01 00:24:14 -0500112 return interfaces.empty();
113}
114
Brad Bishop7b337772017-01-12 16:11:24 -0500115void runTests(phosphor::inventory::manager::Manager& mgr)
Brad Bishop49aefb32016-10-19 11:54:14 -0400116{
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500117 const std::string root{ROOT};
Brad Bishop49aefb32016-10-19 11:54:14 -0400118 auto b = sdbusplus::bus::new_default();
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500119 auto notify = [&]()
Brad Bishop49aefb32016-10-19 11:54:14 -0400120 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500121 return b.new_method_call(
Brad Bishop7b337772017-01-12 16:11:24 -0500122 SERVICE,
123 ROOT,
124 INTERFACE,
125 "Notify");
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500126 };
Brad Bishop7b337772017-01-12 16:11:24 -0500127 auto set = [&](const std::string & path)
Brad Bishop432e3522016-12-01 00:24:14 -0500128 {
129 return b.new_method_call(
Brad Bishop7b337772017-01-12 16:11:24 -0500130 SERVICE,
131 path.c_str(),
132 "org.freedesktop.DBus.Properties",
133 "Set");
Brad Bishop432e3522016-12-01 00:24:14 -0500134 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400135
Brad Bishop7b337772017-01-12 16:11:24 -0500136 Object<std::string> obj
137 {
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500138 {
139 "xyz.openbmc_project.Example.Iface1",
140 {{"ExampleProperty1", "test1"}}
141 },
142 {
143 "xyz.openbmc_project.Example.Iface2",
144 {{"ExampleProperty2", "test2"}}
145 },
146 };
Brad Bishop49aefb32016-10-19 11:54:14 -0400147
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500148 // Make sure the notify method works.
149 {
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500150 sdbusplus::message::object_path relPath{"/foo"};
151 std::string path(root + relPath.str);
Brad Bishop49aefb32016-10-19 11:54:14 -0400152
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500153 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500154 "path='" + root + "',member='InterfacesAdded'");
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500155
156 auto m = notify();
157 m.append(relPath);
158 m.append(obj);
159 b.call(m);
160
161 auto sig{queue.pop()};
162 assert(sig);
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500163 sdbusplus::message::object_path signalPath;
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500164 Object<std::string> signalObject;
165 sig.read(signalPath);
166 assert(path == signalPath);
167 sig.read(signalObject);
168 assert(hasProperties(signalObject, obj));
169 auto moreSignals{queue.pop()};
170 assert(!moreSignals);
Brad Bishop49aefb32016-10-19 11:54:14 -0400171 }
172
Brad Bishop432e3522016-12-01 00:24:14 -0500173 // Make sure DBus signals are handled.
174 {
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500175 sdbusplus::message::object_path relDeleteMeOne{"/deleteme1"};
176 sdbusplus::message::object_path relDeleteMeTwo{"/deleteme2"};
177 sdbusplus::message::object_path relTriggerOne{"/trigger1"};
178 std::string deleteMeOne{root + relDeleteMeOne.str};
179 std::string deleteMeTwo{root + relDeleteMeTwo.str};
180 std::string triggerOne{root + relTriggerOne.str};
Brad Bishop432e3522016-12-01 00:24:14 -0500181
182 // Create some objects to be deleted by an action.
183 {
184 auto m = notify();
185 m.append(relDeleteMeOne);
186 m.append(obj);
187 b.call(m);
188 }
189 {
190 auto m = notify();
191 m.append(relDeleteMeTwo);
192 m.append(obj);
193 b.call(m);
194 }
195
196 // Create the triggering object.
197 {
198 auto m = notify();
199 m.append(relTriggerOne);
200 m.append(obj);
201 b.call(m);
202 }
203
204 // Set a property that should not trigger due to a filter.
205 {
206 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500207 "path='" + root + "',member='InterfacesRemoved'");
Brad Bishop432e3522016-12-01 00:24:14 -0500208 auto m = set(triggerOne);
209 m.append("xyz.openbmc_project.Example.Iface2");
210 m.append("ExampleProperty2");
211 m.append(sdbusplus::message::variant<std::string>("abc123"));
212 b.call(m);
213 auto sig{queue.pop()};
214 assert(!sig);
215 }
216
217 // Set a property that should trigger.
218 {
219 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500220 "path='" + root + "',member='InterfacesRemoved'");
Brad Bishop432e3522016-12-01 00:24:14 -0500221
222 auto m = set(triggerOne);
223 m.append("xyz.openbmc_project.Example.Iface2");
224 m.append("ExampleProperty2");
225 m.append(sdbusplus::message::variant<std::string>("xxxyyy"));
226 b.call(m);
227
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500228 sdbusplus::message::object_path sigpath;
Brad Bishop432e3522016-12-01 00:24:14 -0500229 std::vector<std::string> interfaces;
230 {
231 std::vector<std::string> interfaces;
232 auto sig{queue.pop()};
233 assert(sig);
234 sig.read(sigpath);
235 assert(sigpath == deleteMeOne);
236 sig.read(interfaces);
237 std::sort(interfaces.begin(), interfaces.end());
238 assert(hasInterfaces(interfaces, obj));
239 }
240 {
241 std::vector<std::string> interfaces;
242 auto sig{queue.pop()};
243 assert(sig);
244 sig.read(sigpath);
245 assert(sigpath == deleteMeTwo);
246 sig.read(interfaces);
247 std::sort(interfaces.begin(), interfaces.end());
248 assert(hasInterfaces(interfaces, obj));
249 }
250 {
251 // Make sure there were only two signals.
252 auto sig{queue.pop()};
253 assert(!sig);
254 }
255 }
256 }
257
Brad Bishop22ecacc2016-12-01 08:38:06 -0500258 // Validate the set property action.
259 {
Brad Bishop9aa5e2f2017-01-15 19:45:40 -0500260 sdbusplus::message::object_path relChangeMe{"/changeme"};
261 sdbusplus::message::object_path relTriggerTwo{"/trigger2"};
262 std::string changeMe{root + relChangeMe.str};
263 std::string triggerTwo{root + relTriggerTwo.str};
Brad Bishop22ecacc2016-12-01 08:38:06 -0500264
265 // Create an object to be updated by the set property action.
266 {
267 auto m = notify();
268 m.append(relChangeMe);
269 m.append(obj);
270 b.call(m);
271 }
272
273 // Create the triggering object.
274 {
275 auto m = notify();
276 m.append(relTriggerTwo);
277 m.append(obj);
278 b.call(m);
279 }
280
281 // Trigger and validate the change.
282 {
283 SignalQueue queue(
Brad Bishop7b337772017-01-12 16:11:24 -0500284 "path='" + changeMe + "',member='PropertiesChanged'");
Brad Bishop22ecacc2016-12-01 08:38:06 -0500285 auto m = set(triggerTwo);
286 m.append("xyz.openbmc_project.Example.Iface2");
287 m.append("ExampleProperty2");
288 m.append(sdbusplus::message::variant<std::string>("yyyxxx"));
289 b.call(m);
290
291 std::string sigInterface;
Brad Bishop7b337772017-01-12 16:11:24 -0500292 std::map <
293 std::string,
294 sdbusplus::message::variant<std::string >> sigProperties;
Brad Bishop22ecacc2016-12-01 08:38:06 -0500295 {
296 std::vector<std::string> interfaces;
297 auto sig{queue.pop()};
298 sig.read(sigInterface);
299 assert(sigInterface == "xyz.openbmc_project.Example.Iface1");
300 sig.read(sigProperties);
301 assert(sigProperties["ExampleProperty1"] == "changed");
302 }
303 }
304 }
305
Brad Bishop49aefb32016-10-19 11:54:14 -0400306 mgr.shutdown();
Brad Bishopabb2a1a2016-11-30 22:02:28 -0500307 std::cout << "Success!" << std::endl;
Brad Bishop49aefb32016-10-19 11:54:14 -0400308}
309
310int main()
311{
Brad Bishop65247582017-01-15 19:48:41 -0500312 phosphor::inventory::manager::Manager mgr(
313 sdbusplus::bus::new_default(),
314 SERVICE, ROOT, INTERFACE);
Brad Bishop49aefb32016-10-19 11:54:14 -0400315
Brad Bishop21621432017-01-13 16:35:53 -0500316 auto f = [](auto mgr)
Brad Bishop49aefb32016-10-19 11:54:14 -0400317 {
Brad Bishop21621432017-01-13 16:35:53 -0500318 mgr->run();
319 };
320 auto t = std::thread(f, &mgr);
Brad Bishop49aefb32016-10-19 11:54:14 -0400321 runTests(mgr);
322
323 // Wait for server thread to exit.
Brad Bishop21621432017-01-13 16:35:53 -0500324 t.join();
Brad Bishop49aefb32016-10-19 11:54:14 -0400325
326 return 0;
327}
328
329// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4