1 #include "async_resp.hpp" // IWYU pragma: keep 2 #include "http_request.hpp" 3 #include "routing.hpp" 4 #include "utility.hpp" 5 6 #include <boost/beast/http/message.hpp> // IWYU pragma: keep 7 #include <boost/beast/http/verb.hpp> 8 9 #include <memory> 10 #include <string> 11 #include <string_view> 12 #include <system_error> 13 14 #include <gtest/gtest.h> // IWYU pragma: keep 15 16 // IWYU pragma: no_include <boost/beast/http/impl/message.hpp> 17 // IWYU pragma: no_include "gtest/gtest_pred_impl.h" 18 // IWYU pragma: no_include <boost/intrusive/detail/list_iterator.hpp> 19 // IWYU pragma: no_include <gtest/gtest-message.h> 20 // IWYU pragma: no_include <gtest/gtest-test-part.h> 21 // IWYU pragma: no_forward_declare bmcweb::AsyncResp 22 23 namespace crow 24 { 25 namespace 26 { 27 28 using ::crow::utility::getParameterTag; 29 30 TEST(Router, AllowHeader) 31 { 32 // Callback handler that does nothing 33 auto nullCallback = 34 [](const Request&, const std::shared_ptr<bmcweb::AsyncResp>&) {}; 35 36 Router router; 37 std::error_code ec; 38 39 constexpr std::string_view url = "/foo"; 40 41 Request req{{boost::beast::http::verb::get, url, 11}, ec}; 42 43 // No route should return no methods. 44 router.validate(); 45 EXPECT_EQ(router.findRoute(req).allowHeader, ""); 46 EXPECT_EQ(router.findRoute(req).route.rule, nullptr); 47 48 router.newRuleTagged<getParameterTag(url)>(std::string(url)) 49 .methods(boost::beast::http::verb::get)(nullCallback); 50 router.validate(); 51 EXPECT_EQ(router.findRoute(req).allowHeader, "GET"); 52 EXPECT_NE(router.findRoute(req).route.rule, nullptr); 53 54 Request patchReq{{boost::beast::http::verb::patch, url, 11}, ec}; 55 EXPECT_EQ(router.findRoute(patchReq).route.rule, nullptr); 56 57 router.newRuleTagged<getParameterTag(url)>(std::string(url)) 58 .methods(boost::beast::http::verb::patch)(nullCallback); 59 router.validate(); 60 EXPECT_EQ(router.findRoute(req).allowHeader, "GET, PATCH"); 61 EXPECT_NE(router.findRoute(req).route.rule, nullptr); 62 EXPECT_NE(router.findRoute(patchReq).route.rule, nullptr); 63 } 64 65 TEST(Router, OverlapingRoutes) 66 { 67 // Callback handler that does nothing 68 auto fooCallback = 69 [](const Request&, const std::shared_ptr<bmcweb::AsyncResp>&) { 70 EXPECT_FALSE(true); 71 }; 72 bool barCalled = false; 73 auto foobarCallback = 74 [&barCalled](const Request&, const std::shared_ptr<bmcweb::AsyncResp>&, 75 const std::string& bar) { 76 barCalled = true; 77 EXPECT_EQ(bar, "bar"); 78 }; 79 80 Router router; 81 std::error_code ec; 82 83 router.newRuleTagged<getParameterTag("/foo/<str>")>("/foo/<str>")( 84 foobarCallback); 85 router.newRuleTagged<getParameterTag("/foo")>("/foo")(fooCallback); 86 router.validate(); 87 { 88 constexpr std::string_view url = "/foo/bar"; 89 90 auto req = std::make_shared<Request>( 91 Request::Body{boost::beast::http::verb::get, url, 11}, ec); 92 93 std::shared_ptr<bmcweb::AsyncResp> asyncResp = 94 std::make_shared<bmcweb::AsyncResp>(); 95 96 router.handle(req, asyncResp); 97 } 98 EXPECT_TRUE(barCalled); 99 } 100 101 TEST(Router, 404) 102 { 103 bool notFoundCalled = false; 104 // Callback handler that does nothing 105 auto nullCallback = 106 [¬FoundCalled](const Request&, 107 const std::shared_ptr<bmcweb::AsyncResp>&) { 108 notFoundCalled = true; 109 }; 110 111 Router router; 112 std::error_code ec; 113 114 constexpr std::string_view url = "/foo/bar"; 115 116 auto req = std::make_shared<Request>( 117 Request::Body{boost::beast::http::verb::get, url, 11}, ec); 118 119 router.newRuleTagged<getParameterTag(url)>("/foo/<path>") 120 .notFound()(nullCallback); 121 router.validate(); 122 { 123 std::shared_ptr<bmcweb::AsyncResp> asyncResp = 124 std::make_shared<bmcweb::AsyncResp>(); 125 126 router.handle(req, asyncResp); 127 } 128 EXPECT_TRUE(notFoundCalled); 129 } 130 131 TEST(Router, 405) 132 { 133 // Callback handler that does nothing 134 auto nullCallback = 135 [](const Request&, const std::shared_ptr<bmcweb::AsyncResp>&) {}; 136 bool called = false; 137 auto notAllowedCallback = 138 [&called](const Request&, const std::shared_ptr<bmcweb::AsyncResp>&) { 139 called = true; 140 }; 141 142 Router router; 143 std::error_code ec; 144 145 constexpr std::string_view url = "/foo/bar"; 146 147 auto req = std::make_shared<Request>( 148 Request::Body{boost::beast::http::verb::patch, url, 11}, ec); 149 150 router.newRuleTagged<getParameterTag(url)>(std::string(url)) 151 .methods(boost::beast::http::verb::get)(nullCallback); 152 router.newRuleTagged<getParameterTag(url)>("/foo/<path>") 153 .methodNotAllowed()(notAllowedCallback); 154 router.validate(); 155 { 156 std::shared_ptr<bmcweb::AsyncResp> asyncResp = 157 std::make_shared<bmcweb::AsyncResp>(); 158 159 router.handle(req, asyncResp); 160 } 161 EXPECT_TRUE(called); 162 } 163 } // namespace 164 } // namespace crow 165