ca_response_creator_unittests.cc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <agent/ca_command_mgr.h>
  8. #include <agent/ca_response_creator.h>
  9. #include <cc/command_interpreter.h>
  10. #include <http/post_request.h>
  11. #include <http/post_request_json.h>
  12. #include <http/response_json.h>
  13. #include <gtest/gtest.h>
  14. #include <boost/bind.hpp>
  15. #include <boost/pointer_cast.hpp>
  16. using namespace isc::agent;
  17. using namespace isc::config;
  18. using namespace isc::data;
  19. using namespace isc::http;
  20. namespace {
  21. /// @brief Test fixture class for @ref CtrlAgentResponseCreator.
  22. class CtrlAgentResponseCreatorTest : public ::testing::Test {
  23. public:
  24. /// @brief Constructor.
  25. ///
  26. /// Creates instance of the response creator and uses this instance to
  27. /// create "empty" request. It also removes registered commands from the
  28. /// command manager.
  29. CtrlAgentResponseCreatorTest()
  30. : response_creator_(),
  31. request_(response_creator_.createNewHttpRequest()) {
  32. // Deregisters commands.
  33. CtrlAgentCommandMgr::instance().deregisterAll();
  34. CtrlAgentCommandMgr::instance().
  35. registerCommand("foo", boost::bind(&CtrlAgentResponseCreatorTest::
  36. fooCommandHandler,
  37. this, _1, _2));
  38. // Make sure that the request has been initialized properly.
  39. if (!request_) {
  40. ADD_FAILURE() << "CtrlAgentResponseCreator::createNewHttpRequest"
  41. " returns NULL!";
  42. }
  43. }
  44. /// @brief Destructor.
  45. ///
  46. /// Removes registered commands from the command manager.
  47. virtual ~CtrlAgentResponseCreatorTest() {
  48. CtrlAgentCommandMgr::instance().deregisterAll();
  49. }
  50. /// @brief Fills request context with required data to create new request.
  51. ///
  52. /// @param request Request which context should be configured.
  53. void setBasicContext(const HttpRequestPtr& request) {
  54. request->context()->method_ = "POST";
  55. request->context()->http_version_major_ = 1;
  56. request->context()->http_version_minor_ = 1;
  57. request->context()->uri_ = "/foo";
  58. // Content-Type
  59. HttpHeaderContext content_type;
  60. content_type.name_ = "Content-Type";
  61. content_type.value_ = "application/json";
  62. request->context()->headers_.push_back(content_type);
  63. // Content-Length
  64. HttpHeaderContext content_length;
  65. content_length.name_ = "Content-Length";
  66. content_length.value_ = "0";
  67. request->context()->headers_.push_back(content_length);
  68. }
  69. /// @brief Test creation of stock response.
  70. ///
  71. /// @param status_code Status code to be included in the response.
  72. /// @param must_contain Text that must be present in the textual
  73. /// representation of the generated response.
  74. void testStockResponse(const HttpStatusCode& status_code,
  75. const std::string& must_contain) {
  76. HttpResponsePtr response;
  77. ASSERT_NO_THROW(
  78. response = response_creator_.createStockHttpResponse(request_,
  79. status_code)
  80. );
  81. ASSERT_TRUE(response);
  82. HttpResponseJsonPtr response_json = boost::dynamic_pointer_cast<
  83. HttpResponseJson>(response);
  84. ASSERT_TRUE(response_json);
  85. // Make sure the response contains the string specified as argument.
  86. EXPECT_TRUE(response_json->toString().find(must_contain) != std::string::npos);
  87. }
  88. /// @brief Handler for the 'foo' test command.
  89. ///
  90. /// @param command_name Command name, i.e. 'foo'.
  91. /// @param command_arguments Command arguments (empty).
  92. ///
  93. /// @return Returns response with a single string "bar".
  94. ConstElementPtr fooCommandHandler(const std::string& /*command_name*/,
  95. const ConstElementPtr& /*command_arguments*/) {
  96. ElementPtr arguments = Element::createList();
  97. arguments->add(Element::create("bar"));
  98. return (createAnswer(CONTROL_RESULT_SUCCESS, arguments));
  99. }
  100. /// @brief Instance of the response creator.
  101. CtrlAgentResponseCreator response_creator_;
  102. /// @brief Instance of the "empty" request.
  103. ///
  104. /// The context belonging to this request may be modified by the unit
  105. /// tests to verify various scenarios of response creation.
  106. HttpRequestPtr request_;
  107. };
  108. // This test verifies that the created "empty" request has valid type.
  109. TEST_F(CtrlAgentResponseCreatorTest, createNewHttpRequest) {
  110. // The request must be of PostHttpRequestJson type.
  111. PostHttpRequestJsonPtr request_json = boost::dynamic_pointer_cast<
  112. PostHttpRequestJson>(request_);
  113. ASSERT_TRUE(request_json);
  114. }
  115. // Test that HTTP version of stock response is set to 1.0 if the request
  116. // context doesn't specify any version.
  117. TEST_F(CtrlAgentResponseCreatorTest, createStockHttpResponseNoVersion) {
  118. testStockResponse(HttpStatusCode::BAD_REQUEST, "HTTP/1.0 400 Bad Request");
  119. }
  120. // Test that HTTP version of stock response is set to 1.0 if the request
  121. // version is higher than 1.1.
  122. TEST_F(CtrlAgentResponseCreatorTest, createStockHttpResponseHighVersion) {
  123. request_->context()->http_version_major_ = 2;
  124. testStockResponse(HttpStatusCode::REQUEST_TIMEOUT,
  125. "HTTP/1.0 408 Request Timeout");
  126. }
  127. // Test that the server responds with version 1.1 if request version is 1.1.
  128. TEST_F(CtrlAgentResponseCreatorTest, createStockHttpResponseCorrectVersion) {
  129. request_->context()->http_version_major_ = 1;
  130. request_->context()->http_version_minor_ = 1;
  131. testStockResponse(HttpStatusCode::NO_CONTENT, "HTTP/1.1 204 No Content");
  132. }
  133. // Test successful server response when the client specifies valid command.
  134. TEST_F(CtrlAgentResponseCreatorTest, createDynamicHttpResponse) {
  135. setBasicContext(request_);
  136. // Body: "foo" command has been registered in the test fixture constructor.
  137. request_->context()->body_ = "{ \"command\": \"foo\" }";
  138. // All requests must be finalized before they can be processed.
  139. ASSERT_NO_THROW(request_->finalize());
  140. // Create response from the request.
  141. HttpResponsePtr response;
  142. ASSERT_NO_THROW(response = response_creator_.createHttpResponse(request_));
  143. ASSERT_TRUE(response);
  144. // Response must be convertible to HttpResponseJsonPtr.
  145. HttpResponseJsonPtr response_json = boost::dynamic_pointer_cast<
  146. HttpResponseJson>(response);
  147. ASSERT_TRUE(response_json);
  148. // Response must be successful.
  149. EXPECT_TRUE(response_json->toString().find("HTTP/1.1 200 OK") !=
  150. std::string::npos);
  151. // Response must contain JSON body with "result" of 0.
  152. EXPECT_TRUE(response_json->toString().find("\"result\": 0") !=
  153. std::string::npos);
  154. }
  155. // This test verifies that Internal Server Error is returned when invalid C++
  156. // request type is used. This is considered an error in the server logic.
  157. TEST_F(CtrlAgentResponseCreatorTest, createDynamicHttpResponseInvalidType) {
  158. PostHttpRequestPtr request(new PostHttpRequest());
  159. setBasicContext(request);
  160. // Body: "list-commands" is natively supported by the command manager.
  161. request->context()->body_ = "{ \"command\": \"list-commands\" }";
  162. // All requests must be finalized before they can be processed.
  163. ASSERT_NO_THROW(request->finalize());
  164. HttpResponsePtr response;
  165. ASSERT_NO_THROW(response = response_creator_.createHttpResponse(request));
  166. ASSERT_TRUE(response);
  167. // Response must be convertible to HttpResponseJsonPtr.
  168. HttpResponseJsonPtr response_json = boost::dynamic_pointer_cast<
  169. HttpResponseJson>(response);
  170. ASSERT_TRUE(response_json);
  171. // Response must contain Internal Server Error status code.
  172. EXPECT_TRUE(response_json->toString().find("HTTP/1.1 500 Internal Server Error") !=
  173. std::string::npos);
  174. }
  175. }