fastlane-plugin-test_center 3.7.0 → 3.8.0.parallelizing.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +71 -6
  3. data/lib/fastlane/plugin/test_center/actions/collate_html_reports.rb +2 -0
  4. data/lib/fastlane/plugin/test_center/actions/collate_json_reports.rb +2 -0
  5. data/lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb +2 -1
  6. data/lib/fastlane/plugin/test_center/actions/collate_test_result_bundles.rb +2 -0
  7. data/lib/fastlane/plugin/test_center/actions/multi_scan.rb +127 -32
  8. data/lib/fastlane/plugin/test_center/actions/quit_core_simulator_service.rb +40 -0
  9. data/lib/fastlane/plugin/test_center/actions/suppress_tests.rb +2 -0
  10. data/lib/fastlane/plugin/test_center/actions/suppress_tests_from_junit.rb +3 -1
  11. data/lib/fastlane/plugin/test_center/actions/suppressed_tests.rb +2 -0
  12. data/lib/fastlane/plugin/test_center/actions/tests_from_junit.rb +2 -0
  13. data/lib/fastlane/plugin/test_center/actions/tests_from_xctestrun.rb +2 -0
  14. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/device_manager.rb +30 -0
  15. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/parallel_test_batch_worker.rb +73 -0
  16. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/report_collator.rb +129 -0
  17. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan.rb +77 -0
  18. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb +272 -0
  19. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/runner.rb +109 -0
  20. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/simulator_helper.rb +49 -0
  21. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker.rb +24 -0
  22. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker_pool.rb +133 -0
  23. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager.rb +3 -0
  24. data/lib/fastlane/plugin/test_center/helper/reportname_helper.rb +15 -6
  25. data/lib/fastlane/plugin/test_center/helper/test_collector.rb +55 -14
  26. data/lib/fastlane/plugin/test_center/helper/xctestrun_info.rb +42 -0
  27. data/lib/fastlane/plugin/test_center/version.rb +1 -1
  28. data/lib/fastlane/plugin/test_center.rb +1 -1
  29. metadata +22 -11
  30. data/lib/fastlane/plugin/test_center/helper/correcting_scan_helper.rb +0 -315
@@ -0,0 +1,133 @@
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_testrun_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
+ return [] unless @options[:platform] == :ios
23
+
24
+ @simhelper = SimulatorHelper.new(
25
+ parallel_testrun_count: @options[:parallel_testrun_count]
26
+ )
27
+ @simhelper.setup
28
+ @clones = @simhelper.clone_destination_simulators
29
+ main_pid = Process.pid
30
+ at_exit do
31
+ clean_up_cloned_simulators(@clones) if Process.pid == main_pid
32
+ end
33
+ @clones
34
+ end
35
+
36
+ def destination_for_worker(worker_index)
37
+ return @options[:destination] unless @options[:platform] == :ios
38
+
39
+ @clones[worker_index].map do |simulator|
40
+ "platform=iOS Simulator,id=#{simulator.udid}"
41
+ end
42
+ end
43
+
44
+ def setup_parallel_workers
45
+ setup_cloned_simulators
46
+ desired_worker_count = @options[:parallel_testrun_count]
47
+ @workers = []
48
+ (0...desired_worker_count).each do |worker_index|
49
+ @workers << ParallelTestBatchWorker.new(parallel_scan_options(worker_index))
50
+ end
51
+ end
52
+
53
+ def parallel_scan_options(worker_index)
54
+ options = @options.reject { |key| %i[device devices].include?(key) }
55
+ options[:destination] = destination_for_worker(worker_index)
56
+ options[:xctestrun] = xctestrun_products_clone if @options[:xctestrun]
57
+ options[:buildlog_path] = buildlog_path_for_worker(worker_index) if @options[:buildlog_path]
58
+ options[:derived_data_path] = derived_data_path_for_worker(worker_index)
59
+ options[:batch_index] = worker_index
60
+ options[:test_batch_results] = @options[:test_batch_results]
61
+ options
62
+ end
63
+
64
+ def xctestrun_products_clone
65
+ xctestrun_filename = File.basename(@options[:xctestrun])
66
+ xcproduct_dirpath = File.dirname(@options[:xctestrun])
67
+ tmp_xcproduct_dirpath = Dir.mktmpdir
68
+ FileUtils.cp_r(xcproduct_dirpath, tmp_xcproduct_dirpath)
69
+ at_exit do
70
+ FileUtils.rm_rf(tmp_xcproduct_dirpath)
71
+ end
72
+ "#{tmp_xcproduct_dirpath}/#{File.basename(xcproduct_dirpath)}/#{xctestrun_filename}"
73
+ end
74
+
75
+ def buildlog_path_for_worker(worker_index)
76
+ "#{@options[:buildlog_path]}/parallel-simulators-#{worker_index}-logs"
77
+ end
78
+
79
+ def derived_data_path_for_worker(worker_index)
80
+ Dir.mktmpdir(['derived_data_path', "-worker-#{worker_index.to_s}"])
81
+ end
82
+
83
+ def clean_up_cloned_simulators(clones)
84
+ return if clones.nil?
85
+
86
+ clones.flatten.each(&:delete)
87
+ end
88
+
89
+ def setup_serial_workers
90
+ serial_scan_options = @options.reject { |key| %i[device devices].include?(key) }
91
+ serial_scan_options[:destination] ||= Scan&.config&.fetch(:destination)
92
+ @workers = [
93
+ TestBatchWorker.new(serial_scan_options)
94
+ ]
95
+ end
96
+
97
+ def wait_for_worker
98
+ if is_serial?
99
+ return @workers[0]
100
+ else
101
+ if_no_available_workers = Proc.new do
102
+ worker = nil
103
+ loop do
104
+ freed_child_proc_pid = Process.wait
105
+ worker = @workers.find do |w|
106
+ w.pid == freed_child_proc_pid
107
+ end
108
+
109
+ break if worker
110
+ end
111
+ worker.process_results
112
+ worker
113
+ end
114
+
115
+ first_ready_to_work_worker = @workers.find(if_no_available_workers) do |worker|
116
+ worker.state == :ready_to_work
117
+ end
118
+ end
119
+ end
120
+
121
+ def wait_for_all_workers
122
+ unless is_serial?
123
+ busy_workers = @workers.each.select { |w| w.state == :working }
124
+ busy_workers.map(&:pid).each do |pid|
125
+ Process.wait(pid)
126
+ end
127
+ busy_workers.each { |w| w.process_results }
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'multi_scan_manager/report_collator'
2
+ require_relative 'multi_scan_manager/runner'
3
+ require_relative 'xctestrun_info'
@@ -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,13 +17,13 @@ module TestCenter
15
17
  end
