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
@@ -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