root/chrome/test/chromedriver/commands_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. OnGetStatus
  2. TEST
  3. ExecuteStubQuit
  4. OnQuitAll
  5. TEST
  6. ExecuteSimpleCommand
  7. OnSimpleCommand
  8. TEST
  9. ShouldNotBeCalled
  10. OnNoSuchSession
  11. OnNoSuchSessionIsOk
  12. TEST
  13. TEST
  14. OnNoSuchSessionAndQuit
  15. TEST
  16. current_count_
  17. Verify
  18. CallFunction
  19. TEST
  20. TEST
  21. TEST
  22. TEST
  23. TEST
  24. TEST
  25. TEST
  26. TEST
  27. TEST
  28. code_
  29. CallFunction
  30. TEST
  31. TEST

// Copyright (c) 2012 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 <string>

#include "base/bind.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/status.h"
#include "chrome/test/chromedriver/chrome/stub_chrome.h"
#include "chrome/test/chromedriver/chrome/stub_web_view.h"
#include "chrome/test/chromedriver/chrome/web_view.h"
#include "chrome/test/chromedriver/commands.h"
#include "chrome/test/chromedriver/element_commands.h"
#include "chrome/test/chromedriver/session.h"
#include "chrome/test/chromedriver/session_commands.h"
#include "chrome/test/chromedriver/window_commands.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/webdriver/atoms.h"

namespace {

void OnGetStatus(const Status& status,
                 scoped_ptr<base::Value> value,
                 const std::string& session_id) {
  ASSERT_EQ(kOk, status.code());
  base::DictionaryValue* dict;
  ASSERT_TRUE(value->GetAsDictionary(&dict));
  base::Value* unused;
  ASSERT_TRUE(dict->Get("os.name", &unused));
  ASSERT_TRUE(dict->Get("os.version", &unused));
  ASSERT_TRUE(dict->Get("os.arch", &unused));
  ASSERT_TRUE(dict->Get("build.version", &unused));
}

}  // namespace

TEST(CommandsTest, GetStatus) {
  base::DictionaryValue params;
  ExecuteGetStatus(params, std::string(), base::Bind(&OnGetStatus));
}

namespace {

void ExecuteStubQuit(
    int* count,
    const base::DictionaryValue& params,
    const std::string& session_id,
    const CommandCallback& callback) {
  if (*count == 0) {
    EXPECT_STREQ("id", session_id.c_str());
  } else {
    EXPECT_STREQ("id2", session_id.c_str());
  }
  (*count)++;
  callback.Run(Status(kOk), scoped_ptr<base::Value>(), session_id);
}

void OnQuitAll(const Status& status,
               scoped_ptr<base::Value> value,
               const std::string& session_id) {
  ASSERT_EQ(kOk, status.code());
  ASSERT_FALSE(value.get());
}

}  // namespace

TEST(CommandsTest, QuitAll) {
  SessionThreadMap map;
  Session session("id");
  Session session2("id2");
  map[session.id] = make_linked_ptr(new base::Thread("1"));
  map[session2.id] = make_linked_ptr(new base::Thread("2"));

  int count = 0;
  Command cmd = base::Bind(&ExecuteStubQuit, &count);
  base::DictionaryValue params;
  base::MessageLoop loop;
  ExecuteQuitAll(cmd, &map, params, std::string(), base::Bind(&OnQuitAll));
  ASSERT_EQ(2, count);
}

namespace {

Status ExecuteSimpleCommand(
    const std::string& expected_id,
    base::DictionaryValue* expected_params,
    base::Value* value,
    Session* session,
    const base::DictionaryValue& params,
    scoped_ptr<base::Value>* return_value) {
  EXPECT_EQ(expected_id, session->id);
  EXPECT_TRUE(expected_params->Equals(&params));
  return_value->reset(value->DeepCopy());
  session->quit = true;
  return Status(kOk);
}

void OnSimpleCommand(base::RunLoop* run_loop,
                     const std::string& expected_session_id,
                     base::Value* expected_value,
                     const Status& status,
                     scoped_ptr<base::Value> value,
                     const std::string& session_id) {
  ASSERT_EQ(kOk, status.code());
  ASSERT_TRUE(expected_value->Equals(value.get()));
  ASSERT_EQ(expected_session_id, session_id);
  run_loop->Quit();
}

}  // namespace

