stf-client 0.1.6 → 0.2.0

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
2
  SHA1:
3
- metadata.gz: 3f4e33126f8648b92df84f8f064226d2cda27f06
4
- data.tar.gz: ec864ead54872cd022c637b16e8860298a7438bd
3
+ metadata.gz: d8f269d60d1314cb4cdff19a25cdb99cd7ea38a7
4
+ data.tar.gz: 82fc43f8e9a2fb35b11e7db677280b207c077253
5
5
  SHA512:
6
- metadata.gz: 6fd1cf716d57494d7c3e244b995ee947f11182f9dff13b192927e5db81d2c93f384f375caa91462656d1832069299972b279ce7b67bd34eba4d206e8b7372ca7
7
- data.tar.gz: eb8c0476effa4f868403464d7bd7a6d35b56a12cbd00e236504c8526abfb5aeba4b2ebb4a9551f7ce53ed2caca636f4d241e94c8bbd204c041f1eecf543d155c
6
+ metadata.gz: 0f53f1970b97975a6998e3d5e9b6bf624dbc2b60912a56e3a94460b53f6aa400e30fa9237bf5fac9daf94dcf5a304b603d1216121b76b7d7542dff2f770266f0
7
+ data.tar.gz: fc027dea907010428aec5d7976f59838ea77b77ce63f6e2a3809ca4e6ffc7b3dfe3289a23e9f8da30d5a4a7b26cd0e59a019f27a41a9d2df2ca631b0a077084b
data/.rspec CHANGED
@@ -1,2 +1,5 @@
1
1
  --color
2
2
  --require spec_helper
3
+ --format documentation
4
+ --format RspecJunitFormatter --out spec/reports/rspec.xml
5
+ --format html --out spec/reports/rspec.html
data/.simplecov ADDED
@@ -0,0 +1,10 @@
1
+ require 'simplecov-json'
2
+
3
+ SimpleCov.formatters = [
4
+ SimpleCov::Formatter::HTMLFormatter,
5
+ SimpleCov::Formatter::JSONFormatter
6
+ ]
7
+ SimpleCov.minimum_coverage 80
8
+ SimpleCov.start do
9
+ add_filter '/spec/'
10
+ end
data/Gemfile CHANGED
@@ -1,2 +1,4 @@
1
1
  source 'https://rubygems.org'
2
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+
2
4
  gemspec
