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 +4 -4
- data/.rspec +3 -0
- data/.simplecov +10 -0
- data/Gemfile +2 -0
- data/README.md +5 -1
- data/lib/di.rb +73 -0
- data/lib/stf/errors.rb +6 -4
- data/lib/stf/interactor/get_keys_interactor.rb +16 -19
- data/lib/stf/interactor/get_values_interactor.rb +15 -16
- data/lib/stf/interactor/remove_all_user_devices_interactor.rb +9 -8
- data/lib/stf/interactor/start_debug_session_interactor.rb +104 -65
- data/lib/stf/interactor/start_one_debug_session_interactor.rb +55 -0
- data/lib/stf/interactor/stop_all_debug_sessions_interactor.rb +21 -13
- data/lib/stf/interactor/stop_debug_session_interactor.rb +36 -30
- data/lib/stf/log/log.rb +11 -9
- data/lib/stf/model/device.rb +35 -27
- data/lib/stf/model/device_list.rb +51 -0
- data/lib/stf/model/session.rb +9 -7
- data/lib/stf/system/demonizer.rb +20 -0
- data/lib/stf/version.rb +1 -1
- data/lib/stf/view/cli.rb +39 -33
- data/stf-client.gemspec +10 -3
- metadata +87 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8f269d60d1314cb4cdff19a25cdb99cd7ea38a7
|
4
|
+
data.tar.gz: 82fc43f8e9a2fb35b11e7db677280b207c077253
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f53f1970b97975a6998e3d5e9b6bf624dbc2b60912a56e3a94460b53f6aa400e30fa9237bf5fac9daf94dcf5a304b603d1216121b76b7d7542dff2f770266f0
|
7
|
+
data.tar.gz: fc027dea907010428aec5d7976f59838ea77b77ce63f6e2a3809ca4e6ffc7b3dfe3289a23e9f8da30d5a4a7b26cd0e59a019f27a41a9d2df2ca631b0a077084b
|
data/.rspec
CHANGED
data/.simplecov
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
[](https://travis-ci.org/Malinskiy/stf-client)
|
2
|
+
[]()
|
3
|
+
[]()
|
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,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
|
-
|
10
|
+
module Stf
|
11
|
+
class GetKeysInteractor
|
12
|
+
include Log
|
13
|
+
include ADB
|
10
14
|
|
11
|
-
|
12
|
-
|
15
|
+
def execute
|
16
|
+
devices = DI[:stf].get_devices
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
10
|
+
module Stf
|
11
|
+
class GetValuesInteractor
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
+
include Log
|
14
|
+
include ADB
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
end
|
16
|
+
def execute(key)
|
17
|
+
devices = DI[:stf].get_devices
|
17
18
|
|
18
|
-
|
19
|
-
|
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
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
1
|
+
require 'di'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
module Stf
|
4
|
+
class RemoveAllUserDevicesInteractor
|
5
|
+
def execute(opts = {})
|
6
|
+
DI[:demonizer].kill unless opts[:nokill]
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
9
|
+
module Stf
|
10
|
+
class StartDebugSessionInteractor
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
+
include Log
|
13
|
+
include ADB
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
18
|
-
wanted = 1 if wanted.nil?
|
19
|
-
wanted = wanted.to_i
|
25
|
+
DI[:demonizer].kill unless opts[:nokill]
|
20
26
|
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
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
|
-
|
37
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
36
|
+
rescue SignalException => e
|
37
|
+
DI[:stop_all_debug_sessions_interactor].execute
|
38
|
+
return false
|
46
39
|
|
47
|
-
|
48
|
-
|
40
|
+
rescue
|
41
|
+
end
|
49
42
|
|
50
|
-
|
51
|
-
|
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
|
-
|
56
|
-
|
57
|
-
return
|
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
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
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
|
-
|
67
|
-
|
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
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
-
|
89
|
-
|
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
|
-
|
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
|
-
|
9
|
-
|
10
|
-
|
10
|
+
module Stf
|
11
|
+
class StopAllDebugSessionsInteractor
|
12
|
+
include Log
|
13
|
+
include ADB
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
8
|
+
module Stf
|
9
|
+
class StopDebugSessionInteractor
|
10
|
+
include Log
|
11
|
+
include ADB
|
8
12
|
|
9
|
-
|
10
|
-
|
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
|
-
|
13
|
-
|
14
|
-
end
|
17
|
+
# try to disconnect anyway
|
18
|
+
execute_adb_with 30, "disconnect #{remote_connect_url}"
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
if device.nil?
|
21
|
+
logger.error "Device #{remote_connect_url} is not available"
|
22
|
+
return false
|
23
|
+
end
|
19
24
|
|
20
|
-
|
25
|
+
success = false
|
21
26
|
|
22
|
-
|
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
|
-
|
34
|
+
logger.error 'Can\'t stop debug session. Retrying'
|
35
|
+
end
|
25
36
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
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
|
3
|
+
module Stf
|
4
|
+
module Log
|
4
5
|
|
5
|
-
|
6
|
-
|
6
|
+
@@logger = Logger.new(STDOUT)
|
7
|
+
@@logger.level = Logger::INFO
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
def logger
|
10
|
+
@@logger
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
def self.verbose(enable)
|
14
|
+
@@logger.level = enable ? Logger::DEBUG : Logger::INFO
|
15
|
+
end
|
15
16
|
|
17
|
+
end
|
16
18
|
end
|
data/lib/stf/model/device.rb
CHANGED
@@ -1,38 +1,46 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module Stf
|
2
|
+
class Device < OpenStruct
|
3
|
+
def getValue(key)
|
4
|
+
getValueFromObject(self, key)
|
5
|
+
end
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
def getKeys
|
8
|
+
getKeysNextLevel('', self)
|
9
|
+
end
|
9
10
|
|
10
|
-
|
11
|
-
|
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
|
-
|
14
|
-
if
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
29
|
+
def concat(prefix, key)
|
30
|
+
prefix.to_s.empty? ? key : prefix + '.' + key
|
31
|
+
end
|
25
32
|
|
26
33
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
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
|
data/lib/stf/model/session.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
-
|
1
|
+
module Stf
|
2
|
+
class Session
|
2
3
|
|
3
|
-
|
4
|
+
attr_accessor :serial, :url
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
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
|
-
|
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.
|
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.
|
47
|
-
|
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
|
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.
|
73
|
+
c.action do |_, _, args|
|
74
|
+
exit_now!('Please specify one key') if args.empty?
|
61
75
|
|
62
|
-
|
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 |
|
78
|
-
if
|
79
|
-
|
80
|
-
elsif !
|
81
|
-
|
82
|
-
elsif
|
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
|
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.
|
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.
|
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:
|
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: '
|
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: '
|
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:
|
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:
|
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:
|
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:
|
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
|