stf-client 0.2.6 → 0.3.0.pre.rc.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7db448c2c0164d028021aa694aa0a726cee55941
4
- data.tar.gz: 5dca57695b59bfa254ced82f32ba0c8cc10489b4
2
+ SHA256:
3
+ metadata.gz: 52a4f2a68edf69cda4d74621215c184f14ea2fbf97d2c27948581f7dee93e838
4
+ data.tar.gz: 622083a2cd27df2e8b3ba9dd78ff79cf9054bdfe27049544816dc04fed77b3b6
5
5
  SHA512:
6
- metadata.gz: 597d3bd7df408f76a32f0a6b6f79534a450e0a8233df2e70893fdf7981cebee79c810bb9dadef5fa275d622d6062a4a6ad06abf50a21f5a5d388581ea1b055a6
7
- data.tar.gz: 762ca50470092120eeda8b84348f650a95da64406f8da2c75b1d1a1f68bef1a8be99d14768fb506d185c12d7e7591730d67730eb349902265a424d00ebbdf6b9
6
+ metadata.gz: 42f63749eb0a0f748b3a66051f3a409d92765d7b519627608b52e34a7241ae8b58b91a35dcc1c28ef61d18c482d18b0aebba88af50e52227cfd78fbdc4f6671d
7
+ data.tar.gz: 3a27762217fad2da4895997c33def45bd35044b3b4a0a3e17f48fa0434236b899ae058802c0fa1c6e9a110aae3ccfc4fd2f72f068360adbd8c47f04ab0085554
data/README.md CHANGED
@@ -48,7 +48,7 @@ COMMANDS
48
48
  connect - Search for a device available in STF and attach it to local adb server
49
49
  disconnect - Disconnect device(s) from local adb server and remove device(s) from user devices in STF
50
50
  help - Shows a list of commands or help for one command
51
- keys - Show avaliable keys for filtering
51
+ keys - Show available keys for filtering
52
52
  values - Show known values for the filtering key
53
53
 
54
54
  ENVIRONMENT VARIABLES
data/lib/di.rb CHANGED
@@ -9,6 +9,7 @@ require 'stf/interactor/stop_all_debug_sessions_interactor'
9
9
  require 'stf/interactor/remove_all_user_devices_interactor'
10
10
  require 'stf/interactor/get_keys_interactor'
11
11
  require 'stf/interactor/get_values_interactor'
12
+ require 'stf/validate/uri_validator'
12
13
 
13
14
  class DI
14
15
  class << self
@@ -60,6 +61,9 @@ class DI
60
61
  -> {Stf::RemoveAllUserDevicesInteractor.new},
61
62
  memoize: true)
62
63
 
64
+ c.register(:uri_validator,
65
+ -> {Stf::URIValidator.new},
66
+ memoize: true)
63
67
  end
64
68
 
65
69
  def [](what)
data/lib/stf/client.rb CHANGED
@@ -4,7 +4,6 @@ require 'ostruct'
4
4
 
5
5
  require 'stf/version'
6
6
  require 'stf/log/log'
7
- require 'stf/errors'
8
7
 
9
8
  module Stf
10
9
  class Client
@@ -3,8 +3,6 @@ require 'di'
3
3
 
4
4
  require 'stf/client'
5
5
  require 'stf/log/log'
6
- require 'stf/errors'
7
- require 'stf/model/session'
8
6
  require 'stf/model/device'
9
7
 
10
8
  module Stf
@@ -3,8 +3,6 @@ require 'ADB'
3
3
 
4
4
  require 'stf/client'
5
5
  require 'stf/log/log'
6
- require 'stf/errors'
7
- require 'stf/model/session'
8
6
  require 'stf/model/device'
9
7
 
10
8
  module Stf
@@ -2,8 +2,6 @@ require 'ADB'
2
2
 
3
3
  require 'stf/client'
4
4
  require 'stf/log/log'
5
- require 'stf/errors'
6
- require 'stf/model/session'
7
5
  require 'stf/model/device_list'
8
6
 
9
7
  module Stf
@@ -14,30 +12,34 @@ module Stf
14
12
 
15
13
  def execute(opts = {})
