一個有意思的Ruby Webdriver逾時問題的解決過程

來源:互聯網
上載者:User

標籤:begin   com   計算   是什麼   發送   and   safari   source   bug   

rescue in receive

由於寫ruby的時候感覺混身上下都拽起來了,所以比較喜歡用ruby寫代碼。

今天遇到了一個webdriver timeout的問題,問題本身還是由於我對webdriver不瞭解以及破文檔導致的。首先我們把問題簡化一下:


driver = Selenium::WebDriver.for :safari
driver.navigate.to "http://www.faraway.com"

wait = Selenium::WebDriver::Wait.new(:timeout => 1000) # seconds
wait.until { driver.find_element(:css, ‘input[name="username"]‘) }

由於考慮到網站太遠了,速度比較慢,於是timeout設的值比較大:timeout => 1000

這裡我們訪問:faraway這個網站,然後等待出現輸入框輸入username。

得到了例如以下錯誤資訊:

/Users/twer/.rvm/gems/[email protected]/gems/selenium-webdriver-2.42.0/lib/ selenium/webdriver/safari/server.rb:41:in`rescue in receive‘: timed out waiting for Safari to respond (Selenium::WebDriver::Error::TimeOutError)
from /Users/twer/.rvm/gems/[email protected]/gems/selenium-webdriver-2.42.0/lib/selenium/webdriver/safari/server.rb:36:in `receive‘
from /Users/twer/.rvm/gems/[email protected]/gems/selenium-webdriver-2.42.0/lib/selenium/webdriver/safari/bridge.rb:68:in `raw_execute‘
from /Users/twer/.rvm/gems/[email protected]/gems/selenium-webdriver-2.42.0/lib/selenium/webdriver/remote/bridge.rb:612:in `execute‘
from /Users/twer/.rvm/gems/[email protected]/gems/selenium-webdriver-2.42.0/lib/selenium/webdriver/remote/bridge.rb:110:in `get‘
from /Users/twer/.rvm/gems/[email protected]/gems/selenium-webdriver-2.42.0/lib/selenium/webdriver/common/navigation.rb:14:in `to‘
from faraway.rb:26:in `<main>‘


看了出錯的地方就是我wait的地方調用的。我心想我這不是設了:timeout => 1000。wait的等待時間為1000秒嗎,怎麼還搞不定啊?


Monkey Patch來解救我了

搞不定啊,上面有人在吹啊,咋辦嘛。暴力解決。

我找到了上面紅色部分標明的檔案/selenium/webdriver/safari/server.rb。(https://code.google.com/p/selenium/source/browse/rb/lib/selenium/webdriver/safari/server.rb)

找到了出錯的地方41行,是在receive函數裡:

def receive
   @frame ||= WebSocket::Frame::Incoming::Server.new(:version => @version)
   until msg = @frame.next

   end_time = Time.now + @command_timeout

   begin
      data = @ws.read_nonblock(1)
      rescue Errno::EWOULDBLOCK, Errno::EAGAIN
         now = Time.now
         if now >= end_time
            raise Error::TimeOutError, "timed out waiting for Safari to respond"   #第41行
         end

         IO.select([@ws], nil, nil, end_time - now)
         retry
      end

      @frame << data
   end

   puts "<<< #{msg}" if $DEBUG

   WebDriver.json_load msg.to_s
end


能夠看出,是now >= end_time用來計算是否逾時。在看前面end_time是由Time.now + @command_timeout得到的,然後進入begin/rescue/retry的。奇怪,我的:timeout => 1000不應該是work的嗎?


第一個monkey patch

我把上面那部分代碼直接拷到了我的源檔案faraway.rb中,做了例如以下改動:

if now >= end_time
   puts @command_timeout
   raise Error::TimeOutError, "timed out waiting for Safari to respond"
end

發現@command_timeout不是1000。而是60,也就是一分鐘


第二個monkey patch

until msg = @frame.next
   end_time = Time.now + 1000
這樣強制讓@command_timeout設為1000


這樣執行,沒有問題了


探個到底

儘管monkey patch能夠解決我串連faraway的問題。可是,作為高速實驗得到反饋還行。真這樣用還是不太愉快。

於是我就開始讀源碼,webdriver本身的代碼還是挺簡單的。非常easy看懂。詳細怎麼看我就不講了。分分鐘發現了問題事實上是在這裡:


driver = Selenium::WebDriver.for :safari,timeout: 1000
driver.navigate.to "http://www.faraway.com"


紅色的部分在文檔上是沒有交代的,那這裡的timeout是什麼意思呢?我的wait不是已經有timeout了嗎。怎麼在Driver的建立時還須要呢?

原因是這是兩種不同的timeout。wait的timeout表示的是。我們的driver會等待多久知道這個元素出現。而我們出錯的地方是driver接收server返回資訊的timeout。

還不清楚?

這樣說,在wait的時候,driver會周期輪詢的去運行until中的代碼。看看until中的情況是否得到了滿足。

每次啟動並執行時候Driver對會發一個請求。這個請求事實上也是有timeout時間的。所以我們最開始遇到的問題並非wait本身timeout了。

而是driver發送命令後接收的時候timeout了。

明了了吧,都是faraway.com搞得怪,想重現這個問題。把command timeout改為1試試


假設我再次不幸。。

我一僅僅攪得自己是運氣比較背的那種人。

只是解決這個問題的過程還是非常開心。ruby這樣的動態語言,能夠打monkey patch,對於高速定位問題,解決這個問題還是非常有協助的。開心。


一個有意思的Ruby Webdriver逾時問題的解決過程

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.