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.
Files changed (26) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +4 -0
  3. data/lib/fastlane/plugin/test_center.rb +1 -1
  4. data/lib/fastlane/plugin/test_center/actions/collate_test_result_bundles.rb +1 -1
  5. data/lib/fastlane/plugin/test_center/actions/multi_scan.rb +109 -25
  6. data/lib/fastlane/plugin/test_center/actions/restart_core_simulator_service.rb +38 -0
  7. data/lib/fastlane/plugin/test_center/actions/tests_from_xctestrun.rb +16 -4
  8. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager.rb +5 -0
  9. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/device_manager.rb +30 -0
  10. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/interstitial.rb +143 -0
  11. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/parallel_test_batch_worker.rb +27 -0
  12. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/report_collator.rb +115 -0
  13. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan.rb +74 -0
  14. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb +255 -0
  15. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/runner.rb +356 -0
  16. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/simulator_helper.rb +49 -0
  17. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/simulator_manager.rb +317 -0
  18. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker.rb +20 -0
  19. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker_pool.rb +129 -0
  20. data/lib/fastlane/plugin/test_center/helper/reportname_helper.rb +15 -6
  21. data/lib/fastlane/plugin/test_center/helper/test_collector.rb +49 -3
  22. data/lib/fastlane/plugin/test_center/helper/xcodebuild_string.rb +4 -0
  23. data/lib/fastlane/plugin/test_center/helper/xctestrun_info.rb +42 -0
  24. data/lib/fastlane/plugin/test_center/version.rb +1 -1
  25. metadata +38 -10
  26. data/lib/fastlane/plugin/test_center/helper/correcting_scan_helper.rb +0 -293
