| #include "macros.hpp" | |
| #include <memory> | |
| #include <system_error> // NOLINT | |
| #include <string_view> | |
| #include <utility> | |
| #include <string> | |
| #include <gtest/gtest.h> | |
| #include "boost/asio/io_context.hpp" // NOLINT | |
| #include "boost/beast/http/verb.hpp" // NOLINT | |
| #include "app.hpp" | |
| #include "app_singleton.hpp" | |
| #include "http_request.hpp" | |
| #include "async_resp.hpp" | |
| #include "logging.hpp" | |
| #include "utility.hpp" | |
| #include "interface.hpp" | |
| #include "http_response.hpp" | |
| #include "query.hpp" | |
| #include "registries/privilege_registry.hpp" | |
| #include <nlohmann/json.hpp> | |
| 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 |