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

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