Home | History | Annotate | Download | only in chromedriver
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <string>
      6 
      7 #include "base/bind.h"
      8 #include "base/callback.h"
      9 #include "base/compiler_specific.h"
     10 #include "base/files/file_path.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/run_loop.h"
     14 #include "base/synchronization/lock.h"
     15 #include "base/threading/thread.h"
     16 #include "base/values.h"
     17 #include "chrome/test/chromedriver/chrome/status.h"
     18 #include "chrome/test/chromedriver/chrome/stub_chrome.h"
     19 #include "chrome/test/chromedriver/chrome/stub_web_view.h"
     20 #include "chrome/test/chromedriver/chrome/web_view.h"
     21 #include "chrome/test/chromedriver/commands.h"
     22 #include "chrome/test/chromedriver/element_commands.h"
     23 #include "chrome/test/chromedriver/session.h"
     24 #include "chrome/test/chromedriver/session_commands.h"
     25 #include "chrome/test/chromedriver/window_commands.h"
     26 #include "testing/gtest/include/gtest/gtest.h"
     27 #include "third_party/webdriver/atoms.h"
     28 
     29 namespace {
     30 
     31 void OnGetStatus(const Status& status,
     32                  scoped_ptr<base::Value> value,
     33                  const std::string& session_id) {
     34   ASSERT_EQ(kOk, status.code());
     35   base::DictionaryValue* dict;
     36   ASSERT_TRUE(value->GetAsDictionary(&dict));
     37   base::Value* unused;
     38   ASSERT_TRUE(dict->Get("os.name", &unused));
     39   ASSERT_TRUE(dict->Get("os.version", &unused));
     40   ASSERT_TRUE(dict->Get("os.arch", &unused));
     41   ASSERT_TRUE(dict->Get("build.version", &unused));
     42 }
     43 
     44 }  // namespace
     45 
     46 TEST(CommandsTest, GetStatus) {
     47   base::DictionaryValue params;
     48   ExecuteGetStatus(params, std::string(), base::Bind(&OnGetStatus));
     49 }
     50 
     51 namespace {
     52 
     53 void ExecuteStubQuit(
     54     int* count,
     55     const base::DictionaryValue& params,
     56     const std::string& session_id,
     57     const CommandCallback& callback) {
     58   if (*count == 0) {
     59     EXPECT_STREQ("id", session_id.c_str());
     60   } else {
     61     EXPECT_STREQ("id2", session_id.c_str());
     62   }
     63   (*count)++;
     64   callback.Run(Status(kOk), scoped_ptr<base::Value>(), session_id);
     65 }
     66 
     67 void OnQuitAll(const Status& status,
     68                scoped_ptr<base::Value> value,
     69                const std::string& session_id) {
     70   ASSERT_EQ(kOk, status.code());
     71   ASSERT_FALSE(value.get());
     72 }
     73 
     74 }  // namespace
     75 
     76 TEST(CommandsTest, QuitAll) {
     77   SessionThreadMap map;
     78   Session session("id");
     79   Session session2("id2");
     80   map[session.id] = make_linked_ptr(new base::Thread("1"));
     81   map[session2.id] = make_linked_ptr(new base::Thread("2"));
     82 
     83   int count = 0;
     84   Command cmd = base::Bind(&ExecuteStubQuit, &count);
     85   base::DictionaryValue params;
     86   base::MessageLoop loop;
     87   ExecuteQuitAll(cmd, &map, params, std::string(), base::Bind(&OnQuitAll));
     88   ASSERT_EQ(2, count);
     89 }
     90 
     91 namespace {
     92 
     93 Status ExecuteSimpleCommand(
     94     const std::string& expected_id,
     95     base::DictionaryValue* expected_params,
     96     base::Value* value,
     97     Session* session,
     98     const base::DictionaryValue& params,
     99     scoped_ptr<base::Value>* return_value) {
    100   EXPECT_EQ(expected_id, session->id);
    101   EXPECT_TRUE(expected_params->Equals(&params));
    102   return_value->reset(value->DeepCopy());
    103   session->quit = true;
    104   return Status(kOk);
    105 }
    106 
    107 void OnSimpleCommand(base::RunLoop* run_loop,
    108                      const std::string& expected_session_id,
    109                      base::Value* expected_value,
    110                      const Status& status,
    111                      scoped_ptr<base::Value> value,
    112                      const std::string& session_id) {
    113   ASSERT_EQ(kOk, status.code());
    114   ASSERT_TRUE(expected_value->Equals(value.get()));
    115   ASSERT_EQ(expected_session_id, session_id);
    116   run_loop->Quit();
    117 }
    118 
    119 }  // namespace
    120 
    121 TEST(CommandsTest, ExecuteSessionCommand) {
    122   SessionThreadMap map;
    123   linked_ptr<base::Thread> thread(new base::Thread("1"));
    124   ASSERT_TRUE(thread->Start());
    125   std::string id("id");
    126   thread->message_loop()->PostTask(
    127       FROM_HERE,
    128       base::Bind(&internal::CreateSessionOnSessionThreadForTesting, id));
    129   map[id] = thread;
    130 
    131   base::DictionaryValue params;
    132   params.SetInteger("param", 5);
    133   base::FundamentalValue expected_value(6);
    134   SessionCommand cmd = base::Bind(
    135       &ExecuteSimpleCommand, id, &params, &expected_value);
    136 
    137   base::MessageLoop loop;
    138   base::RunLoop run_loop;
    139   ExecuteSessionCommand(
    140       &map,
    141       cmd,
    142       false,
    143       params,
    144       id,
    145       base::Bind(&OnSimpleCommand, &run_loop, id, &expected_value));
    146   run_loop.Run();
    147 }
    148 
    149 namespace {
    150 
    151 Status ShouldNotBeCalled(
    152     Session* session,
    153     const base::DictionaryValue& params,
    154     scoped_ptr<base::Value>* value) {
    155   EXPECT_TRUE(false);
    156   return Status(kOk);
    157 }
    158 
    159 void OnNoSuchSession(const Status& status,
    160                      scoped_ptr<base::Value> value,
    161                      const std::string& session_id) {
    162   EXPECT_EQ(kNoSuchSession, status.code());
    163   EXPECT_FALSE(value.get());
    164 }
    165 
    166 void OnNoSuchSessionIsOk(const Status& status,
    167                          scoped_ptr<base::Value> value,
    168                          const std::string& session_id) {
    169   EXPECT_EQ(kOk, status.code());
    170   EXPECT_FALSE(value.get());
    171 }
    172 
    173 }  // namespace
    174 
    175 TEST(CommandsTest, ExecuteSessionCommandOnNoSuchSession) {
    176   SessionThreadMap map;
    177   base::DictionaryValue params;
    178   ExecuteSessionCommand(&map,
    179                         base::Bind(&ShouldNotBeCalled),
    180                         false,
    181                         params,
    182                         "session",
    183                         base::Bind(&OnNoSuchSession));
    184 }
    185 
    186 TEST(CommandsTest, ExecuteSessionCommandOnNoSuchSessionWhenItExpectsOk) {
    187   SessionThreadMap map;
    188   base::DictionaryValue params;
    189   ExecuteSessionCommand(&map,
    190                         base::Bind(&ShouldNotBeCalled),
    191                         true,
    192                         params,
    193                         "session",
    194                         base::Bind(&OnNoSuchSessionIsOk));
    195 }
    196 
    197 namespace {
    198 
    199 void OnNoSuchSessionAndQuit(base::RunLoop* run_loop,
    200                             const Status& status,
    201                             scoped_ptr<base::Value> value,
    202                             const std::string& session_id) {
    203   run_loop->Quit();
    204   EXPECT_EQ(kNoSuchSession, status.code());
    205   EXPECT_FALSE(value.get());
    206 }
    207 
    208 }  // namespace
    209 
    210 TEST(CommandsTest, ExecuteSessionCommandOnJustDeletedSession) {
    211   SessionThreadMap map;
    212   linked_ptr<base::Thread> thread(new base::Thread("1"));
    213   ASSERT_TRUE(thread->Start());
    214   std::string id("id");
    215   map[id] = thread;
    216 
    217   base::MessageLoop loop;
    218   base::RunLoop run_loop;
    219   ExecuteSessionCommand(&map,
    220                         base::Bind(&ShouldNotBeCalled),
    221                         false,
    222                         base::DictionaryValue(),
    223                         "session",
    224                         base::Bind(&OnNoSuchSessionAndQuit, &run_loop));
    225   run_loop.Run();
    226 }
    227 
    228 namespace {
    229 
    230 enum TestScenario {
    231   kElementExistsQueryOnce = 0,
    232   kElementExistsQueryTwice,
    233   kElementNotExistsQueryOnce,
    234   kElementExistsTimeout
    235 };
    236 
    237 class FindElementWebView : public StubWebView {
    238  public:
    239   FindElementWebView(bool only_one, TestScenario scenario)
    240       : StubWebView("1"), only_one_(only_one), scenario_(scenario),
    241         current_count_(0) {
    242     switch (scenario_) {
    243       case kElementExistsQueryOnce:
    244       case kElementExistsQueryTwice:
    245       case kElementExistsTimeout: {
    246         if (only_one_) {
    247           base::DictionaryValue element;
    248           element.SetString("ELEMENT", "1");
    249           result_.reset(element.DeepCopy());
    250         } else {
    251           base::DictionaryValue element1;
    252           element1.SetString("ELEMENT", "1");
    253           base::DictionaryValue element2;
    254           element2.SetString("ELEMENT", "2");
    255           base::ListValue list;
    256           list.Append(element1.DeepCopy());
    257           list.Append(element2.DeepCopy());
    258           result_.reset(list.DeepCopy());
    259         }
    260         break;
    261       }
    262       case kElementNotExistsQueryOnce: {
    263         if (only_one_)
    264           result_.reset(base::Value::CreateNullValue());
    265         else
    266           result_.reset(new base::ListValue());
    267         break;
    268       }
    269     }
    270   }
    271   virtual ~FindElementWebView() {}
    272 
    273   void Verify(const std::string& expected_frame,
    274               const base::ListValue* expected_args,
    275               const base::Value* actrual_result) {
    276     EXPECT_EQ(expected_frame, frame_);
    277     std::string function;
    278     if (only_one_)
    279       function = webdriver::atoms::asString(webdriver::atoms::FIND_ELEMENT);
    280     else
    281       function = webdriver::atoms::asString(webdriver::atoms::FIND_ELEMENTS);
    282     EXPECT_EQ(function, function_);
    283     ASSERT_TRUE(args_.get());
    284     EXPECT_TRUE(expected_args->Equals(args_.get()));
    285     ASSERT_TRUE(actrual_result);
    286     EXPECT_TRUE(result_->Equals(actrual_result));
    287   }
    288 
    289   // Overridden from WebView:
    290   virtual Status CallFunction(const std::string& frame,
    291                               const std::string& function,
    292                               const base::ListValue& args,
    293                               scoped_ptr<base::Value>* result) OVERRIDE {
    294     ++current_count_;
    295     if (scenario_ == kElementExistsTimeout ||
    296         (scenario_ == kElementExistsQueryTwice && current_count_ == 1)) {
    297         // Always return empty result when testing timeout.
    298         if (only_one_)
    299           result->reset(base::Value::CreateNullValue());
    300         else
    301           result->reset(new base::ListValue());
    302     } else {
    303       switch (scenario_) {
    304         case kElementExistsQueryOnce:
    305         case kElementNotExistsQueryOnce: {
    306           EXPECT_EQ(1, current_count_);
    307           break;
    308         }
    309         case kElementExistsQueryTwice: {
    310           EXPECT_EQ(2, current_count_);
    311           break;
    312         }
    313         default: {
    314           break;
    315         }
    316       }
    317 
    318       result->reset(result_->DeepCopy());
    319       frame_ = frame;
    320       function_ = function;
    321       args_.reset(args.DeepCopy());
    322     }
    323     return Status(kOk);
    324   }
    325 
    326  private:
    327   bool only_one_;
    328   TestScenario scenario_;
    329   int current_count_;
    330   std::string frame_;
    331   std::string function_;
    332   scoped_ptr<base::ListValue> args_;
    333   scoped_ptr<base::Value> result_;
    334 };
    335 
    336 }  // namespace
    337 
    338 TEST(CommandsTest, SuccessfulFindElement) {
    339   FindElementWebView web_view(true, kElementExistsQueryTwice);
    340   Session session("id");
    341   session.implicit_wait = 1000;
    342   session.SwitchToSubFrame("frame_id1", std::string());
    343   base::DictionaryValue params;
    344   params.SetString("using", "id");
    345   params.SetString("value", "a");
    346   scoped_ptr<base::Value> result;
    347   ASSERT_EQ(kOk,
    348             ExecuteFindElement(1, &session, &web_view, params, &result).code());
    349   base::DictionaryValue param;
    350   param.SetString("id", "a");
    351   base::ListValue expected_args;
    352   expected_args.Append(param.DeepCopy());
    353   web_view.Verify("frame_id1", &expected_args, result.get());
    354 }
    355 
    356 TEST(CommandsTest, FailedFindElement) {
    357   FindElementWebView web_view(true, kElementNotExistsQueryOnce);
    358   Session session("id");
    359   base::DictionaryValue params;
    360   params.SetString("using", "id");
    361   params.SetString("value", "a");
    362   scoped_ptr<base::Value> result;
    363   ASSERT_EQ(kNoSuchElement,
    364             ExecuteFindElement(1, &session, &web_view, params, &result).code());
    365 }
    366 
    367 TEST(CommandsTest, SuccessfulFindElements) {
    368   FindElementWebView web_view(false, kElementExistsQueryTwice);
    369   Session session("id");
    370   session.implicit_wait = 1000;
    371   session.SwitchToSubFrame("frame_id2", std::string());
    372   base::DictionaryValue params;
    373   params.SetString("using", "name");
    374   params.SetString("value", "b");
    375   scoped_ptr<base::Value> result;
    376   ASSERT_EQ(
    377       kOk,
    378       ExecuteFindElements(1, &session, &web_view, params, &result).code());
    379   base::DictionaryValue param;
    380   param.SetString("name", "b");
    381   base::ListValue expected_args;
    382   expected_args.Append(param.DeepCopy());
    383   web_view.Verify("frame_id2", &expected_args, result.get());
    384 }
    385 
    386 TEST(CommandsTest, FailedFindElements) {
    387   Session session("id");
    388   FindElementWebView web_view(false, kElementNotExistsQueryOnce);
    389   base::DictionaryValue params;
    390   params.SetString("using", "id");
    391   params.SetString("value", "a");
    392   scoped_ptr<base::Value> result;
    393   ASSERT_EQ(
    394       kOk,
    395       ExecuteFindElements(1, &session, &web_view, params, &result).code());
    396   base::ListValue* list;
    397   ASSERT_TRUE(result->GetAsList(&list));
    398   ASSERT_EQ(0U, list->GetSize());
    399 }
    400 
    401 TEST(CommandsTest, SuccessfulFindChildElement) {
    402   FindElementWebView web_view(true, kElementExistsQueryTwice);
    403   Session session("id");
    404   session.implicit_wait = 1000;
    405   session.SwitchToSubFrame("frame_id3", std::string());
    406   base::DictionaryValue params;
    407   params.SetString("using", "tag name");
    408   params.SetString("value", "div");
    409   std::string element_id = "1";
    410   scoped_ptr<base::Value> result;
    411   ASSERT_EQ(
    412       kOk,
    413       ExecuteFindChildElement(
    414           1, &session, &web_view, element_id, params, &result).code());
    415   base::DictionaryValue locator_param;
    416   locator_param.SetString("tag name", "div");
    417   base::DictionaryValue root_element_param;
    418   root_element_param.SetString("ELEMENT", element_id);
    419   base::ListValue expected_args;
    420   expected_args.Append(locator_param.DeepCopy());
    421   expected_args.Append(root_element_param.DeepCopy());
    422   web_view.Verify("frame_id3", &expected_args, result.get());
    423 }
    424 
    425 TEST(CommandsTest, FailedFindChildElement) {
    426   Session session("id");
    427   FindElementWebView web_view(true, kElementNotExistsQueryOnce);
    428   base::DictionaryValue params;
    429   params.SetString("using", "id");
    430   params.SetString("value", "a");
    431   std::string element_id = "1";
    432   scoped_ptr<base::Value> result;
    433   ASSERT_EQ(
    434       kNoSuchElement,
    435       ExecuteFindChildElement(
    436           1, &session, &web_view, element_id, params, &result).code());
    437 }
    438 
    439 TEST(CommandsTest, SuccessfulFindChildElements) {
    440   FindElementWebView web_view(false, kElementExistsQueryTwice);
    441   Session session("id");
    442   session.implicit_wait = 1000;
    443   session.SwitchToSubFrame("frame_id4", std::string());
    444   base::DictionaryValue params;
    445   params.SetString("using", "class name");
    446   params.SetString("value", "c");
    447   std::string element_id = "1";
    448   scoped_ptr<base::Value> result;
    449   ASSERT_EQ(
    450       kOk,
    451       ExecuteFindChildElements(
    452           1, &session, &web_view, element_id, params, &result).code());
    453   base::DictionaryValue locator_param;
    454   locator_param.SetString("class name", "c");
    455   base::DictionaryValue root_element_param;
    456   root_element_param.SetString("ELEMENT", element_id);
    457   base::ListValue expected_args;
    458   expected_args.Append(locator_param.DeepCopy());
    459   expected_args.Append(root_element_param.DeepCopy());
    460   web_view.Verify("frame_id4", &expected_args, result.get());
    461 }
    462 
    463 TEST(CommandsTest, FailedFindChildElements) {
    464   Session session("id");
    465   FindElementWebView web_view(false, kElementNotExistsQueryOnce);
    466   base::DictionaryValue params;
    467   params.SetString("using", "id");
    468   params.SetString("value", "a");
    469   std::string element_id = "1";
    470   scoped_ptr<base::Value> result;
    471   ASSERT_EQ(
    472       kOk,
    473       ExecuteFindChildElements(
    474           1, &session, &web_view, element_id, params, &result).code());
    475   base::ListValue* list;
    476   ASSERT_TRUE(result->GetAsList(&list));
    477   ASSERT_EQ(0U, list->GetSize());
    478 }
    479 
    480 TEST(CommandsTest, TimeoutInFindElement) {
    481   Session session("id");
    482   FindElementWebView web_view(true, kElementExistsTimeout);
    483   session.implicit_wait = 2;
    484   base::DictionaryValue params;
    485   params.SetString("using", "id");
    486   params.SetString("value", "a");
    487   params.SetString("id", "1");
    488   scoped_ptr<base::Value> result;
    489   ASSERT_EQ(kNoSuchElement,
    490             ExecuteFindElement(1, &session, &web_view, params, &result).code());
    491 }
    492 
    493 namespace {
    494 
    495 class ErrorCallFunctionWebView : public StubWebView {
    496  public:
    497   explicit ErrorCallFunctionWebView(StatusCode code)
    498       : StubWebView("1"), code_(code) {}
    499   virtual ~ErrorCallFunctionWebView() {}
    500 
    501   // Overridden from WebView:
    502   virtual Status CallFunction(const std::string& frame,
    503                               const std::string& function,
    504                               const base::ListValue& args,
    505                               scoped_ptr<base::Value>* result) OVERRIDE {
    506     return Status(code_);
    507   }
    508 
    509  private:
    510   StatusCode code_;
    511 };
    512 
    513 }  // namespace
    514 
    515 TEST(CommandsTest, ErrorFindElement) {
    516   Session session("id");
    517   ErrorCallFunctionWebView web_view(kUnknownError);
    518   base::DictionaryValue params;
    519   params.SetString("using", "id");
    520   params.SetString("value", "a");
    521   scoped_ptr<base::Value> value;
    522   ASSERT_EQ(kUnknownError,
    523             ExecuteFindElement(1, &session, &web_view, params, &value).code());
    524   ASSERT_EQ(kUnknownError,
    525             ExecuteFindElements(1, &session, &web_view, params, &value).code());
    526 }
    527 
    528 TEST(CommandsTest, ErrorFindChildElement) {
    529   Session session("id");
    530   ErrorCallFunctionWebView web_view(kStaleElementReference);
    531   base::DictionaryValue params;
    532   params.SetString("using", "id");
    533   params.SetString("value", "a");
    534   std::string element_id = "1";
    535   scoped_ptr<base::Value> result;
    536   ASSERT_EQ(
    537       kStaleElementReference,
    538       ExecuteFindChildElement(
    539           1, &session, &web_view, element_id, params, &result).code());
    540   ASSERT_EQ(
    541       kStaleElementReference,
    542       ExecuteFindChildElements(
    543           1, &session, &web_view, element_id, params, &result).code());
    544 }
    545