@@ -1,293 +0,0 @@
1
- module TestCenter
2
- module Helper
3
- require 'fastlane_core/ui/ui.rb'
4
- require 'plist'
5
- require 'json'
6
- class CorrectingScanHelper
7
- attr_reader :retry_total_count
8
-
9
- def initialize(multi_scan_options)
10
- @batch_count = multi_scan_options[:batch_count] || 1
11
- @output_directory = multi_scan_options[:output_directory] || 'test_results'
12
- @try_count = multi_scan_options[:try_count]
13
- @quit_simulators = multi_scan_options[:quit_simulators]
14
- @retry_total_count = 0
15
- @testrun_completed_block = multi_scan_options[:testrun_completed_block]
16
- @given_custom_report_file_name = multi_scan_options[:custom_report_file_name]
17
- @given_output_types = multi_scan_options[:output_types]
18
- @given_output_files = multi_scan_options[:output_files]
19
- @scan_options = multi_scan_options.reject do |option, _|
20
- %i[
21
- output_directory
22
- only_testing
23
- skip_testing
24
- clean
25
- try_count
26
- batch_count
27
- quit_simulators
28
- custom_report_file_name
29
- fail_build
30
- testrun_completed_block
31
- output_types
32
- output_files
33
- ].include?(option)
34
- end
35
- @scan_options[:clean] = false
36
- @test_collector = TestCollector.new(multi_scan_options)
37
- end
38
-
39
- def scan
40
- tests_passed = true
41
- @testables_count = @test_collector.testables.size
42
- @test_collector.testables.each do |testable|
43
- tests_passed = scan_testable(testable) && tests_passed
44
- end
45
- tests_passed
46
- end
47
-
48
- def scan_testable(testable)
49
- tests_passed = true
50
- reportnamer = ReportNameHelper.new(
51
- @given_output_types,
52
- @given_output_files,
53
- @given_custom_report_file_name
54
- )
55
- output_directory = @output_directory
56
- testable_tests = @test_collector.testables_tests[testable]
57
- if testable_tests.empty?
58
- FastlaneCore::UI.important("There are no tests to run in testable '#{testable}'. Skipping")
59
- return true
60
- end
61
-
62
- if @batch_count > 1 || @testables_count > 1
63
- current_batch = 1
64
- testable_tests.each_slice((testable_tests.length / @batch_count.to_f).round).to_a.each do |tests_batch|
65
- if @testables_count > 1
66
- output_directory = File.join(@output_directory, "results-#{testable}")
67
- end
68
- FastlaneCore::UI.header("Starting test run on testable '#{testable}'")
69
- if @scan_options[:result_bundle]
70
- FastlaneCore::UI.message("Clearing out previous test_result bundles in #{output_directory}")
71
- FileUtils.rm_rf(Dir.glob("#{output_directory}/*.test_result"))
72
- end
73
-
74
- tests_passed = correcting_scan(
75
- {
76
- only_testing: tests_batch,
77
- output_directory: output_directory
78
- },
79
- current_batch,
80
- reportnamer
81
- ) && tests_passed
82
- current_batch += 1
83
- reportnamer.increment
84
- end
85
- else
86
- options = {
87
- output_directory: output_directory,
88
- only_testing: testable_tests
89
- }
90
- tests_passed = correcting_scan(options, 1, reportnamer) && tests_passed
91
- end
92
- collate_reports(output_directory, reportnamer)
93
- tests_passed
94
- end
95
-
96
- def test_result_bundlepaths(output_directory, reportnamer)
97
- [
98
- File.join(output_directory, @scan_options[:scheme]) + '.test_result',
99
- File.join(output_directory, @scan_options[:scheme]) + "_#{reportnamer.report_count}.test_result"
100
- ]
101
- end
102
-
103
- def collate_reports(output_directory, reportnamer)
104
- collate_junit_reports(output_directory, reportnamer)
105
-
106
- if reportnamer.includes_html?
107
- collate_html_reports(output_directory, reportnamer)
108
- end
109
-
110
- if reportnamer.includes_json?
111
- collate_json_reports(output_directory, reportnamer)
112
- end
113
-
114
- if @scan_options[:result_bundle]
115
- collate_test_result_bundles(output_directory, reportnamer)
116
- end
117
- end
118
-
119
- def passed_test_count_from_summary(summary)
120
- /.*Executed (?<test_count>\d+) test, with (?<test_failures>\d+) failure/ =~ summary
121
- test_count.to_i - test_failures.to_i
122
- end
123
-
124
- def collate_test_result_bundles(output_directory, reportnamer)
125
- test_result_bundlepaths = Dir.glob("#{output_directory}/#{@scan_options[:scheme]}*.test_result").map do |relative_test_result_bundle_filepath|
126
- File.absolute_path(relative_test_result_bundle_filepath)
127
- end
128
- if test_result_bundlepaths.size > 1
129
- config = FastlaneCore::Configuration.create(
130
- Fastlane::Actions::CollateTestResultBundlesAction.available_options,
131
- {
132
- bundles: test_result_bundlepaths.sort { |f1, f2| File.mtime(f1) <=> File.mtime(f2) },
133
- collated_bundle: File.join(output_directory, @scan_options[:scheme]) + '.test_result'
134
- }
135
- )
136
- Fastlane::Actions::CollateTestResultBundlesAction.run(config)
137
- end
138
- retried_test_result_bundlepaths = Dir.glob("#{output_directory}/#{@scan_options[:scheme]}_*.test_result")
139
- FileUtils.rm_rf(retried_test_result_bundlepaths)
140
- end
141
-
142
- def collate_json_reports(output_directory, reportnamer)
143
- report_filepaths = Dir.glob("#{output_directory}/#{reportnamer.json_fileglob}").map do |relative_filepath|
144
- File.absolute_path(relative_filepath)
145
- end
146
- if report_filepaths.size > 1
147
- config = FastlaneCore::Configuration.create(
148
- Fastlane::Actions::CollateJsonReportsAction.available_options,
149
- {
150
- reports: report_filepaths.sort { |f1, f2| File.mtime(f1) <=> File.mtime(f2) },
151
- collated_report: File.absolute_path(File.join(output_directory, reportnamer.json_reportname))
152
- }
153
- )
154
- Fastlane::Actions::CollateJsonReportsAction.run(config)
155
- end
156
- retried_json_reportfiles = Dir.glob("#{output_directory}/#{reportnamer.json_numbered_fileglob}")
157
- FileUtils.rm_f(retried_json_reportfiles)
158
- end
159
-
160
- def collate_html_reports(output_directory, reportnamer)
161
- report_files = Dir.glob("#{output_directory}/#{reportnamer.html_fileglob}").map do |relative_filepath|
162
- File.absolute_path(relative_filepath)
163
- end
164
- if report_files.size > 1
165
- config = FastlaneCore::Configuration.create(
166
- Fastlane::Actions::CollateHtmlReportsAction.available_options,
167
- {
168
- reports: report_files.sort { |f1, f2| File.mtime(f1) <=> File.mtime(f2) },
169
- collated_report: File.absolute_path(File.join(output_directory, reportnamer.html_reportname))
170
- }
171
- )
172
- Fastlane::Actions::CollateHtmlReportsAction.run(config)
173
- end
174
- retried_html_reportfiles = Dir.glob("#{output_directory}/#{reportnamer.html_numbered_fileglob}")
175
- FileUtils.rm_f(retried_html_reportfiles)
176
- end
177
-
178
- def collate_junit_reports(output_directory, reportnamer)
179
- report_files = Dir.glob("#{output_directory}/#{reportnamer.junit_fileglob}").map do |relative_filepath|
180
- File.absolute_path(relative_filepath)
181
- end
182
- if report_files.size > 1
183
- config = FastlaneCore::Configuration.create(
184
- Fastlane::Actions::CollateJunitReportsAction.available_options,
185
- {
186
- reports: report_files.sort { |f1, f2| File.mtime(f1) <=> File.mtime(f2) },
187
- collated_report: File.absolute_path(File.join(output_directory, reportnamer.junit_reportname))
188
- }
189
- )
190
- Fastlane::Actions::CollateJunitReportsAction.run(config)
191
- end
192
- retried_junit_reportfiles = Dir.glob("#{output_directory}/#{reportnamer.junit_numbered_fileglob}")
193
- FileUtils.rm_f(retried_junit_reportfiles)
194
- end
195
-
196
- def correcting_scan(scan_run_options, batch, reportnamer)
197
- scan_options = @scan_options.merge(scan_run_options)
198
- try_count = 0
199
- tests_passed = true
200
- xcpretty_json_file_output = ENV['XCPRETTY_JSON_FILE_OUTPUT']
201
- begin
202
- try_count += 1
203
- config = FastlaneCore::Configuration.create(
204
- Fastlane::Actions::ScanAction.available_options,
205
- scan_options.merge(reportnamer.scan_options)
206
- )
207
- quit_simulators
208
- if reportnamer.includes_json?
209
- ENV['XCPRETTY_JSON_FILE_OUTPUT'] = File.join(
210
- scan_options[:output_directory],
211
- reportnamer.json_last_reportname
212
- )
213
- end
214
- Fastlane::Actions::ScanAction.run(config)
215
- @testrun_completed_block && @testrun_completed_block.call(
216
- testrun_info(batch, try_count, reportnamer, scan_options[:output_directory])
217
- )
218
- tests_passed = true
219
- rescue FastlaneCore::Interface::FastlaneTestFailure => e
220
- FastlaneCore::UI.verbose("Scan failed with #{e}")
221
- info = testrun_info(batch, try_count, reportnamer, scan_options[:output_directory])
222
- @testrun_completed_block && @testrun_completed_block.call(
223
- info
224
- )
225
- if try_count < @try_count
226
- @retry_total_count += 1
227
- scan_options.delete(:code_coverage)
228
- scan_options[:only_testing] = info[:failed].map(&:shellsafe_testidentifier)
229
- FastlaneCore::UI.message('Re-running scan on only failed tests')
230
- reportnamer.increment
231
- if @scan_options[:result_bundle]
232
- built_test_result, moved_test_result = test_result_bundlepaths(
233
- scan_options[:output_directory], reportnamer
234
- )
235
- FileUtils.mv(built_test_result, moved_test_result)
236
- end
237
- retry
238
- end
239
- tests_passed = false
240
- ensure
241
- ENV['XCPRETTY_JSON_FILE_OUTPUT'] = xcpretty_json_file_output
242
- end
243
- tests_passed
244
- end
245
-
246
- def testrun_info(batch, try_count, reportnamer, output_directory)
247
- report_filepath = File.join(output_directory, reportnamer.junit_last_reportname)
248
- config = FastlaneCore::Configuration.create(
249
- Fastlane::Actions::TestsFromJunitAction.available_options,
250
- {
251
- junit: File.absolute_path(report_filepath)
252
- }
253
- )
254
- junit_results = Fastlane::Actions::TestsFromJunitAction.run(config)
255
-
256
- info = {
257
- failed: junit_results[:failed],
258
- passing: junit_results[:passing],
259
- batch: batch,
260
- try_count: try_count,
261
- report_filepath: report_filepath
262
- }
263
- if reportnamer.includes_html?
264
- html_report_filepath = File.join(output_directory, reportnamer.html_last_reportname)
265
- info[:html_report_filepath] = html_report_filepath
266
- end
267
- if reportnamer.includes_json?
268
- json_report_filepath = File.join(output_directory, reportnamer.json_last_reportname)
269
- info[:json_report_filepath] = json_report_filepath
270
- end
271
- if @scan_options[:result_bundle]
272
- test_result_suffix = '.test_result'
273
- test_result_suffix.prepend("_#{reportnamer.report_count}") unless reportnamer.report_count.zero?
274
- test_result_bundlepath = File.join(output_directory, @scan_options[:scheme]) + test_result_suffix
275
- info[:test_result_bundlepath] = test_result_bundlepath
276
- end
277
- info
278
- end
279
-
280
- def quit_simulators
281
- return unless @quit_simulators
282
-
283
- Fastlane::Actions.sh("killall -9 'iPhone Simulator' 'Simulator' 'SimulatorBridge' &> /dev/null || true", log: false)
284
- launchctl_list_count = 0
285
- while Fastlane::Actions.sh('launchctl list | grep com.apple.CoreSimulator.CoreSimulatorService || true', log: false) != ''
286
- break if (launchctl_list_count += 1) > 10
287
- Fastlane::Actions.sh('launchctl remove com.apple.CoreSimulator.CoreSimulatorService &> /dev/null || true', log: false)
288
- sleep(1)
289
- end
290
- end
291
- end
292
- end
293
- end