// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/format_macros.h" #include "base/json/json_reader.h" #include "base/memory/scoped_ptr.h" #include "base/stringprintf.h" #include "base/values.h" #include "chrome/test/webdriver/commands/response.h" #include "chrome/test/webdriver/http_response.h" #include "chrome/test/webdriver/webdriver_dispatch.h" #include "chrome/test/webdriver/webdriver_session_manager.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/mongoose/mongoose.h" namespace webdriver { namespace { void ExpectHeaderValue(const HttpResponse& response, const std::string& name, const std::string& expected_value) { std::string actual_value; EXPECT_TRUE(response.GetHeader(name, &actual_value)); EXPECT_EQ(expected_value, actual_value); } void ExpectHttpStatus(int expected_status, const Response& command_response, HttpResponse* const http_response) { internal::PrepareHttpResponse(command_response, http_response); EXPECT_EQ(expected_status, http_response->status()); } void ExpectInternalError(ErrorCode command_status, Response* command_response, HttpResponse* const http_response) { command_response->SetStatus(command_status); http_response->set_status(HttpResponse::kOk); // Reset to detect changes. ExpectHttpStatus(HttpResponse::kInternalServerError, *command_response, http_response); } } // namespace TEST(DispatchTest, CorrectlyConvertsResponseCodesToHttpStatusCodes) { HttpResponse http_response; Response command_response; command_response.SetValue(Value::CreateStringValue("foobar")); command_response.SetStatus(kSuccess); ExpectHttpStatus(HttpResponse::kOk, command_response, &http_response); command_response.SetStatus(kSeeOther); ExpectHttpStatus(HttpResponse::kSeeOther, command_response, &http_response); ExpectHeaderValue(http_response, "location", "foobar"); http_response.ClearHeaders(); command_response.SetStatus(kBadRequest); ExpectHttpStatus(HttpResponse::kBadRequest, command_response, &http_response); command_response.SetStatus(kSessionNotFound); ExpectHttpStatus(HttpResponse::kNotFound, command_response, &http_response); ListValue* methods = new ListValue; methods->Append(Value::CreateStringValue("POST")); methods->Append(Value::CreateStringValue("GET")); command_response.SetValue(methods); command_response.SetStatus(kMethodNotAllowed); ExpectHttpStatus(HttpResponse::kMethodNotAllowed, command_response, &http_response); ExpectHeaderValue(http_response, "allow", "POST,GET"); http_response.ClearHeaders(); ExpectInternalError(kNoSuchElement, &command_response, &http_response); ExpectInternalError(kNoSuchFrame, &command_response, &http_response); ExpectInternalError(kUnknownCommand, &command_response, &http_response); ExpectInternalError(kStaleElementReference, &command_response, &http_response); ExpectInternalError(kInvalidElementState, &command_response, &http_response); ExpectInternalError(kUnknownError, &command_response, &http_response); ExpectInternalError(kElementNotSelectable, &command_response, &http_response); ExpectInternalError(kXPathLookupError, &command_response, &http_response); ExpectInternalError(kNoSuchWindow, &command_response, &http_response); ExpectInternalError(kInvalidCookieDomain, &command_response, &http_response); ExpectInternalError(kUnableToSetCookie, &command_response, &http_response); ExpectInternalError(kInternalServerError, &command_response, &http_response); } TEST(DispatchTest, ReturnsAnErrorOnNonStringMethodsListedOnAMethodNotAllowedResponse) { ListValue* methods = new ListValue; methods->Append(Value::CreateStringValue("POST")); methods->Append(new DictionaryValue); methods->Append(Value::CreateStringValue("GET")); methods->Append(new DictionaryValue); methods->Append(Value::CreateStringValue("DELETE")); Response command_response; command_response.SetStatus(kMethodNotAllowed); command_response.SetValue(methods); HttpResponse http_response; ExpectHttpStatus(HttpResponse::kInternalServerError, command_response, &http_response); } TEST(DispatchTest, ReturnsCommandResponseAsJson) { const std::string kExpectedData = "{\"status\":0,\"value\":\"foobar\"}"; Response command_response; command_response.SetStatus(kSuccess); command_response.SetValue(Value::CreateStringValue("foobar")); HttpResponse http_response; internal::PrepareHttpResponse(command_response, &http_response); EXPECT_EQ(HttpResponse::kOk, http_response.status()); ExpectHeaderValue(http_response, "content-type", "application/json; charset=utf-8"); ExpectHeaderValue(http_response, "content-length", base::StringPrintf("%"PRIuS, kExpectedData.length())); // We do not know whether the response status or value will be // encoded first, so we have to parse the response body to // verify it is correct. std::string actual_data(http_response.data(), http_response.length()); int error_code; std::string error_message; scoped_ptr parsed_response(base::JSONReader::ReadAndReturnError( actual_data, base::JSON_PARSE_RFC, &error_code, &error_message)); ASSERT_TRUE(parsed_response.get() != NULL) << error_message; ASSERT_TRUE(parsed_response->IsType(Value::TYPE_DICTIONARY)) << "Response should be a dictionary: " << actual_data; DictionaryValue* dict = static_cast(parsed_response.get()); EXPECT_EQ(2u, dict->size()); EXPECT_TRUE(dict->HasKey("status")); EXPECT_TRUE(dict->HasKey("value")); int status = -1; EXPECT_TRUE(dict->GetInteger("status", &status)); EXPECT_EQ(kSuccess, static_cast(status)); std::string value; EXPECT_TRUE(dict->GetStringASCII("value", &value)); EXPECT_EQ("foobar", value); } class ParseRequestInfoTest : public testing::Test { public: static char kGet[]; static char kTestPath[]; ParseRequestInfoTest() {} virtual ~ParseRequestInfoTest() {} virtual void TearDown() { SessionManager::GetInstance()->set_url_base(""); } private: DISALLOW_COPY_AND_ASSIGN(ParseRequestInfoTest); }; char ParseRequestInfoTest::kGet[] = "GET"; char ParseRequestInfoTest::kTestPath[] = "/foo/bar/baz"; TEST_F(ParseRequestInfoTest, ParseRequestWithEmptyUrlBase) { struct mg_request_info request_info; request_info.request_method = kGet; request_info.uri = kTestPath; std::string method; std::vector path_segments; DictionaryValue* parameters; Response response; SessionManager::GetInstance()->set_url_base(""); EXPECT_TRUE(internal::ParseRequestInfo( &request_info, NULL, //NULL is ok because GET not POST is used &method, &path_segments, ¶meters, &response)); EXPECT_EQ("GET", method); ASSERT_EQ(4u, path_segments.size()); EXPECT_EQ("", path_segments[0]); EXPECT_EQ("foo", path_segments[1]); EXPECT_EQ("bar", path_segments[2]); EXPECT_EQ("baz", path_segments[3]); } TEST_F(ParseRequestInfoTest, ParseRequestStripsNonEmptyUrlBaseFromPath) { struct mg_request_info request_info; request_info.request_method = kGet; request_info.uri = kTestPath; std::string method; std::vector path_segments; DictionaryValue* parameters; Response response; SessionManager::GetInstance()->set_url_base("/foo"); EXPECT_TRUE(internal::ParseRequestInfo( &request_info, NULL, //NULL is ok because GET not POST is used &method, &path_segments, ¶meters, &response)); EXPECT_EQ("GET", method); ASSERT_EQ(3u, path_segments.size()); EXPECT_EQ("", path_segments[0]); EXPECT_EQ("bar", path_segments[1]); EXPECT_EQ("baz", path_segments[2]); } } // namespace webdriver