fastlane-plugin-test_center 3.6.3 → 3.7.0.parallelizing.alpha.4

Sign up to get free protection for your applications and to get access to all the features.
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