16
14
  all_flag = opts[:all]
17
- forever_flag = opts[:forever]
18
15
  nodaemon_flag = opts[:nodaemon]
19
16
  filter = opts[:filter]
20
17
  max_n = opts[:n].to_i > 0 ? opts[:n].to_i : 1
21
18
  start_timeout = opts[:starttime].to_i > 0 ? opts[:starttime].to_i : 120
22
19
  session = opts[:worktime].to_i > 0 ? opts[:session].to_i : 10800
23
- min_n = opts[:min].to_s.empty? ? (max_n + 1) / 2 : opts[:min].to_i
20
+ min_n = opts[:min].to_s.empty? ? (max_n + 1) / 2 : [opts[:min].to_i, max_n].min
21
+ healthcheck = opts[:health]
22
+ force_filter = opts[:forcefilter]
24
23
 
25
24
  DI[:demonizer].kill unless opts[:nokill]
26
25
 
27
- if filter
28
- DI[:stop_all_debug_sessions_interactor].execute(exceptFilter: filter)
29
- end
30
-
31
26
  wanted = nodaemon_flag ? max_n : min_n
32
27
 
33
28
  begin
34
- connect_loop(all_flag, wanted, filter, false, 5, start_timeout)
29
+ connect_loop(all_flag: all_flag,
30
+ wanted: wanted,
31
+ filter: filter,
32
+ force_filter: force_filter,
33
+ healthcheck: healthcheck,
34
+ delay: 5,
35
+ timeout: start_timeout)
36
+
35
37
  rescue SignalException => e
36
- logger.info "Caught signal #{e}"
38
+ logger.info "Caught signal \"#{e.message}\""
37
39
  DI[:stop_all_debug_sessions_interactor].execute
38
40
  return false
39
- rescue
40
- logger.info "Exception #{e} during initial connect loop"
41
+ rescue Exception => e
42
+ logger.info "Exception \"#{e.message}\" during initial connect loop"
41
43
  DI[:stop_all_debug_sessions_interactor].execute
42
44
  return false
43
45
  end
@@ -49,13 +51,14 @@ module Stf
49
51
 
50
52
  # will be daemon here
51
53
  DI[:demonizer].run do
52
- connect_loop(all_flag,
53
- max_n,
54
- filter,
55
- true,
56
- 30,
57
- session,
58
- forever_flag)
54
+ connect_loop(all_flag: all_flag,
55
+ wanted: max_n,
56
+ filter: filter,
57
+ force_filter: force_filter,
58
+ healthcheck: healthcheck,
59
+ daemon_mode: true,
60
+ delay: 30,
61
+ timeout: session)
59
62
 
60
63
  DI[:stop_all_debug_sessions_interactor].execute(byFilter: filter, nokill: true)
61
64
  end
@@ -63,74 +66,91 @@ module Stf
63
66
  return true
64
67
  end
65
68
 
66
- def connect_loop(all_flag, wanted, filter, infinite_flag, delay, timeout, forever_flag = false)
69
+ def connect_loop(all_flag: false,
70
+ wanted: 1,
71
+
72
+ filter: nil,
73
+ force_filter: false,
74
+ healthcheck: nil,
75
+
76
+ daemon_mode: false,
77
+ delay: 5,
78
+ timeout: 120)
67
79
  finish_time = Time.now + timeout
80
+ one_time_mode = !daemon_mode
68
81
 
69
82
  while true do
70
- cleanup_disconnected_devices(filter)
83
+ cleanup_disconnected_devices(filter, force_filter, healthcheck)
84
+
85
+ if one_time_mode && Time.now > finish_time
86
+ raise "Connect loop timeout reached"
87
+ end
71
88
 
72
- stf_devices = DeviceList.new(DI[:stf].get_devices)
73
- stf_devices = stf_devices.byFilter(filter) if filter
89
+ all_devices = DeviceList.new(DI[:stf].get_devices)
90
+ stf_devices = all_devices.select_ready_to_connect
91
+ stf_devices = stf_devices.by_filter(filter) if filter
92
+ stf_devices = stf_devices.select_healthy_for_connect(healthcheck) if healthcheck
74
93
 
