xref: /openbmc/bmcweb/test/redfish-core/include/redfish_oem_routing_test.cpp (revision 84aad24d55fb0e53128928961ac36242aabb799d)
1 #include "app.hpp"
2 #include "async_resp.hpp"
3 #include "http_request.hpp"
4 #include "redfish.hpp"
5 #include "sub_request.hpp"
6 #include "verb.hpp"
7 
8 #include <boost/beast/http/verb.hpp>
9 #include <nlohmann/json.hpp>
10 
11 #include <memory>
12 #include <string>
13 #include <string_view>
14 #include <system_error>
15 #include <utility>
16 
17 #include <gtest/gtest.h>
18 
19 namespace redfish
20 {
21 namespace
22 {
23 
TEST(OemRouter,FragmentRoutes)24 TEST(OemRouter, FragmentRoutes)
25 {
26     std::error_code ec;
27     App app;
28     RedfishService service(app);
29 
30     // Callback handler that does nothing
31     bool oemCalled = false;
32     auto oemCallback = [&oemCalled](const SubRequest&,
33                                     const std::shared_ptr<bmcweb::AsyncResp>&,
34                                     const std::string& bar) {
35         oemCalled = true;
36         EXPECT_EQ(bar, "bar");
37     };
38     bool standardCalled = false;
39     auto standardCallback =
40         [&standardCalled,
41          &service](const crow::Request& req,
42                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
43                    const std::string& bar) {
44             service.handleSubRoute(req, asyncResp);
45             standardCalled = true;
46             EXPECT_EQ(bar, "bar");
47         };
48     // Need the normal route registered for OEM to work
49     BMCWEB_ROUTE(app, "/foo/<str>/")
50         .methods(boost::beast::http::verb::get)(standardCallback);
51     REDFISH_SUB_ROUTE<"/foo/<str>/#/Oem">(service, HttpVerb::Get)(oemCallback);
52 
53     app.validate();
54     service.validate();
55 
56     {
57         constexpr std::string_view reqUrl = "/foo/bar";
58 
59         std::shared_ptr<crow::Request> req = std::make_shared<crow::Request>(
60             crow::Request::Body{boost::beast::http::verb::get, reqUrl, 11}, ec);
61 
62         std::shared_ptr<bmcweb::AsyncResp> asyncResp =
63             std::make_shared<bmcweb::AsyncResp>();
64 
65         app.handle(req, asyncResp);
66     }
67     EXPECT_TRUE(oemCalled);
68     EXPECT_TRUE(standardCalled);
69 }
70 
TEST(OemRouter,PatchHandlerWithJsonObject)71 TEST(OemRouter, PatchHandlerWithJsonObject)
72 {
73     std::error_code ec;
74     App app;
75     RedfishService service(app);
76 
77     // Callback handlers
78     bool callback1Called = false;
79     auto patchCallback1 =
80         [&callback1Called](
81             const SubRequest& req,
82             [[maybe_unused]] const std::shared_ptr<bmcweb::AsyncResp>&
83                 asyncResp,
84             [[maybe_unused]] const std::string& param) {
85             callback1Called = true;
86 
87             const nlohmann::json::object_t& payload = req.payload();
88             auto oemFooIt = payload.find("OemFoo");
89             ASSERT_NE(oemFooIt, payload.end());
90             ASSERT_TRUE(oemFooIt->second.is_object());
91 
92             auto keyIt = oemFooIt->second.find("OemFooKey");
93             ASSERT_NE(keyIt, oemFooIt->second.end());
94             EXPECT_EQ(keyIt.value(), "fooValue");
95         };
96 
97     bool callback2Called = false;
98     auto patchCallback2 =
99         [&callback2Called](
100             const SubRequest& req,
101             [[maybe_unused]] const std::shared_ptr<bmcweb::AsyncResp>&
102                 asyncResp,
103             [[maybe_unused]] const std::string& param) {
104             callback2Called = true;
105 
106             const nlohmann::json::object_t& payload = req.payload();
107             auto oemBarIt = payload.find("OemBar");
108             ASSERT_NE(oemBarIt, payload.end());
109             ASSERT_TRUE(oemBarIt->second.is_object());
110 
111             auto keyIt = oemBarIt->second.find("OemBarKey");
112             ASSERT_NE(keyIt, oemBarIt->second.end());
113             EXPECT_EQ(keyIt.value(), "barValue");
114         };
115 
116     bool standardCalled = false;
117     auto standardCallback =
118         [&standardCalled,
119          &service](const crow::Request& req,
120                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
121                    const std::string& bar) {
122             service.handleSubRoute(req, asyncResp);
123             standardCalled = true;
124             EXPECT_EQ(bar, "bar");
125         };
126 
127     // Need the normal route registered for OEM to work
128     BMCWEB_ROUTE(app, "/foo/<str>/")
129         .methods(boost::beast::http::verb::patch)(standardCallback);
130 
131     REDFISH_SUB_ROUTE<"/foo/<str>/#/Oem/OemFoo">(service, HttpVerb::Patch)(
132         patchCallback1);
133     REDFISH_SUB_ROUTE<"/foo/<str>/#/Oem/OemBar">(service, HttpVerb::Patch)(
134         patchCallback2);
135 
136     app.validate();
137     service.validate();
138 
139     {
140         constexpr std::string_view reqUrl = "/foo/bar";
141         // OEM payload
142         nlohmann::json reqBody = {{"Oem",
143                                    {{"OemFoo", {{"OemFooKey", "fooValue"}}},
144                                     {"OemBar", {{"OemBarKey", "barValue"}}}}}};
145 
146         // Create request with the body string
147         std::shared_ptr<crow::Request> req = std::make_shared<crow::Request>(
148             crow::Request::Body{
149                 boost::beast::http::verb::patch, reqUrl, 11,
150                 reqBody.dump() // Pass body string directly in the constructor
151             },
152             ec);
153 
154         req->addHeader("Content-Type", "application/json");
155 
156         std::shared_ptr<bmcweb::AsyncResp> asyncResp =
157             std::make_shared<bmcweb::AsyncResp>();
158 
159         app.handle(req, asyncResp);
160     }
161 
162     EXPECT_TRUE(standardCalled);
163     EXPECT_TRUE(callback1Called);
164     EXPECT_TRUE(callback2Called);
165 }
166 
167 } // namespace
168 } // namespace redfish
169