grid 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/examples/bacon/bacon.rb +27 -0
- data/examples/basic/basic.rb +7 -7
- data/examples/basic/selenium/selenium.rb +14 -0
- data/examples/capybara/testunit/example_test.rb +36 -0
- data/examples/cucumber/step_definitions/example_steps.rb +2 -2
- data/examples/rspec/basic_spec.rb +26 -0
- data/examples/testunit/basic_test.rb +25 -0
- data/grid.gemspec +16 -2
- data/lib/grid/extensions/capybara/driver.rb +155 -0
- data/lib/grid/extensions/capybara/node.rb +92 -0
- data/lib/grid/extensions/capybara.rb +10 -0
- data/lib/grid/grid.rb +283 -0
- data/lib/grid.rb +1 -283
- metadata +18 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.2
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'grid'
|
2
|
+
require 'bacon'
|
3
|
+
|
4
|
+
describe 'A simple specification' do
|
5
|
+
|
6
|
+
before do
|
7
|
+
options = {}
|
8
|
+
options[:controller_uri] = "druby://10.0.1.3:11235"
|
9
|
+
options[:browser_type] = 'webdriver'
|
10
|
+
options[:browser] = 'chrome'
|
11
|
+
options[:loglevel] = Logger::DEBUG
|
12
|
+
@grid = Grid.new(options)
|
13
|
+
@grid.setup
|
14
|
+
end
|
15
|
+
|
16
|
+
after do
|
17
|
+
@grid.teardown
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should do a search on Google" do
|
21
|
+
@grid.iterate do |browser|
|
22
|
+
browser.goto "altentee.com"
|
23
|
+
browser.title.should =~ /Automation Company/
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/examples/basic/basic.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
-
require '
|
1
|
+
require 'grid'
|
2
2
|
require 'watir-webdriver-performance' # only if using webdriver_performance
|
3
3
|
|
4
4
|
##
|
5
5
|
# Set some parameters before we begin
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
options={}
|
7
|
+
options[:controller_uri] = "druby://ec2-50-16-63-81.compute-1.amazonaws.com:11235"
|
8
|
+
options[:browser] = "chrome"
|
9
|
+
options[:quantity] = 5
|
10
10
|
|
11
11
|
##
|
12
12
|
# Let's instantiate a grid object
|
13
|
-
grid = Grid.new(
|
13
|
+
grid = Grid.new(options)
|
14
14
|
|
15
15
|
##
|
16
16
|
# How big is my grid?
|
@@ -44,7 +44,7 @@ grid.teardown
|
|
44
44
|
##
|
45
45
|
# There's also a iterate_with_index method if you want to keep track
|
46
46
|
# of individual browsers for further reporting and analysis
|
47
|
-
grid = Grid.new(
|
47
|
+
grid = Grid.new(options)
|
48
48
|
grid.setup
|
49
49
|
|
50
50
|
grid.iterate_with_index do |browser, index|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'grid'
|
2
|
+
|
3
|
+
params={}
|
4
|
+
params[:controller_uri] = 'druby://10.0.1.3:11235'
|
5
|
+
params[:browser] = 'firefox'
|
6
|
+
|
7
|
+
Grid.control(params) do |driver, index|
|
8
|
+
driver.navigate.to 'http://google.com'
|
9
|
+
element = driver.find_element(:name, 'q')
|
10
|
+
element.send_keys 'gridinit'
|
11
|
+
element.submit
|
12
|
+
puts driver.title
|
13
|
+
driver.quit
|
14
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'grid'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'grid/extensions/capybara'
|
4
|
+
|
5
|
+
#require 'capybara'
|
6
|
+
#require 'capybara/dsl'
|
7
|
+
#require 'selenium-webdriver'
|
8
|
+
|
9
|
+
#module Capybara
|
10
|
+
#module Grid
|
11
|
+
#autoload :Node, 'lib/grid/extensions/capybara/node.rb'
|
12
|
+
#autoload :Driver, 'lib/grid/extensions/capybara/driver.rb'
|
13
|
+
#end
|
14
|
+
#end
|
15
|
+
|
16
|
+
Capybara.register_driver :grid do |app|
|
17
|
+
options = {}
|
18
|
+
options[:controller_uri] = 'druby://10.0.1.3:11235'
|
19
|
+
options[:loglevel] = Logger::DEBUG
|
20
|
+
Capybara::Grid::Driver.new(app, options)
|
21
|
+
end
|
22
|
+
|
23
|
+
class HelloWorldTest < Test::Unit::TestCase
|
24
|
+
include Capybara
|
25
|
+
|
26
|
+
Capybara.app_host = 'http://www.google.com'
|
27
|
+
Capybara.default_driver = :grid
|
28
|
+
Capybara.run_server = false
|
29
|
+
|
30
|
+
def test_google
|
31
|
+
visit '/'
|
32
|
+
fill_in 'q', :with => 'gridinit'
|
33
|
+
assert page.has_content?('results')
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -6,12 +6,12 @@ require 'grid'
|
|
6
6
|
|
7
7
|
Given /^(\d+) users open "([^"]*)"$/ do |quantity, browser|
|
8
8
|
params={}
|
9
|
-
params[:controller_uri] = "druby://ec2-
|
9
|
+
params[:controller_uri] = "druby://ec2-50-17-154-31.compute-1.amazonaws.com:11235"
|
10
10
|
params[:browser] = browser # type of webdriver browser to spawn
|
11
11
|
params[:quantity] = quantity.to_i # max number of browsers to use
|
12
12
|
params[:rampup] = 10 # seconds
|
13
13
|
@grid = Grid.new(params)
|
14
|
-
@grid.setup
|
14
|
+
@grid.setup
|
15
15
|
end
|
16
16
|
|
17
17
|
Given /^navigate to the portal$/ do
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'grid'
|
2
|
+
|
3
|
+
describe 'A simple specification' do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
options = {}
|
7
|
+
options[:controller_uri] = "druby://10.0.1.3:11235"
|
8
|
+
options[:browser_type] = 'webdriver'
|
9
|
+
options[:browser] = 'chrome'
|
10
|
+
options[:loglevel] = Logger::DEBUG
|
11
|
+
@grid = Grid.new(options)
|
12
|
+
@grid.setup
|
13
|
+
end
|
14
|
+
|
15
|
+
after(:all) do
|
16
|
+
@grid.teardown
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should do a search on Google" do
|
20
|
+
@grid.iterate do |browser|
|
21
|
+
browser.goto "altentee.com"
|
22
|
+
browser.title.should =~ /Automation Company/
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'grid'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class SimpleTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
options = {}
|
7
|
+
options[:controller_uri] = "druby://10.0.1.3:11235"
|
8
|
+
options[:browser_type] = 'webdriver'
|
9
|
+
options[:browser] = 'chrome'
|
10
|
+
options[:loglevel] = Logger::DEBUG
|
11
|
+
@grid = Grid.new(options)
|
12
|
+
@grid.setup
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
@grid.teardown
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_google
|
20
|
+
@grid.iterate do |browser|
|
21
|
+
browser.goto "altentee.com"
|
22
|
+
assert_match /Automation Company/, browser.title
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/grid.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{grid}
|
8
|
-
s.version = "0.4.
|
8
|
+
s.version = "0.4.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Tim Koopmans"]
|
12
|
-
s.date = %q{2011-04-
|
12
|
+
s.date = %q{2011-04-26}
|
13
13
|
s.default_executable = %q{grid}
|
14
14
|
s.description = %q{Gridinit command line utilities to help you use the Gridinit API}
|
15
15
|
s.email = %q{tim.koops@gmail.com}
|
@@ -28,12 +28,21 @@ Gem::Specification.new do |s|
|
|
28
28
|
"Rakefile",
|
29
29
|
"VERSION",
|
30
30
|
"bin/grid",
|
31
|
+
"examples/bacon/bacon.rb",
|
31
32
|
"examples/basic/basic.rb",
|
33
|
+
"examples/basic/selenium/selenium.rb",
|
34
|
+
"examples/capybara/testunit/example_test.rb",
|
32
35
|
"examples/cucumber/example.feature",
|
33
36
|
"examples/cucumber/step_definitions/.DS_Store",
|
34
37
|
"examples/cucumber/step_definitions/example_steps.rb",
|
38
|
+
"examples/rspec/basic_spec.rb",
|
39
|
+
"examples/testunit/basic_test.rb",
|
35
40
|
"grid.gemspec",
|
36
41
|
"lib/grid.rb",
|
42
|
+
"lib/grid/extensions/capybara.rb",
|
43
|
+
"lib/grid/extensions/capybara/driver.rb",
|
44
|
+
"lib/grid/extensions/capybara/node.rb",
|
45
|
+
"lib/grid/grid.rb",
|
37
46
|
"spec/grid_spec.rb",
|
38
47
|
"spec/spec_helper.rb"
|
39
48
|
]
|
@@ -43,8 +52,13 @@ Gem::Specification.new do |s|
|
|
43
52
|
s.rubygems_version = %q{1.4.2}
|
44
53
|
s.summary = %q{Gridinit command line utilities}
|
45
54
|
s.test_files = [
|
55
|
+
"examples/bacon/bacon.rb",
|
46
56
|
"examples/basic/basic.rb",
|
57
|
+
"examples/basic/selenium/selenium.rb",
|
58
|
+
"examples/capybara/testunit/example_test.rb",
|
47
59
|
"examples/cucumber/step_definitions/example_steps.rb",
|
60
|
+
"examples/rspec/basic_spec.rb",
|
61
|
+
"examples/testunit/basic_test.rb",
|
48
62
|
"spec/grid_spec.rb",
|
49
63
|
"spec/spec_helper.rb"
|
50
64
|
]
|
@@ -0,0 +1,155 @@
|
|
1
|
+
class Capybara::Grid::Driver < Capybara::Driver::Base
|
2
|
+
DEFAULT_OPTIONS = {
|
3
|
+
:resynchronize => false,
|
4
|
+
:resynchronization_timeout => 10,
|
5
|
+
:browser => :firefox
|
6
|
+
}
|
7
|
+
SPECIAL_OPTIONS = [:browser, :resynchronize, :resynchronization_timeout]
|
8
|
+
|
9
|
+
attr_reader :app, :rack_server, :options
|
10
|
+
|
11
|
+
def browser
|
12
|
+
unless @browsers
|
13
|
+
@options[:browser] = 'firefox'
|
14
|
+
@grid = Grid.new(@options)
|
15
|
+
@browsers = []
|
16
|
+
@grid.providers.each_with_index do |provider, index|
|
17
|
+
@browsers[index] = provider[:object].new_browser :firefox
|
18
|
+
end
|
19
|
+
at_exit do
|
20
|
+
@browsers.each do |browser|
|
21
|
+
browser.quit
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
@browsers.first
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(app, options={})
|
29
|
+
@app = app
|
30
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
31
|
+
@rack_server = Capybara::Server.new(@app)
|
32
|
+
@rack_server.boot if Capybara.run_server
|
33
|
+
end
|
34
|
+
|
35
|
+
def visit(path)
|
36
|
+
browser.navigate.to(url(path))
|
37
|
+
end
|
38
|
+
|
39
|
+
def source
|
40
|
+
browser.page_source
|
41
|
+
end
|
42
|
+
|
43
|
+
def body
|
44
|
+
browser.page_source
|
45
|
+
end
|
46
|
+
|
47
|
+
def current_url
|
48
|
+
browser.current_url
|
49
|
+
end
|
50
|
+
|
51
|
+
def find(selector)
|
52
|
+
browser.find_elements(:xpath, selector).map do |node|
|
53
|
+
Capybara::Grid::Node.new(self, node)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def wait?; true; end
|
58
|
+
|
59
|
+
def resynchronize
|
60
|
+
if options[:resynchronize]
|
61
|
+
load_wait_for_ajax_support
|
62
|
+
yield
|
63
|
+
Capybara.timeout(options[:resynchronization_timeout], self, "failed to resynchronize, ajax request timed out") do
|
64
|
+
evaluate_script("!window.capybaraRequestsOutstanding")
|
65
|
+
end
|
66
|
+
else
|
67
|
+
yield
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def execute_script(script)
|
72
|
+
browser.execute_script script
|
73
|
+
end
|
74
|
+
|
75
|
+
def evaluate_script(script)
|
76
|
+
browser.execute_script "return #{script}"
|
77
|
+
end
|
78
|
+
|
79
|
+
def reset!
|
80
|
+
# Use instance variable directly so we avoid starting the browser just to reset the session
|
81
|
+
if @browser
|
82
|
+
begin
|
83
|
+
@browser.manage.delete_all_cookies
|
84
|
+
rescue Selenium::WebDriver::Error::UnhandledError => e
|
85
|
+
# delete_all_cookies fails when we've previously gone
|
86
|
+
# to about:blank, so we rescue this error and do nothing
|
87
|
+
# instead.
|
88
|
+
end
|
89
|
+
@browser.navigate.to('about:blank')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def within_frame(frame_id)
|
94
|
+
old_window = browser.window_handle
|
95
|
+
browser.switch_to.frame(frame_id)
|
96
|
+
yield
|
97
|
+
browser.switch_to.window old_window
|
98
|
+
end
|
99
|
+
|
100
|
+
def find_window( selector )
|
101
|
+
original_handle = browser.window_handle
|
102
|
+
browser.window_handles.each do |handle|
|
103
|
+
browser.switch_to.window handle
|
104
|
+
if( selector == browser.execute_script("return window.name") ||
|
105
|
+
browser.title.include?(selector) ||
|
106
|
+
browser.current_url.include?(selector) ||
|
107
|
+
(selector == handle) )
|
108
|
+
browser.switch_to.window original_handle
|
109
|
+
return handle
|
110
|
+
end
|
111
|
+
end
|
112
|
+
raise Capybara::ElementNotFound, "Could not find a window identified by #{selector}"
|
113
|
+
end
|
114
|
+
|
115
|
+
def within_window(selector, &blk)
|
116
|
+
handle = find_window( selector )
|
117
|
+
browser.switch_to.window(handle, &blk)
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def load_wait_for_ajax_support
|
123
|
+
browser.execute_script <<-JS
|
124
|
+
window.capybaraRequestsOutstanding = 0;
|
125
|
+
(function() { // Overriding XMLHttpRequest
|
126
|
+
var oldXHR = window.XMLHttpRequest;
|
127
|
+
|
128
|
+
function newXHR() {
|
129
|
+
var realXHR = new oldXHR();
|
130
|
+
|
131
|
+
window.capybaraRequestsOutstanding++;
|
132
|
+
realXHR.addEventListener("readystatechange", function() {
|
133
|
+
if( realXHR.readyState == 4 ) {
|
134
|
+
setTimeout( function() {
|
135
|
+
window.capybaraRequestsOutstanding--;
|
136
|
+
if(window.capybaraRequestsOutstanding < 0) {
|
137
|
+
window.capybaraRequestsOutstanding = 0;
|
138
|
+
}
|
139
|
+
}, 500 );
|
140
|
+
}
|
141
|
+
}, false);
|
142
|
+
|
143
|
+
return realXHR;
|
144
|
+
}
|
145
|
+
|
146
|
+
window.XMLHttpRequest = newXHR;
|
147
|
+
})();
|
148
|
+
JS
|
149
|
+
end
|
150
|
+
|
151
|
+
def url(path)
|
152
|
+
rack_server.url(path)
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
class Capybara::Grid::Node < Capybara::Driver::Node
|
2
|
+
def text
|
3
|
+
native.text
|
4
|
+
end
|
5
|
+
|
6
|
+
def [](name)
|
7
|
+
if name == :value
|
8
|
+
value
|
9
|
+
else
|
10
|
+
native.attribute(name.to_s)
|
11
|
+
end
|
12
|
+
rescue Selenium::WebDriver::Error::WebDriverError
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def value
|
17
|
+
if tag_name == "select" and self[:multiple] and not self[:multiple] == "false"
|
18
|
+
native.find_elements(:xpath, ".//option").select { |n| n.selected? }.map { |n| n.value || n.text }
|
19
|
+
else
|
20
|
+
native.value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def set(value)
|
25
|
+
if tag_name == 'input' and type == 'radio'
|
26
|
+
click
|
27
|
+
elsif tag_name == 'input' and type == 'checkbox'
|
28
|
+
click if value ^ native.attribute('checked').to_s.eql?("true")
|
29
|
+
elsif tag_name == 'textarea' or tag_name == 'input'
|
30
|
+
resynchronize do
|
31
|
+
native.clear
|
32
|
+
native.send_keys(value.to_s)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def select_option
|
38
|
+
resynchronize { native.select }
|
39
|
+
end
|
40
|
+
|
41
|
+
def unselect_option
|
42
|
+
if select_node['multiple'] != 'multiple' and select_node['multiple'] != 'true'
|
43
|
+
raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box."
|
44
|
+
end
|
45
|
+
resynchronize { native.toggle } if selected?
|
46
|
+
end
|
47
|
+
|
48
|
+
def click
|
49
|
+
resynchronize { native.click }
|
50
|
+
end
|
51
|
+
|
52
|
+
def drag_to(element)
|
53
|
+
resynchronize { native.drag_and_drop_on(element.native) }
|
54
|
+
end
|
55
|
+
|
56
|
+
def tag_name
|
57
|
+
native.tag_name
|
58
|
+
end
|
59
|
+
|
60
|
+
def visible?
|
61
|
+
displayed = native.displayed?
|
62
|
+
displayed and displayed != "false"
|
63
|
+
end
|
64
|
+
|
65
|
+
def selected?
|
66
|
+
selected = native.selected?
|
67
|
+
selected and selected != "false"
|
68
|
+
end
|
69
|
+
|
70
|
+
alias :checked? :selected?
|
71
|
+
|
72
|
+
def find(locator)
|
73
|
+
native.find_elements(:xpath, locator).map { |n| self.class.new(driver, n) }
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def resynchronize
|
79
|
+
driver.resynchronize { yield }
|
80
|
+
end
|
81
|
+
|
82
|
+
# a reference to the select node if this is an option node
|
83
|
+
def select_node
|
84
|
+
find('./ancestor::select').first
|
85
|
+
end
|
86
|
+
|
87
|
+
def type
|
88
|
+
self[:type]
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
data/lib/grid/grid.rb
ADDED
@@ -0,0 +1,283 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# grid.rb
|
3
|
+
# Grid Helper
|
4
|
+
|
5
|
+
require 'ap'
|
6
|
+
require 'watirgrid'
|
7
|
+
require 'json'
|
8
|
+
require 'rest_client'
|
9
|
+
require 'highline/import'
|
10
|
+
|
11
|
+
class Grid
|
12
|
+
|
13
|
+
def initialize(params = {})
|
14
|
+
@log = Logger.new(STDOUT, 'daily')
|
15
|
+
@log.level = params[:loglevel] || Logger::INFO
|
16
|
+
@exclusive = params[:exclusive]
|
17
|
+
@exclusive ? params[:take_all] = true : params[:read_all] = true
|
18
|
+
@webdriver_browser_type = params[:browser].to_sym if params[:browser]
|
19
|
+
@grid = Watir::Grid.new(params)
|
20
|
+
@grid.start(params)
|
21
|
+
@providers = @grid.browsers
|
22
|
+
@browsers = []
|
23
|
+
end
|
24
|
+
|
25
|
+
def size
|
26
|
+
@grid.size
|
27
|
+
end
|
28
|
+
|
29
|
+
def browsers
|
30
|
+
@browsers
|
31
|
+
end
|
32
|
+
|
33
|
+
def providers
|
34
|
+
@providers
|
35
|
+
end
|
36
|
+
|
37
|
+
def setup
|
38
|
+
@grid.browsers.each_with_index do |browser, index|
|
39
|
+
sleep 0.15
|
40
|
+
@browsers[index] ||= browser[:object].new_browser(@webdriver_browser_type)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def teardown
|
45
|
+
@browsers.each do |browser|
|
46
|
+
browser.close
|
47
|
+
end
|
48
|
+
@grid.release_tuples if @exclusive
|
49
|
+
end
|
50
|
+
|
51
|
+
def iterate &block
|
52
|
+
threads = []
|
53
|
+
@browsers.each do |browser|
|
54
|
+
threads << Thread.new do
|
55
|
+
yield browser
|
56
|
+
end
|
57
|
+
end
|
58
|
+
threads.each {|thread| thread.join}
|
59
|
+
end
|
60
|
+
|
61
|
+
def iterate_with_index &block
|
62
|
+
threads = []
|
63
|
+
@browsers.each_with_index do |browser, index|
|
64
|
+
threads << Thread.new do
|
65
|
+
yield browser, index
|
66
|
+
end
|
67
|
+
end
|
68
|
+
threads.each {|thread| thread.join}
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.control(params = {}, &block)
|
72
|
+
@exclusive = params[:exclusive]
|
73
|
+
@exclusive ? params[:take_all] = true : params[:read_all] = true
|
74
|
+
@webdriver_browser_type = params[:browser].to_sym if params[:browser]
|
75
|
+
@grid = Watir::Grid.new(params)
|
76
|
+
@grid.start(params)
|
77
|
+
@browsers = []
|
78
|
+
threads = []
|
79
|
+
@grid.browsers.each_with_index do |browser, index|
|
80
|
+
sleep rampup(params)
|
81
|
+
threads << Thread.new(@webdriver_browser_type) do |webdriver_browser_type|
|
82
|
+
@browser = browser[:object].new_browser(webdriver_browser_type)
|
83
|
+
yield @browser, index
|
84
|
+
end
|
85
|
+
end
|
86
|
+
threads.each {|thread| thread.join}
|
87
|
+
@grid.release_tuples if @exclusive
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def self.rampup(params = {})
|
93
|
+
if params[:rampup]
|
94
|
+
params[:rampup] / @grid.size
|
95
|
+
else
|
96
|
+
0.5
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class Helper
|
101
|
+
def initialize(params = {})
|
102
|
+
@grid_id = params[:grid_id]
|
103
|
+
@api = params[:api]
|
104
|
+
@uri = params[:uri] || "http://gridin.it/api/v0"
|
105
|
+
logfile = STDOUT
|
106
|
+
@log = Logger.new(logfile, 'daily')
|
107
|
+
@log.level = Logger::DEBUG
|
108
|
+
@log.datetime_format = "%Y-%m-%d %H:%M:%S "
|
109
|
+
if home
|
110
|
+
if File.file? ENV[home]+'/.gridrc'
|
111
|
+
@token = open(ENV[home]+'/.gridrc') { |f| f.read }.split(':')[1]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
@token = get_token(params) unless @token
|
115
|
+
@log.debug("Current token: #{@token}")
|
116
|
+
end
|
117
|
+
|
118
|
+
def get_password(prompt='Password: ', mask='*')
|
119
|
+
ask(prompt) { |q| q.echo = mask }
|
120
|
+
end
|
121
|
+
|
122
|
+
def get_token(params={})
|
123
|
+
if params[:token]
|
124
|
+
params[:token]
|
125
|
+
else
|
126
|
+
HighLine.track_eof = false
|
127
|
+
@email = params[:email] || ask('Email: ')
|
128
|
+
@password = params[:password] || get_password
|
129
|
+
response = RestClient.post "#{@uri}/token.json" , {
|
130
|
+
:email => @email, :password => @password
|
131
|
+
}
|
132
|
+
(JSON.parse(response))["token"]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def home
|
137
|
+
homes = ["HOME", "HOMEPATH"]
|
138
|
+
homes.detect {|h| ENV[h] != nil}
|
139
|
+
end
|
140
|
+
|
141
|
+
def token
|
142
|
+
@token = get_token
|
143
|
+
open(ENV[home]+'/.gridrc', 'w') { |f| f << "TOKEN:#{@token}" } if home and @token
|
144
|
+
@log.debug("New token : #{@token}")
|
145
|
+
end
|
146
|
+
|
147
|
+
def list
|
148
|
+
@log.debug("Listing grids ...")
|
149
|
+
begin
|
150
|
+
response = RestClient.get "#{@uri}/grid.json" , {
|
151
|
+
:token => @token
|
152
|
+
}
|
153
|
+
ap JSON.parse(response)
|
154
|
+
rescue => e
|
155
|
+
@log.error("#{e}")
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def show
|
160
|
+
@grid_id = ask("Grid ID: ") unless @grid_id
|
161
|
+
@log.debug("Listing grid ...")
|
162
|
+
begin
|
163
|
+
response = RestClient.get "#{@uri}/grid/#{@grid_id}.json" , {
|
164
|
+
:token => @token
|
165
|
+
}
|
166
|
+
ap JSON.parse(response)
|
167
|
+
rescue => e
|
168
|
+
@log.error("#{e}")
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def create_grid(name, description)
|
173
|
+
begin
|
174
|
+
@log.debug("Creating grid ...")
|
175
|
+
response = RestClient.post "#{@uri}/grid.json" , {
|
176
|
+
:token => @token,
|
177
|
+
:name => name,
|
178
|
+
:description => description
|
179
|
+
}
|
180
|
+
(JSON.parse(response)).first[1]["id"]
|
181
|
+
rescue => e
|
182
|
+
@log.error("#{e}")
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def create_intranode(grid_id, browser_type, location, nodes)
|
187
|
+
begin
|
188
|
+
@log.debug("Creating intranode ...")
|
189
|
+
response = RestClient.post "#{@uri}/grid/#{grid_id.to_s}/intranode.json", {
|
190
|
+
:token => @token,
|
191
|
+
:browser_type => browser_type,
|
192
|
+
:location => location,
|
193
|
+
:nodes => nodes
|
194
|
+
}
|
195
|
+
rescue => e
|
196
|
+
@log.error("#{e}")
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def delete_intranode
|
201
|
+
begin
|
202
|
+
@log.debug("Deleting intranode ...")
|
203
|
+
response = RestClient.delete "#{@uri}/grid/intranode/#{@intranode_id}.json", {
|
204
|
+
:token => @token
|
205
|
+
}
|
206
|
+
rescue => e
|
207
|
+
@log.error("#{e}")
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def create
|
212
|
+
name = ask("Grid name: ") { |q| q.default = "Grid" }
|
213
|
+
description = ask("Grid description: ") { |q| q.default = "Grid created #{Time.now}" }
|
214
|
+
nodes = ask("Number of nodes: ") { |q| q.default = 5 }
|
215
|
+
location = ask("Location of nodes: ") { |q| q.default = "us-east" }
|
216
|
+
browser_type = ask("Node type: ") { |q| q.default = "webdriver" } unless @api
|
217
|
+
@grid_id = create_grid(name, description)
|
218
|
+
create_intranode(@grid_id, browser_type, location, nodes)
|
219
|
+
show
|
220
|
+
end
|
221
|
+
|
222
|
+
def add
|
223
|
+
@grid_id = ask("Grid ID: ") unless @grid_id
|
224
|
+
nodes = ask("Number of nodes: ") { |q| q.default = 5 }
|
225
|
+
location = ask("Location of nodes: ") { |q| q.default = "us-east" }
|
226
|
+
browser_type = ask("Node type: ") { |q| q.default = "webdriver" } unless @api
|
227
|
+
create_intranode(@grid_id, browser_type, location, nodes)
|
228
|
+
show
|
229
|
+
end
|
230
|
+
|
231
|
+
def delete
|
232
|
+
@grid_id = ask("Grid ID: ") unless @grid_id
|
233
|
+
@intranode_id= ask("Intranode ID: ") unless @intranode_id
|
234
|
+
delete_intranode
|
235
|
+
show
|
236
|
+
end
|
237
|
+
|
238
|
+
def start
|
239
|
+
@grid_id = ask("Grid ID: ") unless @grid_id
|
240
|
+
@log.debug("Starting grid ...")
|
241
|
+
begin
|
242
|
+
response = RestClient.put "#{@uri}/grid/#{@grid_id.to_s}/start.json", {:token => @token}
|
243
|
+
rescue => e
|
244
|
+
@log.error("#{e}")
|
245
|
+
end
|
246
|
+
show
|
247
|
+
end
|
248
|
+
|
249
|
+
def stop
|
250
|
+
@grid_id = ask("Grid ID: ") unless @grid_id
|
251
|
+
@log.debug("Stopping grid ...")
|
252
|
+
begin
|
253
|
+
response = RestClient.put "#{@uri}/grid/#{@grid_id.to_s}/stop.json", {:token => @token}
|
254
|
+
rescue => e
|
255
|
+
@log.error("#{e}")
|
256
|
+
end
|
257
|
+
show
|
258
|
+
end
|
259
|
+
|
260
|
+
def restart
|
261
|
+
@grid_id = ask("Grid ID: ") unless @grid_id
|
262
|
+
@log.debug("Restarting grid ...")
|
263
|
+
begin
|
264
|
+
response = RestClient.put "#{@uri}/grid/#{@grid_id.to_s}/restart.json", {:token => @token}
|
265
|
+
rescue => e
|
266
|
+
@log.error("#{e}")
|
267
|
+
end
|
268
|
+
show
|
269
|
+
end
|
270
|
+
|
271
|
+
def status
|
272
|
+
@grid_id = ask("Grid ID: ") unless @grid_id
|
273
|
+
@log.debug("Updating status of grid ...")
|
274
|
+
begin
|
275
|
+
response = RestClient.put "#{@uri}/grid/#{@grid_id.to_s}/status.json", {:token => @token}
|
276
|
+
rescue => e
|
277
|
+
@log.error("#{e}")
|
278
|
+
end
|
279
|
+
show
|
280
|
+
end
|
281
|
+
|
282
|
+
end
|
283
|
+
end
|
data/lib/grid.rb
CHANGED
@@ -1,283 +1 @@
|
|
1
|
-
|
2
|
-
# grid.rb
|
3
|
-
# Grid Helper
|
4
|
-
|
5
|
-
require 'ap'
|
6
|
-
require 'watirgrid'
|
7
|
-
require 'json'
|
8
|
-
require 'rest_client'
|
9
|
-
require 'highline/import'
|
10
|
-
|
11
|
-
class Grid
|
12
|
-
|
13
|
-
def initialize(params = {})
|
14
|
-
@log = Logger.new(STDOUT, 'daily')
|
15
|
-
@log.level = params[:loglevel] || Logger::INFO
|
16
|
-
@exclusive = params[:exclusive]
|
17
|
-
@exclusive ? params[:take_all] = true : params[:read_all] = true
|
18
|
-
@webdriver_browser_type = params[:browser].to_sym if params[:browser]
|
19
|
-
@grid = Watir::Grid.new(params)
|
20
|
-
@grid.start(params)
|
21
|
-
@providers = @grid.browsers
|
22
|
-
@browsers = []
|
23
|
-
end
|
24
|
-
|
25
|
-
def size
|
26
|
-
@grid.size
|
27
|
-
end
|
28
|
-
|
29
|
-
def browsers
|
30
|
-
@browsers
|
31
|
-
end
|
32
|
-
|
33
|
-
def providers
|
34
|
-
@providers
|
35
|
-
end
|
36
|
-
|
37
|
-
def setup
|
38
|
-
@grid.browsers.each_with_index do |browser, index|
|
39
|
-
sleep 0.15
|
40
|
-
@browsers[index] ||= browser[:object].new_browser(@webdriver_browser_type)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def teardown
|
45
|
-
@browsers.each do |browser|
|
46
|
-
browser.close
|
47
|
-
end
|
48
|
-
@grid.release_tuples if @exclusive
|
49
|
-
end
|
50
|
-
|
51
|
-
def iterate &block
|
52
|
-
threads = []
|
53
|
-
@browsers.each do |browser|
|
54
|
-
threads << Thread.new do
|
55
|
-
yield browser
|
56
|
-
end
|
57
|
-
end
|
58
|
-
threads.each {|thread| thread.join}
|
59
|
-
end
|
60
|
-
|
61
|
-
def iterate_with_index &block
|
62
|
-
threads = []
|
63
|
-
@browsers.each_with_index do |browser, index|
|
64
|
-
threads << Thread.new do
|
65
|
-
yield browser, index
|
66
|
-
end
|
67
|
-
end
|
68
|
-
threads.each {|thread| thread.join}
|
69
|
-
end
|
70
|
-
|
71
|
-
def self.control(params = {}, &block)
|
72
|
-
@exclusive = params[:exclusive]
|
73
|
-
@exclusive ? params[:take_all] = true : params[:read_all] = true
|
74
|
-
@webdriver_browser_type = params[:browser].to_sym if params[:browser]
|
75
|
-
@grid = Watir::Grid.new(params)
|
76
|
-
@grid.start(params)
|
77
|
-
@browsers = []
|
78
|
-
threads = []
|
79
|
-
@grid.browsers.each_with_index do |browser, index|
|
80
|
-
sleep rampup(params)
|
81
|
-
threads << Thread.new(@webdriver_browser_type) do |webdriver_browser_type|
|
82
|
-
@browser = browser[:object].new_browser(webdriver_browser_type)
|
83
|
-
yield @browser, index
|
84
|
-
end
|
85
|
-
end
|
86
|
-
threads.each {|thread| thread.join}
|
87
|
-
@grid.release_tuples if @exclusive
|
88
|
-
end
|
89
|
-
|
90
|
-
private
|
91
|
-
|
92
|
-
def self.rampup(params = {})
|
93
|
-
if params[:rampup]
|
94
|
-
params[:rampup] / @grid.size
|
95
|
-
else
|
96
|
-
0.5
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
class Helper
|
101
|
-
def initialize(params = {})
|
102
|
-
@grid_id = params[:grid_id]
|
103
|
-
@api = params[:api]
|
104
|
-
@uri = params[:uri] || "http://gridin.it/api/v0"
|
105
|
-
logfile = STDOUT
|
106
|
-
@log = Logger.new(logfile, 'daily')
|
107
|
-
@log.level = Logger::DEBUG
|
108
|
-
@log.datetime_format = "%Y-%m-%d %H:%M:%S "
|
109
|
-
if home
|
110
|
-
if File.file? ENV[home]+'/.gridrc'
|
111
|
-
@token = open(ENV[home]+'/.gridrc') { |f| f.read }.split(':')[1]
|
112
|
-
end
|
113
|
-
end
|
114
|
-
@token = get_token(params) unless @token
|
115
|
-
@log.debug("Current token: #{@token}")
|
116
|
-
end
|
117
|
-
|
118
|
-
def get_password(prompt='Password: ', mask='*')
|
119
|
-
ask(prompt) { |q| q.echo = mask }
|
120
|
-
end
|
121
|
-
|
122
|
-
def get_token(params={})
|
123
|
-
if params[:token]
|
124
|
-
params[:token]
|
125
|
-
else
|
126
|
-
HighLine.track_eof = false
|
127
|
-
@email = params[:email] || ask('Email: ')
|
128
|
-
@password = params[:password] || get_password
|
129
|
-
response = RestClient.post "#{@uri}/token.json" , {
|
130
|
-
:email => @email, :password => @password
|
131
|
-
}
|
132
|
-
(JSON.parse(response))["token"]
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def home
|
137
|
-
homes = ["HOME", "HOMEPATH"]
|
138
|
-
homes.detect {|h| ENV[h] != nil}
|
139
|
-
end
|
140
|
-
|
141
|
-
def token
|
142
|
-
@token = get_token
|
143
|
-
open(ENV[home]+'/.gridrc', 'w') { |f| f << "TOKEN:#{@token}" } if home and @token
|
144
|
-
@log.debug("New token : #{@token}")
|
145
|
-
end
|
146
|
-
|
147
|
-
def list
|
148
|
-
@log.debug("Listing grids ...")
|
149
|
-
begin
|
150
|
-
response = RestClient.get "#{@uri}/grid.json" , {
|
151
|
-
:token => @token
|
152
|
-
}
|
153
|
-
ap JSON.parse(response)
|
154
|
-
rescue => e
|
155
|
-
@log.error("#{e}")
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
def show
|
160
|
-
@grid_id = ask("Grid ID: ") unless @grid_id
|
161
|
-
@log.debug("Listing grid ...")
|
162
|
-
begin
|
163
|
-
response = RestClient.get "#{@uri}/grid/#{@grid_id}.json" , {
|
164
|
-
:token => @token
|
165
|
-
}
|
166
|
-
ap JSON.parse(response)
|
167
|
-
rescue => e
|
168
|
-
@log.error("#{e}")
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
def create_grid(name, description)
|
173
|
-
begin
|
174
|
-
@log.debug("Creating grid ...")
|
175
|
-
response = RestClient.post "#{@uri}/grid.json" , {
|
176
|
-
:token => @token,
|
177
|
-
:name => name,
|
178
|
-
:description => description
|
179
|
-
}
|
180
|
-
(JSON.parse(response)).first[1]["id"]
|
181
|
-
rescue => e
|
182
|
-
@log.error("#{e}")
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
def create_intranode(grid_id, browser_type, location, nodes)
|
187
|
-
begin
|
188
|
-
@log.debug("Creating intranode ...")
|
189
|
-
response = RestClient.post "#{@uri}/grid/#{grid_id.to_s}/intranode.json", {
|
190
|
-
:token => @token,
|
191
|
-
:browser_type => browser_type,
|
192
|
-
:location => location,
|
193
|
-
:nodes => nodes
|
194
|
-
}
|
195
|
-
rescue => e
|
196
|
-
@log.error("#{e}")
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
def delete_intranode
|
201
|
-
begin
|
202
|
-
@log.debug("Deleting intranode ...")
|
203
|
-
response = RestClient.delete "#{@uri}/grid/intranode/#{@intranode_id}.json", {
|
204
|
-
:token => @token
|
205
|
-
}
|
206
|
-
rescue => e
|
207
|
-
@log.error("#{e}")
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
def create
|
212
|
-
name = ask("Grid name: ") { |q| q.default = "Grid" }
|
213
|
-
description = ask("Grid description: ") { |q| q.default = "Grid created #{Time.now}" }
|
214
|
-
nodes = ask("Number of nodes: ") { |q| q.default = 5 }
|
215
|
-
location = ask("Location of nodes: ") { |q| q.default = "us-east" }
|
216
|
-
browser_type = ask("Node type: ") { |q| q.default = "webdriver" } unless @api
|
217
|
-
@grid_id = create_grid(name, description)
|
218
|
-
create_intranode(@grid_id, browser_type, location, nodes)
|
219
|
-
show
|
220
|
-
end
|
221
|
-
|
222
|
-
def add
|
223
|
-
@grid_id = ask("Grid ID: ") unless @grid_id
|
224
|
-
nodes = ask("Number of nodes: ") { |q| q.default = 5 }
|
225
|
-
location = ask("Location of nodes: ") { |q| q.default = "us-east" }
|
226
|
-
browser_type = ask("Node type: ") { |q| q.default = "webdriver" } unless @api
|
227
|
-
create_intranode(@grid_id, browser_type, location, nodes)
|
228
|
-
show
|
229
|
-
end
|
230
|
-
|
231
|
-
def delete
|
232
|
-
@grid_id = ask("Grid ID: ") unless @grid_id
|
233
|
-
@intranode_id= ask("Intranode ID: ") unless @intranode_id
|
234
|
-
delete_intranode
|
235
|
-
show
|
236
|
-
end
|
237
|
-
|
238
|
-
def start
|
239
|
-
@grid_id = ask("Grid ID: ") unless @grid_id
|
240
|
-
@log.debug("Starting grid ...")
|
241
|
-
begin
|
242
|
-
response = RestClient.put "#{@uri}/grid/#{@grid_id.to_s}/start.json", {:token => @token}
|
243
|
-
rescue => e
|
244
|
-
@log.error("#{e}")
|
245
|
-
end
|
246
|
-
show
|
247
|
-
end
|
248
|
-
|
249
|
-
def stop
|
250
|
-
@grid_id = ask("Grid ID: ") unless @grid_id
|
251
|
-
@log.debug("Stopping grid ...")
|
252
|
-
begin
|
253
|
-
response = RestClient.put "#{@uri}/grid/#{@grid_id.to_s}/stop.json", {:token => @token}
|
254
|
-
rescue => e
|
255
|
-
@log.error("#{e}")
|
256
|
-
end
|
257
|
-
show
|
258
|
-
end
|
259
|
-
|
260
|
-
def restart
|
261
|
-
@grid_id = ask("Grid ID: ") unless @grid_id
|
262
|
-
@log.debug("Restarting grid ...")
|
263
|
-
begin
|
264
|
-
response = RestClient.put "#{@uri}/grid/#{@grid_id.to_s}/restart.json", {:token => @token}
|
265
|
-
rescue => e
|
266
|
-
@log.error("#{e}")
|
267
|
-
end
|
268
|
-
show
|
269
|
-
end
|
270
|
-
|
271
|
-
def status
|
272
|
-
@grid_id = ask("Grid ID: ") unless @grid_id
|
273
|
-
@log.debug("Updating status of grid ...")
|
274
|
-
begin
|
275
|
-
response = RestClient.put "#{@uri}/grid/#{@grid_id.to_s}/status.json", {:token => @token}
|
276
|
-
rescue => e
|
277
|
-
@log.error("#{e}")
|
278
|
-
end
|
279
|
-
show
|
280
|
-
end
|
281
|
-
|
282
|
-
end
|
283
|
-
end
|
1
|
+
require 'grid/grid'
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 0.4.
|
9
|
+
- 2
|
10
|
+
version: 0.4.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tim Koopmans
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-04-
|
18
|
+
date: 2011-04-26 00:00:00 +10:00
|
19
19
|
default_executable: grid
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -253,12 +253,21 @@ files:
|
|
253
253
|
- Rakefile
|
254
254
|
- VERSION
|
255
255
|
- bin/grid
|
256
|
+
- examples/bacon/bacon.rb
|
256
257
|
- examples/basic/basic.rb
|
258
|
+
- examples/basic/selenium/selenium.rb
|
259
|
+
- examples/capybara/testunit/example_test.rb
|
257
260
|
- examples/cucumber/example.feature
|
258
261
|
- examples/cucumber/step_definitions/.DS_Store
|
259
262
|
- examples/cucumber/step_definitions/example_steps.rb
|
263
|
+
- examples/rspec/basic_spec.rb
|
264
|
+
- examples/testunit/basic_test.rb
|
260
265
|
- grid.gemspec
|
261
266
|
- lib/grid.rb
|
267
|
+
- lib/grid/extensions/capybara.rb
|
268
|
+
- lib/grid/extensions/capybara/driver.rb
|
269
|
+
- lib/grid/extensions/capybara/node.rb
|
270
|
+
- lib/grid/grid.rb
|
262
271
|
- spec/grid_spec.rb
|
263
272
|
- spec/spec_helper.rb
|
264
273
|
has_rdoc: true
|
@@ -296,7 +305,12 @@ signing_key:
|
|
296
305
|
specification_version: 3
|
297
306
|
summary: Gridinit command line utilities
|
298
307
|
test_files:
|
308
|
+
- examples/bacon/bacon.rb
|
299
309
|
- examples/basic/basic.rb
|
310
|
+
- examples/basic/selenium/selenium.rb
|
311
|
+
- examples/capybara/testunit/example_test.rb
|
300
312
|
- examples/cucumber/step_definitions/example_steps.rb
|
313
|
+
- examples/rspec/basic_spec.rb
|
314
|
+
- examples/testunit/basic_test.rb
|
301
315
|
- spec/grid_spec.rb
|
302
316
|
- spec/spec_helper.rb
|