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