TEST(CommandsTest, ExecuteSessionCommand) {
  SessionThreadMap map;
  linked_ptr<base::Thread> thread(new base::Thread("1"));
  ASSERT_TRUE(thread->Start());
  std::string id("id");
  thread->message_loop()->PostTask(
      FROM_HERE,
      base::Bind(&internal::CreateSessionOnSessionThreadForTesting, id));
  map[id] = thread;

  base::DictionaryValue params;
  params.SetInteger("param", 5);
  base::FundamentalValue expected_value(6);
  SessionCommand cmd = base::Bind(
      &ExecuteSimpleCommand, id, &params, &expected_value);

  base::MessageLoop loop;
  base::RunLoop run_loop;
  ExecuteSessionCommand(
      &map,
      "cmd",
      cmd,
      false,
      params,
      id,
      base::Bind(&OnSimpleCommand, &run_loop, id, &expected_value));
  run_loop.Run();
}

namespace {

Status ShouldNotBeCalled(
    Session* session,
    const base::DictionaryValue& params,
    scoped_ptr<base::Value>* value) {
  EXPECT_TRUE(false);
  return Status(kOk);
}

void OnNoSuchSession(const Status& status,
                     scoped_ptr<base::Value> value,
                     const std::string& session_id) {
  EXPECT_EQ(kNoSuchSession, status.code());
  EXPECT_FALSE(value.get());
}

void OnNoSuchSessionIsOk(const Status& status,
                         scoped_ptr<base::Value> value,
                         const std::string& session_id) {
  EXPECT_EQ(kOk, status.code());
  EXPECT_FALSE(value.get());
}

}  // namespace

TEST(CommandsTest, ExecuteSessionCommandOnNoSuchSession) {
  SessionThreadMap map;
  base::DictionaryValue params;
  ExecuteSessionCommand(&map,
                        "cmd",
                        base::Bind(&ShouldNotBeCalled),
                        false,
                        params,
                        "session",
                        base::Bind(&OnNoSuchSession));
}

TEST(CommandsTest, ExecuteSessionCommandOnNoSuchSessionWhenItExpectsOk) {
  SessionThreadMap map;
  base::DictionaryValue params;
  ExecuteSessionCommand(&map,
                        "cmd",
                        base::Bind(&ShouldNotBeCalled),
                        true,
                        params,
                        "session",
                        base::Bind(&OnNoSuchSessionIsOk));
}

namespace {

void OnNoSuchSessionAndQuit(base::RunLoop* run_loop,
                            const Status& status,
                            scoped_ptr<base::Value> value,
                            const std::string& session_id) {
  run_loop->Quit();
  EXPECT_EQ(kNoSuchSession, status.code());
  EXPECT_FALSE(value.get());
}

}  // namespace

TEST(CommandsTest, ExecuteSessionCommandOnJustDeletedSession) {
  SessionThreadMap map;
  linked_ptr<base::Thread> thread(new base::Thread("1"));
  ASSERT_TRUE(thread->Start());
  std::string id("id");
  map[id] = thread;

  base::MessageLoop loop;
  base::RunLoop run_loop;
  ExecuteSessionCommand(&map,
                        "cmd",
                        base::Bind(&ShouldNotBeCalled),
                        false,
                        base::DictionaryValue(),
                        "session",
                        base::Bind(&OnNoSuchSessionAndQuit, &run_loop));
  run_loop.Run();
}

namespace {

enum TestScenario {
  kElementExistsQueryOnce = 0,
  kElementExistsQueryTwice,
  kElementNotExistsQueryOnce,
  kElementExistsTimeout
};

class FindElementWebView : public StubWebView {
 public:
  FindElementWebView(bool only_one, TestScenario scenario)
      : StubWebView("1"), only_one_(only_one), scenario_(scenario),
        current_count_(0) {
    switch (scenario_) {
      case kElementExistsQueryOnce:
      case kElementExistsQueryTwice:
      case kElementExistsTimeout: {
        if (only_one_) {
          base::DictionaryValue element;
          element.SetString("ELEMENT", "1");
          result_.reset(element.DeepCopy());
        } else {
          base::DictionaryValue element1;
          element1.SetString("ELEMENT", "1");
          base::DictionaryValue element2;
          element2.SetString("ELEMENT", "2");
          base::ListValue list;
          list.Append(element1.DeepCopy());
          list.Append(element2.DeepCopy());
          result_.reset(list.DeepCopy());
        }
        break;
      }
      case kElementNotExistsQueryOnce: {
        if (only_one_)
          result_.reset(base::Value::CreateNullValue());
        else
          result_.reset(new base::ListValue());
        break;
      }
    }
  }
  virtual ~FindElementWebView() {}

  void Verify(const std::string& expected_frame,
              const base::ListValue* expected_args,
              const base::Value* actrual_result) {
    EXPECT_EQ(expected_frame, frame_);
    std::string function;
    if (only_one_)
      function = webdriver::atoms::asString(webdriver::atoms::FIND_ELEMENT);
    else
      function = webdriver::atoms::asString(webdriver::atoms::FIND_ELEMENTS);
    EXPECT_EQ(function, function_);
    ASSERT_TRUE(args_.get());
    EXPECT_TRUE(expected_args->Equals(args_.get()));
    ASSERT_TRUE(actrual_result);
    EXPECT_TRUE(result_->Equals(actrual_result));
  }

