xref: /openbmc/bmcweb/test/http/router_test.cpp (revision 40e9b92ec19acffb46f83a6e55b18974da5d708e)
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         [&notFoundCalled](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