diff options
Diffstat (limited to 'src/lib/http/tests/response_unittests.cc')
-rw-r--r-- | src/lib/http/tests/response_unittests.cc | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/src/lib/http/tests/response_unittests.cc b/src/lib/http/tests/response_unittests.cc new file mode 100644 index 0000000..f54e65d --- /dev/null +++ b/src/lib/http/tests/response_unittests.cc @@ -0,0 +1,169 @@ +// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> +#include <http/date_time.h> +#include <http/http_types.h> +#include <http/response.h> +#include <http/tests/response_test.h> +#include <gtest/gtest.h> +#include <sstream> +#include <string> + +using namespace boost::posix_time; +using namespace isc::http; +using namespace isc::http::test; + +namespace { + +/// @brief Response type used in tests. +typedef TestHttpResponseBase<HttpResponse> TestHttpResponse; + +/// @brief Test fixture class for @ref HttpResponse. +class HttpResponseTest : public ::testing::Test { +public: + + /// @brief Checks if the format of the response is correct. + /// + /// @param status_code HTTP status code in the response. + /// @param status_message HTTP status message in the response. + void testResponse(const HttpStatusCode& status_code, + const std::string& status_message) { + // Create the response. Because we're using derived class + // it returns the fixed value of the Date header, which is + // very useful in unit tests. + TestHttpResponse response(HttpVersion(1, 0), status_code); + response.context()->headers_.push_back(HttpHeaderContext("Content-Type", "text/html")); + ASSERT_NO_THROW(response.finalize()); + std::ostringstream response_string; + response_string << "HTTP/1.0 " << static_cast<uint16_t>(status_code) + << " " << status_message; + EXPECT_EQ(response_string.str(), response.toBriefString()); + + response_string + << "\r\nContent-Length: 0\r\n" + << "Content-Type: text/html\r\n" + << "Date: " << response.getDateHeaderValue() << "\r\n\r\n"; + EXPECT_EQ(response_string.str(), response.toString()); + } +}; + +// Test the case of HTTP OK message. +TEST_F(HttpResponseTest, responseOK) { + // Include HTML body. + const std::string sample_body = + "<html>" + "<head><title>Kea page title</title></head>" + "<body><h1>Some header</h1></body>" + "</html>"; + + // Create the message and add some headers. + TestHttpResponse response(HttpVersion(1, 0), HttpStatusCode::OK); + response.context()->headers_.push_back(HttpHeaderContext("Content-Type", "text/html")); + response.context()->headers_.push_back(HttpHeaderContext("Host", "kea.example.org")); + response.context()->body_ = sample_body; + ASSERT_NO_THROW(response.finalize()); + + // Create a string holding expected response. Note that the Date + // is a fixed value returned by the customized TestHttpResponse + // class. + std::ostringstream response_string; + response_string << + "HTTP/1.0 200 OK\r\n" + "Content-Length: " << sample_body.length() << "\r\n" + "Content-Type: text/html\r\n" + "Date: " << response.getDateHeaderValue() << "\r\n" + "Host: kea.example.org\r\n\r\n" << sample_body; + + EXPECT_EQ(response_string.str(), response.toString()); +} + +// Test generic responses for various status codes. +TEST_F(HttpResponseTest, genericResponse) { + testResponse(HttpStatusCode::OK, "OK"); + testResponse(HttpStatusCode::CREATED, "Created"); + testResponse(HttpStatusCode::ACCEPTED, "Accepted"); + testResponse(HttpStatusCode::NO_CONTENT, "No Content"); + testResponse(HttpStatusCode::MULTIPLE_CHOICES, "Multiple Choices"); + testResponse(HttpStatusCode::MOVED_PERMANENTLY, "Moved Permanently"); + testResponse(HttpStatusCode::MOVED_TEMPORARILY, "Moved Temporarily"); + testResponse(HttpStatusCode::NOT_MODIFIED, "Not Modified"); + testResponse(HttpStatusCode::BAD_REQUEST, "Bad Request"); + testResponse(HttpStatusCode::UNAUTHORIZED, "Unauthorized"); + testResponse(HttpStatusCode::FORBIDDEN, "Forbidden"); + testResponse(HttpStatusCode::NOT_FOUND, "Not Found"); + testResponse(HttpStatusCode::REQUEST_TIMEOUT, "Request Timeout"); + testResponse(HttpStatusCode::INTERNAL_SERVER_ERROR, "Internal Server Error"); + testResponse(HttpStatusCode::NOT_IMPLEMENTED, "Not Implemented"); + testResponse(HttpStatusCode::BAD_GATEWAY, "Bad Gateway"); + testResponse(HttpStatusCode::SERVICE_UNAVAILABLE, "Service Unavailable"); +} + +// Test if the class correctly identifies client errors. +TEST_F(HttpResponseTest, isClientError) { + EXPECT_FALSE(HttpResponse::isClientError(HttpStatusCode::OK)); + EXPECT_FALSE(HttpResponse::isClientError(HttpStatusCode::CREATED)); + EXPECT_FALSE(HttpResponse::isClientError(HttpStatusCode::ACCEPTED)); + EXPECT_FALSE(HttpResponse::isClientError(HttpStatusCode::NO_CONTENT)); + EXPECT_FALSE(HttpResponse::isClientError(HttpStatusCode::MULTIPLE_CHOICES)); + EXPECT_FALSE(HttpResponse::isClientError(HttpStatusCode::MOVED_PERMANENTLY)); + EXPECT_FALSE(HttpResponse::isClientError(HttpStatusCode::MOVED_TEMPORARILY)); + EXPECT_FALSE(HttpResponse::isClientError(HttpStatusCode::NOT_MODIFIED)); + EXPECT_TRUE(HttpResponse::isClientError(HttpStatusCode::BAD_REQUEST)); + EXPECT_TRUE(HttpResponse::isClientError(HttpStatusCode::UNAUTHORIZED)); + EXPECT_TRUE(HttpResponse::isClientError(HttpStatusCode::FORBIDDEN)); + EXPECT_TRUE(HttpResponse::isClientError(HttpStatusCode::NOT_FOUND)); + EXPECT_TRUE(HttpResponse::isClientError(HttpStatusCode::REQUEST_TIMEOUT)); + EXPECT_FALSE(HttpResponse::isClientError(HttpStatusCode::INTERNAL_SERVER_ERROR)); + EXPECT_FALSE(HttpResponse::isClientError(HttpStatusCode::NOT_IMPLEMENTED)); + EXPECT_FALSE(HttpResponse::isClientError(HttpStatusCode::BAD_GATEWAY)); + EXPECT_FALSE(HttpResponse::isClientError(HttpStatusCode::SERVICE_UNAVAILABLE)); +} + +// Test if the class correctly identifies server errors. +TEST_F(HttpResponseTest, isServerError) { + EXPECT_FALSE(HttpResponse::isServerError(HttpStatusCode::OK)); + EXPECT_FALSE(HttpResponse::isServerError(HttpStatusCode::CREATED)); + EXPECT_FALSE(HttpResponse::isServerError(HttpStatusCode::ACCEPTED)); + EXPECT_FALSE(HttpResponse::isServerError(HttpStatusCode::NO_CONTENT)); + EXPECT_FALSE(HttpResponse::isServerError(HttpStatusCode::MULTIPLE_CHOICES)); + EXPECT_FALSE(HttpResponse::isServerError(HttpStatusCode::MOVED_PERMANENTLY)); + EXPECT_FALSE(HttpResponse::isServerError(HttpStatusCode::MOVED_TEMPORARILY)); + EXPECT_FALSE(HttpResponse::isServerError(HttpStatusCode::NOT_MODIFIED)); + EXPECT_FALSE(HttpResponse::isServerError(HttpStatusCode::BAD_REQUEST)); + EXPECT_FALSE(HttpResponse::isServerError(HttpStatusCode::UNAUTHORIZED)); + EXPECT_FALSE(HttpResponse::isServerError(HttpStatusCode::FORBIDDEN)); + EXPECT_FALSE(HttpResponse::isServerError(HttpStatusCode::NOT_FOUND)); + EXPECT_FALSE(HttpResponse::isServerError(HttpStatusCode::REQUEST_TIMEOUT)); + EXPECT_TRUE(HttpResponse::isServerError(HttpStatusCode::INTERNAL_SERVER_ERROR)); + EXPECT_TRUE(HttpResponse::isServerError(HttpStatusCode::NOT_IMPLEMENTED)); + EXPECT_TRUE(HttpResponse::isServerError(HttpStatusCode::BAD_GATEWAY)); + EXPECT_TRUE(HttpResponse::isServerError(HttpStatusCode::SERVICE_UNAVAILABLE)); +} + +// Test that the generated time value, being included in the Date +// header, is correct. +TEST_F(HttpResponseTest, getDateHeaderValue) { + // Create a response and retrieve the value to be included in the + // Date header. This value should hold a current time in the + // RFC1123 format. + TestHttpResponse response(HttpVersion(1, 0), HttpStatusCode::OK); + std::string generated_date = response.generateDateHeaderValue(); + + // Use our date/time utilities to parse this value into the ptime. + HttpDateTime parsed_time = HttpDateTime::fromRfc1123(generated_date); + + // Now that we have it converted back, we can check how far this + // value is from the current time. To be on the safe side, we check + // that it is not later than 10 seconds apart, rather than checking + // it for equality. In fact, checking it for equality would almost + // certainly cause an error. Especially on a virtual machine. + time_duration parsed_to_current = + microsec_clock::universal_time() - parsed_time.getPtime(); + EXPECT_LT(parsed_to_current.seconds(), 10); +} + +} |