16
18
  @only_testing = options[:only_testing]
17
19
  @skip_testing = options[:skip_testing]
18
- @invocation_based_tests = options[:invocation_based_tests]
20
+ @batch_count = options[:batch_count]
21
+ if @batch_count == 1 && options[:parallel_testrun_count] > 1
22
+ @batch_count = options[:parallel_testrun_count]
23
+ end
19
24
  end
20
25
 
21
26
  def default_derived_data_path(options)
22
- Scan.project = FastlaneCore::Project.new(
23
- options.select { |k, v| %i[workspace project].include?(k) }
24
- )
25
27
  project_derived_data_path = Scan.project.build_settings(key: "BUILT_PRODUCTS_DIR")
26
28
  File.expand_path("../../..", project_derived_data_path)
27
29
  end
@@ -35,8 +37,8 @@ module TestCenter
35
37
  if @only_testing
36
38
  @testables ||= only_testing_to_testables_tests.keys
37
39
  else
38
- @testables ||= Plist.parse_xml(@xctestrun_path).keys.reject do |retrievedTestable|
39
- Fastlane::Actions::TestsFromXctestrunAction.ignoredTestables.include?(retrievedTestable)
40
+ @testables ||= Plist.parse_xml(@xctestrun_path).keys.reject do |key|
41
+ key == '__xctestrun_metadata__'
40
42
  end
41
43
  end
42
44
  end
@@ -52,19 +54,36 @@ module TestCenter
52
54
  tests
53
55
  end
54
56
 
57
+ def xctestrun_known_tests
58
+ config = FastlaneCore::Configuration.create(
59
+ ::Fastlane::Actions::TestsFromXctestrunAction.available_options,
60
+ {
61
+ xctestrun: @xctestrun_path,
62
+ invocation_based_tests: @invocation_based_tests
63
+ }
64
+ )
65
+ ::Fastlane::Actions::TestsFromXctestrunAction.run(config)
66
+ end
67
+
55
68
  def testables_tests
56
69
  unless @testables_tests
57
70
  if @only_testing
71
+ known_tests = nil
58
72
  @testables_tests = only_testing_to_testables_tests
73
+
74
+ @testables_tests.each do |testable, tests|
75
+ tests.each_with_index do |test, index|
76
+ if test.count('/') < 2
77
+ known_tests ||= xctestrun_known_tests[testable]
78
+ test_components = test.split('/')
79
+ testsuite = test_components.size == 1 ? test_components[0] : test_components[1]
80
+ @testables_tests[testable][index] = known_tests.select { |known_test| known_test.include?(testsuite) }
81
+ end
82
+ end
83
+ @testables_tests[testable].flatten!
84
+ end
59
85
  else