75
94
  if all_flag
76
- batch = stf_devices.filterReadyToConnect.size
95
+ to_connect = stf_devices.size
77
96
  else
78
- connected = devices & stf_devices.asConnectUrlList
79
- batch = wanted - connected.size
97
+ connected = devices & all_devices.as_connect_url_list
98
+ to_connect = wanted - connected.size
80
99
  end
81
100
 
82
- if batch > 0
83
- n = connect(filter, all_flag, batch)
84
- break if n == batch && !infinite_flag
85
- elsif !infinite_flag
86
- break
101
+ return if one_time_mode && to_connect <= 0
102
+
103
+ if to_connect > 0
104
+ if stf_devices.empty?
105
+ logger.error 'There is no available devices with criteria ' + filter
106
+ else
107
+ random_device = stf_devices.asArray.sample
108
+ DI[:start_one_debug_session_interactor].execute(random_device)
109
+ next
110
+ end
87
111
  end
88
112
 
89
113
  sleep delay
90
-
91
- if !forever_flag || Time.now > finish_time
92
- raise "Connect loop timeout reached"
93
- end
94
114
  end
95
-
96
115
  end
97
116
 
98
117
  def count_connected_devices(filter)
99
118
  stf_devices = DeviceList.new(DI[:stf].get_user_devices)
100
- stf_devices = stf_devices.byFilter(filter) if filter
101
- connected = devices & stf_devices.asConnectUrlList
119
+ stf_devices = stf_devices.by_filter(filter) if filter
120
+ connected = devices & stf_devices.as_connect_url_list
102
121
  connected.size
103
122
  end
104
123
 
105
- def cleanup_disconnected_devices(filter)
124
+ def cleanup_disconnected_devices(filter, force_filter, healthcheck)
125
+ to_disconnect = []
106
126
  stf_devices = DeviceList.new(DI[:stf].get_user_devices)
107
- stf_devices = stf_devices.byFilter(filter) if filter
108
- connected = stf_devices.asConnectUrlList - devices
109
127
 
110
- connected.reject {|url| url.to_s.empty?}.each do |url|
111
- logger.info 'Cleanup the device ' + url.to_s
112
- DI[:stop_debug_session_interactor].execute(url)
128
+ if filter && force_filter
129
+ disconnect_because_filter = stf_devices.except_filter(filter).as_connect_url_list
130
+ unless disconnect_because_filter.empty?
131
+ logger.info 'will be disconnected by filter: ' + disconnect_because_filter.join(',')
132
+ to_disconnect += disconnect_because_filter
133
+ end
113
134
  end
114
- end
115
-
116
- def connect(filter, all_flag, wanted)
117
- devices = DeviceList.new(DI[:stf].get_devices)
118
- devices = devices.filterReadyToConnect
119
- devices = devices.byFilter(filter) if filter
120
135
 
121
- if devices.empty?
122
- logger.error 'There is no available devices with criteria ' + filter
123
- return 0
136
+ if healthcheck
137
+ disconnect_by_health = stf_devices.select_not_healthy(healthcheck).as_connect_url_list
138
+ unless disconnect_by_health.empty?
139
+ logger.info 'will be disconnected by health check: ' + disconnect_by_health.join(',')
140
+ to_disconnect += disconnect_by_health
141
+ end
124
142
  end
125
143
 
126
- n = 0
127
- devices.asArray.shuffle.each do |d|
128
- n += 1 if DI[:start_one_debug_session_interactor].execute(d)
129
- break if !all_flag && n >= wanted
144
+ dead_persons = stf_devices.as_connect_url_list - devices
145
+ unless dead_persons.empty?
146
+ logger.info 'will be disconnected because not present locally: ' + dead_persons.join(',')
147
+ to_disconnect += dead_persons
130
148
  end
131
149
 
132
- n
150
+ to_disconnect.reject {|url| url.to_s.empty?}.uniq.each do |url|
151
+ logger.info 'Cleanup the device ' + url.to_s
152
+ DI[:stop_debug_session_interactor].execute(url)
153
+ end
133
154
  end
134
-
135
155
  end
136
156
  end
