grid 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|