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
TEST(Router,AllowHeader)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
TEST(Router,OverlapingRoutes)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&,
__anone77675800502(const Request&, const std::shared_ptr<bmcweb::AsyncResp>&) 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 =
__anone77675800602(const Request&, const std::shared_ptr<bmcweb::AsyncResp>&) 129 [](const Request&, const std::shared_ptr<bmcweb::AsyncResp>&) {};
130 bool called = false;
131 auto notAllowedCallback =
__anone77675800702(const Request&, const std::shared_ptr<bmcweb::AsyncResp>&) 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