@@ -3,8 +3,6 @@ require 'ADB'
3
3
 
4
4
  require 'stf/client'
5
5
  require 'stf/log/log'
6
- require 'stf/errors'
7
- require 'stf/model/session'
8
6
 
9
7
  module Stf
10
8
  class StartOneDebugSessionInteractor
@@ -40,23 +38,26 @@ module Stf
40
38
 
41
39
  return true
42
40
 
43
- rescue SignalException => e
44
- raise e
45
- rescue => e
41
+ rescue StandardError, SignalException => e
46
42
  begin
47
43
  # we will try clean anyway
48
44
  DI[:stf].remove_device serial
49
45
  if test ?d, '/custom-metrics'
50
- File.open('/custom-metrics/openstf_connect_fail', 'a') do
51
- |f| f.write("openstf_connect_fail #{serial} #{Time.now.to_i}")
46
+ File.open('/custom-metrics/openstf_connect_fail', 'a') do |f|
47
+ message = (!e.nil? || !e.message.nil?) ? e.message : ""
48
+ f.write("openstf_connect_fail,reason=\"#{escape(message)}\",serial=\"#{escape(serial)}\" count=1i #{Time.now.to_i}\n")
52
49
  end
53
50
  end
54
51
  rescue
55
52
  end
56
53
 
57
- logger.error "Failed to connect to #{serial}: " + e.message
54
+ logger.error "Failed to connect to #{serial}: " + e&.message
58
55
  return false
59
56
  end
60
57
  end
