fastlane-plugin-test_center 3.6.3.parallelizing.pre.alpha.pre.1 → 3.6.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,93 +0,0 @@
1
- module TestCenter
2
- module Helper
3
- module MultiScanManager
4
- class RetryingScan
5
- def initialize(options = {})
6
- @options = options
7
- @retrying_scan_helper = RetryingScanHelper.new(options)
8
- end
9
-
10
- def delete_xcresults
11
- derived_data_path = File.expand_path(scan_config[:derived_data_path])
12
- xcresults = Dir.glob("#{derived_data_path}/Logs/Test/*.xcresult")
13
- FastlaneCore::UI.message("Deleting xcresults: #{xcresults}")
14
- FileUtils.rm_rf(xcresults)
15
- end
16
-
17
- def scan_config
18
- if Scan.config.nil?
19
- Scan.config = FastlaneCore::Configuration.create(
20
- Fastlane::Actions::ScanAction.available_options,
21
- @options.select { |k,v| %i[project workspace scheme].include?(k) }
22
- )
23
- end
24
- Scan.config
25
- end
26
-
27
- def update_scan_options
28
- valid_scan_keys = Fastlane::Actions::ScanAction.available_options.map(&:key)
29
- scan_options = @options.select { |k,v| valid_scan_keys.include?(k) }
30
- .merge(@retrying_scan_helper.scan_options)
31
-
32
- sc = scan_config
33
- scan_options.each do |k,v|
34
- sc.set(k,v) unless v.nil?
35
- end
36
- end
37
-
38
- def run
39
- update_scan_options
40
- delete_xcresults
41
-
42
- try_count = @options[:try_count] || 1
43
- begin
44
- @retrying_scan_helper.before_testrun
45
-
46
-
47
-
48
- # TODO: Investigate the following error:
49
- """
50
- 2019-05-09 13:32:40.707 xcodebuild[78535:1944070] [MT] DVTAssertions: Warning in /Library/Caches/com.apple.xbs/Sources/IDEFrameworks_Fall2018/IDEFrameworks-14460.46/IDEFoundation/ProjectModel/ActionRecords/IDESchemeActionTestAttachment.m:186
51
- Details: Error writing attachment data to file /Users/lyndsey.ferguson/Library/Developer/Xcode/DerivedData/AtomicBoy-flqqvvvzbouqymbyffgdbtjoiufr/Logs/Test/Test-Transient Testing-2019.05.09_13-32-08--0400.xcresult/1_Test/Attachments/Screenshot_E0AE7940-E7F4-4CA8-BB2B-8822D730D10F.jpg: Error Domain=NSCocoaErrorDomain Code=4 \"The folder “Screenshot_E0AE7940-E7F4-4CA8-BB2B-8822D730D10F.jpg” doesn’t exist.\" UserInfo={NSFilePath=/Users/lyndsey.ferguson/Library/Developer/Xcode/DerivedData/AtomicBoy-flqqvvvzbouqymbyffgdbtjoiufr/Logs/Test/Test-Transient Testing-2019.05.09_13-32-08--0400.xcresult/1_Test/Attachments/Screenshot_E0AE7940-E7F4-4CA8-BB2B-8822D730D10F.jpg, NSUserStringVariant=Folder, NSUnderlyingError=0x7fa6ef34ef90 {Error Domain=NSPOSIXErrorDomain Code=2 \"No such file or directory\"}}
52
- Object: <IDESchemeActionTestAttachment: 0x7fa6ef22d270>
53
- Method: -_savePayload:
54
- Thread: <NSThread: 0x7fa6ea516110>{number = 1, name = main}
55
- Please file a bug at https://bugreport.apple.com with this warning message and any useful information you can provide.
56
-
57
- It may be due to:
58
- 2019-05-09 14:17:30.933 xcodebuild[86893:2045058] IDETestOperationsObserverDebug: Failed to move logarchive from /Users/lyndsey.ferguson/Library/Developer/CoreSimulator/Devices/0D312041-2D60-4221-94CC-3B0040154D74/data/tmp/test-session-systemlogs-2019.05.09_14-17-04--0400.logarchive to diagnostics location /Users/lyndsey.ferguson/Library/Developer/Xcode/DerivedData/AtomicBoy-flqqvvvzbouqymbyffgdbtjoiufr/Logs/Test/Test-Transient Testing-2019.05.09_14-17-04--0400.xcresult/1_Test/Diagnostics/iPhone 5s_0D312041-2D60-4221-94CC-3B0040154D74/test-session-systemlogs-2019.05.09_14-17-04--0400.logarchive: Error Domain=NSCocoaErrorDomain Code=4 \"“test-session-systemlogs-2019.05.09_14-17-04--0400.logarchive” couldn’t be moved to “iPhone 5s_0D312041-2D60-4221-94CC-3B0040154D74” because either the former doesn’t exist, or the folder containing the latter doesn’t exist.\" UserInfo={NSSourceFilePathErrorKey=/Users/lyndsey.ferguson/Library/Developer/CoreSimulator/Devices/0D312041-2D60-4221-94CC-3B0040154D74/data/tmp/test-session-systemlogs-2019.05.09_14-17-04--0400.logarchive, NSUserStringVariant=(
59
- Move
60
- ), NSDestinationFilePath=/Users/lyndsey.ferguson/Library/Developer/Xcode/DerivedData/AtomicBoy-flqqvvvzbouqymbyffgdbtjoiufr/Logs/Test/Test-Transient Testing-2019.05.09_14-17-04--0400.xcresult/1_Test/Diagnostics/iPhone 5s_0D312041-2D60-4221-94CC-3B0040154D74/test-session-systemlogs-2019.05.09_14-17-04--0400.logarchive, NSFilePath=/Users/lyndsey.ferguson/Library/Developer/CoreSimulator/Devices/0D312041-2D60-4221-94CC-3B0040154D74/data/tmp/test-session-systemlogs-2019.05.09_14-17-04--0400.logarchive, NSUnderlyingError=0x7fdf96c6de90 {Error Domain=NSPOSIXErrorDomain Code=2 \"No such file or directory\"}}
61
-
62
- """
63
- update_scan_options
64
- Scan::Runner.new.run
65
- @retrying_scan_helper.after_testrun
66
- true
67
- rescue FastlaneCore::Interface::FastlaneTestFailure => e
68
- @retrying_scan_helper.after_testrun(e)
69
- retry if @retrying_scan_helper.testrun_count < try_count
70
- false
71
- rescue FastlaneCore::Interface::FastlaneBuildFailure => e
72
- @retrying_scan_helper.after_testrun(e)
73
- retry if @retrying_scan_helper.testrun_count < try_count
74
- false
75
- end
76
- end
77
- end
78
- end
79
- end
80
- end
81
- # Ug. How do I name this class?
82
- # I want a class that retries a scan
83
- # I want a class that controls or manages the class that retries the scan and the set up for that
84
- # etc.
85
- # So, the class or the realm could be:
86
- # MultiScanManager
87
- # MultiScanController
88
- # ScanManager
89
- # ScanMaster
90
- # MultiScanMaster
91
- # MasterScanManser
92
- # MasterMultiScan
93
- # I like MultiScanManager
@@ -1,236 +0,0 @@
1
- module TestCenter
2
- module Helper
3
- module MultiScanManager
4
- require_relative 'device_manager'
5
-
6
- class RetryingScanHelper
7
-
8
- attr_reader :testrun_count
9
-
10
- def initialize(options)
11
- raise ArgumentError, 'Do not use the :device or :devices option. Instead use the :destination option.' if (options.key?(:device) or options.key?(:devices))
12
-
13
- @options = options
14
- @testrun_count = 0
15
- @xcpretty_json_file_output = ENV['XCPRETTY_JSON_FILE_OUTPUT']
16
-
17
- @reportnamer = ReportNameHelper.new(
18
- options[:output_types],
19
- options[:output_files],
20
- options[:custom_report_file_name]
21
- )
22
- end
23
-
24
- def before_testrun
25
- remove_preexisting_test_result_bundles
26
- set_json_env
27
- print_starting_scan_message
28
- end
29
-
30
- def print_starting_scan_message
31
- scan_message = "Starting scan ##{@testrun_count + 1} with #{@options.fetch(:only_testing, []).size} tests"
32
- scan_message << " for batch ##{@options[:batch]}" unless @options[:batch].nil?
33
- FastlaneCore::UI.message("#{scan_message}.")
34
- end
35
-
36
- def set_json_env
37
- return unless @reportnamer.includes_json?
38
-
39
- ENV['XCPRETTY_JSON_FILE_OUTPUT'] = File.join(
40
- @options[:output_directory],
41
- @reportnamer.json_last_reportname
42
- )
43
- end
44
-
45
- def reset_json_env
46
- return unless @reportnamer.includes_json?
47
-
48
- ENV['XCPRETTY_JSON_FILE_OUTPUT'] = @xcpretty_json_file_output
49
- end
50
-
51
- def remove_preexisting_test_result_bundles
52
- return unless @options[:result_bundle]
53
-
54
- absolute_output_directory = File.absolute_path(@options[:output_directory])
55
- glob_pattern = "#{absolute_output_directory}/*.test_result"
56
- preexisting_test_result_bundles = Dir.glob(glob_pattern)
57
- FileUtils.rm_rf(preexisting_test_result_bundles)
58
- end
59
-
60
- def scan_options
61
- valid_scan_keys = Fastlane::Actions::ScanAction.available_options.map(&:key)
62
- @options.select { |k,v| valid_scan_keys.include?(k) }
63
- .merge(@reportnamer.scan_options)
64
- end
65
-
66
- # after_testrun methods
67
-
68
- def after_testrun(exception = nil)
69
- @testrun_count = @testrun_count + 1
70
- if exception.kind_of?(FastlaneCore::Interface::FastlaneTestFailure)
71
- handle_test_failure
72
- elsif exception.kind_of?(FastlaneCore::Interface::FastlaneBuildFailure)
73
- handle_build_failure(exception)
74
- else
75
- handle_success
76
- end
77
- end
78
-
79
- def handle_success
80
- send_callback_testrun_info
81
- move_test_result_bundle_for_next_run
82
- reset_json_env
83
- collate_reports
84
- end
85
-
86
- def collate_reports
87
- absolute_output_directory = File.absolute_path(@options[:output_directory])
88
-
89
- TestCenter::Helper::MultiScanManager::ReportCollator.new(
90
- source_reports_directory_glob: absolute_output_directory,
91
- output_directory: absolute_output_directory,
92
- reportnamer: @reportnamer,
93
- scheme: @options[:scheme],
94
- result_bundle: @options[:result_bundle]
95
- ).collate
96
- end
97
-
98
- def handle_test_failure
99
- send_callback_testrun_info
100
- reset_simulators
101
- move_test_result_bundle_for_next_run
102
- update_scan_options
103
- @reportnamer.increment
104
- end
105
-
106
- def send_callback_testrun_info(additional_info = {})
107
- return unless @options[:testrun_completed_block]
108
-
109
- report_filepath = nil
110
- junit_results = {}
111
- unless additional_info.key?(:test_operation_failure)
112
- report_filepath = File.absolute_path(File.join(@options[:output_directory], @reportnamer.junit_last_reportname))
113
-
114
- config = FastlaneCore::Configuration.create(
115
- Fastlane::Actions::TestsFromJunitAction.available_options,
116
- {
117
- junit: File.absolute_path(report_filepath)
118
- }
119
- )
120
- junit_results = Fastlane::Actions::TestsFromJunitAction.run(config)
121
- end
122
-
123
- info = {
124
- failed: junit_results[:failed],
125
- passing: junit_results[:passing],
126
- batch: 1,
127
- try_count: @testrun_count,
128
- report_filepath: report_filepath
129
- }.merge(additional_info)
130
-
131
- if @reportnamer.includes_html?
132
- html_report_filepath = File.join(@options[:output_directory], @reportnamer.html_last_reportname)
133
- info[:html_report_filepath] = html_report_filepath
134
- end
135
- if @reportnamer.includes_json?
136
- json_report_filepath = File.join(@options[:output_directory], @reportnamer.json_last_reportname)
137
- info[:json_report_filepath] = json_report_filepath
138
- end
139
- if @options[:result_bundle]
140
- test_result_suffix = '.test_result'
141
- test_result_suffix.prepend("-#{@reportnamer.report_count}") unless @reportnamer.report_count.zero?
142
- test_result_bundlepath = File.join(@options[:output_directory], @options[:scheme]) + test_result_suffix
143
- info[:test_result_bundlepath] = test_result_bundlepath
144
- end
145
- @options[:testrun_completed_block].call(info)
146
- end
147
-
148
- def update_scan_options
149
- update_only_testing
150
- turn_off_code_coverage
151
- end
152
-
153
- def turn_off_code_coverage
154
- # Turn off code coverage as code coverage reports are not merged and
155
- # the first, more valuable, report will be overwritten
156
- @options.delete(:code_coverage)
157
- end
158
-
159
- def update_only_testing
160
- report_filepath = File.join(@options[:output_directory], @reportnamer.junit_last_reportname)
161
- config = FastlaneCore::Configuration.create(
162
- Fastlane::Actions::TestsFromJunitAction.available_options,
163
- {
164
- junit: File.absolute_path(report_filepath)
165
- }
166
- )
167
- @options[:only_testing] = Fastlane::Actions::TestsFromJunitAction.run(config)[:failed]
168
- end
169
-
170
- def reset_simulators
171
- return unless @options[:reset_simulators]
172
-
173
- @options[:simulators].each(&:reset)
174
- end
175
-
176
- def handle_build_failure(exception)
177
- test_operation_failure = ''
178
-
179
- test_session_last_messages = last_lines_of_test_session_log
180
- test_operation_failure_match = /Test operation failure: (?<test_operation_failure>.*)$/ =~ test_session_last_messages
181
- if test_operation_failure_match.nil?
182
- test_operation_failure = 'Unknown test operation failure'
183
- end
184
-
185
- case test_operation_failure
186
- when /Test runner exited before starting test execution/
187
- FastlaneCore::UI.error(test_operation_failure)
188
- when /Lost connection to testmanagerd/
189
- FastlaneCore::UI.error(test_operation_failure)
190
- FastlaneCore::UI.important("com.apple.CoreSimulator.CoreSimulatorService may have become corrupt, consider quitting it")
191
- if @options[:quit_core_simulator_service]
192
- Fastlane::Actions::RestartCoreSimulatorServiceAction.run
193
- end
194
- else
195
- FastlaneCore::UI.error(test_operation_failure)
196
- send_callback_testrun_info(test_operation_failure: test_operation_failure)
197
- raise exception
198
- end
199
- if @options[:reset_simulators]
200
- @options[:simulators].each do |simulator|
201
- simulator.reset
202
- end
203
- end
204
- send_callback_testrun_info(test_operation_failure: test_operation_failure)
205
- end
206
-
207
- def last_lines_of_test_session_log
208
- derived_data_path = File.expand_path(@options[:derived_data_path])
209
- test_session_logs = Dir.glob("#{derived_data_path}/Logs/Test/*.xcresult/*_Test/Diagnostics/**/Session-*.log")
210
- test_session_logs.sort! { |logfile1, logfile2| File.mtime(logfile1) <=> File.mtime(logfile2) }
211
- test_session = File.open(test_session_logs.last)
212
- backwards_seek_offset = -1 * [1000, test_session.stat.size].min
213
- test_session.seek(backwards_seek_offset, IO::SEEK_END)
214
- test_session_last_messages = test_session.read
215
- end
216
-
217
- def move_test_result_bundle_for_next_run
218
- return unless @options[:result_bundle]
219
-
220
- absolute_output_directory = File.absolute_path(@options[:output_directory])
221
- glob_pattern = "#{absolute_output_directory}/*.test_result"
222
- preexisting_test_result_bundles = Dir.glob(glob_pattern)
223
- unnumbered_test_result_bundles = preexisting_test_result_bundles.reject do |test_result|
224
- test_result =~ /.*-\d+\.test_result/
225
- end
226
- src_test_bundle = unnumbered_test_result_bundles.first
227
- dst_test_bundle_parent_dir = File.dirname(src_test_bundle)
228
- dst_test_bundle_basename = File.basename(src_test_bundle, '.test_result')
229
- dst_test_bundle = "#{dst_test_bundle_parent_dir}/#{dst_test_bundle_basename}-#{@testrun_count}.test_result"
230
- FileUtils.mkdir_p(dst_test_bundle)
231
- FileUtils.mv(src_test_bundle, dst_test_bundle)
232
- end
233
- end
234
- end
235
- end
236
- end
@@ -1,313 +0,0 @@
1
-
2
- module TestCenter
3
- module Helper
4
- module MultiScanManager
5
- require 'fastlane_core/ui/ui.rb'
6
- require 'plist'
7
- require 'json'
8
- require 'shellwords'
9
- require 'snapshot/reset_simulators'
10
- require_relative './simulator_manager'
11
-
12
- class Runner
13
- Parallelization = TestCenter::Helper::MultiScanManager::Parallelization
14
-
15
- attr_reader :retry_total_count
16
-
17
- def initialize(multi_scan_options)
18
- @output_directory = multi_scan_options[:output_directory] || 'test_results'
19
- @try_count = multi_scan_options[:try_count]
20
- @retry_total_count = 0
21
- @testrun_completed_block = multi_scan_options[:testrun_completed_block]
22
- @given_custom_report_file_name = multi_scan_options[:custom_report_file_name]
23
- @given_output_types = multi_scan_options[:output_types]
24
- @given_output_files = multi_scan_options[:output_files]
25
- @parallelize = multi_scan_options[:parallelize]
26
- @test_collector = TestCenter::Helper::TestCollector.new(multi_scan_options)
27
- @scan_options = multi_scan_options.reject do |option, _|
28
- %i[
29
- output_directory
30
- only_testing
31
- skip_testing
32
- clean
33
- try_count
34
- batch_count
35
- custom_report_file_name
36
- fail_build
37
- testrun_completed_block
38
- output_types
39
- output_files
40
- parallelize
41
- quit_simulators
42
- ].include?(option)
43
- end
44
- @scan_options[:clean] = false
45
- @scan_options[:disable_concurrent_testing] = true
46
- @scan_options[:xctestrun] = @test_collector.xctestrun_path
47
- @batch_count = @test_collector.test_batches.size
48
- if @parallelize
49
- @scan_options.delete(:derived_data_path)
50
- @parallelizer = Parallelization.new(@batch_count, @output_directory, @testrun_completed_block)
51
- end
52
- end
53
-
54
- def scan
55
- all_tests_passed = true
56
- @testables_count = @test_collector.testables.size
57
- all_tests_passed = each_batch do |test_batch, current_batch_index|
58
- if ENV['USE_REFACTORED_PARALLELIZED_MULTI_SCAN']
59
- # destination = @parallelizer&.destination_for_batch(current_batch_index) || Scan&.config&.fetch(:destination)
60
- # if destination.nil?
61
- # app_infoplist ||= XCTestrunInfo.new(@scan_options[:xctestrun])
62
-
63
- # batch_deploymentversions = @test_collector.test_batches.map do |test_batch|
64
- # testable = test_batch.first.split('/').first.gsub('\\', '')
65
- # # TODO: investigate the reason for this call that doesn't seem to do
66
- # # anything other than query for and then discard MinimumOSVersion
67
- # app_infoplist.app_plist_for_testable(testable)['MinimumOSVersion']
68
- # end
69
-
70
- # device_description = @scan_options[:device]
71
- # device_name = 'iPhone 5s'
72
- # device_version = batch_deploymentversions[current_batch_index]
73
- # unless device_description.nil?
74
- # /(?<device_name>.*)\s+\((?<device_version>.*)\)/ =~ device_description
75
- # end
76
- # # TODO: check for an existing simulator that can serve
77
- # all_runtimes = ::Snapshot::ResetSimulators.runtimes
78
-
79
- # all_ios_runtimes = all_runtimes.select { |v, id| v[/^iOS/] }
80
- # ios_runtimes_greater_than_equal = all_ios_runtimes.select do |versionstr, _|
81
- # _, version = versionstr.split(' ')
82
- # Gem::Version.new(device_version) <= Gem::Version.new(version)
83
- # end
84
- # ios_runtimes_greater_than_equal.sort! do |a, b|
85
- # version_a = a.first.split(' ').last
86
- # version_b = b.first.split(' ').last
87
- # Gem::Version.new(version_a) <=> Gem::Version.new(version_b)
88
- # end
89
-
90
- # runtime = ios_runtimes_greater_than_equal.first.last
91
- # device_type = `xcrun simctl list devicetypes`.scan(/(.*)\s\((.*)\)/)
92
- # .find { |name, device_id| name == device_name }
93
-
94
- # command = "xcrun simctl create '#{device_name}' #{device_type.last} #{runtime}"
95
- # UI.command(command) if ::FastlaneCore::Globals.verbose?
96
- # udid = `#{command}`.chomp
97
- # destination = "platform=iOS Simulator,id=#{udid}"
98
- # end
99
- retrying_scan = TestCenter::Helper::MultiScanManager::RetryingScan.new(
100
- @scan_options.merge(
101
- # destination: destination,
102
- only_testing: test_batch.map(&:shellsafe_testidentifier),
103
- output_directory: @output_directory
104
- ).reject { |key| %i[device devices].include?(key) }
105
- )
106
- retrying_scan.run
107
- else
108
- output_directory = testrun_output_directory(@output_directory, test_batch, current_batch_index)
109
- reset_for_new_testable(output_directory)
110
- FastlaneCore::UI.header("Starting test run on batch '#{current_batch_index}'")
111
- @interstitial.batch = current_batch_index
112
- @interstitial.output_directory = output_directory
113
- @interstitial.before_all
114
- testrun_passed = correcting_scan(
115
- {
116
- only_testing: test_batch.map(&:shellsafe_testidentifier),
117
- output_directory: output_directory
118
- },
119
- current_batch_index,
120
- @reportnamer
121
- )
122
- all_tests_passed = testrun_passed && all_tests_passed
123
- TestCenter::Helper::MultiScanManager::ReportCollator.new(
124
- source_reports_directory_glob: output_directory,
125
- output_directory: output_directory,
126
- reportnamer: @reportnamer,
127
- scheme: @scan_options[:scheme],
128
- result_bundle: @scan_options[:result_bundle]
129
- ).collate
130
- end
131
- testrun_passed && all_tests_passed
132
- end
133
- all_tests_passed
134
- end
135
-
136
- def each_batch
137
- tests_passed = true
138
- if @parallelize
139
- xctestrun_filename = File.basename(@test_collector.xctestrun_path)
140
- xcproduct_dirpath = File.dirname(@test_collector.xctestrun_path)
141
- tmp_xcproduct_dirpath = Dir.mktmpdir
142
-
143
- FileUtils.copy_entry(xcproduct_dirpath, tmp_xcproduct_dirpath)
144
-
145
- tmp_xctestrun_path = File.join(tmp_xcproduct_dirpath, xctestrun_filename)
146
- app_infoplist = XCTestrunInfo.new(tmp_xctestrun_path)
147
- @scan_options[:xctestrun] = tmp_xctestrun_path
148
- batch_deploymentversions = @test_collector.test_batches.map do |test_batch|
149
- testable = test_batch.first.split('/').first.gsub('\\', '')
150
- # TODO: investigate the reason for this call that doesn't seem to do
151
- # anything other than query for and then discard MinimumOSVersion
152
- app_infoplist.app_plist_for_testable(testable)['MinimumOSVersion']
153
- end
154
- @parallelizer.setup_simulators(@scan_options[:devices] || Array(@scan_options[:device]), batch_deploymentversions)
155
- @parallelizer.setup_pipes_for_fork
156
- @test_collector.test_batches.each_with_index do |test_batch, current_batch_index|
157
- fork do
158
- @parallelizer.connect_subprocess_endpoint(current_batch_index)
159
- begin
160
- @parallelizer.setup_scan_options_for_testrun(@scan_options, current_batch_index)
161
- # add output_directory to map of test-target: [ output_directories ]
162
- tests_passed = yield(test_batch, current_batch_index)
163
- ensure
164
- @parallelizer.send_subprocess_result(current_batch_index, tests_passed)
165
- end
166
- # processes to disconnect from the Simulator subsystems
167
- FastlaneCore::UI.message("batched scan #{current_batch_index} finishing")
168
- end
169
- end
170
- # @parallelizer.wait_for_subprocesses
171
- # tests_passed = @parallelizer.handle_subprocesses_results && tests_passed
172
- @parallelizer.handle_subprocesses
173
- @parallelizer.cleanup_simulators
174
- @test_collector.testables.each do |testable|
175
- # ReportCollator with a testable-batch glob pattern
176
- source_reports_directory_glob = batched_testable_output_directory(@output_directory, '*', testable)
177
- @reportnamer = ReportNameHelper.new(
178
- @given_output_types,
179
- @given_output_files,
180
- @given_custom_report_file_name
181
- )
182
- TestCenter::Helper::MultiScanManager::ReportCollator.new(
183
- source_reports_directory_glob: source_reports_directory_glob,
184
- output_directory: @output_directory,
185
- reportnamer: @reportnamer,
186
- scheme: @scan_options[:scheme],
187
- result_bundle: @scan_options[:result_bundle],
188
- suffix: testable
189
- ).collate
190
- FileUtils.rm_rf(Dir.glob(source_reports_directory_glob))
191
- end
192
- # for each key in test-target : [ output_directories ], call
193
- # collate_junit_reports for each key, the [ output_directories ] being
194
- # used to find the report files.
195
- # the resultant report file is to be placed in the originally requested
196
- # output_directory, with the name changed to include a suffix matching
197
- # the test target's name
198
- else
199
- @test_collector.test_batches.each_with_index do |test_batch, current_batch_index|
200
- tests_passed = yield(test_batch, current_batch_index)
201
- end
202
- end
203
- tests_passed
204
- end
205
-
206
- def batched_testable_output_directory(output_directory, batch_index, testable_name)
207
- File.join(output_directory, "results-#{testable_name}-batch-#{batch_index}")
208
- end
209
-
210
- def testrun_output_directory(base_output_directory, test_batch, batch_index)
211
- return base_output_directory if @batch_count == 1
212
-
213
- testable_name = test_batch.first.split('/').first.gsub(/\\/, '')
214
- batched_testable_output_directory(base_output_directory, batch_index, testable_name)
215
- end
216
-
217
- def reset_reportnamer
218
- @reportnamer = ReportNameHelper.new(
219
- @given_output_types,
220
- @given_output_files,
221
- @given_custom_report_file_name
222
- )
223
- end
224
-
225
- def test_run_completed_callback
226
- if @parallelize && @testrun_completed_block
227
- Proc.new do |info|
228
- puts "about to call @parallelizer.send_subprocess_tryinfo(#{info})"
229
- @parallelizer.send_subprocess_tryinfo(info)
230
- end
231
- else
232
- @testrun_completed_block
233
- end
234
- end
235
-
236
- def reset_interstitial(output_directory)
237
- @interstitial = TestCenter::Helper::MultiScanManager::Interstitial.new(
238
- @scan_options.merge(
239
- {
240
- output_directory: output_directory,
241
- reportnamer: @reportnamer,
242
- testrun_completed_block: @testrun_completed_block,
243
- parallelize: @parallelize
244
- }
245
- )
246
- )
247
- end
248
-
249
- def reset_for_new_testable(output_directory)
250
- reset_reportnamer
251
- reset_interstitial(output_directory)
252
- end
253
-
254
- def correcting_scan(scan_run_options, batch, reportnamer)
255
- scan_options = @scan_options.merge(scan_run_options)
256
- try_count = 0
257
- tests_passed = true
258
- begin
259
- try_count += 1
260
- config = FastlaneCore::Configuration.create(
261
- Fastlane::Actions::ScanAction.available_options,
262
- scan_options.merge(reportnamer.scan_options)
263
- )
264
- Fastlane::Actions::ScanAction.run(config)
265
- @interstitial.finish_try(try_count)
266
- tests_passed = true
267
- rescue FastlaneCore::Interface::FastlaneTestFailure => e
268
- FastlaneCore::UI.verbose("Scan failed with #{e}")
269
- if try_count < @try_count
270
- @retry_total_count += 1
271
- scan_options.delete(:code_coverage)
272
- tests_to_retry = failed_tests(reportnamer, scan_options[:output_directory])
273
-
274
- scan_options[:only_testing] = tests_to_retry.map(&:shellsafe_testidentifier)
275
- FastlaneCore::UI.message('Re-running scan on only failed tests')
276
- @interstitial.finish_try(try_count)
277
- retry
278
- end
279
- tests_passed = false
280
- end
281
- tests_passed
282
- end
283
-
284
- def failed_tests(reportnamer, output_directory)
285
- report_filepath = File.join(output_directory, reportnamer.junit_last_reportname)
286
- config = FastlaneCore::Configuration.create(
287
- Fastlane::Actions::TestsFromJunitAction.available_options,
288
- {
289
- junit: File.absolute_path(report_filepath)
290
- }
291
- )
292
- Fastlane::Actions::TestsFromJunitAction.run(config)[:failed]
293
- end
294
- end
295
- end
296
- end
297
- end
298
-
299
-
300
- module FastlaneCore
301
- class Shell < Interface
302
- def format_string(datetime = Time.now, severity = "")
303
- prefix = $batch_index.nil? ? '' : "#{$batch_index}: "
304
- if FastlaneCore::Globals.verbose?
305
- return "#{prefix}#{severity} [#{datetime.strftime('%Y-%m-%d %H:%M:%S.%2N')}]: "
306
- elsif FastlaneCore::Env.truthy?("FASTLANE_HIDE_TIMESTAMP")
307
- return prefix
308
- else
309
- return "#{prefix}[#{datetime.strftime('%H:%M:%S')}]: "
310
- end
311
- end
312
- end
313
- end