optimus-runner 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: '049b2ebd68e2b3b5f6f65b7a3220d555eda5c4a3'
4
+ data.tar.gz: 0d535587105a8096123b39b2cba2c108dedde3ec
5
+ SHA512:
6
+ metadata.gz: 02dd05ef2756ccb6d15c3a3989d20fa77c5516862b3b9cb071907d83a047db12f7faf44eb9d80db8235acefa14b5ca9c975575a50c84f0e5b226f00ebb231f96
7
+ data.tar.gz: dc68db6814859e4065699d0f8d1e0084ce0c8e74e3638c27a1b31ecf5ce87c92d06861cc919cb8cd3336f48f50ba4cbb0f1bb664158eb8deaa69624d31401c48
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /.idea/
10
+ Gemfile.lock
11
+
12
+ # rspec failure tracking
13
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.5.1
5
+ before_install: gem install bundler -v 1.16.1
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in optimus-runner.gemspec
6
+ gemspec
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Gandalf
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/gandalf`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'optimus-runner'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install gandalf
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/gandalf.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "optimus-runner"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ require 'daemons'
3
+
4
+ `mkdir -p ~/optimus_runner/logs`
5
+ options = {
6
+ :app_name => "optimus-runner",
7
+ :dir_mode => :normal,
8
+ :dir => "#{File.expand_path('~')}/or/pids",
9
+ :multiple => true,
10
+ :log_output => true,
11
+ :pid_delimiter => '.n',
12
+ :backtrace => true,
13
+ :monitor => true,
14
+ :log_dir => "#{File.expand_path('~')}/or/logs",
15
+ :logfilename => 'optimus-runner.log'
16
+ }
17
+ Daemons.run('optimus_runner_manager', options)
18
+
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optimus-runner/server/optimus_runner_sm'
3
+ require 'rufus/scheduler'
4
+ require 'logger'
5
+
6
+
7
+ optimus_runner_sm = OptimusRunnerSM.new
8
+ scheduler = Rufus::Scheduler.new
9
+ logger = Logger.new(STDOUT)
10
+ logger.level = Logger::WARN
11
+ logger.info "Starting Optimus runner..."
12
+
13
+ scheduler.interval '5s', :first_in => 0.1 do
14
+ logger.info "Is Optimus runner idle? #{optimus_runner_sm.idle?}"
15
+ optimus_runner_sm.create if optimus_runner_sm.idle?
16
+ optimus_runner_sm.add if optimus_runner_sm.new_device_added?
17
+ optimus_runner_sm.remove if optimus_runner_sm.device_removed?
18
+ optimus_runner_sm.restart if optimus_runner_sm.session_terminated?
19
+ end
20
+ scheduler.join
@@ -0,0 +1,32 @@
1
+ require 'optimus-runner/version'
2
+ require 'daemons'
3
+ require 'optimus-runner/server/appium_server_manager'
4
+
5
+
6
+ module Gandalf
7
+ class Optimus_Runner
8
+ attr_reader :options, :optimus_runner_sm, :scheduler
9
+
10
+ def initialize(options)
11
+ @options = options
12
+ @optimus_runner_sm = OptimusRunnerSM.new
13
+ @scheduler = Rufus::Scheduler.new
14
+ logger = Logger.new(STDOUT)
15
+ logger.level = Logger::WARN
16
+ logger.info "Starting Optimus runner..."
17
+ end
18
+
19
+
20
+ def run!
21
+ @scheduler.interval '5s', :first_in => 0.1 do
22
+ logger.info "Is Optimus runner idle? #{@optimus_runner_sm.idle?}"
23
+ @optimus_runner_sm.create if @optimus_runner_sm.idle?
24
+ @optimus_runner_sm.add if @optimus_runner_sm.new_device_added?
25
+ @optimus_runner_sm.remove if @optimus_runner_sm.device_removed?
26
+ @optimus_runner_sm.restart if @optimus_runner_sm.session_terminated?
27
+ end
28
+ @scheduler.join
29
+ end
30
+ end
31
+ end
32
+
@@ -0,0 +1,80 @@
1
+ require 'random-port'
2
+ require 'socket'
3
+ require 'open3'
4
+
5
+ class AppiumLocalService
6
+ @@sessions_with_pid = []
7
+
8
+ def get_session_details
9
+ @@sessions_with_pid
10
+ end
11
+
12
+ def launch_appium_sessions(device_details)
13
+ sessions = []
14
+ p "Device details in Launch Appium Sessions = #{device_details}"
15
+ p "Device details in Launch Appium Sessions = #{device_details.length}"
16
+ device_details.each do |device_detail|
17
+ session_id = create_session device_detail
18
+ session_info = {}
19
+ session_info["sessionUrl"] = session_id
20
+ session_info["sessionCapabilities"] = device_detail
21
+ sessions.push(session_info)
22
+ end
23
+ sessions
24
+ end
25
+
26
+ def launch_appium_session(device_detail)
27
+ session_detail = create_session device_detail
28
+ p session_detail
29
+ return session_detail
30
+ end
31
+
32
+ def create_session(device_detail)
33
+ RandomPort::Pool::SINGLETON.acquire do |port|
34
+ @port = port
35
+ end
36
+ puts @port
37
+ begin
38
+ Timeout.timeout(5) do
39
+ @pid = spawn(get_cmd(device_detail))
40
+ Process.wait @pid
41
+ end
42
+ end
43
+ rescue Timeout::Error
44
+ p @pid
45
+ @ipaddress = Socket.ip_address_list[4].ip_address
46
+ session_id = get_session_id
47
+ add_session_details session_id
48
+ return session_id
49
+ end
50
+
51
+
52
+ private
53
+
54
+ def get_cmd(device_detail)
55
+ case device_detail["platform"]
56
+ when "ANDROID"
57
+ return "appium -p #{@port} --bootstrap-port #{get_random_port}"
58
+ when "IOS"
59
+ return "appium -p #{@port} --webdriveragent-port #{get_random_port}"
60
+ end
61
+ end
62
+
63
+ def get_random_port
64
+ port = RandomPort::Pool.new.acquire
65
+ return port
66
+ end
67
+ def get_session_id
68
+ "http://#{@ipaddress}:#{@port}/wd/hub"
69
+ end
70
+
71
+ def add_session_details(session_id)
72
+ session_details = {}
73
+ session_details["session_id"] = session_id
74
+ session_details["session_pid"] = @pid
75
+ @@sessions_with_pid.push session_details
76
+ end
77
+
78
+
79
+
80
+ end
@@ -0,0 +1,56 @@
1
+ require 'HTTParty'
2
+
3
+ class DeviceDetails
4
+
5
+ def get_device_details
6
+ device_names = self.process_android_devices
7
+ android_device_details = find_android_devices(device_names)
8
+ ios_device_details = process_ios_devices
9
+ p "IOS Devices = #{ios_device_details}"
10
+ p "IOS Devices = #{ios_device_details.length}"
11
+ device_details = android_device_details+ios_device_details
12
+ device_details
13
+ end
14
+
15
+ def process_android_devices
16
+ devices = `adb devices`
17
+ query = { deviceLog: devices }.to_json
18
+ puts query
19
+ headers = {
20
+ 'Content-Type': "Application/json"
21
+ }
22
+ response = HTTParty.post('http://localhost:9099/processDevices', body: query, headers: headers)
23
+ end
24
+
25
+ def process_ios_devices
26
+ devices = `instruments -s devices | grep 'iPhone'`
27
+ p devices
28
+ body = { deviceLog: devices }.to_json
29
+ headers = {
30
+ 'Content-Type': "Application/json"
31
+ }
32
+ response = HTTParty.post('http://localhost:9099/processIosDevices', body: body, headers: headers)
33
+ p response
34
+ res = JSON.parse(response.to_s)
35
+ return res
36
+ end
37
+
38
+ def find_android_devices(device_names)
39
+ res = JSON.parse(device_names.to_s)
40
+ device_details = []
41
+ res.each do |a|
42
+ device_model = `adb -s #{a['udid']} shell getprop ro.product.model`
43
+ device_os_version = `adb -s #{a['udid']} shell getprop ro.build.version.release`
44
+ a['deviceName'] = device_model.to_s.rstrip
45
+ a['platformVersion'] = device_os_version.to_s.rstrip
46
+ a["platform"] = "ANDROID"
47
+ device_details.push(a)
48
+ end
49
+ device_details
50
+ end
51
+
52
+ end
53
+
54
+ div_details = DeviceDetails.new
55
+ details = div_details.get_device_details
56
+ p details
@@ -0,0 +1,19 @@
1
+ class SessionInfo
2
+
3
+ def create_session_info
4
+ session_info_list = []
5
+ (0..@session.length - 1).each {|session|
6
+ session_info = {}
7
+ session_info["sessionUrl"] = @session[session]
8
+ session_info["sessionCapabilities"] = @device_details[session]
9
+ session_info_list.push session_info
10
+ }
11
+ session_info_list
12
+ end
13
+
14
+ def initialize(session, device_details)
15
+ @session = session
16
+ @device_details = device_details
17
+ end
18
+
19
+ end
@@ -0,0 +1,50 @@
1
+ require 'HTTParty'
2
+
3
+ class AkriaClient
4
+ attr_accessor :base_uri
5
+
6
+ def initialize
7
+ @base_uri = "http://localhost:6889"
8
+ end
9
+
10
+ def save_sessions(session_info)
11
+ uri = "#{@base_uri}/sessions"
12
+ puts uri
13
+ HTTParty.post(uri , body: session_info.to_json, headers: get_default_headers)
14
+ end
15
+
16
+ def save_session(session_info)
17
+ uri = "#{@base_uri}/session"
18
+ puts uri
19
+ HTTParty.post(uri , body: session_info.to_json, headers: get_default_headers)
20
+ end
21
+
22
+ def remove_session(session_url)
23
+ uri = "#{@base_uri}/removeSession"
24
+ query_params = {
25
+ 'sessionUrl':session_url
26
+ }
27
+ HTTParty.put(uri, query: query_params, headers: get_default_headers)
28
+ end
29
+
30
+ def get_session_info(session_url)
31
+ uri = "#{@base_uri}/sessionInfo"
32
+ puts uri
33
+ query_params = {
34
+ 'sessionUrl':session_url
35
+ }
36
+ response = HTTParty.get(uri, query: query_params, headers: get_default_headers)
37
+ session_info = JSON.parse(response.to_s)
38
+ return session_info
39
+ end
40
+
41
+
42
+ def get_default_headers
43
+ headers = {
44
+ 'Content-Type': "Application/json"
45
+ }
46
+ return headers
47
+ end
48
+
49
+
50
+ end
@@ -0,0 +1,6 @@
1
+
2
+ class ShellCommands
3
+ def kill_process(pid)
4
+ spawn("kill #{pid}")
5
+ end
6
+ end
@@ -0,0 +1,19 @@
1
+ require 'optimus-runner/server/optimus_runner_sm'
2
+ require 'rufus/scheduler'
3
+ require 'logger'
4
+
5
+
6
+ optimus_runner_sm = OptimusRunnerSM.new
7
+ scheduler = Rufus::Scheduler.new
8
+ logger = Logger.new(STDOUT)
9
+ logger.level = Logger::WARN
10
+ logger.info "Starting Optimus runner..."
11
+
12
+ scheduler.interval '5s', :first_in => 0.1 do
13
+ logger.info "Is Optimus runner idle? #{optimus_runner_sm.idle?}"
14
+ optimus_runner_sm.create if optimus_runner_sm.idle?
15
+ optimus_runner_sm.add if optimus_runner_sm.new_device_added?
16
+ optimus_runner_sm.remove if optimus_runner_sm.device_removed?
17
+ optimus_runner_sm.restart if optimus_runner_sm.session_terminated?
18
+ end
19
+ scheduler.join
@@ -0,0 +1,10 @@
1
+
2
+
3
+ class ArrayManipulations
4
+
5
+ init_arr = [{"udid"=>"ae544f54", "deviceType"=>"DEVICE", "deviceName"=>"SM-J510FN", "platformVersion"=>"7.1.1"}, {"udid"=>"HGEPX64G", "deviceType"=>"DEVICE", "deviceName"=>"Lenovo A7700", "platformVersion"=>"6.0" }]
6
+ later_arr = [{"udid"=>"ae544f54", "deviceType"=>"DEVICE", "deviceName"=>"SM-J510FN", "platformVersion"=>"7.1.1"}, {"udid"=>"HGEPX64G", "deviceType"=>"DEVICE", "deviceName"=>"Lenovo A7700", "platformVersion"=>"6.0" }]
7
+
8
+ diff_arr = init_arr-later_arr
9
+ diff_arr1 = later_arr-init_arr
10
+ end
@@ -0,0 +1,207 @@
1
+ require 'aasm'
2
+ require 'json'
3
+ require 'pp'
4
+ require 'HTTParty'
5
+ require 'optimus-runner/DeviceDetails'
6
+ require 'json'
7
+ require 'optimus-runner/AppiumLocalService'
8
+ require 'optimus-runner/SessionInfoBuilder'
9
+ require 'optimus-runner/clients/AkiraClient'
10
+ require 'optimus-runner/clients/AkiraClient'
11
+ require 'logger'
12
+ require 'optimus-runner/commands/ShellCommands'
13
+
14
+ class OptimusRunnerSM
15
+ include AASM
16
+ attr_accessor :session_info
17
+
18
+ def initialize
19
+ @logger = Logger.new(STDOUT)
20
+ @initial_device_set = []
21
+ @device_details = []
22
+ set_restart_session
23
+ set_is_session_added
24
+ set_is_session_removed
25
+ set_is_session_restarted
26
+ end
27
+
28
+ aasm do
29
+ state :idle, :initial => true, :before_enter => :gather_initial_device_set
30
+ state :created, :added, :removed, :restarted
31
+
32
+ event :create, :before => [:create_sessions, :gather_initial_device_set] do
33
+ transitions :from => :idle, :to => :created, :guard => :devices_available?
34
+ transitions :from => :idle, :to => :idle
35
+ end
36
+
37
+ event :add, :before => :add_sessions do
38
+ transitions :from => [:created, :added, :removed, :restarted], :to => :added, :guard => :session_added?
39
+ transitions :from => [:created, :added, :removed, :restarted], :to => :created, :guard => :devices_available?
40
+ transitions :from => [:created, :added, :removed, :restarted], :to => :idle
41
+ end
42
+
43
+ event :remove, :before => :remove_sessions do
44
+ transitions :from => [:created, :added, :removed, :restarted], :to => :removed, :guard => :session_removed?
45
+ transitions :from => [:created, :added, :removed, :restarted], :to => :created, :guard => :devices_available?
46
+ transitions :from => [:created, :added, :removed, :restarted], :to => :idle
47
+ end
48
+
49
+ event :restart, :before => :restart_sessions do
50
+ transitions :from => [:created, :added, :removed, :restarted], :to => :restarted, :guard => :session_restarted?
51
+ transitions :from => [:created, :added, :removed, :restarted], :to => :created, :guard => :devices_available?
52
+ transitions :from => [:created, :added, :removed, :restarted], :to => :idle
53
+ end
54
+ end
55
+
56
+ def devices_available?
57
+ gather_devices
58
+ @device_details.length > 0
59
+ end
60
+
61
+ def gather_initial_device_set
62
+ details = DeviceDetails.new
63
+ @initial_device_set = details.get_device_details
64
+ @logger.info "Initial Device Set #{@initial_device_set}"
65
+ end
66
+
67
+ def session_added?
68
+ @session_added
69
+ end
70
+
71
+ def session_removed?
72
+ @session_removed
73
+ end
74
+
75
+ def session_restarted?
76
+ @session_restarted
77
+ end
78
+
79
+ def gather_devices
80
+ details = DeviceDetails.new
81
+ @device_details = details.get_device_details
82
+ @logger.info "Current devices connected are #{@device_details}"
83
+ end
84
+
85
+ def create_sessions
86
+ return unless devices_available?
87
+ @logger.info "Device details found are #{@device_details}"
88
+ sessions = AppiumLocalService.new.launch_appium_sessions(@device_details)
89
+ puts sessions
90
+ @session_info = sessions
91
+ AkriaClient.new.save_sessions(@session_info)
92
+ end
93
+
94
+ def create_new_session(device_details)
95
+ @logger.info "Found new device added #{device_details}"
96
+ session_info = AppiumLocalService.new.launch_appium_sessions(device_details)
97
+ # puts session
98
+ # session_info = SessionInfo.new(session,device_details).create_session_info
99
+ AkriaClient.new.save_sessions(session_info)
100
+ @session_info.push session_info[0]
101
+ p @session_info
102
+ end
103
+
104
+ def add_sessions
105
+ return unless devices_available?
106
+ if new_device_added?
107
+ create_new_session get_added_devices
108
+ @initial_device_set = @device_details
109
+ @session_added = true
110
+ end
111
+ end
112
+
113
+ def remove_sessions
114
+ return unless devices_available?
115
+ if device_removed?
116
+ get_removed_devices.each do |removed_device|
117
+ p removed_device
118
+ session_info = @session_info.detect {|info| info["sessionCapabilities"]==removed_device}
119
+ p session_info
120
+ AkriaClient.new.remove_session session_info["sessionUrl"]
121
+ session_details = AppiumLocalService.new.get_session_details
122
+ session_detail = session_details.detect {|session_detail| session_detail["session_id"]==session_info["sessionUrl"]}
123
+ puts "Removed session details #{session_details}"
124
+ ShellCommands.new.kill_process session_detail["session_pid"]
125
+ @session_info.delete_if{ |session_inf| session_inf["sessionUrl"] == session_info["sessionUrl"]}
126
+ @session_removed= true
127
+ @initial_device_set = @device_details
128
+ end
129
+ end
130
+
131
+
132
+ end
133
+
134
+ def session_terminated?
135
+ return false unless devices_available?
136
+ akira = AkriaClient.new
137
+ @session_info.each do |session|
138
+ p "Session #{session}"
139
+ @logger.info "Checking if the session #{session["sessionUrl"]} is terminated"
140
+ session_info = akira.get_session_info session["sessionUrl"]
141
+ session_state = session_info["sessionState"]
142
+ @is_session_terminated = session_state.eql? "TERMINATED"
143
+ @logger.info "Is session #{session["sessionUrl"]} terminated? #{@is_session_terminated}"
144
+ @restart_session = session_info if @is_session_terminated
145
+ @logger.info "Session Details to restart #{@restart_session}"
146
+ break unless @restart_session.empty?
147
+ end
148
+ return @is_session_terminated
149
+ end
150
+
151
+ def restart_sessions
152
+ session = AppiumLocalService.new.launch_appium_session @restart_session["sessionCapabilities"]
153
+ @logger.info "Restarting session #{@restart_session}"
154
+ @logger.info "Session details are #{@session_info}"
155
+ @session_info.delete_if{ |session_inf| session_inf["sessionUrl"] == @restart_session["sessionUrl"]}
156
+ @logger.info "Session details are #{@session_info}"
157
+ @restart_session["sessionUrl"] = session
158
+ @session_info.push(@restart_session)
159
+ @logger.info "Session details are #{@session_info}"
160
+ AkriaClient.new.save_session @restart_session
161
+ set_restart_session
162
+ @session_restarted = true
163
+ end
164
+
165
+ def new_device_added?
166
+ added_device = get_added_devices
167
+ p "Is new devices added #{added_device.length>0}"
168
+ p "Added devices length #{added_device.length}"
169
+ p "Added devices #{added_device}"
170
+ return added_device.length>0
171
+ end
172
+
173
+ def device_removed?
174
+ removed_device = get_removed_devices
175
+ @logger.info "Device #{removed_device} is removed"
176
+ return removed_device.length>0
177
+ end
178
+
179
+ def set_is_session_restarted
180
+ @session_restarted = false
181
+ end
182
+
183
+ def set_is_session_removed
184
+ @session_removed = false
185
+ end
186
+
187
+ def set_is_session_added
188
+ @session_added = false
189
+ end
190
+
191
+ def set_restart_session
192
+ @restart_session = {}
193
+ end
194
+
195
+ private
196
+
197
+ def get_added_devices
198
+ added_device = @device_details - @initial_device_set
199
+ return added_device
200
+ end
201
+
202
+ def get_removed_devices
203
+ removed_device = @initial_device_set - @device_details
204
+ return removed_device
205
+ end
206
+ end
207
+