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

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,27 +0,0 @@
1
- module TestCenter
2
- module Helper
3
- module MultiScanManager
4
- class ParallelTestBatchWorker < TestBatchWorker
5
- attr_reader :pid
6
-
7
- def state=(new_state)
8
- super(new_state)
9
- @pid = nil unless new_state == :working
10
- end
11
-
12
- def run(run_options)
13
- self.state = :working
14
- @pid = Process.fork do
15
- begin
16
- super(run_options)
17
- ensure
18
- exit!
19
- end
20
- end
21
- end
22
- end
23
- end
24
- end
25
- end
26
-
27
-
@@ -1,115 +0,0 @@
1
- module TestCenter
2
- module Helper
3
- module MultiScanManager
4
- class ReportCollator
5
- CollateJunitReportsAction = Fastlane::Actions::CollateJunitReportsAction
6
- CollateHtmlReportsAction = Fastlane::Actions::CollateHtmlReportsAction
7
- CollateJsonReportsAction = Fastlane::Actions::CollateJsonReportsAction
8
- CollateTestResultBundlesAction = Fastlane::Actions::CollateTestResultBundlesAction
9
-
10
- def initialize(params)
11
- @source_reports_directory_glob = params[:source_reports_directory_glob]
12
- @output_directory = params[:output_directory]
13
- @reportnamer = params[:reportnamer]
14
- @scheme = params[:scheme]
15
- @result_bundle = params[:result_bundle]
16
- @suffix = params[:suffix] || ''
17
- end
18
-
19
- def collate
20
- collate_junit_reports
21
- collate_html_reports
22
- collate_json_reports
23
- collate_test_result_bundles
24
- end
25
-
26
- def sort_globbed_files(glob)
27
- files = Dir.glob(glob).map do |relative_filepath|
28
- File.absolute_path(relative_filepath)
29
- end
30
- files.sort! { |f1, f2| File.mtime(f1) <=> File.mtime(f2) }
31
- end
32
-
33
- def delete_globbed_intermediatefiles(glob)
34
- retried_reportfiles = Dir.glob(glob)
35
- FileUtils.rm_f(retried_reportfiles)
36
- end
37
-
38
- def create_config(klass, options)
39
- FastlaneCore::Configuration.create(klass.available_options, options)
40
- end
41
-
42
- def collate_junit_reports
43
- glob = "#{@source_reports_directory_glob}/#{@reportnamer.junit_fileglob}"
44
- report_files = sort_globbed_files(glob)
45
- if report_files.size > 1
46
- collated_file = File.absolute_path(File.join(@output_directory, @reportnamer.junit_reportname(@suffix)))
47
- config = create_config(
48
- CollateJunitReportsAction,
49
- {
50
- reports: report_files,
51
- collated_report: collated_file
52
- }
53
- )
54
- CollateJunitReportsAction.run(config)
55
- FileUtils.rm_rf(report_files - [collated_file])
56
- end
57
- end
58
-
59
- def collate_html_reports
60
- return unless @reportnamer.includes_html?
61
-
62
- report_files = sort_globbed_files("#{@source_reports_directory_glob}/#{@reportnamer.html_fileglob}")
63
- if report_files.size > 1
64
- collated_file = File.absolute_path(File.join(@output_directory, @reportnamer.html_reportname(@suffix)))
65
- config = create_config(
66
- CollateJunitReportsAction,
67
- {
68
- reports: report_files,
69
- collated_report: collated_file
70
- }
71
- )
72
- CollateHtmlReportsAction.run(config)
73
- FileUtils.rm_rf(report_files - [collated_file])
74
- end
75
- end
76
-
77
- def collate_json_reports
78
- return unless @reportnamer.includes_json?
79
-
80
- report_files = sort_globbed_files("#{@source_reports_directory_glob}/#{@reportnamer.json_fileglob}")
81
- if report_files.size > 1
82
- collated_file = File.absolute_path(File.join(@output_directory, @reportnamer.json_reportname(@suffix)))
83
- config = create_config(
84
- CollateJsonReportsAction,
85
- {
86
- reports: report_files,
87
- collated_report: collated_file
88
- }
89
- )
90
- CollateJsonReportsAction.run(config)
91
- FileUtils.rm_rf(report_files - [collated_file])
92
- end
93
- end
94
-
95
- def collate_test_result_bundles
96
- return unless @result_bundle
97
-
98
- test_result_bundlepaths = sort_globbed_files("#{@source_reports_directory_glob}/#{@scheme}*.test_result")
99
- if test_result_bundlepaths.size > 1
100
- collated_test_result_bundlepath = File.absolute_path("#{File.join(@output_directory, @scheme)}.test_result")
101
- config = create_config(
102
- CollateTestResultBundlesAction,
103
- {
104
- bundles: test_result_bundlepaths,
105
- collated_bundle: collated_test_result_bundlepath
106
- }
107
- )
108
- CollateTestResultBundlesAction.run(config)
109
- FileUtils.rm_rf(test_result_bundlepaths - [collated_test_result_bundlepath])
110
- end
111
- end
112
- end
113
- end
114
- end
115
- end
@@ -1,74 +0,0 @@
1
- module TestCenter
2
- module Helper
3
- module MultiScanManager
4
-
5
- class RetryingScan
6
- def initialize(options = {})
7
- @options = options
8
- @retrying_scan_helper = RetryingScanHelper.new(options)
9
- end
10
-
11
- def scan_config
12
- Scan.config
13
- end
14
-
15
- def scan_cache
16
- Scan.cache
17
- end
18
-
19
- def prepare_scan_config_for_destination
20
- # this allows multi_scan's `destination` option to be picked up by `scan`
21
- scan_config._values.delete(:device)
22
- scan_config._values.delete(:devices)
23
- scan_cache.clear
24
- end
25
-
26
- def update_scan_options
27
- valid_scan_keys = Fastlane::Actions::ScanAction.available_options.map(&:key)
28
- scan_options = @options.select { |k,v| valid_scan_keys.include?(k) }
29
- .merge(@retrying_scan_helper.scan_options)
30
-
31
- prepare_scan_config_for_destination
32
- scan_options.each do |k,v|
33
- scan_config.set(k,v) unless v.nil?
34
- end
35
- end
36
-
37
- def self.run(options)
38
- RetryingScan.new(options).run
39
- end
40
-
41
- def run
42
- try_count = @options[:try_count] || 1
43
- begin
44
- # TODO move delete_xcresults to `before_testrun`
45
- @retrying_scan_helper.before_testrun
46
- update_scan_options
47
-
48
- values = scan_config.values(ask: false)
49
- values[:xcode_path] = File.expand_path("../..", FastlaneCore::Helper.xcode_path)
50
- FastlaneCore::PrintTable.print_values(
51
- config: values,
52
- hide_keys: [:destination, :slack_url],
53
- title: "Summary for scan #{Fastlane::VERSION}"
54
- ) unless FastlaneCore::Helper.test?
55
-
56
- Scan::Runner.new.run
57
- @retrying_scan_helper.after_testrun
58
- true
59
- rescue FastlaneCore::Interface::FastlaneTestFailure => e
60
- FastlaneCore::UI.message("retrying_scan after test failure")
61
- @retrying_scan_helper.after_testrun(e)
62
- retry if @retrying_scan_helper.testrun_count < try_count
63
- false
64
- rescue FastlaneCore::Interface::FastlaneBuildFailure => e
65
- FastlaneCore::UI.message("retrying_scan after build failure")
66
- @retrying_scan_helper.after_testrun(e)
67
- retry if @retrying_scan_helper.testrun_count < try_count
68
- false
69
- end
70
- end
71
- end
72
- end
73
- end
74
- end
@@ -1,255 +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
- @reportnamer = ReportNameHelper.new(
17
- @options[:output_types],
18
- @options[:output_files],
19
- @options[:custom_report_file_name]
20
- )
21
- end
22
-
23
- def before_testrun
24
- remove_preexisting_test_result_bundles
25
- delete_xcresults # has to be performed _after_ moving a *.test_result
26
-
27
- set_json_env
28
- print_starting_scan_message
29
- end
30
-
31
- def delete_xcresults
32
- derived_data_path = File.expand_path(@options[:derived_data_path] || Scan.config[:derived_data_path])
33
- xcresults = Dir.glob("#{derived_data_path}/Logs/Test/*.xcresult")
34
- FastlaneCore::UI.message("Deleting xcresults: #{xcresults}")
35
- FileUtils.rm_rf(xcresults)
36
- end
37
-
38
- def output_directory
39
- absolute_output_directory = File.absolute_path(@options[:output_directory])
40
- if @options[:batch]
41
- testable = @options.fetch(:only_testing, ['']).first.split('/').first || ''
42
- absolute_output_directory = File.join(absolute_output_directory, "#{testable}-batch-#{@options[:batch]}")
43
- end
44
- absolute_output_directory
45
- end
46
-
47
- def print_starting_scan_message
48
- scan_message = "Starting scan ##{@testrun_count + 1} with #{@options.fetch(:only_testing, []).size} tests"
49
- scan_message << " for batch ##{@options[:batch]}" unless @options[:batch].nil?
50
- FastlaneCore::UI.message("#{scan_message}.")
51
- end
52
-
53
- def set_json_env
54
- return unless @reportnamer.includes_json?
55
-
56
- ENV['XCPRETTY_JSON_FILE_OUTPUT'] = File.join(
57
- output_directory,
58
- @reportnamer.json_last_reportname
59
- )
60
- end
61
-
62
- def reset_json_env
63
- return unless @reportnamer.includes_json?
64
-
65
- ENV['XCPRETTY_JSON_FILE_OUTPUT'] = @xcpretty_json_file_output
66
- end
67
-
68
- def remove_preexisting_test_result_bundles
69
- return unless @options[:result_bundle]
70
-
71
- glob_pattern = "#{output_directory}/*.test_result"
72
- preexisting_test_result_bundles = Dir.glob(glob_pattern)
73
- FileUtils.rm_rf(preexisting_test_result_bundles)
74
- end
75
-
76
- def scan_options
77
- valid_scan_keys = Fastlane::Actions::ScanAction.available_options.map(&:key)
78
- @options.select { |k,v| valid_scan_keys.include?(k) }
79
- .merge(@reportnamer.scan_options)
80
- .merge(output_directory: output_directory)
81
- end
82
-
83
- # after_testrun methods
84
-
85
- def after_testrun(exception = nil)
86
- @testrun_count = @testrun_count + 1
87
- if exception.kind_of?(FastlaneCore::Interface::FastlaneTestFailure)
88
- handle_test_failure
89
- elsif exception.kind_of?(FastlaneCore::Interface::FastlaneBuildFailure)
90
- handle_build_failure(exception)
91
- else
92
- handle_success
93
- end
94
- collate_reports
95
- end
96
-
97
- def handle_success
98
- send_callback_testrun_info
99
- move_test_result_bundle_for_next_run
100
- reset_json_env
101
- end
102
-
103
- def collate_reports
104
-
105
- report_collator_options = {
106
- source_reports_directory_glob: output_directory,
107
- output_directory: output_directory,
108
- reportnamer: @reportnamer,
109
- scheme: @options[:scheme],
110
- result_bundle: @options[:result_bundle]
111
- }
112
- TestCenter::Helper::MultiScanManager::ReportCollator.new(report_collator_options).collate
113
- end
114
-
115
- def handle_test_failure
116
- send_callback_testrun_info
117
- reset_simulators
118
- move_test_result_bundle_for_next_run
119
- update_scan_options
120
- @reportnamer.increment
121
- end
122
-
123
- def send_callback_testrun_info(additional_info = {})
124
- return unless @options[:testrun_completed_block]
125
-
126
- report_filepath = nil
127
- junit_results = {}
128
- unless additional_info.key?(:test_operation_failure)
129
- report_filepath = File.join(output_directory, @reportnamer.junit_last_reportname)
130
-
131
- config = FastlaneCore::Configuration.create(
132
- Fastlane::Actions::TestsFromJunitAction.available_options,
133
- {
134
- junit: File.absolute_path(report_filepath)
135
- }
136
- )
137
- junit_results = Fastlane::Actions::TestsFromJunitAction.run(config)
138
- end
139
-
140
- info = {
141
- failed: junit_results[:failed],
142
- passing: junit_results[:passing],
143
- batch: @options[:batch] || 1,
144
- try_count: @testrun_count,
145
- report_filepath: report_filepath
146
- }.merge(additional_info)
147
-
148
- if @reportnamer.includes_html?
149
- html_report_filepath = File.join(output_directory, @reportnamer.html_last_reportname)
150
- info[:html_report_filepath] = html_report_filepath
151
- end
152
- if @reportnamer.includes_json?
153
- json_report_filepath = File.join(output_directory, @reportnamer.json_last_reportname)
154
- info[:json_report_filepath] = json_report_filepath
155
- end
156
- if @options[:result_bundle]
157
- test_result_suffix = '.test_result'
158
- test_result_suffix.prepend("-#{@reportnamer.report_count}") unless @reportnamer.report_count.zero?
159
- test_result_bundlepath = File.join(output_directory, @options[:scheme]) + test_result_suffix
160
- info[:test_result_bundlepath] = test_result_bundlepath
161
- end
162
- @options[:testrun_completed_block].call(info)
163
- end
164
-
165
- def update_scan_options
166
- update_only_testing
167
- turn_off_code_coverage
168
- end
169
-
170
- def turn_off_code_coverage
171
- # Turn off code coverage as code coverage reports are not merged and
172
- # the first, more valuable, report will be overwritten
173
- @options.delete(:code_coverage)
174
- end
175
-
176
- def update_only_testing
177
- report_filepath = File.join(output_directory, @reportnamer.junit_last_reportname)
178
- config = FastlaneCore::Configuration.create(
179
- Fastlane::Actions::TestsFromJunitAction.available_options,
180
- {
181
- junit: File.absolute_path(report_filepath)
182
- }
183
- )
184
- @options[:only_testing] = Fastlane::Actions::TestsFromJunitAction.run(config)[:failed]
185
- if @options[:invocation_based_tests]
186
- @options[:only_testing] = @options[:only_testing].map(&:strip_testcase).uniq
187
- end
188
- end
189
-
190
- def reset_simulators
191
- return unless @options[:reset_simulators]
192
-
193
- @options[:simulators].each(&:reset)
194
- end
195
-
196
- def handle_build_failure(exception)
197
- test_operation_failure = ''
198
-
199
- test_session_last_messages = last_lines_of_test_session_log
200
- test_operation_failure_match = /Test operation failure: (?<test_operation_failure>.*)$/ =~ test_session_last_messages
201
- if test_operation_failure_match.nil?
202
- test_operation_failure = 'Unknown test operation failure'
203
- end
204
-
205
- case test_operation_failure
206
- when /Test runner exited before starting test execution/
207
- FastlaneCore::UI.error(test_operation_failure)
208
- when /Lost connection to testmanagerd/
209
- FastlaneCore::UI.error(test_operation_failure)
210
- FastlaneCore::UI.important("com.apple.CoreSimulator.CoreSimulatorService may have become corrupt, consider quitting it")
211
- if @options[:quit_core_simulator_service]
212
- Fastlane::Actions::RestartCoreSimulatorServiceAction.run
213
- end
214
- else
215
- FastlaneCore::UI.error(test_operation_failure)
216
- send_callback_testrun_info(test_operation_failure: test_operation_failure)
217
- raise exception
218
- end
219
- if @options[:reset_simulators]
220
- @options[:simulators].each do |simulator|
221
- simulator.reset
222
- end
223
- end
224
- send_callback_testrun_info(test_operation_failure: test_operation_failure)
225
- end
226
-
227
- def last_lines_of_test_session_log
228
- derived_data_path = File.expand_path(@options[:derived_data_path])
229
- test_session_logs = Dir.glob("#{derived_data_path}/Logs/Test/*.xcresult/*_Test/Diagnostics/**/Session-*.log")
230
- test_session_logs.sort! { |logfile1, logfile2| File.mtime(logfile1) <=> File.mtime(logfile2) }
231
- test_session = File.open(test_session_logs.last)
232
- backwards_seek_offset = -1 * [1000, test_session.stat.size].min
233
- test_session.seek(backwards_seek_offset, IO::SEEK_END)
234
- test_session_last_messages = test_session.read
235
- end
236
-
237
- def move_test_result_bundle_for_next_run
238
- return unless @options[:result_bundle]
239
-
240
- glob_pattern = "#{output_directory}/*.test_result"
241
- preexisting_test_result_bundles = Dir.glob(glob_pattern)
242
- unnumbered_test_result_bundles = preexisting_test_result_bundles.reject do |test_result|
243
- test_result =~ /.*-\d+\.test_result/
244
- end
245
- src_test_bundle = unnumbered_test_result_bundles.first
246
- dst_test_bundle_parent_dir = File.dirname(src_test_bundle)
247
- dst_test_bundle_basename = File.basename(src_test_bundle, '.test_result')
248
- dst_test_bundle = "#{dst_test_bundle_parent_dir}/#{dst_test_bundle_basename}-#{@testrun_count}.test_result"
249
- FileUtils.mkdir_p(dst_test_bundle)
250
- FileUtils.mv(src_test_bundle, dst_test_bundle)
251
- end
252
- end
253
- end
254
- end
255
- end