fastlane-plugin-test_center 3.6.3 → 3.7.0.parallelizing.alpha.4
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 +5 -5
- data/README.md +4 -0
- data/lib/fastlane/plugin/test_center.rb +1 -1
- data/lib/fastlane/plugin/test_center/actions/collate_test_result_bundles.rb +1 -1
- data/lib/fastlane/plugin/test_center/actions/multi_scan.rb +109 -25
- data/lib/fastlane/plugin/test_center/actions/restart_core_simulator_service.rb +38 -0
- data/lib/fastlane/plugin/test_center/actions/tests_from_xctestrun.rb +16 -4
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager.rb +5 -0
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/device_manager.rb +30 -0
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/interstitial.rb +143 -0
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/parallel_test_batch_worker.rb +27 -0
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/report_collator.rb +115 -0
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan.rb +74 -0
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb +255 -0
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/runner.rb +356 -0
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/simulator_helper.rb +49 -0
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/simulator_manager.rb +317 -0
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker.rb +20 -0
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker_pool.rb +129 -0
- data/lib/fastlane/plugin/test_center/helper/reportname_helper.rb +15 -6
- data/lib/fastlane/plugin/test_center/helper/test_collector.rb +49 -3
- data/lib/fastlane/plugin/test_center/helper/xcodebuild_string.rb +4 -0
- data/lib/fastlane/plugin/test_center/helper/xctestrun_info.rb +42 -0
- data/lib/fastlane/plugin/test_center/version.rb +1 -1
- metadata +38 -10
- data/lib/fastlane/plugin/test_center/helper/correcting_scan_helper.rb +0 -293
@@ -0,0 +1,20 @@
|
|
1
|
+
module TestCenter
|
2
|
+
module Helper
|
3
|
+
module MultiScanManager
|
4
|
+
class TestBatchWorker
|
5
|
+
attr_accessor :state
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
@options = options
|
9
|
+
@state = :ready_to_work
|
10
|
+
end
|
11
|
+
|
12
|
+
def run(run_options)
|
13
|
+
self.state = :working
|
14
|
+
RetryingScan.run(@options.merge(run_options))
|
15
|
+
self.state = :ready_to_work
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
module TestCenter
|
2
|
+
module Helper
|
3
|
+
module MultiScanManager
|
4
|
+
class TestBatchWorkerPool
|
5
|
+
def initialize(options)
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def is_serial?
|
10
|
+
@options.fetch(:parallel_simulator_fork_count, 1) == 1
|
11
|
+
end
|
12
|
+
|
13
|
+
def setup_workers
|
14
|
+
if is_serial?
|
15
|
+
setup_serial_workers
|
16
|
+
else
|
17
|
+
setup_parallel_workers
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def setup_cloned_simulators
|
22
|
+
@simhelper = SimulatorHelper.new(
|
23
|
+
parallelize: true,
|
24
|
+
batch_count: @options[:parallel_simulator_fork_count] || @options[:batch_count]
|
25
|
+
)
|
26
|
+
@simhelper.setup
|
27
|
+
@clones = @simhelper.clone_destination_simulators
|
28
|
+
main_pid = Process.pid
|
29
|
+
at_exit do
|
30
|
+
clean_up_cloned_simulators(@clones) if Process.pid == main_pid
|
31
|
+
end
|
32
|
+
@clones
|
33
|
+
end
|
34
|
+
|
35
|
+
def destination_from_simulators(simulators)
|
36
|
+
simulators.map do |simulator|
|
37
|
+
"platform=iOS Simulator,id=#{simulator.udid}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup_parallel_workers
|
42
|
+
setup_cloned_simulators
|
43
|
+
desired_worker_count = @options[:parallel_simulator_fork_count]
|
44
|
+
@workers = []
|
45
|
+
(0...desired_worker_count).each do |worker_index|
|
46
|
+
@workers << ParallelTestBatchWorker.new(parallel_scan_options(worker_index))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def parallel_scan_options(worker_index)
|
51
|
+
options = @options.reject { |key| %i[device devices].include?(key) }
|
52
|
+
options[:destination] = destination_from_simulators(@clones[worker_index])
|
53
|
+
options[:xctestrun] = xctestrun_products_clone if @options[:xctestrun]
|
54
|
+
options[:buildlog_path] = buildlog_path_for_worker(worker_index) if @options[:buildlog_path]
|
55
|
+
options[:derived_data_path] = derived_data_path_for_worker(worker_index)
|
56
|
+
options
|
57
|
+
end
|
58
|
+
|
59
|
+
def xctestrun_products_clone
|
60
|
+
xctestrun_filename = File.basename(@options[:xctestrun])
|
61
|
+
xcproduct_dirpath = File.dirname(@options[:xctestrun])
|
62
|
+
tmp_xcproduct_dirpath = Dir.mktmpdir
|
63
|
+
FileUtils.cp_r(xcproduct_dirpath, tmp_xcproduct_dirpath)
|
64
|
+
at_exit do
|
65
|
+
FileUtils.rm_rf(tmp_xcproduct_dirpath)
|
66
|
+
end
|
67
|
+
"#{tmp_xcproduct_dirpath}/#{File.basename(xcproduct_dirpath)}/#{xctestrun_filename}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def buildlog_path_for_worker(worker_index)
|
71
|
+
"#{@options[:buildlog_path]}/parallel-simulators-#{worker_index}-logs"
|
72
|
+
end
|
73
|
+
|
74
|
+
def derived_data_path_for_worker(worker_index)
|
75
|
+
Dir.mktmpdir(['derived_data_path', "-worker-#{worker_index.to_s}"])
|
76
|
+
end
|
77
|
+
|
78
|
+
def clean_up_cloned_simulators(clones)
|
79
|
+
return if clones.nil?
|
80
|
+
|
81
|
+
clones.flatten.each(&:delete)
|
82
|
+
end
|
83
|
+
|
84
|
+
def setup_serial_workers
|
85
|
+
@workers = [
|
86
|
+
TestBatchWorker.new(@options)
|
87
|
+
]
|
88
|
+
end
|
89
|
+
|
90
|
+
def wait_for_worker
|
91
|
+
if is_serial?
|
92
|
+
return @workers[0]
|
93
|
+
else
|
94
|
+
if_no_available_workers = Proc.new do
|
95
|
+
worker = nil
|
96
|
+
loop do
|
97
|
+
freed_child_proc_pid = Process.wait
|
98
|
+
worker = @workers.find do |w|
|
99
|
+
w.pid == freed_child_proc_pid
|
100
|
+
end
|
101
|
+
|
102
|
+
break if worker
|
103
|
+
end
|
104
|
+
# worker.clean_up_or_whatever
|
105
|
+
# TODO: do not set state directly
|
106
|
+
worker.state == :ready_to_work
|
107
|
+
worker
|
108
|
+
end
|
109
|
+
|
110
|
+
first_ready_to_work_worker = @workers.find(if_no_available_workers) do |worker|
|
111
|
+
worker.state == :ready_to_work
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def wait_for_all_workers
|
117
|
+
unless is_serial?
|
118
|
+
FastlaneCore::UI.message("TestBatchWorkerPool.wait_for_all_workers")
|
119
|
+
busy_worker_pids = @workers.each.select { |w| w.state == :working }.map(&:pid)
|
120
|
+
busy_worker_pids.each do |pid|
|
121
|
+
Process.wait(pid)
|
122
|
+
end
|
123
|
+
@workers.each { |w| w.state = :ready_to_work }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -64,9 +64,12 @@ module TestCenter
|
|
64
64
|
numbered_filename(@output_files.to_s.split(',')[junit_index])
|
65
65
|
end
|
66
66
|
|
67
|
-
def junit_reportname
|
67
|
+
def junit_reportname(suffix = '')
|
68
68
|
junit_index = @output_types.split(',').find_index('junit')
|
69
|
-
@output_files.to_s.split(',')[junit_index]
|
69
|
+
report_name = @output_files.to_s.split(',')[junit_index]
|
70
|
+
return report_name if suffix.empty?
|
71
|
+
|
72
|
+
"#{File.basename(report_name, '.*')}-#{suffix}#{junit_filextension}"
|
70
73
|
end
|
71
74
|
|
72
75
|
def junit_filextension
|
@@ -90,9 +93,12 @@ module TestCenter
|
|
90
93
|
numbered_filename(@output_files.to_s.split(',')[html_index])
|
91
94
|
end
|
92
95
|
|
93
|
-
def html_reportname
|
96
|
+
def html_reportname(suffix = '')
|
94
97
|
html_index = @output_types.split(',').find_index('html')
|
95
|
-
@output_files.to_s.split(',')[html_index]
|
98
|
+
report_name = @output_files.to_s.split(',')[html_index]
|
99
|
+
return report_name if suffix.empty?
|
100
|
+
|
101
|
+
"#{File.basename(report_name, '.*')}-#{suffix}#{html_filextension}"
|
96
102
|
end
|
97
103
|
|
98
104
|
def html_filextension
|
@@ -116,9 +122,12 @@ module TestCenter
|
|
116
122
|
numbered_filename(@output_files.to_s.split(',')[json_index])
|
117
123
|
end
|
118
124
|
|
119
|
-
def json_reportname
|
125
|
+
def json_reportname(suffix = '')
|
120
126
|
json_index = @output_types.split(',').find_index('json')
|
121
|
-
@output_files.to_s.split(',')[json_index]
|
127
|
+
report_name = @output_files.to_s.split(',')[json_index]
|
128
|
+
return report_name if suffix.empty?
|
129
|
+
|
130
|
+
"#{File.basename(report_name, '.*')}-#{suffix}#{json_filextension}"
|
122
131
|
end
|
123
132
|
|
124
133
|
def json_filextension
|
@@ -5,6 +5,8 @@ module TestCenter
|
|
5
5
|
require 'plist'
|
6
6
|
|
7
7
|
class TestCollector
|
8
|
+
attr_reader :xctestrun_path
|
9
|
+
|
8
10
|
def initialize(options)
|
9
11
|
unless options[:xctestrun] || options[:derived_data_path]
|
10
12
|
options[:derived_data_path] = default_derived_data_path(options)
|
@@ -15,9 +17,12 @@ module TestCenter
|
|
15
17
|
end
|
16
18
|
@only_testing = options[:only_testing]
|
17
19
|
@skip_testing = options[:skip_testing]
|
20
|
+
@batch_count = options[:batch_count]
|
18
21
|
end
|
19
22
|
|
20
23
|
def default_derived_data_path(options)
|
24
|
+
# TODO: investigate if this is needed. I believe it should already have
|
25
|
+
# been set in multi_scan
|
21
26
|
Scan.project = FastlaneCore::Project.new(
|
22
27
|
options.select { |k, v| %i[workspace project].include?(k) }
|
23
28
|
)
|
@@ -34,7 +39,9 @@ module TestCenter
|
|
34
39
|
if @only_testing
|
35
40
|
@testables ||= only_testing_to_testables_tests.keys
|
36
41
|
else
|
37
|
-
@testables ||= Plist.parse_xml(@xctestrun_path).keys
|
42
|
+
@testables ||= Plist.parse_xml(@xctestrun_path).keys.reject do |key|
|
43
|
+
key == '__xctestrun_metadata__'
|
44
|
+
end
|
38
45
|
end
|
39
46
|
end
|
40
47
|
@testables
|
@@ -49,13 +56,30 @@ module TestCenter
|
|
49
56
|
tests
|
50
57
|
end
|
51
58
|
|
59
|
+
def xctestrun_known_tests
|
60
|
+
config = FastlaneCore::Configuration.create(::Fastlane::Actions::TestsFromXctestrunAction.available_options, xctestrun: @xctestrun_path)
|
61
|
+
::Fastlane::Actions::TestsFromXctestrunAction.run(config)
|
62
|
+
end
|
63
|
+
|
52
64
|
def testables_tests
|
53
65
|
unless @testables_tests
|
54
66
|
if @only_testing
|
67
|
+
known_tests = nil
|
55
68
|
@testables_tests = only_testing_to_testables_tests
|
69
|
+
|
70
|
+
@testables_tests.each do |testable, tests|
|
71
|
+
tests.each_with_index do |test, index|
|
72
|
+
if test.count('/') < 2
|
73
|
+
known_tests ||= xctestrun_known_tests[testable]
|
74
|
+
test_components = test.split('/')
|
75
|
+
testsuite = test_components.size == 1 ? test_components[0] : test_components[1]
|
76
|
+
@testables_tests[testable][index] = known_tests.select { |known_test| known_test.include?(testsuite) }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
@testables_tests[testable].flatten!
|
80
|
+
end
|
56
81
|
else
|
57
|
-
|
58
|
-
@testables_tests = ::Fastlane::Actions::TestsFromXctestrunAction.run(config)
|
82
|
+
@testables_tests = xctestrun_known_tests
|
59
83
|
if @skip_testing
|
60
84
|
skipped_testable_tests = Hash.new { |h, k| h[k] = [] }
|
61
85
|
@skip_testing.sort.each do |skipped_test_identifier|
|
@@ -68,8 +92,30 @@ module TestCenter
|
|
68
92
|
end
|
69
93
|
end
|
70
94
|
end
|
95
|
+
|
71
96
|
@testables_tests
|
72
97
|
end
|
98
|
+
|
99
|
+
def test_batches
|
100
|
+
if @batches.nil?
|
101
|
+
@batches = []
|
102
|
+
testables.each do |testable|
|
103
|
+
testable_tests = testables_tests[testable]
|
104
|
+
next if testable_tests.empty?
|
105
|
+
|
106
|
+
if @batch_count > 1
|
107
|
+
slice_count = [(testable_tests.length / @batch_count.to_f).ceil, 1].max
|
108
|
+
testable_tests.each_slice(slice_count).to_a.each do |tests_batch|
|
109
|
+
@batches << tests_batch
|
110
|
+
end
|
111
|
+
else
|
112
|
+
@batches << testable_tests
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
@batches
|
118
|
+
end
|
73
119
|
end
|
74
120
|
end
|
75
121
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module TestCenter
|
2
|
+
module Helper
|
3
|
+
require 'plist'
|
4
|
+
|
5
|
+
class XCTestrunInfo
|
6
|
+
def initialize(xctestrun_filepath)
|
7
|
+
raise Errno::ENOENT, xctestrun_filepath unless File.exist?(xctestrun_filepath)
|
8
|
+
|
9
|
+
@xctestrun = Plist.parse_xml(xctestrun_filepath)
|
10
|
+
@xctestrun_rootpath = File.dirname(xctestrun_filepath)
|
11
|
+
end
|
12
|
+
|
13
|
+
def app_path_for_testable(testable)
|
14
|
+
@xctestrun[testable].fetch('UITargetAppPath') do |_|
|
15
|
+
@xctestrun[testable]['TestHostPath']
|
16
|
+
end.sub('__TESTROOT__', @xctestrun_rootpath)
|
17
|
+
end
|
18
|
+
|
19
|
+
def app_plist_for_testable(testable)
|
20
|
+
binary_plistfile = File.join(app_path_for_testable(testable), 'Info.plist')
|
21
|
+
|
22
|
+
Plist.parse_binary_xml(binary_plistfile)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'plist'
|
29
|
+
|
30
|
+
class Hash
|
31
|
+
def save_binary_plist(filename, options = {})
|
32
|
+
Plist::Emit.save_plist(self, filename)
|
33
|
+
`plutil -convert binary1 \"#{filename}\"`
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module Plist
|
38
|
+
def self.parse_binary_xml(filename)
|
39
|
+
`plutil -convert xml1 \"#{filename}\"`
|
40
|
+
Plist.parse_xml(filename)
|
41
|
+
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-test_center
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.7.0.parallelizing.alpha.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lyndsey Ferguson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-06-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -67,7 +67,21 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 1.1.7
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: colorize
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: cocoapods
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
72
86
|
requirements:
|
73
87
|
- - ">="
|
@@ -81,7 +95,7 @@ dependencies:
|
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
98
|
+
name: bundler
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
101
|
- - ">="
|
@@ -100,14 +114,14 @@ dependencies:
|
|
100
114
|
requirements:
|
101
115
|
- - ">="
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version: 2.
|
117
|
+
version: 2.108.0
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - ">="
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version: 2.
|
124
|
+
version: 2.108.0
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: pry
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -235,16 +249,29 @@ files:
|
|
235
249
|
- lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb
|
236
250
|
- lib/fastlane/plugin/test_center/actions/collate_test_result_bundles.rb
|
237
251
|
- lib/fastlane/plugin/test_center/actions/multi_scan.rb
|
252
|
+
- lib/fastlane/plugin/test_center/actions/restart_core_simulator_service.rb
|
238
253
|
- lib/fastlane/plugin/test_center/actions/suppress_tests.rb
|
239
254
|
- lib/fastlane/plugin/test_center/actions/suppress_tests_from_junit.rb
|
240
255
|
- lib/fastlane/plugin/test_center/actions/suppressed_tests.rb
|
241
256
|
- lib/fastlane/plugin/test_center/actions/tests_from_junit.rb
|
242
257
|
- lib/fastlane/plugin/test_center/actions/tests_from_xctestrun.rb
|
243
|
-
- lib/fastlane/plugin/test_center/helper/correcting_scan_helper.rb
|
244
258
|
- lib/fastlane/plugin/test_center/helper/junit_helper.rb
|
259
|
+
- lib/fastlane/plugin/test_center/helper/multi_scan_manager.rb
|
260
|
+
- lib/fastlane/plugin/test_center/helper/multi_scan_manager/device_manager.rb
|
261
|
+
- lib/fastlane/plugin/test_center/helper/multi_scan_manager/interstitial.rb
|
262
|
+
- lib/fastlane/plugin/test_center/helper/multi_scan_manager/parallel_test_batch_worker.rb
|
263
|
+
- lib/fastlane/plugin/test_center/helper/multi_scan_manager/report_collator.rb
|
264
|
+
- lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan.rb
|
265
|
+
- lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb
|
266
|
+
- lib/fastlane/plugin/test_center/helper/multi_scan_manager/runner.rb
|
267
|
+
- lib/fastlane/plugin/test_center/helper/multi_scan_manager/simulator_helper.rb
|
268
|
+
- lib/fastlane/plugin/test_center/helper/multi_scan_manager/simulator_manager.rb
|
269
|
+
- lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker.rb
|
270
|
+
- lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker_pool.rb
|
245
271
|
- lib/fastlane/plugin/test_center/helper/reportname_helper.rb
|
246
272
|
- lib/fastlane/plugin/test_center/helper/test_collector.rb
|
247
273
|
- lib/fastlane/plugin/test_center/helper/xcodebuild_string.rb
|
274
|
+
- lib/fastlane/plugin/test_center/helper/xctestrun_info.rb
|
248
275
|
- lib/fastlane/plugin/test_center/version.rb
|
249
276
|
homepage: https://github.com/lyndsey-ferguson/fastlane-plugin-test_center
|
250
277
|
licenses:
|
@@ -261,11 +288,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
261
288
|
version: '0'
|
262
289
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
263
290
|
requirements:
|
264
|
-
- - "
|
291
|
+
- - ">"
|
265
292
|
- !ruby/object:Gem::Version
|
266
|
-
version:
|
293
|
+
version: 1.3.1
|
267
294
|
requirements: []
|
268
|
-
|
295
|
+
rubyforge_project:
|
296
|
+
rubygems_version: 2.6.11
|
269
297
|
signing_key:
|
270
298
|
specification_version: 4
|
271
299
|
summary: Makes testing your iOS app easier
|