optimus-runner 0.2.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 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
+