data/README.md CHANGED
@@ -1,3 +1,7 @@
1
+ [![Build Status](https://travis-ci.org/Malinskiy/stf-client.svg?branch=master)](https://travis-ci.org/Malinskiy/stf-client)
2
+ [![Gem](https://img.shields.io/gem/v/stf-client.svg)]()
3
+ [![Gem](https://img.shields.io/gem/dt/stf-client.svg)]()
4
+
1
5
  # Stf::Client
2
6
 
3
7
  Automation client for connecting to [OpenSTF](https://github.com/openstf/stf) devices.
@@ -58,4 +62,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/Malins
58
62
 
59
63
  ## License
60
64
 
61
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
65
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/lib/di.rb ADDED
@@ -0,0 +1,73 @@
1
+ require 'dry-container'
2
+ require 'dante'
3
+ require 'stf/system/demonizer'
4
+
5
+ require 'stf/interactor/start_debug_session_interactor'
6
+ require 'stf/interactor/start_one_debug_session_interactor'
7
+ require 'stf/interactor/stop_debug_session_interactor'
8
+ require 'stf/interactor/stop_all_debug_sessions_interactor'
9
+ require 'stf/interactor/remove_all_user_devices_interactor'
10
+ require 'stf/interactor/get_keys_interactor'
11
+ require 'stf/interactor/get_values_interactor'
12
+
13
+ class DI
14
+ class << self
15
+ def init (opts = {})
16
+
17
+ c = Dry::Container.new
18
+ @@container = c
19
+
20
+ # one time object
21
+ c.register(:dante_runner,
22
+ -> {Dante::Runner.new('stf-client')})
23
+
24
+ # one time object because dante is one time
25
+ c.register(:demonizer,
26
+ -> do
27
+ Stf::Demonizer.new(c[:dante_runner],
28
+ log_path: opts[:log], pid_path: opts[:pid])
29
+ end)
30
+
31
+ c.register(:stf,
32
+ -> {Stf::Client.new(opts[:url], opts[:token])},
33
+ memoize: true)
34
+
35
+ c.register(:start_debug_session_interactor,
36
+ -> {Stf::StartDebugSessionInteractor.new},
37
+ memoize: true)
38
+
39
+ c.register(:start_one_debug_session_interactor,
40
+ -> {Stf::StartOneDebugSessionInteractor.new},
41
+ memoize: true)
42
+
43
+ c.register(:get_keys_interactor,
44
+ -> {Stf::GetKeysInteractor.new},
45
+ memoize: true)
46
+
47
+ c.register(:get_values_interactor,
48
+ -> {Stf::GetValuesInteractor.new},
49
+ memoize: true)
50
+
51
+ c.register(:stop_all_debug_sessions_interactor,
52
+ -> {Stf::StopAllDebugSessionsInteractor.new},
53
+ memoize: true)
54
+
55
+ c.register(:stop_debug_session_interactor,
56
+ -> {Stf::StopDebugSessionInteractor.new},
57
+ memoize: true)
58
+
59
+ c.register(:remove_all_user_devices_interactor,
60
+ -> {Stf::RemoveAllUserDevicesInteractor.new},
61
+ memoize: true)
62
+
63
+ end
64
+
65
+ def [](what)
66
+ @@container.resolve(what)
67
+ end
68
+
69
+ def container
70
+ @@container
71
+ end
72
+ end
73
+ end
data/lib/stf/errors.rb CHANGED
@@ -1,5 +1,7 @@
1
- class DeviceNotAvailableError < StandardError
2
- def message
3
- 'Device not available'
1
+ module Stf
2
+ class DeviceNotAvailableError < StandardError
3
+ def message
4
+ 'Device not available'
5
+ end
4
6
  end
5
- end
7
+ end
@@ -1,4 +1,5 @@
1
1
  require 'ADB'
2
+ require 'di'
2
3
 
3
4
  require 'stf/client'
4
5
  require 'stf/log/log'
@@ -6,28 +7,24 @@ require 'stf/errors'
6
7
  require 'stf/model/session'
7
8
  require 'stf/model/device'
8
9
 
9
- class GetKeysInteractor
10
+ module Stf
11
+ class GetKeysInteractor
12
+ include Log
13
+ include ADB
10
14
 
11
- include Log
12
- include ADB
15
+ def execute
16
+ devices = DI[:stf].get_devices
13
17
 
14
- def initialize(stf)
15
- @stf = stf
16
- end
17
-
18
- def execute
19
- devices = @stf.get_devices
18
+ if devices.nil? || (devices.is_a?(Array) && devices.empty?)
19
+ logger.info 'No devices connected to STF'
20
+ return []
21
+ end
20
22
 
21
- if devices.nil? || (devices.is_a?(Array) && devices.empty?)
22
- logger.info 'No devices connected to STF'
23
- return []
23
+ devices
24
+ .map {|d| Device.new(d)}
25
+ .flat_map {|d| d.getKeys}
26
+ .uniq
27
+ .sort
24
28
  end
25
-
26
- return devices
27
- .map {|d| Device.new(d)}
28
- .flat_map {|d| d.getKeys }
29
- .uniq
30
- .sort
31
29
  end
32
-
33
30
  end
@@ -1,3 +1,4 @@
1
+ require 'di'
1
2
  require 'ADB'
2
3
 
3
4
  require 'stf/client'
@@ -6,27 +7,25 @@ require 'stf/errors'
6
7
  require 'stf/model/session'
7
8
  require 'stf/model/device'
8
9
 
9
- class GetValuesInteractor
10
+ module Stf
11
+ class GetValuesInteractor
10
12
 
11
- include Log
12
- include ADB
13
+ include Log
14
+ include ADB
13
15
 
14
- def initialize(stf)
15
- @stf = stf
16
- end
16
+ def execute(key)
17
+ devices = DI[:stf].get_devices
17
18
 
18
- def execute(key)
19
- devices = @stf.get_devices
19
+ if devices.nil? || (devices.is_a?(Array) && devices.empty?)
20
+ logger.info r 'No devices connected to STF'
21
+ return []
22
+ end
20
23
 
21
- if devices.nil? || (devices.is_a?(Array) && devices.empty?)
22
- logger.info r 'No devices connected to STF'
23
- return []
24
+ devices
25
+ .map {|d| Device.new(d)}
26
+ .map {|d| d.getValue(key)}
27
+ .uniq
24
28
  end
25
29
 
26
- return devices
27
- .map {|d| Device.new(d)}
28
- .map {|d| d.getValue(key)}
29
- .uniq
30
30
  end
31
-
32
31
  end
@@ -1,11 +1,12 @@
1
- class RemoveAllUserDevicesInteractor
1
+ require 'di'
2
2
 
3
- def initialize(stf)
4
- @stf = stf
5
- end
3
+ module Stf
4
+ class RemoveAllUserDevicesInteractor
5
+ def execute(opts = {})
6
+ DI[:demonizer].kill unless opts[:nokill]
6
7
 
7
- def execute
8
- devices = @stf.get_user_devices
9
- devices.each { |d| @stf.remove_device d.serial }
8
+ devices = DI[:stf].get_user_devices
9
+ devices.each {|d| DI[:stf].remove_device d.serial}
10
+ end
10
11
  end
11
- end
12
+ end
@@ -4,93 +4,132 @@ require 'stf/client'
4
4
  require 'stf/log/log'
5
5
  require 'stf/errors'
6
6
  require 'stf/model/session'
7
+ require 'stf/model/device_list'
7
8
 
8
- class StartDebugSessionInteractor
9
+ module Stf
10
+ class StartDebugSessionInteractor
9
11
 
10
- include Log
11
- include ADB
12
+ include Log
13
+ include ADB
12
14
 
13
- def initialize(stf)
14
- @stf = stf
15
- end
15
+ def execute(opts = {})
16
+ all_flag = opts[:all]
17
+ forever_flag = opts[:forever]
18
+ nodaemon_flag = opts[:nodaemon]
19
+ filter = opts[:filter]
20
+ max_n = opts[:n].to_i > 0 ? opts[:n].to_i : 1
21
+ start_timeout = opts[:starttime].to_i > 0 ? opts[:starttime].to_i : 120
22
+ 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
16
24
 
17
- def execute(wanted, all_flag, filter)
18
- wanted = 1 if wanted.nil?
19
- wanted = wanted.to_i
25
+ DI[:demonizer].kill unless opts[:nokill]
20
26
 
21
- 1..10.times do
22
- wanted -= connect(wanted, all_flag, filter)
23
- return if all_flag || wanted <= 0
24
- logger.info 'We are still waiting for ' + wanted.to_s + ' device(s). Retrying'
25
- sleep 5
26
- end
27
- end
27
+ if filter
28
+ DI[:stop_all_debug_sessions_interactor].execute(exceptFilter: filter)
29
+ end
28
30
 
29
- def connect(wanted, all_flag, filter)
30
- devices = @stf.get_devices
31
- if devices.nil? || (devices.is_a?(Array) && devices.empty?)
32
- logger.info 'No devices connected to STF'
33
- return 0
34
- end
31
+ wanted = nodaemon_flag ? max_n : min_n
35
32
 
36
- usable_devices = devices
37
- .map {|d| Device.new(d)}
38
- .select do |d|
39
- d.ready == true && d.present == true && d.using == false
40
- end
33
+ begin
34
+ connect_loop(all_flag, wanted, filter, false, 5, start_timeout)
41
35
 
42
- if usable_devices.empty?
43
- logger.error 'All devices are being used'
44
- return 0
45
- end
36
+ rescue SignalException => e
37
+ DI[:stop_all_debug_sessions_interactor].execute
38
+ return false
46
39
 
47
- unless filter.nil?
48
- key, value = filter.split(':', 2)
40
+ rescue
41
+ end
49
42
 
50
- usable_devices = usable_devices.select do |d|
51
- d.getValue(key) == value
43
+ connected_count = count_connected_devices(filter)
44
+ if all_flag ? connected_count.zero? : connected_count < wanted
45
+ DI[:stop_all_debug_sessions_interactor].execute
46
+ return false
52
47
  end
53
- end
54
48
 
55
- if usable_devices.empty?
56
- logger.error 'There is no device with criteria ' + filter
57
- return 0
49
+ logger.info "Lower quantity achieved, already connected #{connected_count}"
50
+
51
+ return true if nodaemon_flag
52
+
53
+ # will be daemon here
54
+ DI[:demonizer].run do
55
+ connect_loop(all_flag,
56
+ max_n,
57
+ filter,
58
+ true,
59
+ 30,
60
+ session,
61
+ forever_flag)
62
+
63
+ DI[:stop_all_debug_sessions_interactor].execute(byFilter: filter, nokill: true)
64
+ end
65
+
66
+ return true
58
67
  end
59
68
 
60
- n = 0
61
- usable_devices.shuffle.each do |d|
62
- n += 1 if connect_device(d)
63
- break if !all_flag && n >= wanted
69
+ def connect_loop(all_flag, wanted, filter, infinite_flag, delay, timeout, forever_flag = false)
70
+ finish_time = Time.now + timeout
71
+
72
+ while forever_flag || Time.now < finish_time do
73
+ cleanup_disconnected_devices(filter)
74
+
75
+ stf_devices = DeviceList.new(DI[:stf].get_devices)
76
+ stf_devices = stf_devices.byFilter(filter) if filter
77
+
78
+ if all_flag
79
+ batch = stf_devices.filterReadyToConnect.size
80
+ else
81
+ connected = devices & stf_devices.asConnectUrlList
82
+ batch = wanted - connected.size
83
+ end
84
+
85
+ if batch > 0
86
+ n = connect(filter, all_flag, batch)
87
+ break if n == batch && !infinite_flag
88
+ elsif !infinite_flag
89
+ break
90
+ end
91
+
92
+ sleep delay
93
+ end
94
+
64
95
  end
65
96
 
66
- n
67
- end
97
+ def count_connected_devices(filter)
98
+ stf_devices = DeviceList.new(DI[:stf].get_user_devices)
99
+ stf_devices = stf_devices.byFilter(filter) if filter
100
+ connected = devices & stf_devices.asConnectUrlList
101
+ connected.size
102
+ end
68
103
 
69
- def connect_device(device)
70
- begin
71
- return false if device.nil?
104
+ def cleanup_disconnected_devices(filter)
105
+ stf_devices = DeviceList.new(DI[:stf].get_user_devices)
106
+ stf_devices = stf_devices.byFilter(filter) if filter
107
+ connected = stf_devices.asConnectUrlList - devices
72
108
 
73
- serial = device.serial
74
- success = @stf.add_device serial
75
- if success
76
- logger.info "Device #{serial} added"
77
- elsif logger.error "Can't add device #{serial}"
78
- return false
109
+ connected.reject {|url| url.to_s.empty?}.each do |url|
110
+ logger.info 'Cleanup the device ' + url.to_s
111
+ DI[:stop_debug_session_interactor].execute(url)
79
112
  end
113
+ end
80
114
 
81
- result = @stf.start_debug serial
82
- unless result.success
83
- logger.error "Can't start debugging session for device #{serial}"
84
- @stf.remove_device serial
85
- return false
115
+ def connect(filter, all_flag, wanted)
116
+ devices = DeviceList.new(DI[:stf].get_devices)
117
+ devices = devices.filterReadyToConnect
118
+ devices = devices.byFilter(filter) if filter
119
+
120
+ if devices.empty?
121
+ logger.error 'There is no available devices with criteria ' + filter
122
+ return 0
86
123
  end
87
124
 
88
- execute_adb_with 30, "connect #{result.remoteConnectUrl}"
89
- return true
125
+ n = 0
126
+ devices.asArray.shuffle.each do |d|
127
+ n += 1 if DI[:start_one_debug_session_interactor].execute(d)
128
+ break if !all_flag && n >= wanted
129
+ end
90
130
 
91
- rescue Net::HTTPFatalError
92
- logger.error 'Failed to start debug session'
93
- return false
131
+ n
94
132
  end
133
+
95
134
  end
96
- end
135
+ end
@@ -0,0 +1,55 @@
1
+ require 'di'
2
+ require 'ADB'
3
+
4
+ require 'stf/client'
5
+ require 'stf/log/log'
6
+ require 'stf/errors'
7
+ require 'stf/model/session'
8
+
9
+ module Stf
10
+ class StartOneDebugSessionInteractor
11
+
12
+ include Log
13
+ include ADB
14
+
15
+ def execute(device)
16
+ return false if device.nil?
17
+ serial = device.serial
18
+
19
+ begin
20
+ success = DI[:stf].add_device serial
21
+ if success
22
+ logger.info "Device added #{serial}"
23
+ else
24
+ logger.error "Can't add device #{serial}"
25
+ raise
26
+ end
27
+
28
+ result = DI[:stf].start_debug serial
29
+ if result.success
30
+ logger.info "Debug started #{serial}"
31
+ else
32
+ logger.error "Can't start debugging session for device #{serial}"
33
+ raise
34
+ end
35
+
36
+ execute_adb_with 30, "connect #{result.remoteConnectUrl}"
37
+
38
+ return true
39
+
40
+ rescue SignalException => e
41
+ raise e
42
+
43
+ rescue => e
44
+ begin
45
+ # we will try clean anyway
46
+ DI[:stf].remove_device serial
47
+ rescue
48
+ end
49
+
50
+ logger.error "Failed to connect to #{serial}"
51
+ return false
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,25 +1,33 @@
1
+ require 'di'
1
2
  require 'ADB'
2
3
 
3
4
  require 'stf/client'
4
5
  require 'stf/log/log'
5
6
  require 'stf/errors'
6
7
  require 'stf/interactor/stop_debug_session_interactor'
8
+ require 'stf/model/device_list'
7
9
 
8
- class StopAllDebugSessionsInteractor
9
- include Log
10
- include ADB
10
+ module Stf
11
+ class StopAllDebugSessionsInteractor
12
+ include Log
13
+ include ADB
11
14
 
12
- def initialize(stf)
13
- @stf = stf
14
- end
15
+ # byFilter:
16
+ # exceptFilter:
17
+ def execute(options = {})
18
+ DI[:demonizer].kill unless options[:nokill]
19
+
20
+ stf_devices = DeviceList.new(DI[:stf].get_user_devices)
21
+
22
+ stf_devices = stf_devices.byFilter options[:byFilter] if options[:byFilter]
23
+ stf_devices = stf_devices.exceptFilter options[:exceptFilter] if options[:exceptFilter]
24
+
25
+ connected_devices = devices()
26
+ remote_devices = stf_devices.asConnectUrlList
15
27
 
16
- def execute
17
- connected_devices = devices()
18
- remote_devices = @stf.get_user_devices.map { |d| d.remoteConnectUrl }
28
+ pending_disconnect = connected_devices & remote_devices
19
29
 
20
- pending_disconnect = connected_devices & remote_devices
21
- pending_disconnect.each do |d|
22
- StopDebugSessionInteractor.new(@stf).execute d
30
+ pending_disconnect.each {|d| DI[:stop_debug_session_interactor].execute d}
23
31
  end
24
32
  end
25
- end
33
+ end
@@ -1,49 +1,55 @@
1
+ require 'di'
1
2
  require 'ADB'
2
3
 
3
4
  require 'stf/client'
4
5
  require 'stf/log/log'
5
6
  require 'stf/errors'
6
7
 
7
- class StopDebugSessionInteractor
8
+ module Stf
9
+ class StopDebugSessionInteractor
10
+ include Log
11
+ include ADB
8
12
 
9
- include Log
10
- include ADB
13
+ def execute(remote_connect_url)
14
+ remote_devices = DI[:stf].get_user_devices
15
+ device = remote_devices.find {|d| d.remoteConnect == true && d.remoteConnectUrl.eql?(remote_connect_url)}
11
16
 
12
- def initialize(stf)
13
- @stf = stf
14
- end
17
+ # try to disconnect anyway
18
+ execute_adb_with 30, "disconnect #{remote_connect_url}"
15
19
 
16
- def execute(remoteConnectUrl)
17
- remote_devices = @stf.get_user_devices
18
- device = remote_devices.find { |d| d.remoteConnect == true && d.remoteConnectUrl.eql?(remoteConnectUrl) }
20
+ if device.nil?
21
+ logger.error "Device #{remote_connect_url} is not available"
22
+ return false
23
+ end
19
24
 
20
- raise DeviceNotAvailableError if device.nil?
25
+ success = false
21
26
 
22
- execute_adb_with 30, "disconnect #{device.remoteConnectUrl}"
27
+ 1..10.times do
28
+ begin
29
+ success = DI[:stf].stop_debug(device.serial)
30
+ break if success
31
+ rescue
32
+ end
23
33
 
24
- success = false
34
+ logger.error 'Can\'t stop debug session. Retrying'
35
+ end
25
36
 
26
- 1..10.times do
27
- success = @stf.stop_debug(device.serial)
28
- if success == true
29
- break
30
- elsif logger.error 'Can\'t stop debug session. Retrying'
37
+ 1..10.times do
38
+ begin
39
+ success = DI[:stf].remove_device(device.serial)
40
+ break if success
41
+ rescue
42
+ end
43
+ logger.error 'Can\'t remove device from user devices. Retrying'
31
44
  end
32
- end
33
45
 
34
- 1..10.times do
35
- success = @stf.remove_device(device.serial)
36
- if success == true
37
- break
38
- elsif logger.error 'Can\'t remove device from user devices. Retrying'
46
+ if success
47
+ logger.info "Successfully removed #{remote_connect_url}"
48
+ else
49
+ logger.error "Error removing #{remote_connect_url}"
39
50
  end
40
- end
41
51
 
42
- if success == true
43
- logger.info "Successfully removed #{remoteConnectUrl}"
44
- elsif logger.error "Error removing #{remoteConnectUrl}"
52
+ success
45
53
  end
46
-
47
- return success
48
54
  end
49
- end
55
+ end
data/lib/stf/log/log.rb CHANGED
@@ -1,16 +1,18 @@
1
1
  require 'logger'
2
2
 
3
- module Log
3
+ module Stf
4
+ module Log
4
5
 
5
- @@logger = Logger.new(STDOUT)
6
- @@logger.level = Logger::INFO
6
+ @@logger = Logger.new(STDOUT)
7
+ @@logger.level = Logger::INFO
7
8
 
8
- def logger
9
- @@logger
10
- end
9
+ def logger
10
+ @@logger
11
+ end
11
12
 
12
- def self.verbose(enable)
13
- @@logger.level = enable ? Logger::DEBUG : Logger::INFO
14
- end
13
+ def self.verbose(enable)
14
+ @@logger.level = enable ? Logger::DEBUG : Logger::INFO
15
+ end
15
16
 
17
+ end
16
18
  end
@@ -1,38 +1,46 @@
1
- class Device < OpenStruct
2
- def getValue(key)
3
- getValueFromObject(self, key)
4
- end
1
+ module Stf
2
+ class Device < OpenStruct
3
+ def getValue(key)
4
+ getValueFromObject(self, key)
5
+ end
5
6
 
6
- def getKeys
7
- getKeysNextLevel('', self)
8
- end
7
+ def getKeys
8
+ getKeysNextLevel('', self)
9
+ end
9
10
 
10
- def getKeysNextLevel(prefix, o)
11
- return [] if o.nil?
11
+ def checkFilter(filter)
12
+ return true if filter.nil?
13
+ key, value = filter.split(':', 2)
14
+ getValue(key) == value
15
+ end
12
16
 
13
- o.each_pair.flat_map do |k, v|
14
- if v.is_a? OpenStruct
15
- getKeysNextLevel(concat(prefix, k.to_s), v)
16
- else
17
- [concat(prefix, k.to_s)]
17
+ def getKeysNextLevel(prefix, o)
18
+ return [] if o.nil?
19
+
20
+ o.each_pair.flat_map do |k, v|
21
+ if v.is_a? OpenStruct
22
+ getKeysNextLevel(concat(prefix, k.to_s), v)
23
+ else
24
+ [concat(prefix, k.to_s)]
25
+ end
18
26
  end
19
27
  end
20
- end
21
28
 
22
- def concat(prefix, key)
23
- prefix.to_s.empty? ? key : prefix + '.' + key
24
- end
29
+ def concat(prefix, key)
30
+ prefix.to_s.empty? ? key : prefix + '.' + key
31
+ end
25
32
 
26
33
 
27
- def getValueFromObject(obj, key)
28
- keys = key.split('.', 2)
29
- if keys[1].nil?
30
- obj[key]
31
- else
32
- getValueFromObject(obj[keys[0]], keys[1])
34
+ def getValueFromObject(obj, key)
35
+ keys = key.split('.', 2)
36
+ if keys[1].nil?
37
+ obj[key]
38
+ else
39
+ getValueFromObject(obj[keys[0]], keys[1])
40
+ end
33
41
  end
34
- end
35
42
 
36
- private :getValueFromObject,:concat, :getKeysNextLevel
43
+ private :getValueFromObject, :concat, :getKeysNextLevel
37
44
 
38
- end
45
+ end
46
+ end
@@ -0,0 +1,51 @@
1
+ require 'stf/model/device'
2
+
3
+ module Stf
4
+ # can not inherite from Array because http://words.steveklabnik.com/beware-subclassing-ruby-core-classes
5
+ class DeviceList
6
+ def initialize(devices)
7
+ if devices.nil?
8
+ @devices = Array.new
9
+ else
10
+ @devices = devices.map {|d| (d.kind_of? Device) ? d : Device.new(d)}
11
+ end
12
+ end
13
+
14
+ def byFilter(filter)
15
+ filter ? select {|d| d.checkFilter(filter)} : Array.new
16
+ end
17
+
18
+ def exceptFilter(filter)
19
+ filter ? reject {|d| d.checkFilter(filter)} : this
20
+ end
21
+
22
+ def filterReadyToConnect
23
+ select {|d| d.ready == true && d.present == true && d.using == false}
24
+ end
25
+
26
+ def asConnectUrlList
27
+ @devices.map {|d| d.remoteConnectUrl}
28
+ end
29
+
30
+ def select
31
+ DeviceList.new(@devices.select {|d| yield(d)})
32
+ end
33
+
34
+ def reject
35
+ # DeviceList.new(@devices.reject {|d| yield(d)})
36
+ DeviceList.new(@devices.select {|d| !yield(d)})
37
+ end
38
+
39
+ def empty?
40
+ @devices.empty?
41
+ end
42
+
43
+ def size
44
+ @devices.size
45
+ end
46
+
47
+ def asArray
48
+ @devices
49
+ end
50
+ end
51
+ end
@@ -1,10 +1,12 @@
1
- class Session
1
+ module Stf
2
+ class Session
2
3
 
3
- attr_accessor :serial, :url
4
+ attr_accessor :serial, :url
4
5
 
5
- def initialize(serial, url)
6
- @serial = serial
7
- @url = url
8
- end
6
+ def initialize(serial, url)
7
+ @serial = serial
8
+ @url = url
9
+ end
9
10
 
10
- end
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ module Stf
2
+ class Demonizer
3
+ def initialize(dante, opts = {})
4
+ @dante = dante
5
+
6
+ @pid_path = opts[:pid_path].to_s.empty? ? '/tmp/stf-client.pid' : opts[:pid_path]
7
+ @log_path = opts[:log_path].to_s.empty? ? '/tmp/stf-client.log' : opts[:log_path]
8
+ end
9
+
10
+ def run
11
+ @dante.execute(daemonize: true,
12
+ pid_path: @pid_path,
13
+ log_path: @log_path) {yield}
14
+ end
15
+
16
+ def kill
17
+ @dante.execute(kill: true, pid_path: @pid_path)
18
+ end
19
+ end
20
+ end
data/lib/stf/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Stf
2
- VERSION = '0.1.6'
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/stf/view/cli.rb CHANGED
@@ -1,16 +1,10 @@
1
1
  module Stf
2
2
  module CLI
3
+ require 'di'
3
4
  require 'gli'
4
- require 'stf/client'
5
-
6
- require 'stf/interactor/start_debug_session_interactor'
7
- require 'stf/interactor/stop_debug_session_interactor'
8
- require 'stf/interactor/stop_all_debug_sessions_interactor'
9
- require 'stf/interactor/remove_all_user_devices_interactor'
10
- require 'stf/interactor/get_keys_interactor'
11
- require 'stf/interactor/get_values_interactor'
12
5
 
13
6
  include GLI::App
7
+
14
8
  extend self
15
9
 
16
10
  program_desc 'Smartphone Test Lab client'
@@ -18,6 +12,12 @@ module Stf
18
12
  desc 'Be verbose'
19
13
  switch [:v, :verbose]
20
14
 
15
+ desc 'PID file'
16
+ flag [:pid]
17
+
18
+ desc 'Log file'
19
+ flag [:log]
20
+
21
21
  desc 'Authorization token, can also be set by environment variable STF_TOKEN'
22
22
  flag [:t, :token]
23
23
 
@@ -34,61 +34,67 @@ module Stf
34
34
 
35
35
  Log::verbose(global_options[:verbose])
36
36
 
37
- $stf = Stf::Client.new(global_options[:url], global_options[:token])
37
+ DI.init(global_options)
38
38
  end
39
39
 
40
40
  desc 'Search for a device available in STF and attach it to local adb server'
41
41
  command :connect do |c|
42
+ c.desc 'Connect to all available devices'
42
43
  c.switch [:all]
43
- c.flag [:n, :number]
44
+ c.desc 'Required quantity of devices'
45
+ c.flag [:n]
46
+ c.desc 'Minimal quantity of devices, n/2 by default'
47
+ c.flag [:min]
48
+ c.desc 'Filter key:value for devices'
44
49
  c.flag [:f, :filter]
45
-
46
- c.action do |global_options, options, args|
47
- StartDebugSessionInteractor.new($stf).execute(options[:number], options[:all], options[:filter])
50
+ c.desc 'Maximum session duration in seconds, 10800 (3h) by default'
51
+ c.flag [:session]
52
+ c.desc 'Maximum time to connect minimal quantity of devices in seconds, 120 (2m) by default'
53
+ c.flag [:starttime]
54
+ c.desc 'Maintain connactions before explicitly kill'
55
+ c.switch [:forever]
56
+ c.desc 'Do not start daemon'
57
+ c.switch [:nodaemon]
58
+
59
+ c.action do |_, options, _|
60
+ unless DI[:start_debug_session_interactor].execute(options)
61
+ raise GLI::CustomExit.new('Connect failed', 1)
62
+ end
48
63
  end
49
64
  end
50
65
 
51
66
  desc 'Show avaliable keys for filtering'
52
67
  command :keys do |c|
53
- c.action do |global_options, options, args|
54
- puts GetKeysInteractor.new($stf).execute
55
- end
68
+ c.action {puts DI[:get_keys_interactor].execute}
56
69
  end
57
70
 
58
71
  desc 'Show known values for the filtering key'
59
72
  command :values do |c|
60
- c.flag [:k, :key]
73
+ c.action do |_, _, args|
74
+ exit_now!('Please specify one key') if args.empty?
61
75
 
62
- c.action do |global_options, options, args|
63
- if options[:key].nil?
64
- help_now!('Please specify the key (--key)')
65
- else
66
- puts GetValuesInteractor.new($stf).execute(options[:key])
67
- end
76
+ puts DI[:get_values_interactor].execute(args.first)
68
77
  end
69
78
  end
70
79
 
71
80
  desc 'Disconnect device(s) from local adb server and remove device(s) from user devices in STF'
72
81
  command :disconnect do |c|
73
82
  c.desc '(optional) ADB connection url of the device'
74
- c.flag [:d, :device]
75
83
  c.switch [:all]
76
84
 
77
- c.action do |global_options, options, args|
78
- if options[:device].nil? && options[:all] == true
79
- StopAllDebugSessionsInteractor.new($stf).execute
80
- elsif !options[:device].nil? && options[:all] == false
81
- StopDebugSessionInteractor.new($stf).execute(options[:device])
82
- elsif help_now!('Please specify disconnect mode (--all or --device)')
85
+ c.action do |_, options, args|
86
+ if args.empty? && options[:all] == true
87
+ DI[:stop_all_debug_sessions_interactor].execute
88
+ elsif !args.empty? && options[:all] == false
89
+ DI[:stop_debug_session_interactor].execute(args.first)
90
+ elsif exit_now!('Please specify one device or mode --all')
83
91
  end
84
92
  end
85
93
  end
86
94
 
87
95
  desc 'Frees all devices that are assigned to current user in STF. Doesn\'t modify local adb'
88
96
  command :clean do |c|
89
- c.action do |global_options, options, args|
90
- RemoveAllUserDevicesInteractor.new($stf).execute
91
- end
97
+ c.action {DI[:remove_all_user_devices_interactor].execute}
92
98
  end
93
99
 
94
100
  exit run(ARGV)
data/stf-client.gemspec CHANGED
@@ -15,12 +15,19 @@ Gem::Specification.new do |spec|
15
15
  spec.require_paths = ['lib']
16
16
  spec.executables = ['stf-client']
17
17
 
18
- spec.add_runtime_dependency 'gli'
19
- spec.add_runtime_dependency 'ADB'
18
+ spec.add_runtime_dependency 'gli', '~> 2.17'
19
+ spec.add_runtime_dependency 'ADB', '~> 0.5'
20
+ spec.add_runtime_dependency 'dante', '~> 0.2.0'
21
+ spec.add_runtime_dependency 'dry-container', '~> 0.6.0'
20
22
 
21
- spec.add_development_dependency 'bundler', '~> 1.12'
23
+ # spec.add_runtime_dependency 'pry', '~> 0.10.4'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.16.a'
22
26
  spec.add_development_dependency 'rake', '~> 10.0'
23
27
  spec.add_development_dependency 'rspec', '~> 3.5'
28
+ spec.add_development_dependency 'rspec_junit_formatter', '~> 0.2'
24
29
  spec.add_development_dependency 'webmock', '~> 2.1'
25
30
  spec.add_development_dependency 'sinatra', '~> 1.4'
31
+ spec.add_development_dependency 'simplecov', '~> 0.14'
32
+ spec.add_development_dependency 'simplecov-json', '~> 0.2'
26
33
  end
metadata CHANGED
@@ -1,57 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stf-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anton Malinskiy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-27 00:00:00.000000000 Z
11
+ date: 2018-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gli
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '2.17'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '2.17'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: ADB
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dante
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.2.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.2.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: dry-container
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
32
60
  - !ruby/object:Gem::Version
33
- version: '0'
61
+ version: 0.6.0
34
62
  type: :runtime
35
63
  prerelease: false
36
64
  version_requirements: !ruby/object:Gem::Requirement
37
65
  requirements:
38
- - - ">="
66
+ - - "~>"
39
67
  - !ruby/object:Gem::Version
40
- version: '0'
68
+ version: 0.6.0
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: bundler
43
71
  requirement: !ruby/object:Gem::Requirement
44
72
  requirements:
45
73
  - - "~>"
46
74
  - !ruby/object:Gem::Version
47
- version: '1.12'
75
+ version: 1.16.a
48
76
  type: :development
49
77
  prerelease: false
50
78
  version_requirements: !ruby/object:Gem::Requirement
51
79
  requirements:
52
80
  - - "~>"
53
81
  - !ruby/object:Gem::Version
54
- version: '1.12'
82
+ version: 1.16.a
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: rake
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +108,20 @@ dependencies:
80
108
  - - "~>"
81
109
  - !ruby/object:Gem::Version
82
110
  version: '3.5'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec_junit_formatter
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.2'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.2'
83
125
  - !ruby/object:Gem::Dependency
84
126
  name: webmock
85
127
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +150,34 @@ dependencies:
108
150
  - - "~>"
109
151
  - !ruby/object:Gem::Version
110
152
  version: '1.4'
153
+ - !ruby/object:Gem::Dependency
154
+ name: simplecov
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.14'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.14'
167
+ - !ruby/object:Gem::Dependency
168
+ name: simplecov-json
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '0.2'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '0.2'
111
181
  description:
112
182
  email:
113
183
  - anton@malinskiy.com
@@ -118,6 +188,7 @@ extra_rdoc_files: []
118
188
  files:
119
189
  - ".gitignore"
120
190
  - ".rspec"
191
+ - ".simplecov"
121
192
  - ".travis.yml"
122
193
  - Gemfile
123
194
  - LICENSE.txt
@@ -125,6 +196,7 @@ files:
125
196
  - Rakefile
126
197
  - bin/setup
127
198
  - bin/stf-client
199
+ - lib/di.rb
128
200
  - lib/stf.rb
129
201
  - lib/stf/client.rb
130
202
  - lib/stf/errors.rb
@@ -132,11 +204,14 @@ files:
132
204
  - lib/stf/interactor/get_values_interactor.rb
133
205
  - lib/stf/interactor/remove_all_user_devices_interactor.rb
134
206
  - lib/stf/interactor/start_debug_session_interactor.rb
207
+ - lib/stf/interactor/start_one_debug_session_interactor.rb
135
208
  - lib/stf/interactor/stop_all_debug_sessions_interactor.rb
136
209
  - lib/stf/interactor/stop_debug_session_interactor.rb
137
210
  - lib/stf/log/log.rb
138
211
  - lib/stf/model/device.rb
212
+ - lib/stf/model/device_list.rb
139
213
  - lib/stf/model/session.rb
214
+ - lib/stf/system/demonizer.rb
140
215
  - lib/stf/version.rb
141
216
  - lib/stf/view/cli.rb
142
217
  - stf-client.gemspec