aaet 0.1.0
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.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +145 -0
- data/LICENSE +201 -0
- data/README.md +177 -0
- data/Rakefile +6 -0
- data/aaet.gemspec +51 -0
- data/bin/aaet +143 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/generate_reports.rb +512 -0
- data/lib/aaet.rb +43 -0
- data/lib/aaet/android/android.rb +190 -0
- data/lib/aaet/android/parser.rb +76 -0
- data/lib/aaet/common/applitools.rb +41 -0
- data/lib/aaet/common/common_methods.rb +646 -0
- data/lib/aaet/common/locators.rb +180 -0
- data/lib/aaet/common/redis.rb +108 -0
- data/lib/aaet/ios/ios.rb +18 -0
- data/lib/aaet/ios/parser.rb +1 -0
- data/lib/version.rb +3 -0
- data/run.rb +294 -0
- data/setup/android_setup_methods.rb +161 -0
- data/setup/common_setup_methods.rb +209 -0
- data/setup/ios_setup_methods.rb +11 -0
- data/template_google_api_format.haml +48 -0
- metadata +354 -0
@@ -0,0 +1,180 @@
|
|
1
|
+
module Aaet
|
2
|
+
class Locators
|
3
|
+
|
4
|
+
def activity
|
5
|
+
count = 0
|
6
|
+
begin
|
7
|
+
JSON.parse(`curl -s #{caps_url}/session/#{driver.session_id}/appium/device/current_activity`)['value']
|
8
|
+
rescue
|
9
|
+
count+=1
|
10
|
+
return if count > 3
|
11
|
+
retry
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_center(element)
|
16
|
+
location = element.location
|
17
|
+
location_x = location.x.to_f
|
18
|
+
location_y = location.y.to_f
|
19
|
+
size = element.size
|
20
|
+
size_width = size.width.to_f
|
21
|
+
size_height = size.height.to_f
|
22
|
+
x = location_x + (size_width / 2.0)
|
23
|
+
y = location_y + (size_height / 2.0)
|
24
|
+
{x: x, y: y}
|
25
|
+
end
|
26
|
+
|
27
|
+
def element_center(location, size)
|
28
|
+
location_x = location.x.to_f
|
29
|
+
location_y = location.y.to_f
|
30
|
+
size_width = size.width.to_f
|
31
|
+
size_height = size.height.to_f
|
32
|
+
x = location_x + (size_width / 2.0)
|
33
|
+
y = location_y + (size_height / 2.0)
|
34
|
+
{x: x, y: y}
|
35
|
+
end
|
36
|
+
|
37
|
+
def long_press element
|
38
|
+
center = get_center(element)
|
39
|
+
center.merge!(fingers: 1, duration: 550)
|
40
|
+
action = Appium::TouchAction.new.long_press center
|
41
|
+
action.release.perform
|
42
|
+
end
|
43
|
+
|
44
|
+
def press coords
|
45
|
+
coords.merge!(fingers: 1, duration: 550)
|
46
|
+
action = Appium::TouchAction.new.long_press coords
|
47
|
+
begin action.release.perform rescue nil end
|
48
|
+
end
|
49
|
+
|
50
|
+
def tap args = {}
|
51
|
+
begin
|
52
|
+
Appium::TouchAction.new.tap(args).release.perform
|
53
|
+
rescue
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def tap2 coords
|
59
|
+
begin
|
60
|
+
Appium::TouchAction.new.tap(coords).release.perform
|
61
|
+
rescue
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def random_tap
|
67
|
+
x = rand(0..@window_size[0])
|
68
|
+
y = rand(0..@window_size[1])
|
69
|
+
puts "\nRandom Tap Location: { x: #{x}, y: #{y} }\n".yellow
|
70
|
+
tap({:x=>x, :y=>y})
|
71
|
+
end
|
72
|
+
|
73
|
+
def pull_to_refresh
|
74
|
+
size = get_window_size
|
75
|
+
start_x = size[:width] / 2
|
76
|
+
start_y = size[:height] / 2
|
77
|
+
end_x = size[:width] / 2
|
78
|
+
end_y = size[:height] - 100
|
79
|
+
Appium::TouchAction.new.press({x:start_x,y:start_y}).wait(200).move_to({x:end_x,y:end_y}).release.perform
|
80
|
+
end
|
81
|
+
|
82
|
+
def get_window_size
|
83
|
+
window_size.to_h
|
84
|
+
end
|
85
|
+
|
86
|
+
def swipe_down
|
87
|
+
size = @window_size
|
88
|
+
start_x = size[0] / 2
|
89
|
+
start_y = size[1] / 2
|
90
|
+
end_x = size[0] / 2
|
91
|
+
end_y = size[1] - 200
|
92
|
+
Appium::TouchAction.new.press({x:start_x,y:start_y}).wait(200).move_to({x:end_x,y:end_y}).release.perform
|
93
|
+
end
|
94
|
+
|
95
|
+
def swipe_up
|
96
|
+
size = @window_size
|
97
|
+
start_x = size[0] / 2
|
98
|
+
start_y = size[1] / 2
|
99
|
+
end_x = size[0] / 2
|
100
|
+
end_y = 100
|
101
|
+
Appium::TouchAction.new.press({x:start_x,y:start_y}).wait(200).move_to({x:end_x,y:end_y}).release.perform
|
102
|
+
end
|
103
|
+
|
104
|
+
def swipe_left
|
105
|
+
size = @window_size
|
106
|
+
start_x = (size[0] - 60).to_f
|
107
|
+
start_y = (size[1] / 2).to_f
|
108
|
+
end_x = 60.to_f
|
109
|
+
end_y = (size[1] / 2).to_f
|
110
|
+
Appium::TouchAction.new.press({x:start_x,y:start_y}).wait(200).move_to({x:end_x,y:end_y}).release.perform
|
111
|
+
#swipe({start_x:63,end_y:326})
|
112
|
+
end
|
113
|
+
|
114
|
+
def swipe_right
|
115
|
+
size = @window_size
|
116
|
+
start_x = 60.to_f
|
117
|
+
start_y = (size[1] / 2).to_f
|
118
|
+
end_x = (size[0] - 60).to_f
|
119
|
+
end_y = (size[1] / 2).to_f
|
120
|
+
Appium::TouchAction.new.press({x:start_x,y:start_y}).wait(200).move_to({x:end_x,y:end_y}).release.perform
|
121
|
+
end
|
122
|
+
|
123
|
+
def fe locator
|
124
|
+
begin
|
125
|
+
find_element(locator)
|
126
|
+
rescue
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def fa locator
|
132
|
+
begin
|
133
|
+
find_elements(locator)
|
134
|
+
rescue
|
135
|
+
[]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def get_text string
|
140
|
+
begin
|
141
|
+
text string
|
142
|
+
rescue
|
143
|
+
nil
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def displayed? locator
|
148
|
+
begin
|
149
|
+
fe(locator).displayed?
|
150
|
+
rescue
|
151
|
+
false
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def click locator, *optional
|
156
|
+
begin
|
157
|
+
locator.click
|
158
|
+
rescue
|
159
|
+
nil
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def type string
|
164
|
+
begin
|
165
|
+
driver.keyboard.send_keys string
|
166
|
+
rescue
|
167
|
+
nil
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
###For Login Method
|
172
|
+
def enter locator, string
|
173
|
+
begin
|
174
|
+
locator.send_keys string
|
175
|
+
rescue
|
176
|
+
nil
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Aaet
|
2
|
+
class Redis
|
3
|
+
|
4
|
+
attr_accessor :redis, :process
|
5
|
+
|
6
|
+
def initialize process
|
7
|
+
self.redis = Redic.new
|
8
|
+
self.process = process
|
9
|
+
update_list("crashed", false)
|
10
|
+
end
|
11
|
+
|
12
|
+
def del_list list
|
13
|
+
redis.call "DEL", "#{list}-#{process}" rescue nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def update_applitools list, body
|
17
|
+
redis.call "LPUSH", list, JSON.generate(body)
|
18
|
+
end
|
19
|
+
|
20
|
+
def update_list list, body
|
21
|
+
redis.call "LPUSH", "#{list}-#{process}", JSON.generate(body)
|
22
|
+
end
|
23
|
+
|
24
|
+
def activity_exists? act
|
25
|
+
activities.any? { |a| a.include? act }
|
26
|
+
end
|
27
|
+
|
28
|
+
def remove_activity activity
|
29
|
+
redis.call "LREM", "activities", -1, activity
|
30
|
+
end
|
31
|
+
|
32
|
+
def activities
|
33
|
+
redis.call("LRANGE", "activities", 0, -1)
|
34
|
+
end
|
35
|
+
|
36
|
+
def found_activities
|
37
|
+
redis.call("LRANGE", "found_activities-#{process}", 0, -1)
|
38
|
+
end
|
39
|
+
|
40
|
+
def found_activity_exists? act
|
41
|
+
found_activities.any? { |a| a.include? act }
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_found_activity act
|
45
|
+
redis.call "LPUSH", "found_activities-#{process}", act
|
46
|
+
end
|
47
|
+
|
48
|
+
def update_activity_count act
|
49
|
+
unless found_activity_exists? act
|
50
|
+
checkmark = "\u2713"
|
51
|
+
puts ""
|
52
|
+
puts "\nNew Activity Found! #{checkmark}".green
|
53
|
+
add_found_activity act
|
54
|
+
remaining = (activities.count - found_activities.count)
|
55
|
+
puts "Remaining Activities: #{remaining}\n"
|
56
|
+
puts ""
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_list list
|
61
|
+
redis_list = redis.call("LRANGE", "#{list}-#{process}", 0, -1).map { |x| JSON.parse(x) }.uniq.flatten rescue []
|
62
|
+
unless redis_list.empty?
|
63
|
+
redis_list = symbolize(redis_list)
|
64
|
+
end
|
65
|
+
redis_list
|
66
|
+
end
|
67
|
+
|
68
|
+
def symbolize(obj)
|
69
|
+
return obj.reduce({}) do |memo, (k, v)|
|
70
|
+
memo.tap { |m| m[k.to_sym] = symbolize(v) }
|
71
|
+
end if obj.is_a? Hash
|
72
|
+
|
73
|
+
return obj.reduce([]) do |memo, v|
|
74
|
+
memo << symbolize(v); memo
|
75
|
+
end if obj.is_a? Array
|
76
|
+
|
77
|
+
obj
|
78
|
+
end
|
79
|
+
|
80
|
+
def list_includes_value list, value
|
81
|
+
redis.call("LRANGE", "#{list}-#{process}", 0, -1).any? { |a| a.include? value }
|
82
|
+
end
|
83
|
+
|
84
|
+
def list_includes_applitools_value list, value
|
85
|
+
redis.call("LRANGE", list, 0, -1).any? { |a| a.include? value }
|
86
|
+
end
|
87
|
+
|
88
|
+
def app_crashed boolean
|
89
|
+
redis.call "LPUSH", "crashed-#{process}", boolean
|
90
|
+
end
|
91
|
+
|
92
|
+
def lpop list
|
93
|
+
redis.call "LPOP", "#{list}-#{process}"
|
94
|
+
end
|
95
|
+
|
96
|
+
def hincr(key, field)
|
97
|
+
redis.call("HINCRBY", "#{key}-#{process}", field, 1)
|
98
|
+
end
|
99
|
+
|
100
|
+
def hset(key, field, value)
|
101
|
+
redis.call("HSET", "#{key}-#{process}", field, value)
|
102
|
+
end
|
103
|
+
|
104
|
+
def hget(key, field)
|
105
|
+
redis.call("HGET", "#{key}-#{process}", field)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/lib/aaet/ios/ios.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#iOS Placeholder
|
2
|
+
module Aaet
|
3
|
+
class Ios
|
4
|
+
|
5
|
+
# include Appium::Ios
|
6
|
+
# include Appium::Common
|
7
|
+
# include Appium::Device
|
8
|
+
|
9
|
+
def keyboard_open?
|
10
|
+
begin
|
11
|
+
#driver.driver.manage.timeouts.implicit_wait = 0.1
|
12
|
+
fe({xpath: '//UIAKeyboard'}).displayed?
|
13
|
+
rescue Selenium::WebDriver::Error::NoSuchElementError
|
14
|
+
false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
#iOS Placeholder
|
data/lib/version.rb
ADDED
data/run.rb
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
require_relative 'lib/aaet'
|
2
|
+
require 'parallel'
|
3
|
+
require_relative 'generate_reports'
|
4
|
+
require_relative 'setup/common_setup_methods'
|
5
|
+
require_relative "setup/android_setup_methods"
|
6
|
+
require_relative "setup/ios_setup_methods"
|
7
|
+
require 'pry'
|
8
|
+
require 'uri'
|
9
|
+
|
10
|
+
class Executer < ReportBuilder
|
11
|
+
|
12
|
+
attr_accessor :program_opts, :appium_reset, :platform_setup, :appium_arg, :uuid_arg, :setup
|
13
|
+
attr_writer :run
|
14
|
+
|
15
|
+
def initialize settings
|
16
|
+
self.program_opts = settings
|
17
|
+
generate_instance_variables nil, settings
|
18
|
+
if caps_platform == 'android'
|
19
|
+
self.platform_setup = AndroidSetup.new settings
|
20
|
+
avd = caps_avd rescue nil
|
21
|
+
uuid = caps_udid rescue nil
|
22
|
+
if avd
|
23
|
+
platform_setup.check_emulator caps_avd
|
24
|
+
self.appium_arg = "--avd #{caps_avd}"
|
25
|
+
elsif uuid
|
26
|
+
platform_setup.check_uuid caps_udid
|
27
|
+
self.appium_arg = "--udid #{caps_udid}"
|
28
|
+
end
|
29
|
+
elsif caps_platform == 'ios'
|
30
|
+
#placeholder for iOS
|
31
|
+
self.platform_setup = IosSetup.new settings
|
32
|
+
end
|
33
|
+
|
34
|
+
if options[:resetAppium]
|
35
|
+
self.appium_reset = nil
|
36
|
+
else
|
37
|
+
self.appium_reset = '--no-reset'
|
38
|
+
end
|
39
|
+
|
40
|
+
if options_debug
|
41
|
+
self.instance_variables.each { |var| puts "#{var}: #{self.instance_variable_get(var)}" }
|
42
|
+
end
|
43
|
+
self.setup = CommonSetup.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def generate_instance_variables(parent, hash)
|
47
|
+
#turn options/settings nested hash into instance variables
|
48
|
+
hash.each do |key, value|
|
49
|
+
if value.is_a?(Hash)
|
50
|
+
generate_instance_variables(key, value)
|
51
|
+
self.class.send(:attr_accessor, key.to_sym)
|
52
|
+
self.instance_variable_set("@#{key}", value)
|
53
|
+
else
|
54
|
+
if parent.nil?
|
55
|
+
self.class.send(:attr_accessor, "#{key}".to_sym)
|
56
|
+
self.instance_variable_set("@#{key}", value)
|
57
|
+
else
|
58
|
+
self.class.send(:attr_accessor, "#{parent}_#{key}".to_sym)
|
59
|
+
self.instance_variable_set("@#{parent}_#{key}", value)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def driver_alive?
|
66
|
+
@run.current_activity["message"] != "A session is either terminated or not started"
|
67
|
+
end
|
68
|
+
|
69
|
+
def kill_everything
|
70
|
+
if caps_platform == "android" and !options_cloud
|
71
|
+
Process.kill("HUP", program_opts[:logcat_pid])
|
72
|
+
#binding.pry
|
73
|
+
setup.kill_processes "'#{@uuid} logcat'"
|
74
|
+
%x(adb -s #{@uuid} shell settings put global policy_control null*) #put status bar back...
|
75
|
+
system("adb -s #{@uuid} emu kill") if options_emulator and !options_keepEmulatorAlive
|
76
|
+
sleep 1
|
77
|
+
end
|
78
|
+
driver.quit rescue nil
|
79
|
+
unless options_cloud
|
80
|
+
pid = Process.getpgid(Process.pid)
|
81
|
+
Signal.trap('TERM') { Process.kill('TERM', -pid); exit }
|
82
|
+
Signal.trap('INT' ) { Process.kill('INT', -pid); exit }
|
83
|
+
Process.kill("HUP", program_opts[:appium_pid])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def runner time
|
88
|
+
require 'timeout'
|
89
|
+
begin
|
90
|
+
Timeout.timeout(time) { go }
|
91
|
+
rescue Timeout::Error
|
92
|
+
puts "\n#{time} Seconds Exceeded!!!\nKilling Driver for #{@uuid}...".red
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def force_device_orientation(orientation)
|
97
|
+
desired_orientation = orientation.downcase.to_sym
|
98
|
+
begin
|
99
|
+
if desired_orientation != driver.orientation.to_sym
|
100
|
+
puts "Current orientation: #{driver.orientation.to_sym}"
|
101
|
+
puts "Setting device to orientation: #{desired_orientation}"
|
102
|
+
driver.rotate desired_orientation
|
103
|
+
end
|
104
|
+
rescue
|
105
|
+
puts "\n#{@uuid}: Cannot rotate device to desired orientation: #{desired_orientation}".red
|
106
|
+
puts "Keeping Current orientation: #{driver.orientation}\n".yellow
|
107
|
+
end
|
108
|
+
driver.orientation.to_s.upcase
|
109
|
+
end
|
110
|
+
|
111
|
+
def initialize_driver
|
112
|
+
if options_cloud #only do once for crawler, reply will have these settings already.
|
113
|
+
local_app_path = caps[:caps][:app]
|
114
|
+
caps[:caps][:app] = caps_cloud_app
|
115
|
+
if ["crawler", "monkey"].include? options[:mode]
|
116
|
+
cloud_url = caps[:appium_lib][:server_url].insert(7, "#{cloud_user}:#{cloud_key}")
|
117
|
+
caps[:caps][:url] = cloud_url
|
118
|
+
caps[:appium_lib][:server_url] = cloud_url
|
119
|
+
end
|
120
|
+
else
|
121
|
+
old_url = URI(caps[:caps][:url])
|
122
|
+
old_port = old_url.port.to_s
|
123
|
+
new_url = old_url.to_s.gsub(old_port, program_opts[:appium_port].to_s) #replace port with parallel process port
|
124
|
+
caps[:caps][:url] = new_url
|
125
|
+
caps[:appium_lib][:server_url] = new_url
|
126
|
+
end
|
127
|
+
Appium::Driver.new(caps, true).start_driver
|
128
|
+
Appium.promote_appium_methods Object
|
129
|
+
caps[:caps][:app] = local_app_path if options_cloud #set app back to local app file for activity parsing later...
|
130
|
+
sleep 5
|
131
|
+
#update program data...
|
132
|
+
@uuid = driver.capabilities["deviceUDID"]
|
133
|
+
caps[:caps][:udid] = @uuid
|
134
|
+
program_opts[:app_and_device_data] = platform_setup.app_and_device_data @uuid
|
135
|
+
@resolution = driver.capabilities["deviceScreenSize"]
|
136
|
+
program_opts[:app_and_device_data][:device][:resolution] = @resolution
|
137
|
+
program_opts[:app_and_device_data][:activities] = program_opts[:activities] #will need to figure out how to parse iOS activities
|
138
|
+
end
|
139
|
+
|
140
|
+
def generate_output_dir
|
141
|
+
dir_array = [
|
142
|
+
run_time,
|
143
|
+
"#{program_opts[:app_and_device_data][:app_package]}-v#{program_opts[:app_and_device_data][:app_version]}",
|
144
|
+
@resolution,
|
145
|
+
"#{@uuid}-#{process}",
|
146
|
+
program_opts[:app_and_device_data][:device][:os],
|
147
|
+
caps_language,
|
148
|
+
@orientation
|
149
|
+
]
|
150
|
+
dir = setup.create_directories dir_array
|
151
|
+
program_opts[:output_dir] = dir
|
152
|
+
end
|
153
|
+
|
154
|
+
def go
|
155
|
+
unless options_cloud
|
156
|
+
appium_info = setup.start_appium_server(program_opts[:process], appium_reset, appium_arg, run_time)
|
157
|
+
program_opts[:appium_pid] = appium_info[:appium_pid]
|
158
|
+
program_opts[:appium_port] = appium_info[:appium_port]
|
159
|
+
program_opts[:appium_log] = appium_info[:appium_log]
|
160
|
+
end
|
161
|
+
initialize_driver
|
162
|
+
caps[:caps][:desired_orientation] = caps[:caps][:orientation] #set this ignored capabilitiy for reporting later...
|
163
|
+
@orientation = force_device_orientation(caps[:caps][:orientation]) #setting in caps does not always change orientation so I'm forcing it...
|
164
|
+
options[:orientation] = @orientation
|
165
|
+
caps[:caps][:orientation] = @orientation
|
166
|
+
generate_output_dir
|
167
|
+
@run = Aaet::Runner.new program_opts
|
168
|
+
unless options_cloud
|
169
|
+
if caps_platform == 'android'
|
170
|
+
program_opts[:logcat_pid] = @run.monitor_log_start
|
171
|
+
elsif caps_platform == 'ios'
|
172
|
+
#placeholder for iOS
|
173
|
+
#TODO: do something with iOS...
|
174
|
+
end
|
175
|
+
end
|
176
|
+
begin
|
177
|
+
if ["crawler", "monkey"].include? options_mode
|
178
|
+
loop { @run.instance_eval(options_mode) }
|
179
|
+
else
|
180
|
+
@run.instance_eval(options_mode)
|
181
|
+
end
|
182
|
+
rescue Interrupt
|
183
|
+
puts "\nGot Interrupted. Stopping...".red
|
184
|
+
ensure
|
185
|
+
kill_everything
|
186
|
+
if options_mode == "crawler"
|
187
|
+
ReportBuilder.new(options_translate, process, program_opts).generate_reports
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def crawler options
|
194
|
+
setup = CommonSetup.new
|
195
|
+
setup.prep_environment
|
196
|
+
settings = setup.format_options options
|
197
|
+
settings[:run_time] = Time.now.strftime("%Y.%m.%d.%H.%M")
|
198
|
+
output_dir_base = setup.create_output_directory "output", settings[:run_time]
|
199
|
+
settings[:output_dir_base] = output_dir_base
|
200
|
+
|
201
|
+
if options[:applitools] and settings[:config][:applitools][0][:key].empty?
|
202
|
+
if ENV['APPLITOOLS_API_KEY'].nil?
|
203
|
+
puts "\nYou must provide and Applitools Key in the config file or add APPLITOOLS_API_KEY environment variable\n".red
|
204
|
+
abort
|
205
|
+
else
|
206
|
+
settings[:config][:applitools][0][:key] = ENV['APPLITOOLS_API_KEY']
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
#TODO: https://github.com/celluloid/celluloid #maybe look into replacing parallel gem with this...
|
211
|
+
Parallel.each(settings[:caps], in_processes: settings[:caps].count, interrupt_signal: 'TERM') do |caps|
|
212
|
+
settings[:process] = Parallel.worker_number #set the current process running...
|
213
|
+
settings[:config][:caps] = caps
|
214
|
+
if settings[:options][:bothOrientations] and settings[:caps].count > 1
|
215
|
+
if settings[:process].even?
|
216
|
+
settings[:config][:caps][:caps][:orientation] = "PORTRAIT"
|
217
|
+
else
|
218
|
+
settings[:config][:caps][:caps][:orientation] = "LANDSCAPE"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
settings.delete :caps
|
222
|
+
puts "Testing Languages: #{settings[:options][:language]}"
|
223
|
+
settings[:options][:language].shuffle.each do |language|
|
224
|
+
puts "Running Language: #{language}"
|
225
|
+
settings[:config][:caps][:caps][:language] = language
|
226
|
+
Executer.new(settings).runner(settings[:options][:seconds])
|
227
|
+
puts "Finished language: #{language}\n"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def monkey options
|
233
|
+
setup = CommonSetup.new
|
234
|
+
setup.prep_environment
|
235
|
+
settings = setup.format_options options
|
236
|
+
settings[:run_time] = Time.now.strftime("%Y.%m.%d.%H.%M")
|
237
|
+
output_dir_base = setup.create_output_directory "output", settings[:run_time]
|
238
|
+
settings[:output_dir_base] = output_dir_base
|
239
|
+
|
240
|
+
Parallel.each(settings[:caps], in_processes: settings[:caps].count, interrupt_signal: 'TERM') do |caps|
|
241
|
+
settings[:process] = Parallel.worker_number #set the current process running...
|
242
|
+
settings[:config][:caps] = caps
|
243
|
+
if settings[:options][:bothOrientations] and settings[:caps].count > 1
|
244
|
+
if settings[:process].even?
|
245
|
+
settings[:config][:caps][:caps][:orientation] = "PORTRAIT"
|
246
|
+
else
|
247
|
+
settings[:config][:caps][:caps][:orientation] = "LANDSCAPE"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
settings.delete :caps
|
251
|
+
settings[:config][:caps][:caps][:language] = settings[:options][:language]
|
252
|
+
Executer.new(settings).runner(settings[:options][:seconds])
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def replay options
|
257
|
+
puts "\nREPLAY Mode is Experimental. Not 100% to work every time...\n".yellow
|
258
|
+
#TODO: create a report with images highlighting each step clicked with ImageMagik in case replay does not work.
|
259
|
+
|
260
|
+
setup = CommonSetup.new
|
261
|
+
setup.prep_environment
|
262
|
+
|
263
|
+
config = TomlRB.load_file(options[:config], symbolize_keys: true)
|
264
|
+
package_name = config[:caps][:appPackage]
|
265
|
+
file = setup.select_run(package_name)
|
266
|
+
last_run = setup.symbolize(eval(open(file).read))
|
267
|
+
|
268
|
+
if options[:applitools] and last_run[:options][:config][:applitools][0][:key].empty?
|
269
|
+
if ENV['APPLITOOLS_API_KEY'].nil?
|
270
|
+
puts "\nYou must provide and Applitools Key in the config file or add APPLITOOLS_API_KEY environment variable\n".red
|
271
|
+
abort
|
272
|
+
else
|
273
|
+
settings[:config][:applitools][0][:key] = ENV['APPLITOOLS_API_KEY']
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
#override last crawl run options with current replay options.
|
278
|
+
options.each { |k,v| last_run[:options][:options][k] = v }
|
279
|
+
|
280
|
+
setup.load_activities last_run[:activities]
|
281
|
+
|
282
|
+
settings = {
|
283
|
+
activities: last_run[:activities],
|
284
|
+
options: last_run[:options][:options],
|
285
|
+
config: last_run[:options][:config]
|
286
|
+
}
|
287
|
+
settings[:run_time] = Time.now.strftime("%Y.%m.%d.%H.%M")
|
288
|
+
output_dir_base = setup.create_output_directory "output", settings[:run_time]
|
289
|
+
settings[:output_dir_base] = output_dir_base
|
290
|
+
settings[:last_run_steps] = last_run[:data]
|
291
|
+
settings[:process] = 0
|
292
|
+
|
293
|
+
Executer.new(settings).runner(settings[:options][:seconds])
|
294
|
+
end
|