hive-runner-android 1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8df609a1edec60819bf8372dd0519f7851e7105f
4
+ data.tar.gz: f816df9c708723cb1515f205add30d59769a6934
5
+ SHA512:
6
+ metadata.gz: d458e4ce5f50c4df97b8618c5ba97f95a3df6b36f35bf032868ac56c1d843a8be483080408f7b7fd2dc9eb1cc805356969adefeb9642f72d3ad1d6b23acfdec3
7
+ data.tar.gz: aef6e7d5bafde000682b901372ab897e53b57adc10810950ff02f3e9763027fcc286ae3d19f23ee4bc052a59bcb9bd38de5d2d5e28f67620cf20d133acd9e1ba
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # hive-runner-android
2
+ Android module for Hive Runner
3
+
4
+ ## Quick start
5
+ Install the hive-runner gem and set up your hive:
6
+
7
+ gem install hive-runner
8
+ hive_setup my_hive
9
+
10
+ When you are asked whether you want to add a module, press 1 and enter `android` as the module name. You will then be able to select the latest version from either Github or Rubygems.
11
+
12
+ Follow the configuration instructions and, in particular, ensure that the
13
+ `HIVE_CONFIG` variable is set.
14
+
15
+ Start the Hive daemon:
16
+
17
+ hived start
18
+
19
+ Determine the status of the Hive:
20
+
21
+ hived status
22
+
23
+ Stop the Hive:
24
+
25
+ hived stop
26
+
27
+ ## Configuration file
28
+
29
+ Example config file:
30
+
31
+ android:
32
+ name_stub: ANDROID_WORKER
33
+ port_range_size: 10
@@ -0,0 +1,179 @@
1
+ require 'hive/controller'
2
+ require 'hive/worker/android'
3
+ require 'device_api/android'
4
+
5
+ module Hive
6
+ class Controller
7
+ class Android < Controller
8
+
9
+ # Uses either DeviceAPI or DeviceDB to generate queue names for a device
10
+ def calculate_queue_names(device)
11
+ if device.is_a? DeviceAPI::Android::Device
12
+ queues = [
13
+ device.model,
14
+ device.manufacturer,
15
+ 'android',
16
+ "android-#{device.version}",
17
+ "android-#{device.version}-#{device.model}"
18
+ ]
19
+ else
20
+
21
+ queues = [
22
+ device['device_model'],
23
+ device['device_brand'],
24
+ device['os'],
25
+ "#{device['os']}-#{device['os_version']}",
26
+ "#{device['os']}-#{device['os_version']}-#{device['device_model']}"
27
+ ]
28
+
29
+ queues << device["features"] unless device["features"].empty?
30
+
31
+ queues.flatten
32
+ end
33
+ queues
34
+ end
35
+
36
+ def populate_queues(device)
37
+ queues = calculate_queue_names(device)
38
+
39
+ # Add the queue prefix if it hase been setup in the config
40
+ queues = queues.map { |a| "#{@config['queue_prefix']}-#{a}"} if @config['queue_prefix']
41
+
42
+ devicedb_queues = device['device_queues'].map { |d| d['name'] }
43
+ # Check to see if the queues have already been registered with this device
44
+ missing_queues = (queues - devicedb_queues) + (devicedb_queues - queues)
45
+ return if missing_queues.empty?
46
+
47
+ queues << missing_queues
48
+
49
+ queue_ids = queues.flatten.uniq.map { |queue| find_or_create_queue(queue) }
50
+
51
+ values = {
52
+ name: device['name'],
53
+ hive_id: device['hive_id'],
54
+ feature_list: device['features'],
55
+ device_queue_ids: queue_ids
56
+ }
57
+
58
+ Hive.devicedb('Device').edit(device['id'], values)
59
+ end
60
+
61
+ def find_or_create_queue(name)
62
+ queue = Hive.devicedb('Queue').find_by_name(name)
63
+ return queue.first['id'] unless queue.empty?
64
+
65
+ queue = create_queue(name, "#{name} queue created by Hive Runner")
66
+ queue['id'] unless queue.empty?
67
+ end
68
+
69
+ def create_queue(name, description)
70
+ queue_attributes = {
71
+ name: name,
72
+ description: description
73
+ }
74
+
75
+ Hive.devicedb('Queue').register(device_queue: queue_attributes )
76
+ end
77
+
78
+ def detect
79
+ devices = DeviceAPI::Android.devices
80
+ Hive.logger.debug('No devices attached') if devices.empty?
81
+ Hive.logger.debug("#{Time.now} Retrieving hive details")
82
+ hive_details = Hive.devicedb('Hive').find(Hive.id)
83
+ Hive.logger.debug("#{Time.now} Finished fetching hive details")
84
+
85
+ if hive_details.key?('devices')
86
+ # Update the 'cached' results from DeviceDB
87
+ @hive_details = hive_details
88
+ else
89
+ # DeviceDB isn't available - use the cached version
90
+ hive_details = @hive_details
91
+ end
92
+
93
+ if hive_details.is_a? Hash
94
+ # DeviceDB information is available, use it
95
+ hive_details['devices'].select {|a| a['os'] == 'android'}.each do |device|
96
+ registered_device = devices.select { |a| a.serial == device['serial'] && a.status != :unauthorized}
97
+ if registered_device.empty?
98
+ # A previously registered device isn't attached
99
+ Hive.logger.debug("Removing previously registered device - #{device}")
100
+ Hive.devicedb('Device').hive_disconnect(device['id'])
101
+ else
102
+ # A previously registered device is attached, poll it
103
+ Hive.logger.debug("#{Time.now} Polling attached device - #{device}")
104
+ Hive.devicedb('Device').poll(device['id'])
105
+ Hive.logger.debug("#{Time.now} Finished polling device")
106
+
107
+ # Make sure that this device has all the queues it should have
108
+ populate_queues(device)
109
+
110
+ devices = devices - registered_device
111
+ end
112
+ end
113
+
114
+ devices.each do |device|
115
+ register_new_device(device)
116
+ end
117
+
118
+ display_devices(hive_details)
119
+
120
+ hive_details['devices'].select {|a| a['os'] == 'android'}.collect do |hive_device|
121
+ self.create_device(hive_device)
122
+ end
123
+ else
124
+ # DeviceDB isn't available, use DeviceAPI instead
125
+ device_info = devices.map do |device|
126
+ {'id' => device.serial, 'serial' => device.serial, status: 'idle', devices: [{ device_queues: [ calculate_queue_names(device).map { |q| { name: q } } ]}]}
127
+ end
128
+
129
+ device_info.collect do |physical_device|
130
+ self.create_device(physical_device)
131
+ end
132
+ end
133
+ end
134
+
135
+ def register_new_device(device)
136
+ begin
137
+ Hive.logger.debug("Adding new Android device: #{device.model}")
138
+
139
+ attributes = {
140
+ os: 'android',
141
+ os_version: device.version,
142
+ serial: device.serial,
143
+ device_type: 'mobile',
144
+ device_model: device.model,
145
+ device_brand: device.manufacturer,
146
+ device_range: device.range,
147
+ hive: Hive.id
148
+ }
149
+ rescue DeviceAPI::Android::ADBCommandError
150
+ # If a device has been disconnected while we're trying to add it, the device_api
151
+ # gem will throw an error
152
+ Hive.logger.debug('Device disconnected while attempting to add')
153
+ end
154
+
155
+ registration = Hive.devicedb('Device').register(attributes)
156
+ Hive.devicedb('Device').hive_connect(registration['id'], Hive.id)
157
+ end
158
+
159
+ def display_devices(hive_details)
160
+ rows = []
161
+ if hive_details.key?('devices')
162
+ unless hive_details['devices'].empty?
163
+ rows = hive_details['devices'].map do |device|
164
+ [
165
+ "#{device['device_brand']} #{device['device_model']}",
166
+ device['serial'],
167
+ (device['device_queues'].map { |queue| queue['name']}).join("\n"),
168
+ device['status']
169
+ ]
170
+ end
171
+ end
172
+ end
173
+ table = Terminal::Table.new :headings => ['Device', 'Serial', 'Queue Name', 'Status'], :rows => rows
174
+
175
+ Hive.logger.info(table)
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,12 @@
1
+ require 'hive/device'
2
+
3
+ module Hive
4
+ class Device
5
+ class Android < Device
6
+ def initialize(config)
7
+ @identity = config['id']
8
+ super
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,38 @@
1
+ require 'hive/diagnostic'
2
+ module Hive
3
+ class Diagnostic
4
+ class Android
5
+ class Battery < Diagnostic
6
+
7
+ def battery
8
+ self.device_api.battery_info
9
+ end
10
+
11
+ def diagnose
12
+ result = nil
13
+ battery_info = battery
14
+ begin
15
+ if config != nil && config.keys.count != 0
16
+ temperature = battery_info['temperature']
17
+ if temperature.to_i < config['temperature'].to_i
18
+ result = self.pass("Temperature: #{temperature}\n Battery status: OK", "battery")
19
+ else
20
+ result = self.fail("Battery temperature above threshold. Temperature: #{temperature} ", "battery")
21
+ end
22
+ else
23
+ result = self.pass("No parameter specified for battery", "battery")
24
+ end
25
+ rescue
26
+ Hive.logger.error("Invalid Battery Parameter")
27
+ raise InvalidParameterError.new("Invalid Parameter for battery") if !result
28
+ end
29
+ result
30
+ end
31
+
32
+ def repair(result)
33
+ result = self.fail("Battery temperature above threshold.", "battery")
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,47 @@
1
+ require 'hive/diagnostic'
2
+ module Hive
3
+ class Diagnostic
4
+ class Android
5
+ class Memory < Diagnostic
6
+
7
+ def memory
8
+ @memory = self.device_api.memory unless @memory
9
+ mem = @memory.mem_info
10
+ return {:free => mem.free.split(' ')[0],
11
+ :total => mem.total.split(' ')[0],
12
+ :used => mem.used.split(' ')[0], }
13
+ end
14
+
15
+ def diagnose
16
+ result = nil
17
+ operator = {:free => :>=, :used => :<= , :total => :==}
18
+ memory_status = memory
19
+ if config != nil && config.keys.count != 0
20
+ config.each do |key, value|
21
+ begin
22
+ if memory_status[:"#{key}"].to_i.send(operator[:"#{key}"], value.to_i)
23
+ result = self.pass("#{key.capitalize} Memory (#{memory_status[:"#{key}"]}) #{operator[:"#{key}"]} #{value}", "memory" )
24
+ else
25
+ result = self.fail("Error: #{key.capitalize} Memory (#{memory_status[:"#{key}"]}) is not #{operator[:"#{key}"]} #{value}", "memory")
26
+ break
27
+ end
28
+ rescue
29
+ Hive.logger.error("Invalid Memory Parameter")
30
+ raise InvalidParameterError.new("Invalid Parameter for memory") if !result
31
+ end
32
+ end
33
+ else
34
+ result = self.pass("No parameter specified", "memory")
35
+ end
36
+ result
37
+ end
38
+
39
+ def repair(result)
40
+ # Add repair for memory
41
+ self.fail("Cannot repair memory", "memory")
42
+ end
43
+
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,33 @@
1
+ require 'hive/diagnostic'
2
+ module Hive
3
+ class Diagnostic
4
+ class Android
5
+ class Uptime < Diagnostic
6
+
7
+ def diagnose
8
+ if config.has_key?(:reboot_timeout)
9
+ uptime = self.device_api.uptime
10
+ if uptime < config[:reboot_timeout]
11
+ self.pass("Time for next reboot: #{config[:reboot_timeout] - uptime}s", "Reboot")
12
+ else
13
+ self.fail("Reboot required", "Reboot")
14
+ end
15
+ else
16
+ self.pass("Not configured for reboot", "Reboot")
17
+ end
18
+ end
19
+
20
+ def repair(result)
21
+ Hive.logger.info("Rebooting the device")
22
+ begin
23
+ self.device_api.reboot
24
+ sleep 30
25
+ rescue
26
+ Hive.logger.error("Device not found")
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,58 @@
1
+ require 'hive/diagnostic'
2
+ module Hive
3
+ class Diagnostic
4
+ class Android
5
+ class Wifi < Diagnostic
6
+
7
+ def wifi
8
+ wifi_details = self.device_api.wifi_status
9
+ return {:status => wifi_details[:status].scan(/^[^\/]*/)[0], :access_point => wifi_details[:access_point]}
10
+ end
11
+
12
+ def diagnose
13
+ result = nil
14
+ wifi_status = wifi
15
+
16
+ if wifi_status[:access_point].capitalize == "Xxxx"
17
+ result = self.pass("Kindle returns wifi 'xxxx'", "wifi")
18
+ return result
19
+ end
20
+
21
+ config.each do |key, value|
22
+ if config != nil && config.keys.count != 0
23
+ begin
24
+ if wifi_status[:"#{key}"].capitalize == value.capitalize
25
+ result = self.pass("#{key.capitalize} : #{wifi_status[:"#{key}"]}", "wifi" )
26
+ else
27
+ result = self.fail(" Error: #{key.capitalize} : #{wifi_status[:"#{key}"]} ", "wifi")
28
+ break
29
+ end
30
+ rescue
31
+ Hive.logger.error("Invalid Parameter for Wifi #{key}")
32
+ raise InvalidParameter.new("Invalid Wifi Parameter for Wifi: #{key}") if !result
33
+ end
34
+ else
35
+ result = self.pass("No parameter specified", "wifi")
36
+ end
37
+ end
38
+ result
39
+ end
40
+
41
+ def repair(result)
42
+ Hive.logger.info("Trying to repair wifi")
43
+ options = {:apk => '/path/to/apk/to/toggle/wifi', :package => '/pkg/name/ex: com.wifi.togglewifi'}
44
+ begin
45
+ self.device_api.install(options[:apk])
46
+ self.device_api.start_intent("-n com.wifi.togglewifi/.MainActivity -e wifi true")
47
+ sleep 5
48
+ self.device_api.uninstall(options[:package])
49
+ rescue
50
+ Hive.logger.error("Unable to fix wifi issue")
51
+ end
52
+ diagnose
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,11 @@
1
+ require 'hive/messages'
2
+
3
+ module Hive
4
+ module Messages
5
+ class AndroidJob < Hive::Messages::Job
6
+ def build
7
+ self.target.symbolize_keys[:build]
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,102 @@
1
+ require 'hive/worker'
2
+ require 'hive/messages/android_job'
3
+
4
+ module Hive
5
+ class PortReserver
6
+ attr_accessor :ports
7
+ def initialize
8
+ self.ports = {}
9
+ end
10
+
11
+ def reserve(queue_name)
12
+ self.ports[queue_name] = yield
13
+ self.ports[queue_name]
14
+ end
15
+ end
16
+
17
+ class Worker
18
+ class Android < Worker
19
+
20
+ attr_accessor :device
21
+
22
+ def initialize(device)
23
+ @worker_ports = PortReserver.new
24
+ begin
25
+ device.merge!({"device_api" => DeviceAPI::Android.device(device['serial'])})
26
+ rescue DeviceAPI::Android::ADBCommandError
27
+ Hive.logger.info("Device disconnected during worker initialization")
28
+ end
29
+ set_device_status('idle')
30
+ self.device = device
31
+ super(device)
32
+ end
33
+
34
+ def adb_port
35
+ # Assign adb port for this worker
36
+ return @adb_port unless @adb_port.nil?
37
+ @adb_port = @port_allocator.allocate_port
38
+ end
39
+
40
+ def pre_script(job, file_system, script)
41
+ set_device_status('busy')
42
+ script.set_env "TEST_SERVER_PORT", adb_port
43
+
44
+ # TODO: Allow the scheduler to specify the ports to use
45
+ script.set_env "CHARLES_PROXY_PORT", @worker_ports.reserve(queue_name: 'Charles') { @port_allocator.allocate_port }
46
+ script.set_env "APPIUM_PORT", @worker_ports.reserve(queue_name: 'Appium') { @port_allocator.allocate_port }
47
+ script.set_env "BOOTSTRAP_PORT", @worker_ports.reserve(queue_name: 'Bootstrap') { @port_allocator.allocate_port }
48
+ script.set_env "CHROMEDRIVER_PORT", @worker_ports.reserve(queue_name: 'Chromedriver') { @port_allocator.allocate_port }
49
+
50
+ script.set_env 'ADB_DEVICE_ARG', self.device['serial']
51
+
52
+ FileUtils.mkdir(file_system.home_path + '/build')
53
+ apk_path = file_system.home_path + '/build/' + 'build.apk'
54
+
55
+ script.set_env "APK_PATH", apk_path
56
+ if job.build
57
+ file_system.fetch_build(job.build, apk_path)
58
+ DeviceAPI::Android::Signing.sign_apk({apk: apk_path, resign: true})
59
+ end
60
+
61
+ DeviceAPI::Android.device(device['serial']).unlock
62
+
63
+ "#{self.device['serial']} #{@worker_ports.ports['Appium']} #{apk_path} #{file_system.results_path}"
64
+ end
65
+
66
+ def job_message_klass
67
+ Hive::Messages::AndroidJob
68
+ end
69
+
70
+ def post_script(job, file_system, script)
71
+ @log.info('Post script')
72
+ @worker_ports.ports.each do |name, port|
73
+ @port_allocator.release_port(port)
74
+ end
75
+ set_device_status('idle')
76
+ end
77
+
78
+ def device_status
79
+ details = Hive.devicedb('Device').find(@options['id'])
80
+ if details.key?('status')
81
+ @state = details['status']
82
+ else
83
+ @state
84
+ end
85
+ end
86
+
87
+ def set_device_status(status)
88
+ @state = status
89
+ begin
90
+ details = Hive.devicedb('Device').poll(@options['id'], status)
91
+ if details.key?('status')
92
+ details['status']
93
+ else
94
+ @state
95
+ end
96
+ rescue
97
+ @state
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hive-runner-android
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jon Wilson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: device_api-android
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: hive-runner
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: terminal-table
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '1.4'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '1.4'
55
+ description: The Android controller module for Hive Runner
56
+ email: jon.wilson01@bbc.co.uk
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - README.md
62
+ - lib/hive/controller/android.rb
63
+ - lib/hive/device/android.rb
64
+ - lib/hive/diagnostic/android/battery.rb
65
+ - lib/hive/diagnostic/android/memory.rb
66
+ - lib/hive/diagnostic/android/uptime.rb
67
+ - lib/hive/diagnostic/android/wifi.rb
68
+ - lib/hive/messages/android_job.rb
69
+ - lib/hive/worker/android.rb
70
+ homepage: https://github.com/bbc/hive-runner-android
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.4.8
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: Hive Runner Android
94
+ test_files: []