  // Overridden from WebView:
  virtual Status CallFunction(const std::string& frame,
                              const std::string& function,
                              const base::ListValue& args,
                              scoped_ptr<base::Value>* result) OVERRIDE {
    ++current_count_;
    if (scenario_ == kElementExistsTimeout ||
        (scenario_ == kElementExistsQueryTwice && current_count_ == 1)) {
        // Always return empty result when testing timeout.
        if (only_one_)
          result->reset(base::Value::CreateNullValue());
        else
          result->reset(new base::ListValue());
    } else {
      switch (scenario_) {
        case kElementExistsQueryOnce:
        case kElementNotExistsQueryOnce: {
          EXPECT_EQ(1, current_count_);
          break;
        }
        case kElementExistsQueryTwice: {
          EXPECT_EQ(2, current_count_);
          break;
        }
        default: {
          break;
        }
      }

      result->reset(result_->DeepCopy());
      frame_ = frame;
      function_ = function;
      args_.reset(args.DeepCopy());
    }
    return Status(kOk);
  }

 private:
  bool only_one_;
  TestScenario scenario_;
  int current_count_;
  std::string frame_;
  std::string function_;
  scoped_ptr<base::ListValue> args_;
  scoped_ptr<base::Value> result_;
};

}  // namespace

TEST(CommandsTest, SuccessfulFindElement) {
  FindElementWebView web_view(true, kElementExistsQueryTwice);
  Session session("id");
  session.implicit_wait = base::TimeDelta::FromSeconds(1);
  session.SwitchToSubFrame("frame_id1", std::string());
  base::DictionaryValue params;
  params.SetString("using", "id");
  params.SetString("value", "a");
  scoped_ptr<base::Value> result;
  ASSERT_EQ(kOk,
            ExecuteFindElement(1, &session, &web_view, params, &result).code());
  base::DictionaryValue param;
  param.SetString("id", "a");
  base::ListValue expected_args;
  expected_args.Append(param.DeepCopy());
  web_view.Verify("frame_id1", &expected_args, result.get());
}

TEST(CommandsTest, FailedFindElement) {
  FindElementWebView web_view(true, kElementNotExistsQueryOnce);
  Session session("id");
  base::DictionaryValue params;
  params.SetString("using", "id");
  params.SetString("value", "a");
  scoped_ptr<base::Value> result;
  ASSERT_EQ(kNoSuchElement,
            ExecuteFindElement(1, &session, &web_view, params, &result).code());
}

TEST(CommandsTest, SuccessfulFindElements) {
  FindElementWebView web_view(false, kElementExistsQueryTwice);
  Session session("id");
  session.implicit_wait = base::TimeDelta::FromSeconds(1);
  session.SwitchToSubFrame("frame_id2", std::string());
  base::DictionaryValue params;
  params.SetString("using", "name");
  params.SetString("value", "b");
  scoped_ptr<base::Value> result;
  ASSERT_EQ(
      kOk,
      ExecuteFindElements(1, &session, &web_view, params, &result).code());
  base::DictionaryValue param;
  param.SetString("name", "b");
  base::ListValue expected_args;
  expected_args.Append(param.DeepCopy());
  web_view.Verify("frame_id2", &expected_args, result.get());
}

TEST(CommandsTest, FailedFindElements) {
  Session session("id");
  FindElementWebView web_view(false, kElementNotExistsQueryOnce);
  base::DictionaryValue params;
  params.SetString("using", "id");
  params.SetString("value", "a");
  scoped_ptr<base::Value> result;
  ASSERT_EQ(
      kOk,
      ExecuteFindElements(1, &session, &web_view, params, &result).code());
  base::ListValue* list;
  ASSERT_TRUE(result->GetAsList(&list));
  ASSERT_EQ(0U, list->GetSize());
}

TEST(CommandsTest, SuccessfulFindChildElement) {
  FindElementWebView web_view(true, kElementExistsQueryTwice);
  Session session("id");
  session.implicit_wait = base::TimeDelta::FromSeconds(1);
  session.SwitchToSubFrame("frame_id3", std::string());
  base::DictionaryValue params;
  params.SetString("using", "tag name");
  params.SetString("value", "div");
  std::string element_id = "1";
  scoped_ptr<base::Value> result;
  ASSERT_EQ(
      kOk,
      ExecuteFindChildElement(
          1, &session, &web_view, element_id, params, &result).code());
  base::DictionaryValue locator_param;
  locator_param.SetString("tag name", "div");
  base::DictionaryValue root_element_param;
  root_element_param.SetString("ELEMENT", element_id);
  base::ListValue expected_args;
  expected_args.Append(locator_param.DeepCopy());
  expected_args.Append(root_element_param.DeepCopy());
  web_view.Verify("frame_id3", &expected_args, result.get());
}

