plugin: implement addRedfishHandler
This commit implements the first Redfish Plugin macro:
REDFISH_HANDLER_ADD
This plugin macro gives plugin user ability to add a platform specific
route. The plugin takes URL, Verb, Redfish Privileges, and the callback.
A few refacotring has been implemented (e.g., string_view instead of
string reference) to make this happen.
A unit test is added which demostrates how the plugin adds a new route.
The test also ensures duplicate routes throws.
Tested: unit test.
Change-Id: Id15d79a681f74367ce5108c67d9da146eac9fef8
Signed-off-by: Nan Zhou <nanzhou@google.com>
diff --git a/http/app.hpp b/http/app.hpp
index 85104fc..bd30007 100644
--- a/http/app.hpp
+++ b/http/app.hpp
@@ -12,6 +12,7 @@
#include <boost/beast/ssl/ssl_stream.hpp>
#endif
+#include <array>
#include <chrono>
#include <cstdint>
#include <functional>
@@ -118,6 +119,13 @@
return router.getRoutes(parent);
}
+ template <uint64_t Tag, typename Func, size_t N>
+ void addHandler(std::string_view url, boost::beast::http::verb verb,
+ const std::array<redfish::Privileges, N>& p, Func&& func)
+ {
+ router.newRuleTagged<Tag>(url).methods(verb).privileges(p)(func);
+ }
+
#ifdef BMCWEB_ENABLE_SSL
App& ssl(std::shared_ptr<boost::asio::ssl::context>&& ctx)
{
diff --git a/http/routing.hpp b/http/routing.hpp
index 3c9d555..c60721c 100644
--- a/http/routing.hpp
+++ b/http/routing.hpp
@@ -41,7 +41,7 @@
class BaseRule
{
public:
- explicit BaseRule(const std::string& thisRule) : rule(thisRule)
+ explicit BaseRule(std::string_view thisRule) : rule(thisRule)
{}
virtual ~BaseRule() = default;
@@ -596,7 +596,7 @@
public:
using self_t = TaggedRule<Args...>;
- explicit TaggedRule(const std::string& ruleIn) : BaseRule(ruleIn)
+ explicit TaggedRule(std::string_view ruleIn) : BaseRule(ruleIn)
{}
void validate() override
@@ -806,7 +806,7 @@
template <uint64_t N>
typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
- newRuleTagged(const std::string& rule)
+ newRuleTagged(std::string_view rule)
{
using RuleT = typename black_magic::Arguments<N>::type::template rebind<
TaggedRule>;
diff --git a/meson.build b/meson.build
index 29e1740..0245754 100644
--- a/meson.build
+++ b/meson.build
@@ -432,6 +432,7 @@
'test/redfish-core/lib/thermal_subsystem_test.cpp',
'test/redfish-core/lib/power_subsystem_test.cpp',
# 'test/redfish-core/lib/chassis_test.cpp',
+ 'plugins/macros_test.cpp',
)
if(get_option('tests').enabled())
diff --git a/plugins/macros.hpp b/plugins/macros.hpp
new file mode 100644
index 0000000..0d90605
--- /dev/null
+++ b/plugins/macros.hpp
@@ -0,0 +1,26 @@
+#include "app_singleton.hpp"
+#include "async_resp.hpp"
+#include "http_request.hpp"
+#include "privileges.hpp"
+#include "utility.hpp"
+
+#include <boost/beast/http/verb.hpp>
+
+#include <array>
+#include <string_view>
+
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
+#define REDFISH_HANDLER_ADD(url, verb, privileges, func) \
+ plugins::addRedfishHandler<crow::black_magic::getParameterTag(url)>( \
+ url, verb, privileges, func);
+
+namespace plugins
+{
+template <uint64_t tag, typename RedfishHandler, size_t N>
+void addRedfishHandler(std::string_view url, boost::beast::http::verb verb,
+ const std::array<redfish::Privileges, N>& p,
+ RedfishHandler&& func)
+{
+ crow::globalBmcWebApp->addHandler<tag>(url, verb, p, func);
+}
+} // namespace plugins
\ No newline at end of file
diff --git a/plugins/macros_test.cpp b/plugins/macros_test.cpp
new file mode 100644
index 0000000..ca15030
--- /dev/null
+++ b/plugins/macros_test.cpp
@@ -0,0 +1,75 @@
+#include "app.hpp"
+#include "app_singleton.hpp"
+#include "async_resp.hpp"
+#include "http_request.hpp"
+#include "macros.hpp"
+#include "privileges.hpp"
+#include "registries/privilege_registry.hpp"
+#include "utility.hpp"
+
+#include <boost/asio/io_context.hpp>
+#include <boost/beast/http/verb.hpp>
+
+#include <memory>
+#include <string_view>
+
+#include <gtest/gtest.h>
+
+namespace crow
+{
+namespace
+{
+
+class PluginMacrosTest : public testing::Test
+{
+ public:
+ PluginMacrosTest()
+ {
+ io = std::make_shared<boost::asio::io_context>();
+ app = std::make_unique<crow::App>(io);
+ crow::globalBmcWebApp = app.get();
+ }
+
+ private:
+ std::shared_ptr<boost::asio::io_context> io;
+ std::unique_ptr<crow::App> app;
+};
+
+TEST_F(PluginMacrosTest, AddHandlerCanBeInvoked)
+{
+ bool called = false;
+ auto callback = [&called](const Request&,
+ const std::shared_ptr<bmcweb::AsyncResp>&) {
+ called = true;
+ };
+
+ REDFISH_HANDLER_ADD("/hello/", boost::beast::http::verb::get,
+ redfish::privileges::getChassis, std::move(callback));
+
+ crow::globalBmcWebApp->validate();
+
+ constexpr std::string_view url = "/hello/";
+ std::error_code ec;
+ Request req{{boost::beast::http::verb::get, url, 11}, ec};
+
+ auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
+ crow::globalBmcWebApp->handle(req, asyncResp);
+
+ EXPECT_TRUE(called);
+}
+
+TEST_F(PluginMacrosTest, DuplicateHandlerThrows)
+{
+ auto callback =
+ [](const Request&, const std::shared_ptr<bmcweb::AsyncResp>&) {};
+
+ REDFISH_HANDLER_ADD("/hello/", boost::beast::http::verb::get,
+ redfish::privileges::getChassis, std::move(callback));
+ REDFISH_HANDLER_ADD("/hello/", boost::beast::http::verb::get,
+ redfish::privileges::getChassis, std::move(callback));
+
+ EXPECT_ANY_THROW(crow::globalBmcWebApp->validate());
+}
+
+} // namespace
+} // namespace crow
\ No newline at end of file