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