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

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 (23) hide show
  1. checksums.yaml +4 -4
  2. data/lib/fastlane/plugin/test_center.rb +1 -1
  3. data/lib/fastlane/plugin/test_center/actions/collate_test_result_bundles.rb +1 -1
  4. data/lib/fastlane/plugin/test_center/actions/multi_scan.rb +34 -89
  5. data/lib/fastlane/plugin/test_center/helper/correcting_scan_helper.rb +315 -0
  6. data/lib/fastlane/plugin/test_center/helper/reportname_helper.rb +6 -15
  7. data/lib/fastlane/plugin/test_center/helper/test_collector.rb +11 -48
  8. data/lib/fastlane/plugin/test_center/version.rb +1 -1
  9. metadata +11 -24
  10. data/lib/fastlane/plugin/test_center/actions/restart_core_simulator_service.rb +0 -38
  11. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager.rb +0 -5
  12. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/device_manager.rb +0 -30
  13. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/interstitial.rb +0 -143
  14. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/parallel_test_batch_worker.rb +0 -27
  15. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/report_collator.rb +0 -115
  16. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan.rb +0 -74
  17. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb +0 -255
  18. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/runner.rb +0 -356
  19. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/simulator_helper.rb +0 -49
  20. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/simulator_manager.rb +0 -317
  21. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker.rb +0 -20
  22. data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker_pool.rb +0 -129
  23. data/lib/fastlane/plugin/test_center/helper/xctestrun_info.rb +0 -42
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ac1d3616de1a2ad7f95123d43b899227325b485c
4
- data.tar.gz: 6cdd4e31e41ef0c998b52ad8666c8eb08c0c5e8d
3
+ metadata.gz: dd7fbaf52ee79115ad9ea8f260bdd35e90868c14
4
+ data.tar.gz: 03ab87b0d261fde47d37edfa7d997e33a6f3faa7
5
5
  SHA512:
6
- metadata.gz: '09d7060687e873c399e8d77833db3ba1c7a804e94b9de5ec7b4cd32fda0a5b9813a3b02942d3f9dbe2c26d7df9cab3f369842dc246ac9dd6efac8f94b339133a'
7
- data.tar.gz: 8b027123c0ff018e9227326652a6a298e9ed2a90b8b795d1a6c6841a35188f5cf1efb148f156c4c7e706dc72c3ab4d8a693e4833487301763ba90b0a45bb0618
6
+ metadata.gz: 9cd9189973cddeab19e82f2bee16577eca64b0eea355d0229cf17fa555b6231f536d558ac44a086ddbfb22ae6877cf857f45db20a9fedbe80a392cc0594db7b6
7
+ data.tar.gz: 3d3747b5497960d65c97b44b20291eea6133c68752449f29d442b6f2e144b4dfc853a7b44eb09523f383749b11d143abbdab028ff73ee314e2bef1e056725ef7
@@ -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
@@ -14,7 +14,7 @@ module Fastlane
14
14
  collate_bundles(base_bundle_path, other_bundlepath)
15
15
  end
16
16
  end
17
- # FileUtils.rm_rf(params[:collated_bundle])
17
+ FileUtils.rm_rf(params[:collated_bundle])
18
18
  FileUtils.cp_r(base_bundle_path, params[:collated_bundle])
19
19
  UI.message("Finished collating test_result bundle to '#{params[:collated_bundle]}'")
20
20
  end
@@ -5,7 +5,6 @@ module Fastlane
5
5
  require 'shellwords'
6
6
  require 'xctest_list'
7
7
  require 'plist'
8
- require_relative '../helper/multi_scan_manager/runner'
9
8
 
10
9
  class MultiScanAction < Action
11
10
  def self.run(params)
@@ -15,16 +14,14 @@ module Fastlane
15
14
  title: "Summary for multi_scan (test_center v#{Fastlane::TestCenter::VERSION})"
16
15
  )
17
16
  end
18
-
19
- prepare_for_testing(params._values)
20
-
21
- runner = ::TestCenter::Helper::MultiScanManager::Runner.new(params.values)
22
- tests_passed = runner.run
23
- if params[:fail_build] && !tests_passed
24
- raise UI.test_failure!('Tests have failed')
17
+ unless params[:test_without_building] || params[:skip_build]
18
+ build_for_testing(
19
+ params._values
20
+ )
25
21
  end
26
-
27
- summary = run_summary(params, tests_passed, runner.retry_total_count)
22
+ smart_scanner = ::TestCenter::Helper::CorrectingScanHelper.new(params.values)
23
+ tests_passed = smart_scanner.scan
24
+ summary = run_summary(params, tests_passed, smart_scanner.retry_total_count)
28
25
  unless Helper.test?
29
26
  FastlaneCore::PrintTable.print_values(
30
27
  config: summary,
@@ -83,51 +80,27 @@ module Fastlane
83
80
  }
84
81
  end
85
82
 
