post_request_json_unittests.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // Copyright (C) 2016 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 <cc/data.h>
  8. #include <http/post_request_json.h>
  9. #include <http/tests/request_test.h>
  10. #include <gtest/gtest.h>
  11. #include <map>
  12. using namespace isc::data;
  13. using namespace isc::http;
  14. using namespace isc::http::test;
  15. namespace {
  16. /// @brief Test fixture class for @ref PostHttpRequestJson.
  17. class PostHttpRequestJsonTest :
  18. public HttpRequestTestBase<PostHttpRequestJson> {
  19. public:
  20. /// @brief Constructor.
  21. PostHttpRequestJsonTest()
  22. : HttpRequestTestBase<PostHttpRequestJson>(),
  23. json_body_("{ \"service\": \"dhcp4\", \"param1\": \"foo\" }") {
  24. }
  25. /// @brief Sets new JSON body for the HTTP request context.
  26. ///
  27. /// If the body parameter is empty, it will use the value of
  28. /// @ref json_body_ member. Otherwise, it will assign the body
  29. /// provided as parameter.
  30. ///
  31. /// @param body new body value.
  32. void setBody(const std::string& body = "") {
  33. request_.context()->body_ = body.empty() ? json_body_ : body;
  34. }
  35. /// @brief Default value of the JSON body.
  36. std::string json_body_;
  37. };
  38. // This test verifies that PostHttpRequestJson class only accepts
  39. // POST messages.
  40. TEST_F(PostHttpRequestJsonTest, requiredPost) {
  41. // Use a GET method that is not supported.
  42. setContextBasics("GET", "/isc/org", std::make_pair(1, 0));
  43. addHeaderToContext("Content-Length", json_body_.length());
  44. addHeaderToContext("Content-Type", "application/json");
  45. ASSERT_THROW(request_.create(), HttpRequestError);
  46. // Now use POST. It should be accepted.
  47. setContextBasics("POST", "/isc/org", std::make_pair(1, 0));
  48. addHeaderToContext("Content-Length", json_body_.length());
  49. addHeaderToContext("Content-Type", "application/json");
  50. EXPECT_NO_THROW(request_.create());
  51. }
  52. // This test verifies that PostHttpRequest requires "Content-Length"
  53. // header equal to "application/json".
  54. TEST_F(PostHttpRequestJsonTest, requireContentTypeJson) {
  55. // Specify "Content-Type" other than "application/json".
  56. setContextBasics("POST", "/isc/org", std::make_pair(1, 0));
  57. addHeaderToContext("Content-Length", json_body_.length());
  58. addHeaderToContext("Content-Type", "text/html");
  59. ASSERT_THROW(request_.create(), HttpRequestError);
  60. // This time specify correct "Content-Type". It should pass.
  61. setContextBasics("POST", "/isc/org", std::make_pair(1, 0));
  62. addHeaderToContext("Content-Length", json_body_.length());
  63. addHeaderToContext("Content-Type", "application/json");
  64. EXPECT_NO_THROW(request_.create());
  65. }
  66. // This test verifies that PostHttpRequest requires "Content-Length"
  67. // header.
  68. TEST_F(PostHttpRequestJsonTest, requireContentLength) {
  69. // "Content-Length" is not specified initially. It should fail.
  70. setContextBasics("POST", "/isc/org", std::make_pair(1, 0));
  71. addHeaderToContext("Content-Type", "text/html");
  72. ASSERT_THROW(request_.create(), HttpRequestError);
  73. // Specify "Content-Length". It should pass.
  74. setContextBasics("POST", "/isc/org", std::make_pair(1, 0));
  75. addHeaderToContext("Content-Length", json_body_.length());
  76. addHeaderToContext("Content-Type", "application/json");
  77. }
  78. // This test verifies that JSON body can be retrieved from the
  79. // HTTP request.
  80. TEST_F(PostHttpRequestJsonTest, getBodyAsJson) {
  81. // Create HTTP POST request with JSON body.
  82. setContextBasics("POST", "/isc/org", std::make_pair(1, 0));
  83. addHeaderToContext("Content-Length", json_body_.length());
  84. addHeaderToContext("Content-Type", "application/json");
  85. setBody();
  86. ASSERT_NO_THROW(request_.finalize());
  87. // Try to retrieve pointer to the root element of the JSON body.
  88. ConstElementPtr json = request_.getBodyAsJson();
  89. ASSERT_TRUE(json);
  90. // Iterate over JSON values and store them in a simple map.
  91. std::map<std::string, std::string> config_values;
  92. for (auto config_element = json->mapValue().begin();
  93. config_element != json->mapValue().end();
  94. ++config_element) {
  95. ASSERT_FALSE(config_element->first.empty());
  96. ASSERT_TRUE(config_element->second);
  97. config_values[config_element->first] = config_element->second->stringValue();
  98. }
  99. // Verify the values.
  100. EXPECT_EQ("dhcp4", config_values["service"]);
  101. EXPECT_EQ("foo", config_values["param1"]);
  102. }
  103. // This test verifies that an attempt to parse/retrieve malformed
  104. // JSON structure will cause an exception.
  105. TEST_F(PostHttpRequestJsonTest, getBodyAsJsonMalformed) {
  106. setContextBasics("POST", "/isc/org", std::make_pair(1, 0));
  107. addHeaderToContext("Content-Length", json_body_.length());
  108. addHeaderToContext("Content-Type", "application/json");
  109. // No colon before 123.
  110. setBody("{ \"command\" 123 }" );
  111. EXPECT_THROW(request_.finalize(), HttpRequestJsonError);
  112. }
  113. // This test verifies that NULL pointer is returned when trying to
  114. // retrieve root element of the empty JSON structure.
  115. TEST_F(PostHttpRequestJsonTest, getEmptyJsonBody) {
  116. setContextBasics("POST", "/isc/org", std::make_pair(1, 0));
  117. addHeaderToContext("Content-Length", json_body_.length());
  118. addHeaderToContext("Content-Type", "application/json");
  119. ASSERT_NO_THROW(request_.finalize());
  120. ConstElementPtr json = request_.getBodyAsJson();
  121. EXPECT_FALSE(json);
  122. }
  123. // This test verifies that the specific JSON element can be retrieved.
  124. TEST_F(PostHttpRequestJsonTest, getJsonElement) {
  125. setContextBasics("POST", "/isc/org", std::make_pair(1, 0));
  126. addHeaderToContext("Content-Length", json_body_.length());
  127. addHeaderToContext("Content-Type", "application/json");
  128. setBody();
  129. ASSERT_NO_THROW(request_.finalize());
  130. ConstElementPtr element;
  131. ASSERT_NO_THROW(element = request_.getJsonElement("service"));
  132. ASSERT_TRUE(element);
  133. EXPECT_EQ("dhcp4", element->stringValue());
  134. // An attempt to retrieve non-existing element should return NULL.
  135. EXPECT_FALSE(request_.getJsonElement("bar"));
  136. }
  137. }