blob: 669879d4d2bb4687158f6dd46c3061dd6eb98e79 [file] [log] [blame]
/**
* Copyright © 2016 IBM Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "../manager.hpp"
#include "../config.h"
#include <cassert>
#include <iostream>
#include <algorithm>
constexpr auto SERVICE = "phosphor.inventory.test";
constexpr auto INTERFACE = IFACE;
constexpr auto ROOT = "/testing/inventory";
auto server_thread(void *data)
{
auto mgr = static_cast<phosphor::inventory::manager::Manager*>(data);
mgr->run();
return static_cast<void *>(nullptr);
}
/** @class SignalQueue
* @brief Store DBus signals in a queue.
*/
class SignalQueue
{
public:
~SignalQueue() = default;
SignalQueue() = delete;
SignalQueue(const SignalQueue &) = delete;
SignalQueue(SignalQueue &&) = default;
SignalQueue& operator=(const SignalQueue &) = delete;
SignalQueue& operator=(SignalQueue &&) = default;
explicit SignalQueue(const std::string &match) :
_bus(sdbusplus::bus::new_default()),
_match(_bus, match.c_str(), &callback, this),
_next(nullptr)
{
}
auto &&pop(unsigned timeout=1000000)
{
while(timeout > 0 && !_next)
{
_bus.process_discard();
_bus.wait(50000);
timeout -= 50000;
}
return std::move(_next);
}
private:
static int callback(sd_bus_message *m, void *context, sd_bus_error *)
{
auto *me = static_cast<SignalQueue *>(context);
sd_bus_message_ref(m);
sdbusplus::message::message msg{m};
me->_next = std::move(msg);
return 0;
}
sdbusplus::bus::bus _bus;
sdbusplus::server::match::match _match;
sdbusplus::message::message _next;
};
template <typename ...T>
using Object = std::map<
std::string,
std::map<
std::string,
sdbusplus::message::variant<T...>>>;
using ObjectPath = std::string;
/**@brief Find a subset of interfaces and properties in an object. */
template <typename ...T>
auto hasProperties(const Object<T...> &l, const Object<T...> &r)
{
Object<T...> result;
std::set_difference(
r.cbegin(),
r.cend(),
l.cbegin(),
l.cend(),
std::inserter(result, result.end()));
return result.empty();
}
void runTests(phosphor::inventory::manager::Manager &mgr)
{
const std::string root{ROOT};
auto b = sdbusplus::bus::new_default();
auto notify = [&]()
{
return b.new_method_call(
SERVICE,
ROOT,
INTERFACE,
"Notify");
};
Object<std::string> obj{
{
"xyz.openbmc_project.Example.Iface1",
{{"ExampleProperty1", "test1"}}
},
{
"xyz.openbmc_project.Example.Iface2",
{{"ExampleProperty2", "test2"}}
},
};
// Make sure the notify method works.
{
ObjectPath relPath{"/foo"};
ObjectPath path{root + relPath};
SignalQueue queue(
"path='" + root + "',member='InterfacesAdded'");
auto m = notify();
m.append(relPath);
m.append(obj);
b.call(m);
auto sig{queue.pop()};
assert(sig);
ObjectPath signalPath;
Object<std::string> signalObject;
sig.read(signalPath);
assert(path == signalPath);
sig.read(signalObject);
assert(hasProperties(signalObject, obj));
auto moreSignals{queue.pop()};
assert(!moreSignals);
}
mgr.shutdown();
std::cout << "Success!" << std::endl;
}
int main()
{
auto mgr = phosphor::inventory::manager::Manager(
sdbusplus::bus::new_default(),
SERVICE, ROOT, INTERFACE);
pthread_t t;
{
pthread_create(&t, nullptr, server_thread, &mgr);
}
runTests(mgr);
// Wait for server thread to exit.
pthread_join(t, nullptr);
return 0;
}
// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4