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