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