TEST(CommandsTest, FailedFindChildElement) {
  Session session("id");
  FindElementWebView web_view(true, kElementNotExistsQueryOnce);
  base::DictionaryValue params;
  params.SetString("using", "id");
  params.SetString("value", "a");
  std::string element_id = "1";
  scoped_ptr<base::Value> result;
  ASSERT_EQ(
      kNoSuchElement,
      ExecuteFindChildElement(
          1, &session, &web_view, element_id, params, &result).code());
}

TEST(CommandsTest, SuccessfulFindChildElements) {
  FindElementWebView web_view(false, kElementExistsQueryTwice);
  Session session("id");
  session.implicit_wait = base::TimeDelta::FromSeconds(1);
  session.SwitchToSubFrame("frame_id4", std::string());
  base::DictionaryValue params;
  params.SetString("using", "class name");
  params.SetString("value", "c");
  std::string element_id = "1";
  scoped_ptr<base::Value> result;
  ASSERT_EQ(
      kOk,
      ExecuteFindChildElements(
          1, &session, &web_view, element_id, params, &result).code());
  base::DictionaryValue locator_param;
  locator_param.SetString("class name", "c");
  base::DictionaryValue root_element_param;
  root_element_param.SetString("ELEMENT", element_id);
  base::ListValue expected_args;
  expected_args.Append(locator_param.DeepCopy());
  expected_args.Append(root_element_param.DeepCopy());
  web_view.Verify("frame_id4", &expected_args, result.get());
}

TEST(CommandsTest, FailedFindChildElements) {
  Session session("id");
  FindElementWebView web_view(false, kElementNotExistsQueryOnce);
  base::DictionaryValue params;
  params.SetString("using", "id");
  params.SetString("value", "a");
  std::string element_id = "1";
  scoped_ptr<base::Value> result;
  ASSERT_EQ(
      kOk,
      ExecuteFindChildElements(
          1, &session, &web_view, element_id, params, &result).code());
  base::ListValue* list;
  ASSERT_TRUE(result->GetAsList(&list));
  ASSERT_EQ(0U, list->GetSize());
}

TEST(CommandsTest, TimeoutInFindElement) {
  Session session("id");
  FindElementWebView web_view(true, kElementExistsTimeout);
  session.implicit_wait = base::TimeDelta::FromMilliseconds(2);
  base::DictionaryValue params;
  params.SetString("using", "id");
  params.SetString("value", "a");
  params.SetString("id", "1");
  scoped_ptr<base::Value> result;
  ASSERT_EQ(kNoSuchElement,
            ExecuteFindElement(1, &session, &web_view, params, &result).code());
}

namespace {

class ErrorCallFunctionWebView : public StubWebView {
 public:
  explicit ErrorCallFunctionWebView(StatusCode code)
      : StubWebView("1"), code_(code) {}
  virtual ~ErrorCallFunctionWebView() {}

  // Overridden from WebView:
  virtual Status CallFunction(const std::string& frame,
                              const std::string& function,
                              const base::ListValue& args,
                              scoped_ptr<base::Value>* result) OVERRIDE {
    return Status(code_);
  }

 private:
  StatusCode code_;
};

}  // namespace

TEST(CommandsTest, ErrorFindElement) {
  Session session("id");
  ErrorCallFunctionWebView web_view(kUnknownError);
  base::DictionaryValue params;
  params.SetString("using", "id");
  params.SetString("value", "a");
  scoped_ptr<base::Value> value;
  ASSERT_EQ(kUnknownError,
            ExecuteFindElement(1, &session, &web_view, params, &value).code());
  ASSERT_EQ(kUnknownError,
            ExecuteFindElements(1, &session, &web_view, params, &value).code());
}

TEST(CommandsTest, ErrorFindChildElement) {
  Session session("id");
  ErrorCallFunctionWebView web_view(kStaleElementReference);
  base::DictionaryValue params;
  params.SetString("using", "id");
  params.SetString("value", "a");
  std::string element_id = "1";
  scoped_ptr<base::Value> result;
  ASSERT_EQ(
      kStaleElementReference,
      ExecuteFindChildElement(
          1, &session, &web_view, element_id, params, &result).code());
  ASSERT_EQ(
      kStaleElementReference,
      ExecuteFindChildElements(
          1, &session, &web_view, element_id, params, &result).code());
}

/* [<][>][^][v][top][bottom][index][help] */