stf-client 0.1.6 → 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 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