86
- def self.prepare_for_testing(scan_options)
87
- if scan_options[:test_without_building] || scan_options[:skip_build]
88
- prepare_scan_config(scan_options)
89
- else
90
- build_for_testing(scan_options)
91
- end
92
- end
93
-
94
- def self.prepare_scan_config(scan_options)
95
- Scan.config ||= FastlaneCore::Configuration.create(
83
+ def self.build_for_testing(scan_options)
84
+ options_to_remove = %i[
85
+ try_count
86
+ batch_count
87
+ quit_simulators
88
+ testrun_completed_block
89
+ test_without_building
90
+ invocation_based_tests
91
+ output_types
92
+ output_files
93
+ ]
94
+ config = FastlaneCore::Configuration.create(
96
95
  Fastlane::Actions::ScanAction.available_options,
97
- scan_options.select { |k,v| %i[project workspace scheme].include?(k) }
96
+ scan_options.merge(build_for_testing: true).reject { |k, _| options_to_remove.include?(k) }
98
97
  )
99
- end
100
-
101
- def self.build_for_testing(scan_options)
102
- valid_scan_keys = Fastlane::Actions::ScanAction.available_options.map(&:key)
103
- scan_options = scan_options.select { |k,v| valid_scan_keys.include?(k) }
104
-
105
- Scan.config = FastlaneCore::Configuration.create(
106
- Fastlane::Actions::ScanAction.available_options,
107
- scan_options.merge(build_for_testing: true)
108
- )
109
- values = Scan.config.values(ask: false)
110
- values[:xcode_path] = File.expand_path("../..", FastlaneCore::Helper.xcode_path)
111
- FastlaneCore::PrintTable.print_values(
112
- config: values,
113
- hide_keys: [:destination, :slack_url],
114
- title: "Summary for scan #{Fastlane::VERSION}"
115
- )
116
- Scan::Runner.new.run
117
- remove_build_report_files
98
+ Fastlane::Actions::ScanAction.run(config)
118
99
 
119
- Scan.config._values.delete(:build_for_testing)
120
- scan_options[:derived_data_path] = Scan.config[:derived_data_path]
121
- end
122
-
123
- def self.remove_build_report_files
124
- report_options = Scan::XCPrettyReporterOptionsGenerator.generate_from_scan_config
125
- output_files = report_options.instance_variable_get(:@output_files)
126
- output_directory = report_options.instance_variable_get(:@output_directory)
127
-
128
- output_files.each do |output_file|
129
- FileUtils.rm_f(File.join(output_directory, output_file))
130
- end
100
+ scan_options.merge!(
101
+ test_without_building: true,
102
+ derived_data_path: Scan.config[:derived_data_path]
103
+ ).delete(:build_for_testing)
131
104
  end
132
105
 
133
106
  #####################################################
@@ -214,28 +187,6 @@ module Fastlane
214
187
  description: "Comma separated list of the output types (e.g. html, junit, json, json-compilation-database)",
215
188
  default_value: "html,junit"
216
189
  ),
217
- FastlaneCore::ConfigItem.new(
218
- key: :parallelize,
219
- description: 'Run each batch of tests and/or each test target in parallel on its own Simulator',
220
- optional: true,
221
- is_string: false,
222
- default_value: false,
223
- conflicting_options: [:parallel_simulator_count],
224
- conflict_block: proc do |value|
225
- UI.user_error!("You can't use 'parallelize' and 'parallel_simulator_count' options in one run")
226
- end
227
- ),
228
- FastlaneCore::ConfigItem.new(
229
- key: :parallel_simulator_fork_count,
230
- description: 'Run simulators each batch of tests and/or each test target in parallel on its own Simulator',
231
- optional: true,
232
- is_string: false,
233
- default_value: false,
234
- conflicting_options: [:parallelize],
235
- conflict_block: proc do |value|
236
- UI.user_error!("You can't use 'parallelize' and 'parallel_simulator_count' options in one run")
237
- end
238
- ),
239
190
  FastlaneCore::ConfigItem.new(
240
191
  key: :testrun_completed_block,
241
192
  description: 'A block invoked each time a test run completes',
@@ -385,22 +336,16 @@ module Fastlane
385
336
  "
386
337
  UI.important(
387
338
  'example: ' \\
388
- 'use the :xctestrun parameter instead of the :project parameter to find, ' \\
389
- 'build, and test the iOS app.'
339
+ 'multi_scan also works with invocation based tests.'
340
+ )
341
+ cocoapods
342
+ multi_scan(
343
+ workspace: File.absolute_path('../KiwiDemo/KiwiDemo.xcworkspace'),
344
+ scheme: 'KiwiDemoTests',
345
+ try_count: 3,
346
+ invocation_based_tests: true,
347
+ fail_build: false
390
348
  )
391
- Dir.mktmpdir do |derived_data_path|
392
- project_path = '/Users/lyndsey.ferguson/repo/fastlane-plugin-test_center/AtomicBoy/AtomicBoy.xcodeproj'
393
- command = \"bundle exec fastlane scan --build_for_testing true --project '#{project_path}' --derived_data_path #{derived_data_path} --scheme AtomicBoy\"
394
- `#{command}`
395
- xctestrun_file = Dir.glob(\"#{derived_data_path}/Build/Products/AtomicBoy*.xctestrun\").first
396
- multi_scan(
397
- scheme: 'AtomicBoy',
398
- try_count: 3,
399
- fail_build: false,
400
- xctestrun: xctestrun_file,
401
- test_without_building: true
402
- )
403
- end
404
349
  "
405
350
  ]
406
351
  end
@@ -0,0 +1,315 @@
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