58
+
59
+ def escape(s)
60
+ s.gsub(/["]/, '\"').gsub(/[ ]/, '\ ').gsub(/[=]/, '\=').gsub(/[,]/, '\,')
61
+ end
61
62
  end
62
63
  end
@@ -3,7 +3,6 @@ require 'ADB'
3
3
 
4
4
  require 'stf/client'
5
5
  require 'stf/log/log'
6
- require 'stf/errors'
7
6
  require 'stf/interactor/stop_debug_session_interactor'
8
7
  require 'stf/model/device_list'
9
8
 
@@ -13,19 +12,14 @@ module Stf
13
12
  include ADB
14
13
 
15
14
  # byFilter:
16
- # exceptFilter:
17
15
  def execute(options = {})
18
16
  DI[:demonizer].kill unless options[:nokill]
19
17
 
20
18
  stf_devices = DeviceList.new(DI[:stf].get_user_devices)
21
19
 
22
- stf_devices = stf_devices.byFilter options[:byFilter] if options[:byFilter]
23
- stf_devices = stf_devices.exceptFilter options[:exceptFilter] if options[:exceptFilter]
20
+ stf_devices = stf_devices.by_filter options[:byFilter] if options[:byFilter]
24
21
 
25
- connected_devices = devices()
26
- remote_devices = stf_devices.asConnectUrlList
27
-
28
- pending_disconnect = connected_devices & remote_devices
22
+ pending_disconnect = stf_devices.as_connect_url_list
29
23
 
30
24
  pending_disconnect.each {|d| DI[:stop_debug_session_interactor].execute d}
31
25
  end
@@ -3,7 +3,6 @@ require 'ADB'
3
3
 
4
4
  require 'stf/client'
5
5
  require 'stf/log/log'
6
- require 'stf/errors'
7
6
 
8
7
  module Stf
9
8
  class StopDebugSessionInteractor
@@ -8,7 +8,33 @@ module Stf
8
8
  getKeysNextLevel('', self)
9
9
  end
10
10
 
11
- def checkFilter(filter)
11
+ # more pessimistic decision
12
+ def healthy_for_connect?(pattern)
13
+ return true if pattern.nil?
14
+ health = healthy?(pattern)
15
+ ppp = pattern.split(',')
16
+ ppp.each do |p|
17
+ health &&= getValue('battery.temp').to_i < 30 if ['t', 'temp', 'temperature'].include? p
18
+ health &&= getValue('battery.level').to_f > 30.0 if ['b', 'batt', 'battery'].include? p
19
+ end
20
+ health
21
+ end
22
+
23
+ def healthy?(pattern)
24
+ return true if pattern.nil?
25
+ ppp = pattern.split(',')
26
+ health = true
27
+ ppp.each do |p|
28
+ health &&= getValue('battery.temp').to_i < 32 if ['t', 'temp', 'temperature'].include? p
29
+ health &&= getValue('battery.level').to_f > 20.0 if ['b', 'batt', 'battery'].include? p
30
+ health &&= getValue('network.connected') if ['n', 'net', 'network'].include? p
31
+ health &&= getValue('network.type') == 'VPN' if ['vpn'].include? p
32
+ health &&= getValue('network.type') == 'WIFI' if ['wifi'].include? p
33
+ end
34
+ health
35
+ end
36
+
37
+ def checkFilter?(filter)
12
38
  return true if filter.nil?
13
39
  key, value = filter.split(':', 2)
14
40
  getValue(key) == value
@@ -11,20 +11,49 @@ module Stf
11
11
  end
12
12
  end
13
13
 
14
- def byFilter(filter)
15
- filter ? select {|d| d.checkFilter(filter)} : Array.new
14
+ def by_filter(filter)
15
+ filter ? select {|d| d.checkFilter?(filter)} : []
16
16
  end
17
17
 
18
- def exceptFilter(filter)
19
- filter ? reject {|d| d.checkFilter(filter)} : this
18
+ def except_filter(filter)
19
+ filter ? reject {|d| d.checkFilter?(filter)} : this
20
20
  end
21
21
 
22
- def filterReadyToConnect
23
- select {|d| d.ready == true && d.present == true && d.usage.nil? }
22
+ def select_healthy(pattern)
23
+ pattern ? select { |d| d.healthy?(pattern) } : this
24
24
  end
25
25
 
26
- def asConnectUrlList
27
- @devices.map {|d| d.remoteConnectUrl}
26
+ # more pessimistic than healthy()
27
+ def select_healthy_for_connect(pattern)
28
+ pattern ? select { |d| d.healthy_for_connect?(pattern) } : this
29
+ end
30
+
31
+ def select_not_healthy(pattern)
32
+ pattern ? reject { |d| d.healthy?(pattern) } : []
33
+ end
34
+
35
+ def select_ready_to_connect
36
+ # https://github.com/openstf/stf/blob/93d9d7fe859bb7ca71669f375d841d94fa47d751/lib/wire/wire.proto#L170
37
+ # enum DeviceStatus {
38
+ # OFFLINE = 1;
39
+ # UNAUTHORIZED = 2;
40
+ # ONLINE = 3;
41
+ # CONNECTING = 4;
42
+ # AUTHORIZING = 5;
43
+ # }
44
+ #
45
+ # https://github.com/openstf/stf/blob/93d9d7fe859bb7ca71669f375d841d94fa47d751/res/app/components/stf/device/enhance-device/enhance-device-service.js
46
+ select {|d|
47
+ d.present == true &&
48
+ d.status == 3 &&
49
+ d.ready == true &&
50
+ d.using == false &&
51
+ d.owner.nil?
52
+ }
53
+ end
54
+
55
+ def as_connect_url_list
56
+ @devices.map {|d| d.remoteConnectUrl}.reject { |c| c.nil? || c.empty? }
28
57
  end
29
58
 
30
59
  def select
@@ -32,7 +61,6 @@ module Stf
32
61
  end
33
62
 
34
63
  def reject
35
- # DeviceList.new(@devices.reject {|d| yield(d)})
36
64
  DeviceList.new(@devices.select {|d| !yield(d)})
37
65
  end
38
66
 
@@ -48,4 +76,4 @@ module Stf
48
76
  @devices
49
77
  end
50
78
  end
51
- end
79
+ end
@@ -0,0 +1,7 @@
1
+ module Stf
2
+ class URIValidator
3
+ def validate(uri)
4
+ return (uri =~ /\A#{URI::regexp(%w(http https))}\z/) != nil
5
+ end
6
+ end
7
+ end
data/lib/stf/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Stf
2
- VERSION = '0.2.6'
2
+ VERSION = '0.3.0-rc.12'
3
3
  end
data/lib/stf/view/cli.rb CHANGED
@@ -7,7 +7,7 @@ module Stf
7
7
 
8
8
  extend self
9
9
 
10
- program_desc 'Smartphone Test Lab client'
10
+ program_desc "Smartphone Test Lab client (version #{Stf::VERSION})"
11
11
 
12
12
  desc 'Be verbose'
13
13
  switch [:v, :verbose]
@@ -35,6 +35,9 @@ module Stf
35
35
  Log::verbose(global_options[:verbose])
36
36
 
37
37
  DI.init(global_options)
38
+
39
+ help_now!('Valid STF url is required, e.g. http(s)://openstf.local') if !DI[:uri_validator].validate(global_options[:url])
40
+ true
38
41
  end
39
42
 
40
43
  desc 'Search for a device available in STF and attach it to local adb server'
@@ -47,12 +50,14 @@ module Stf
47
50
  c.flag [:min]
48
51
  c.desc 'Filter key:value for devices'
49
52
  c.flag [:f, :filter]
53
+ c.desc 'Force filter check for connected devices'
54
+ c.switch [:forcefilter, :ff]
55
+ c.desc 'Check selected health parameters, could be any of the: battery,temperature,network,vpn,wifi'
56
+ c.flag [:health]
50
57
  c.desc 'Maximum session duration in seconds, 10800 (3h) by default'
51
58
  c.flag [:session]
52
59
  c.desc 'Maximum time to connect minimal quantity of devices in seconds, 120 (2m) by default'
53
60
  c.flag [:starttime]
54
- c.desc 'Maintain connactions before explicitly kill'
55
- c.switch [:forever]
56
61
  c.desc 'Do not start daemon'
57
62
  c.switch [:nodaemon]
58
63
 
@@ -63,7 +68,7 @@ module Stf
63
68
  end
64
69
  end
65
70
 
66
- desc 'Show avaliable keys for filtering'
71
+ desc 'Show available keys for filtering'
67
72
  command :keys do |c|
68
73
  c.action {puts DI[:get_keys_interactor].execute}
69
74
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stf-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.3.0.pre.rc.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anton Malinskiy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-28 00:00:00.000000000 Z
11
+ date: 2018-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gli
@@ -199,7 +199,6 @@ files:
199
199
  - lib/di.rb
200
200
  - lib/stf.rb
201
201
  - lib/stf/client.rb
202
- - lib/stf/errors.rb
203
202
  - lib/stf/interactor/get_keys_interactor.rb
204
203
  - lib/stf/interactor/get_values_interactor.rb
205
204
  - lib/stf/interactor/remove_all_user_devices_interactor.rb
@@ -210,8 +209,8 @@ files:
210
209
  - lib/stf/log/log.rb
211
210
  - lib/stf/model/device.rb
212
211
  - lib/stf/model/device_list.rb
213
- - lib/stf/model/session.rb
214
212
  - lib/stf/system/demonizer.rb
213
+ - lib/stf/validate/uri_validator.rb
215
214
  - lib/stf/version.rb
216
215
  - lib/stf/view/cli.rb
217
216
  - stf-client.gemspec
@@ -230,12 +229,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
230
229
  version: '0'
231
230
  required_rubygems_version: !ruby/object:Gem::Requirement
232
231
  requirements:
233
- - - ">="
232
+ - - ">"
234
233
  - !ruby/object:Gem::Version
235
- version: '0'
234
+ version: 1.3.1
236
235
  requirements: []
237
236
  rubyforge_project:
238
- rubygems_version: 2.6.13
237
+ rubygems_version: 2.7.7
239
238
  signing_key:
240
239
  specification_version: 4
241
240
  summary: Request devices from Smartphone Test Farm for adb connection
data/lib/stf/errors.rb DELETED
@@ -1,7 +0,0 @@
1
- module Stf
2
- class DeviceNotAvailableError < StandardError
3
- def message
4
- 'Device not available'
5
- end
6
- end
7
- end
@@ -1,12 +0,0 @@
1
- module Stf
2
- class Session
3
-
4
- attr_accessor :serial, :url
5
-
6
- def initialize(serial, url)
7
- @serial = serial
8
- @url = url
9
- end
10
-
11
- end
12
- end