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