60
- config = FastlaneCore::Configuration.create(
61
- ::Fastlane::Actions::TestsFromXctestrunAction.available_options,
62
- {
63
- xctestrun: @xctestrun_path,
64
- invocation_based_tests: @invocation_based_tests
65
- }
66
- )
67
- @testables_tests = ::Fastlane::Actions::TestsFromXctestrunAction.run(config)
86
+ @testables_tests = xctestrun_known_tests
68
87
  if @skip_testing
69
88
  skipped_testable_tests = Hash.new { |h, k| h[k] = [] }
70
89
  @skip_testing.sort.each do |skipped_test_identifier|
@@ -77,8 +96,30 @@ module TestCenter
77
96
  end
78
97
  end
79
98
  end
99
+
80
100
  @testables_tests
81
101
  end
102
+
103
+ def test_batches
104
+ if @batches.nil?
105
+ @batches = []
106
+ testables.each do |testable|
107
+ testable_tests = testables_tests[testable]
108
+ next if testable_tests.empty?
109
+
110
+ if @batch_count > 1
111
+ slice_count = [(testable_tests.length / @batch_count.to_f).ceil, 1].max
112
+ testable_tests.each_slice(slice_count).to_a.each do |tests_batch|
113
+ @batches << tests_batch
114
+ end
115
+ else
116
+ @batches << testable_tests
117
+ end
118
+ end
119
+ end
120
+
121
+ @batches
122
+ end
82
123
  end
83
124
  end
84
125
  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
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module TestCenter
3
- VERSION = "3.7.0"
3
+ VERSION = "3.8.0.parallelizing.beta.1"
4
4
  end
5
5
  end
@@ -4,7 +4,7 @@ module Fastlane
4
4
  module TestCenter
5
5
  # Return all .rb files inside the "actions" and "helper" directory
6
6
  def self.all_classes
7
- Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
7
+ Dir[File.expand_path('**/{actions,helper}/**/*.rb', File.dirname(__FILE__))]
8
8
  end
9
9
  end
10
10
  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.7.0
4
+ version: 3.8.0.parallelizing.beta.1
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-05-30 00:00:00.000000000 Z
11
+ date: 2019-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -67,13 +67,13 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: 1.1.7
69
69
  - !ruby/object:Gem::Dependency
70
- name: cocoapods
70
+ name: colorize
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
- type: :development
76
+ type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: bundler
84
+ name: cocoapods
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: colorize
98
+ name: bundler
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: 2.56.0
117
+ version: 2.108.0
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: 2.56.0
124
+ version: 2.108.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: pry
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -249,16 +249,27 @@ files:
249
249
  - lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb
250
250
  - lib/fastlane/plugin/test_center/actions/collate_test_result_bundles.rb
251
251
  - lib/fastlane/plugin/test_center/actions/multi_scan.rb
252
+ - lib/fastlane/plugin/test_center/actions/quit_core_simulator_service.rb
252
253
  - lib/fastlane/plugin/test_center/actions/suppress_tests.rb
253
254
  - lib/fastlane/plugin/test_center/actions/suppress_tests_from_junit.rb
254
255
  - lib/fastlane/plugin/test_center/actions/suppressed_tests.rb
255
256
  - lib/fastlane/plugin/test_center/actions/tests_from_junit.rb
256
257
  - lib/fastlane/plugin/test_center/actions/tests_from_xctestrun.rb
257
- - lib/fastlane/plugin/test_center/helper/correcting_scan_helper.rb
258
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/parallel_test_batch_worker.rb
262
+ - lib/fastlane/plugin/test_center/helper/multi_scan_manager/report_collator.rb
263
+ - lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan.rb
264
+ - lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb
265
+ - lib/fastlane/plugin/test_center/helper/multi_scan_manager/runner.rb
266
+ - lib/fastlane/plugin/test_center/helper/multi_scan_manager/simulator_helper.rb
267
+ - lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker.rb
268
+ - lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker_pool.rb
259
269
  - lib/fastlane/plugin/test_center/helper/reportname_helper.rb
260
270
  - lib/fastlane/plugin/test_center/helper/test_collector.rb
261
271
  - lib/fastlane/plugin/test_center/helper/xcodebuild_string.rb
272
+ - lib/fastlane/plugin/test_center/helper/xctestrun_info.rb
262
273
  - lib/fastlane/plugin/test_center/version.rb
263
274
  homepage: https://github.com/lyndsey-ferguson/fastlane-plugin-test_center
264
275
  licenses:
@@ -275,9 +286,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
275
286
  version: '0'
276
287
  required_rubygems_version: !ruby/object:Gem::Requirement
277
288
  requirements:
278
- - - ">="
289
+ - - ">"
279
290
  - !ruby/object:Gem::Version
280
- version: '0'
291
+ version: 1.3.1
281
292
  requirements: []
282
293
  rubyforge_project:
283
294
  rubygems_version: 2.6.11