1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 #include "error_message_utils.hpp"
4 #include "http_response.hpp"
5 #include "utils/error_code.hpp"
6
7 #include <boost/beast/http/status.hpp>
8 #include <nlohmann/json.hpp>
9
10 #include <array>
11 #include <string>
12
13 #include <gtest/gtest.h>
14
15 namespace redfish::error_code
16 {
17 namespace
18 {
19
20 TEST(PropogateErrorCode, 500IsWorst)
21 {
22 constexpr std::array<unsigned, 7> codes = {100, 200, 300, 400,
23 401, 500, 501};
24 for (auto code : codes)
25 {
26 EXPECT_EQ(propogateErrorCode(500, code), 500);
27 EXPECT_EQ(propogateErrorCode(code, 500), 500);
28 }
29 }
30
31 TEST(PropogateErrorCode, 5xxAreWorseThanOthers)
32 {
33 constexpr std::array<unsigned, 7> codes = {100, 200, 300, 400,
34 401, 501, 502};
35 for (auto code : codes)
36 {
37 EXPECT_EQ(propogateErrorCode(code, 505), 505);
38 EXPECT_EQ(propogateErrorCode(505, code), 505);
39 }
40 EXPECT_EQ(propogateErrorCode(502, 501), 502);
41 EXPECT_EQ(propogateErrorCode(501, 502), 502);
42 EXPECT_EQ(propogateErrorCode(503, 502), 503);
43 }
44
45 TEST(PropogateErrorCode, 401IsWorseThanOthers)
46 {
47 constexpr std::array<unsigned, 7> codes = {100, 200, 300, 400, 401};
48 for (auto code : codes)
49 {
50 EXPECT_EQ(propogateErrorCode(code, 401), 401);
51 EXPECT_EQ(propogateErrorCode(401, code), 401);
52 }
53 }
54
55 TEST(PropogateErrorCode, 4xxIsWorseThanOthers)
56 {
57 constexpr std::array<unsigned, 7> codes = {100, 200, 300, 400, 402};
58 for (auto code : codes)
59 {
60 EXPECT_EQ(propogateErrorCode(code, 405), 405);
61 EXPECT_EQ(propogateErrorCode(405, code), 405);
62 }
63 EXPECT_EQ(propogateErrorCode(400, 402), 402);
64 EXPECT_EQ(propogateErrorCode(402, 403), 403);
65 EXPECT_EQ(propogateErrorCode(403, 402), 403);
66 }
67
TEST(PropogateError,IntermediateNoErrorMessageMakesNoChange)68 TEST(PropogateError, IntermediateNoErrorMessageMakesNoChange)
69 {
70 crow::Response intermediate;
71 intermediate.result(boost::beast::http::status::ok);
72
73 crow::Response finalRes;
74 finalRes.result(boost::beast::http::status::ok);
75 propogateError(finalRes, intermediate);
76 EXPECT_EQ(finalRes.result(), boost::beast::http::status::ok);
77 EXPECT_EQ(finalRes.jsonValue.find("error"), finalRes.jsonValue.end());
78 }
79
TEST(PropogateError,ErrorsArePropergatedWithErrorInRoot)80 TEST(PropogateError, ErrorsArePropergatedWithErrorInRoot)
81 {
82 nlohmann::json root = R"(
83 {
84 "@odata.type": "#Message.v1_1_1.Message",
85 "Message": "The request failed due to an internal service error. The service is still operational.",
86 "MessageArgs": [],
87 "MessageId": "Base.1.13.0.InternalError",
88 "MessageSeverity": "Critical",
89 "Resolution": "Resubmit the request. If the problem persists, consider resetting the service."
90 }
91 )"_json;
92 crow::Response intermediate;
93 intermediate.result(boost::beast::http::status::internal_server_error);
94 intermediate.jsonValue = root;
95
96 crow::Response final;
97 final.result(boost::beast::http::status::ok);
98
99 propogateError(final, intermediate);
100
101 EXPECT_EQ(final.jsonValue["error"]["code"].get<std::string>(),
102 "Base.1.13.0.InternalError");
103 EXPECT_EQ(
104 final.jsonValue["error"]["message"].get<std::string>(),
105 "The request failed due to an internal service error. The service is still operational.");
106 EXPECT_EQ(intermediate.jsonValue, R"({})"_json);
107 EXPECT_EQ(final.result(),
108 boost::beast::http::status::internal_server_error);
109 }
110
TEST(PropogateError,ErrorsArePropergatedWithErrorCode)111 TEST(PropogateError, ErrorsArePropergatedWithErrorCode)
112 {
113 crow::Response intermediate;
114 intermediate.result(boost::beast::http::status::internal_server_error);
115
116 nlohmann::json error = R"(
117 {
118 "error": {
119 "@Message.ExtendedInfo": [],
120 "code": "Base.1.13.0.InternalError",
121 "message": "The request failed due to an internal service error. The service is still operational."
122 }
123 }
124 )"_json;
125 nlohmann::json extendedInfo = R"(
126 {
127 "@odata.type": "#Message.v1_1_1.Message",
128 "Message": "The request failed due to an internal service error. The service is still operational.",
129 "MessageArgs": [],
130 "MessageId": "Base.1.13.0.InternalError",
131 "MessageSeverity": "Critical",
132 "Resolution": "Resubmit the request. If the problem persists, consider resetting the service."
133 }
134 )"_json;
135
136 for (int i = 0; i < 10; ++i)
137 {
138 error["error"][messages::messageAnnotation].push_back(extendedInfo);
139 }
140 intermediate.jsonValue = error;
141 crow::Response final;
142 final.result(boost::beast::http::status::ok);
143
144 propogateError(final, intermediate);
145 EXPECT_EQ(final.jsonValue["error"][messages::messageAnnotation],
146 error["error"][messages::messageAnnotation]);
147 std::string errorCode = messages::messageVersionPrefix;
148 errorCode += "GeneralError";
149 std::string errorMessage =
150 "A general error has occurred. See Resolution for "
151 "information on how to resolve the error.";
152 EXPECT_EQ(final.jsonValue["error"]["code"].get<std::string>(), errorCode);
153 EXPECT_EQ(final.jsonValue["error"]["message"].get<std::string>(),
154 errorMessage);
155 EXPECT_EQ(intermediate.jsonValue, R"({})"_json);
156 EXPECT_EQ(final.result(),
157 boost::beast::http::status::internal_server_error);
158 }
159
160 } // namespace
161 } // namespace redfish::error_code
162