RequestFailedException includes error information #3398 (#3397)

* RequestFailedException includes error information

* Fixed test collateral

* Added changelog entry for new core version; Added tests to verify response message contains all expected fields
This commit is contained in:
Larry Osterman 2022-03-11 13:15:10 -08:00 committed by GitHub
parent 8672f985aa
commit f4e99416c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 32 deletions

View File

@ -3,10 +3,7 @@
## 1.5.0-beta.1 (Unreleased)
### Features Added
### Breaking Changes
### Bugs Fixed
- When a `RequestFailedException` exception is thrown, the `what()` method now includes information about the HTTP request which failed.
### Other Changes

View File

@ -22,6 +22,12 @@ namespace Azure { namespace Core {
*/
class RequestFailedException : public std::runtime_error {
public:
/**
* @brief The entire HTTP raw response.
*
*/
std::unique_ptr<Azure::Core::Http::RawResponse> RawResponse;
/**
* @brief The HTTP response code.
*
@ -61,12 +67,6 @@ namespace Azure { namespace Core {
*/
std::string Message;
/**
* @brief The entire HTTP raw response.
*
*/
std::unique_ptr<Azure::Core::Http::RawResponse> RawResponse;
/**
* @brief Constructs a new `%RequestFailedException` with a \p message string.
*
@ -96,13 +96,14 @@ namespace Azure { namespace Core {
* @param other The `%RequestFailedException` to be copied.
*/
RequestFailedException(const RequestFailedException& other)
: std::runtime_error(other.Message), StatusCode(other.StatusCode),
ReasonPhrase(other.ReasonPhrase), ClientRequestId(other.ClientRequestId),
RequestId(other.RequestId), ErrorCode(other.ErrorCode), Message(other.Message),
: std::runtime_error(other.Message),
RawResponse(
other.RawResponse
? std::make_unique<Azure::Core::Http::RawResponse>(*other.RawResponse)
: nullptr)
: nullptr),
StatusCode(other.StatusCode), ReasonPhrase(other.ReasonPhrase),
ClientRequestId(other.ClientRequestId), RequestId(other.RequestId),
ErrorCode(other.ErrorCode), Message(other.Message)
{
}
@ -132,8 +133,14 @@ namespace Azure { namespace Core {
~RequestFailedException() = default;
private:
std::string GetRawResponseField(
std::unique_ptr<Azure::Core::Http::RawResponse>& rawResponse,
static std::string GetRawResponseField(
std::unique_ptr<Azure::Core::Http::RawResponse> const& rawResponse,
std::string fieldName);
/**
* @brief Returns a descriptive string for this RawResponse.
*/
static std::string GetRawResponseErrorMessage(
std::unique_ptr<Azure::Core::Http::RawResponse> const& rawResponse);
};
}} // namespace Azure::Core

View File

@ -21,25 +21,38 @@ namespace Azure { namespace Core {
RequestFailedException::RequestFailedException(
std::unique_ptr<Azure::Core::Http::RawResponse>& rawResponse)
: RequestFailedException("Received an HTTP unsuccessful status code.")
: std::runtime_error(GetRawResponseErrorMessage(rawResponse)),
RawResponse(std::move(rawResponse)),
// These are guaranteed to always be present in the rawResponse.
StatusCode(RawResponse->GetStatusCode()), ReasonPhrase(RawResponse->GetReasonPhrase()),
// The response body may or may not have these fields
ErrorCode(GetRawResponseField(RawResponse, "code")),
Message(GetRawResponseField(RawResponse, "message"))
{
const auto& headers = rawResponse->GetHeaders();
// These are guaranteed to always be present in the rawResponse.
StatusCode = rawResponse->GetStatusCode();
ReasonPhrase = rawResponse->GetReasonPhrase();
RawResponse = std::move(rawResponse);
// The response body may or may not have these fields
ErrorCode = GetRawResponseField(RawResponse, "code");
Message = GetRawResponseField(RawResponse, "message");
const auto& headers = RawResponse->GetHeaders();
ClientRequestId = HttpShared::GetHeaderOrEmptyString(headers, HttpShared::MsClientRequestId);
RequestId = HttpShared::GetHeaderOrEmptyString(headers, HttpShared::MsRequestId);
}
std::string RequestFailedException::GetRawResponseErrorMessage(
std::unique_ptr<Azure::Core::Http::RawResponse> const& rawResponse)
{
std::string returnValue("Received an HTTP unsuccessful status code: ");
// The status code will always be present in the rawResponse.
returnValue += std::to_string(
static_cast<typename std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
rawResponse->GetStatusCode()));
// If there is a Reason phrase in the rawResponse, add it to the message.
if (!rawResponse->GetReasonPhrase().empty())
{
returnValue += " Reason: " + rawResponse->GetReasonPhrase();
}
return returnValue;
}
std::string RequestFailedException::GetRawResponseField(
std::unique_ptr<Azure::Core::Http::RawResponse>& rawResponse,
std::unique_ptr<Azure::Core::Http::RawResponse> const& rawResponse,
std::string fieldName)
{
auto& headers = rawResponse->GetHeaders();

View File

@ -33,7 +33,14 @@ TEST(RequestFailedException, JSONError)
EXPECT_EQ(exception.RequestId, "1");
EXPECT_EQ(exception.ClientRequestId, "2");
EXPECT_EQ(exception.ReasonPhrase, "retry please :");
EXPECT_EQ(exception.what(), std::string("Received an HTTP unsuccessful status code."));
EXPECT_EQ(std::string(exception.what()).find("Received an HTTP unsuccessful status code"), 0);
EXPECT_NE(
std::string(exception.what())
.find(std::to_string(
static_cast<std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
Azure::Core::Http::HttpStatusCode::ServiceUnavailable))),
std::string::npos);
EXPECT_NE(std::string(exception.what()).find("retry please :"), std::string::npos);
}
TEST(RequestFailedException, JSONErrorNoError)
@ -58,7 +65,14 @@ TEST(RequestFailedException, JSONErrorNoError)
EXPECT_EQ(exception.RequestId, "1");
EXPECT_EQ(exception.ClientRequestId, "2");
EXPECT_EQ(exception.ReasonPhrase, "retry please :");
EXPECT_EQ(exception.what(), std::string("Received an HTTP unsuccessful status code."));
EXPECT_EQ(std::string(exception.what()).find("Received an HTTP unsuccessful status code"), 0);
EXPECT_NE(
std::string(exception.what())
.find(std::to_string(
static_cast<std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
Azure::Core::Http::HttpStatusCode::ServiceUnavailable))),
std::string::npos);
EXPECT_NE(std::string(exception.what()).find("retry please :"), std::string::npos);
}
TEST(RequestFailedException, EmptyValues)
@ -74,5 +88,11 @@ TEST(RequestFailedException, EmptyValues)
EXPECT_EQ(exception.RequestId, std::string());
EXPECT_EQ(exception.ClientRequestId, std::string());
EXPECT_EQ(exception.ReasonPhrase, std::string());
EXPECT_EQ(exception.what(), std::string("Received an HTTP unsuccessful status code."));
EXPECT_EQ(std::string(exception.what()).find("Received an HTTP unsuccessful status code"), 0);
EXPECT_NE(
std::string(exception.what())
.find(std::to_string(
static_cast<std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
Azure::Core::Http::HttpStatusCode::None))),
std::string::npos);
}