| #include "app.hpp" |
| #include "app_singleton.hpp" |
| #include "async_resp.hpp" |
| #include "http_request.hpp" |
| #include "interface.hpp" |
| #include "macros.hpp" |
| #include "privileges.hpp" |
| #include "query.hpp" |
| #include "registries/privilege_registry.hpp" |
| #include "utility.hpp" |
| |
| #include <boost/asio/io_context.hpp> |
| #include <boost/beast/http/verb.hpp> |
| #include <nlohmann/json.hpp> |
| |
| #include <memory> |
| #include <string_view> |
| |
| #include <gtest/gtest.h> |
| |
| namespace redfish_plugin |
| { |
| |
| int platform_plugins_called = 0; // NOLINT |
| |
| void loadPlatformPlugins() |
| { |
| auto callback = [](const crow::Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) { |
| platform_plugins_called++; |
| }; |
| |
| REDFISH_HANDLER_ADD("/platform_plugins/", boost::beast::http::verb::get, |
| redfish::privileges::getChassis, std::move(callback)); |
| } |
| |
| int google_plugins_called = 0; // NOLINT |
| |
| void loadGooglePlugins() |
| { |
| auto callback = [](const crow::Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) { |
| google_plugins_called++; |
| }; |
| |
| REDFISH_HANDLER_ADD("/google_plugins/", boost::beast::http::verb::get, |
| redfish::privileges::getChassis, std::move(callback)); |
| } |
| |
| } // namespace redfish_plugin |
| |
| namespace crow |
| { |
| namespace |
| { |
| |
| class PluginMacrosTest : public testing::Test |
| { |
| public: |
| PluginMacrosTest() |
| { |
| io = std::make_shared<boost::asio::io_context>(); |
| app = std::make_unique<crow::App>(/*allowSessionEmpty=*/true, io); |
| crow::globalBmcWebApp = app.get(); |
| } |
| |
| private: |
| std::shared_ptr<boost::asio::io_context> io; |
| std::unique_ptr<crow::App> app; |
| }; |
| |
| TEST_F(PluginMacrosTest, AddedHandlerCanBeInvoked) |
| { |
| int called = 0; |
| auto callback = [&called](const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) { |
| called++; |
| }; |
| |
| 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_EQ(called, 1); |
| } |
| |
| #ifdef PLATFORM_PLUGINS_ENABLED |
| TEST_F(PluginMacrosTest, AddedRedfishResourceHandlerCanBeInvoked) |
| { |
| crow::Logger::setLogLevel(crow::LogLevel::Debug); |
| |
| int called_generic = 0; |
| BMCWEB_ROUTE((*crow::globalBmcWebApp), |
| "/redfish/v1/UpdateService/FirmwareInventory/<str>/") |
| .privileges(redfish::privileges::getSoftwareInventory) |
| .methods(boost::beast::http::verb::get)( |
| [&called_generic]( |
| const crow::Request& reqIn, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn, |
| const std::string& param) { |
| called_generic++; |
| std::shared_ptr<std::string> swId = |
| std::make_shared<std::string>(param); |
| |
| asyncRespIn->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( |
| "redfish", "v1", "UpdateService", "FirmwareInventory", *swId); |
| BMCWEB_LOG_DEBUG << "DEBUG: Inside generic FW ROUTE for " << *swId; |
| BMCWEB_LOG_DEBUG << "DEBUG: req method is: " << reqIn.methodString(); |
| }); |
| |
| int called_404 = 0; |
| BMCWEB_ROUTE((*crow::globalBmcWebApp), "/redfish/<path>") |
| .methodNotAllowed() |
| .privileges(redfish::privileges::privilegeSetLogin)( |
| [&called_404](const crow::Request& reqIn, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn, |
| const std::string& path) { |
| called_404++; |
| asyncRespIn->res.jsonValue["@odata.id"] = |
| crow::utility::urlFromPieces("redfish", "v1", path); |
| BMCWEB_LOG_DEBUG << "DEBUG: req method for 404 is: " |
| << reqIn.methodString(); |
| }); |
| |
| int called = 0; |
| auto callback = [&called](const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) { |
| called++; |
| }; |
| |
| REDFISH_HANDLER_ADD( |
| "/redfish/v1/UpdateService/FirmwareInventory/SpecialFW/", |
| boost::beast::http::verb::get, |
| redfish::privileges::getSoftwareInventory, std::move(callback)); |
| |
| crow::globalBmcWebApp->validate(); |
| |
| constexpr std::string_view url = |
| "/redfish/v1/UpdateService/FirmwareInventory/SpecialFW"; |
| 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); |
| crow::globalBmcWebApp->handle(req, asyncResp); |
| crow::globalBmcWebApp->handle(req, asyncResp); |
| |
| EXPECT_EQ(called, 3); |
| EXPECT_EQ(called_generic, 0); |
| EXPECT_EQ(called_404, 0); |
| |
| constexpr std::string_view url2 = |
| "/redfish/v1/UpdateService/FirmwareInventory/foo"; |
| std::error_code ec2; |
| Request req2{{boost::beast::http::verb::get, url2, 11}, ec2}; |
| auto asyncResp2 = std::make_shared<bmcweb::AsyncResp>(); |
| crow::globalBmcWebApp->handle(req2, asyncResp2); |
| crow::globalBmcWebApp->handle(req2, asyncResp2); |
| crow::globalBmcWebApp->handle(req2, asyncResp2); |
| crow::globalBmcWebApp->handle(req2, asyncResp2); |
| crow::globalBmcWebApp->handle(req2, asyncResp2); |
| |
| EXPECT_EQ(called, 3); |
| EXPECT_EQ(called_generic, 5); |
| EXPECT_EQ(called_404, 0); |
| } |
| #endif |
| |
| 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, callback); |
| REDFISH_HANDLER_ADD("/hello/", boost::beast::http::verb::get, |
| redfish::privileges::getChassis, std::move(callback)); |
| |
| EXPECT_ANY_THROW(crow::globalBmcWebApp->validate()); |
| } |
| |
| TEST_F(PluginMacrosTest, ReplacedNonExistHandlerThrows) |
| { |
| auto callback = [](const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) {}; |
| EXPECT_ANY_THROW(REDFISH_HANDLER_REPLACE("/hello/", |
| boost::beast::http::verb::get, |
| std::move(callback));); |
| } |
| |
| TEST_F(PluginMacrosTest, ReplacedHandlerCanBeInvoked) |
| { |
| int originalCalled = 0; |
| auto originalCallback = |
| [&originalCalled](const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) { |
| originalCalled++; |
| }; |
| |
| int replacedCalled = 0; |
| auto replacedCallback = |
| [&replacedCalled](const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) { |
| replacedCalled++; |
| }; |
| |
| REDFISH_HANDLER_ADD("/hello/", boost::beast::http::verb::get, |
| redfish::privileges::getChassis, |
| std::move(originalCallback)); |
| REDFISH_HANDLER_REPLACE("/hello/", boost::beast::http::verb::get, |
| std::move(replacedCallback)); |
| 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_EQ(originalCalled, 0); |
| EXPECT_EQ(replacedCalled, 1); |
| } |
| |
| TEST_F(PluginMacrosTest, RemoveNonExistHandlerThrows) |
| { |
| EXPECT_ANY_THROW( |
| REDFISH_HANDLER_REMOVE("/hello/", boost::beast::http::verb::get)); |
| } |
| |
| TEST_F(PluginMacrosTest, RemovedHandlerNotBeInvoked) |
| { |
| int originalCalled = 0; |
| auto originalCallback = |
| [&originalCalled](const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) { |
| originalCalled++; |
| }; |
| |
| REDFISH_HANDLER_ADD("/hello/", boost::beast::http::verb::get, |
| redfish::privileges::getChassis, |
| std::move(originalCallback)); |
| REDFISH_HANDLER_REMOVE("/hello/", boost::beast::http::verb::get); |
| 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_EQ(originalCalled, 0); |
| } |
| |
| TEST_F(PluginMacrosTest, AppendNonExistHandlerThrows) |
| { |
| auto callback = [](const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) {}; |
| |
| EXPECT_ANY_THROW(REDFISH_HANDLER_APPEND( |
| "/hello/", boost::beast::http::verb::get, std::move(callback))); |
| } |
| |
| TEST_F(PluginMacrosTest, AppendRemovedHandlerThrows) |
| { |
| int originalCalled = 0; |
| auto originalCallback = |
| [&originalCalled](const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) { |
| originalCalled++; |
| }; |
| int appendedCalled = 0; |
| auto appendedCallback = |
| [&appendedCalled](const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) { |
| appendedCalled++; |
| }; |
| REDFISH_HANDLER_ADD("/hello/", boost::beast::http::verb::get, |
| redfish::privileges::getChassis, |
| std::move(originalCallback)); |
| REDFISH_HANDLER_APPEND("/hello/", boost::beast::http::verb::get, |
| std::move(appendedCallback)); |
| REDFISH_HANDLER_REMOVE("/hello/", boost::beast::http::verb::get); |
| |
| 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_EQ(originalCalled, 0); |
| EXPECT_EQ(appendedCalled, 0); |
| } |
| |
| TEST_F(PluginMacrosTest, AppendedHandlerCanBeCompletelyRemoved) |
| { |
| auto callback = [](const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) {}; |
| REDFISH_HANDLER_ADD("/hello/", boost::beast::http::verb::get, |
| redfish::privileges::getChassis, callback); |
| REDFISH_HANDLER_REMOVE("/hello/", boost::beast::http::verb::get); |
| EXPECT_ANY_THROW(REDFISH_HANDLER_APPEND( |
| "/hello/", boost::beast::http::verb::get, std::move(callback))); |
| } |
| |
| TEST_F(PluginMacrosTest, ReplacedHandlerCanBeAppended) |
| { |
| |
| int replacedCalled = 0; |
| auto replacedCallback = |
| [&replacedCalled](const Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& resp) { |
| EXPECT_TRUE(redfish::setUpRedfishRouteOnGlobalApp(req, resp)); |
| replacedCalled++; |
| }; |
| |
| int appendedCalled = 0; |
| auto appendedCallback = |
| [&appendedCalled](const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) { |
| appendedCalled++; |
| }; |
| |
| REDFISH_HANDLER_ADD( |
| "/hello/", boost::beast::http::verb::get, |
| redfish::privileges::getChassis, |
| [](const Request&, const std::shared_ptr<bmcweb::AsyncResp>&) {}); |
| REDFISH_HANDLER_REPLACE("/hello/", boost::beast::http::verb::get, |
| std::move(replacedCallback)); |
| REDFISH_HANDLER_APPEND("/hello/", boost::beast::http::verb::get, |
| std::move(appendedCallback)); |
| crow::globalBmcWebApp->validate(); |
| |
| constexpr std::string_view url = "/hello/"; |
| std::error_code ec; |
| Request req{{boost::beast::http::verb::get, url, 11}, ec}; |
| |
| // This is to make sure |asyncResp| destructs |
| { |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); |
| crow::globalBmcWebApp->handle(req, asyncResp); |
| } |
| |
| EXPECT_EQ(appendedCalled, 1); |
| EXPECT_EQ(replacedCalled, 1); |
| } |
| |
| // The test makes sure the execution order is: |
| // 1. originalCallback |
| // 2. appendedCallback (if multiple appends exist, the order is LIFO; please |
| // note multiple appends should be rarely used) |
| // 3. callback setup by setUpRedfishRoute |
| TEST_F(PluginMacrosTest, AppendedHandlerBeInvokedInOrder) |
| { |
| crow::Logger::setLogLevel(crow::LogLevel::Debug); |
| |
| int originalCalled = 0; |
| int appendedOneCalled = 0; |
| int appendedTwoCalled = 0; |
| int onlyCalled = 0; |
| auto originalCallback = |
| [&originalCalled, &appendedOneCalled, &appendedTwoCalled, |
| &onlyCalled](const Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& resp) { |
| EXPECT_TRUE(redfish::setUpRedfishRouteOnGlobalApp(req, resp)); |
| EXPECT_EQ(appendedOneCalled, 0); |
| EXPECT_EQ(appendedTwoCalled, 0); |
| EXPECT_EQ(onlyCalled, 0); |
| originalCalled++; |
| resp->res.jsonValue = R"( |
| { |
| "Members": [ |
| { |
| "@odata.id": "/only" |
| } |
| ] |
| } |
| )"_json; |
| }; |
| |
| auto appendedOneCallback = |
| [&originalCalled, &appendedOneCalled, &appendedTwoCalled, &onlyCalled]( |
| const Request&, const std::shared_ptr<bmcweb::AsyncResp>&) { |
| EXPECT_EQ(originalCalled, 1); |
| // this tests that the callback setup by setUpRedfishRoute hasn't run |
| EXPECT_EQ(onlyCalled, 0); |
| // the order is LIFO |
| EXPECT_EQ(appendedTwoCalled, 1); |
| appendedOneCalled++; |
| }; |
| |
| auto appendedTwoCallback = |
| [&originalCalled, &appendedOneCalled, &appendedTwoCalled, &onlyCalled]( |
| const Request&, const std::shared_ptr<bmcweb::AsyncResp>&) { |
| EXPECT_EQ(originalCalled, 1); |
| // this tests that the callback setup by setUpRedfishRoute hasn't run |
| EXPECT_EQ(onlyCalled, 0); |
| EXPECT_EQ(appendedOneCalled, 0); |
| appendedTwoCalled++; |
| }; |
| |
| auto onlyCallback = |
| [&originalCalled, &appendedOneCalled, &appendedTwoCalled, &onlyCalled]( |
| const Request&, const std::shared_ptr<bmcweb::AsyncResp>&) { |
| EXPECT_TRUE(originalCalled); |
| EXPECT_TRUE(appendedOneCalled); |
| EXPECT_TRUE(appendedTwoCalled); |
| onlyCalled = 1; |
| }; |
| |
| REDFISH_HANDLER_ADD("/hello/", boost::beast::http::verb::get, |
| redfish::privileges::getChassis, |
| std::move(originalCallback)); |
| REDFISH_HANDLER_ADD("/only", boost::beast::http::verb::get, |
| redfish::privileges::getChassis, |
| std::move(onlyCallback)); |
| REDFISH_HANDLER_APPEND("/hello/", boost::beast::http::verb::get, |
| std::move(appendedOneCallback)); |
| REDFISH_HANDLER_APPEND("/hello/", boost::beast::http::verb::get, |
| std::move(appendedTwoCallback)); |
| crow::globalBmcWebApp->validate(); |
| |
| constexpr std::string_view url = "/hello/?only"; |
| std::error_code ec; |
| Request req{{boost::beast::http::verb::get, url, 11}, ec}; |
| |
| // This is to make sure |asyncResp| destructs |
| { |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); |
| asyncResp->res.setCompleteRequestHandler([](crow::Response&) {}); |
| crow::globalBmcWebApp->handle(req, asyncResp); |
| } |
| |
| EXPECT_EQ(onlyCalled, 1); |
| } |
| |
| TEST_F(PluginMacrosTest, AppendedHandlerGetsParams) |
| { |
| auto originalCallback = [](const Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& resp, |
| const std::string&) { |
| EXPECT_TRUE(redfish::setUpRedfishRouteOnGlobalApp(req, resp)); |
| }; |
| |
| int appendedCalled = 0; |
| auto appendedCallback = |
| [&appendedCalled](const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&, |
| const std::string& param) { |
| EXPECT_EQ(param, "awesome"); |
| appendedCalled++; |
| }; |
| |
| REDFISH_HANDLER_ADD("/hello/<str>/", boost::beast::http::verb::get, |
| redfish::privileges::getChassis, |
| std::move(originalCallback)); |
| REDFISH_HANDLER_APPEND("/hello/<str>/", boost::beast::http::verb::get, |
| std::move(appendedCallback)); |
| crow::globalBmcWebApp->validate(); |
| |
| constexpr std::string_view url = "/hello/awesome/"; |
| std::error_code ec; |
| Request req{{boost::beast::http::verb::get, url, 11}, ec}; |
| |
| // This is to make sure |asyncResp| destructs |
| { |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); |
| asyncResp->res.setCompleteRequestHandler([](crow::Response&) {}); |
| crow::globalBmcWebApp->handle(req, asyncResp); |
| } |
| |
| EXPECT_EQ(appendedCalled, 1); |
| } |
| |
| // Every Redfish Route is suppose to have Redfish parameter handler; however, |
| // plugin code shouldn't fail if a Redfish route is not configured properly. |
| // This test ensures that scenario. |
| TEST_F(PluginMacrosTest, AppendedHandlerRunsWithoutRedfishParamsHandler) |
| { |
| auto originalCallback = [](const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) {}; |
| |
| int appendedCalled = 0; |
| auto appendedCallback = |
| [&appendedCalled](const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>&) { |
| appendedCalled++; |
| }; |
| |
| REDFISH_HANDLER_ADD("/hello/", boost::beast::http::verb::get, |
| redfish::privileges::getChassis, |
| std::move(originalCallback)); |
| REDFISH_HANDLER_APPEND("/hello/", boost::beast::http::verb::get, |
| std::move(appendedCallback)); |
| crow::globalBmcWebApp->validate(); |
| |
| constexpr std::string_view url = "/hello/"; |
| std::error_code ec; |
| Request req{{boost::beast::http::verb::get, url, 11}, ec}; |
| |
| // This is to make sure |asyncResp| destructs |
| { |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); |
| asyncResp->res.setCompleteRequestHandler([](crow::Response&) {}); |
| crow::globalBmcWebApp->handle(req, asyncResp); |
| } |
| |
| EXPECT_EQ(appendedCalled, 1); |
| } |
| |
| TEST_F(PluginMacrosTest, AddHandlerWorksWithArbitraryLayerOfPlugins) |
| { |
| redfish_plugin::loadPlatformPlugins(); |
| redfish_plugin::loadGooglePlugins(); |
| |
| crow::globalBmcWebApp->validate(); |
| |
| std::error_code ec; |
| Request req1{{boost::beast::http::verb::get, "/platform_plugins/", 11}, ec}; |
| |
| auto asyncResp1 = std::make_shared<bmcweb::AsyncResp>(); |
| crow::globalBmcWebApp->handle(req1, asyncResp1); |
| |
| Request req2{{boost::beast::http::verb::get, "/google_plugins/", 11}, ec}; |
| |
| auto asyncResp2 = std::make_shared<bmcweb::AsyncResp>(); |
| crow::globalBmcWebApp->handle(req2, asyncResp2); |
| |
| EXPECT_EQ(redfish_plugin::platform_plugins_called, 1); |
| EXPECT_EQ(redfish_plugin::google_plugins_called, 1); |
| } |
| |
| TEST_F(PluginMacrosTest, AppendHandlerCanGetDelegateExpandLevelOfQuery) |
| { |
| constexpr int expandLevelInGenericHandler = 6; |
| BMCWEB_ROUTE((*crow::globalBmcWebApp), |
| "/redfish/v1/Systems/system/Processors/") |
| .privileges(redfish::privileges::headProcessorCollection) |
| .methods(boost::beast::http::verb::get)( |
| [](const crow::Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { |
| asyncResp->delegatedExpandLevel = expandLevelInGenericHandler; |
| }); |
| |
| int delegatedExpandLevelInAppendHandler = 0; |
| auto appendedCallback = |
| [&delegatedExpandLevelInAppendHandler]( |
| const Request&, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { |
| delegatedExpandLevelInAppendHandler = asyncResp->delegatedExpandLevel; |
| }; |
| |
| REDFISH_HANDLER_APPEND("/redfish/v1/Systems/system/Processors/", |
| boost::beast::http::verb::get, |
| std::move(appendedCallback)); |
| crow::globalBmcWebApp->validate(); |
| |
| constexpr std::string_view url = "/redfish/v1/Systems/system/Processors/"; |
| std::error_code ec; |
| Request req{{boost::beast::http::verb::get, url, 11}, ec}; |
| |
| // This is to make sure |asyncResp| destructs |
| { |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); |
| asyncResp->res.setCompleteRequestHandler([](crow::Response&) {}); |
| crow::globalBmcWebApp->handle(req, asyncResp); |
| } |
| |
| EXPECT_EQ(delegatedExpandLevelInAppendHandler, expandLevelInGenericHandler); |
| } |
| |
| TEST_F(PluginMacrosTest, AppendHandlerCaptureByReferenceCheck) |
| { |
| // check the safety of pass by copy for callback handler |
| boost::asio::io_context io; |
| |
| auto originalCallback = |
| [&io](const Request& req, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { |
| |
| boost::asio::post(io, [asyncResp](){ |
| BMCWEB_LOG_DEBUG << "Delay the call \n"; |
| }); |
| |
| EXPECT_EQ(req.target(), "/hello"); |
| }; |
| |
| auto appendedCallback = |
| [](const Request& req, const std::shared_ptr<bmcweb::AsyncResp>&) { |
| EXPECT_EQ(req.target(), "/hello"); |
| }; |
| |
| REDFISH_HANDLER_ADD("/hello/", boost::beast::http::verb::get, |
| redfish::privileges::getChassis, |
| std::move(originalCallback)); |
| REDFISH_HANDLER_APPEND("/hello/", boost::beast::http::verb::get, |
| std::move(appendedCallback)); |
| |
| crow::globalBmcWebApp->validate(); |
| |
| constexpr std::string_view url = "/hello"; |
| std::error_code ec; |
| |
| // This is to make sure |asyncResp| destructs |
| { |
| Request req{{boost::beast::http::verb::get, url, 11}, ec}; |
| |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); |
| asyncResp->res.setCompleteRequestHandler( |
| [](crow::Response&) {} |
| ); |
| crow::globalBmcWebApp->handle(req, asyncResp); |
| } |
| io.run_one(); |
| } |
| |
| } // namespace |
| } // namespace crow |