fastlane-plugin-test_center 3.8.0.parallelizing.beta.7 → 3.8.0.parallelizing.beta.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/fastlane/plugin/test_center/actions/multi_scan.rb +43 -32
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager.rb +7 -0
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/parallel_test_batch_worker.rb +25 -6
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/report_collator.rb +9 -0
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan.rb +1 -8
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb +80 -44
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/runner.rb +32 -5
- data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker_pool.rb +3 -5
- data/lib/fastlane/plugin/test_center/helper/scan_helper.rb +13 -0
- data/lib/fastlane/plugin/test_center/helper/test_collector.rb +1 -2
- data/lib/fastlane/plugin/test_center/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e73880166b9ba845963df59878b80eba77ca64d
|
4
|
+
data.tar.gz: 182b6aea7cbb03dfd121efc35dc832ca85a1bb6c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d6998f5f5f3515b8aaf10c75a2b804e32e192088be2323ff442208034c01568c013122a8db9c602856fce420f66983eeaf3b32769b7ddcbbb522ffdbb758d86
|
7
|
+
data.tar.gz: cd1f2ff6cbe717c40564514dff042a747a082d5e82e33212cdab478c83899d788154f867d16f23964669e38a0e7231b9bc7cfee9e3c54b46ff7806fa75653cd4
|
@@ -5,27 +5,18 @@ 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)
|
12
|
-
# :nocov:
|
13
|
-
unless Helper.test?
|
14
|
-
scan_keys = Fastlane::Actions::ScanAction.available_options.map(&:key)
|
15
|
-
FastlaneCore::PrintTable.print_values(
|
16
|
-
config: params._values.reject { |k, _| scan_keys.include?(k) },
|
17
|
-
title: "Summary for multi_scan (test_center v#{Fastlane::TestCenter::VERSION})"
|
18
|
-
)
|
19
|
-
end
|
20
|
-
# :nocov:
|
21
11
|
params[:quit_simulators] ||= params._values[:force_quit_simulator]
|
22
12
|
|
13
|
+
print_multi_scan_parameters(params)
|
23
14
|
force_quit_simulator_processes if params[:quit_simulators]
|
24
15
|
|
25
16
|
prepare_for_testing(params.values)
|
26
17
|
|
27
18
|
platform = :mac
|
28
|
-
platform = :
|
19
|
+
platform = :ios_simulator if Scan.config[:destination].any? { |d| d.include?('platform=iOS Simulator') }
|
29
20
|
|
30
21
|
runner_options = params.values.merge(platform: platform)
|
31
22
|
runner = ::TestCenter::Helper::MultiScanManager::Runner.new(runner_options)
|
@@ -35,14 +26,7 @@ module Fastlane
|
|
35
26
|
end
|
36
27
|
|
37
28
|
summary = run_summary(params, tests_passed, runner.retry_total_count)
|
38
|
-
|
39
|
-
unless Helper.test?
|
40
|
-
FastlaneCore::PrintTable.print_values(
|
41
|
-
config: summary,
|
42
|
-
title: "multi_scan results"
|
43
|
-
)
|
44
|
-
end
|
45
|
-
# :nocov:
|
29
|
+
print_run_summary(summary)
|
46
30
|
|
47
31
|
if params[:fail_build] && !tests_passed
|
48
32
|
raise UI.test_failure!('Tests have failed')
|
@@ -50,6 +34,28 @@ module Fastlane
|
|
50
34
|
summary
|
51
35
|
end
|
52
36
|
|
37
|
+
def self.print_multi_scan_parameters(params)
|
38
|
+
return if Helper.test?
|
39
|
+
# :nocov:
|
40
|
+
scan_keys = Fastlane::Actions::ScanAction.available_options.map(&:key)
|
41
|
+
FastlaneCore::PrintTable.print_values(
|
42
|
+
config: params._values.reject { |k, _| scan_keys.include?(k) },
|
43
|
+
title: "Summary for multi_scan (test_center v#{Fastlane::TestCenter::VERSION})"
|
44
|
+
)
|
45
|
+
# :nocov:
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.print_run_summary(summary)
|
49
|
+
return if Helper.test?
|
50
|
+
|
51
|
+
# :nocov:
|
52
|
+
FastlaneCore::PrintTable.print_values(
|
53
|
+
config: summary,
|
54
|
+
title: "multi_scan results"
|
55
|
+
)
|
56
|
+
# :nocov:
|
57
|
+
end
|
58
|
+
|
53
59
|
def self.run_summary(scan_options, tests_passed, retry_total_count)
|
54
60
|
reportnamer = ::TestCenter::Helper::ReportNameHelper.new(
|
55
61
|
scan_options[:output_types],
|
@@ -98,8 +104,10 @@ module Fastlane
|
|
98
104
|
|
99
105
|
def self.prepare_for_testing(scan_options)
|
100
106
|
if scan_options[:test_without_building] || scan_options[:skip_build]
|
107
|
+
UI.verbose("Preparing Scan config options for multi_scan testing")
|
101
108
|
prepare_scan_config(scan_options)
|
102
109
|
else
|
110
|
+
UI.verbose("Building the project in preparation for multi_scan testing")
|
103
111
|
build_for_testing(scan_options)
|
104
112
|
end
|
105
113
|
end
|
@@ -113,15 +121,7 @@ module Fastlane
|
|
113
121
|
|
114
122
|
def self.build_for_testing(scan_options)
|
115
123
|
values = prepare_scan_options_for_build_for_testing(scan_options)
|
116
|
-
|
117
|
-
unless Helper.test?
|
118
|
-
FastlaneCore::PrintTable.print_values(
|
119
|
-
config: values,
|
120
|
-
hide_keys: [:destination, :slack_url],
|
121
|
-
title: "Summary for scan #{Fastlane::VERSION}"
|
122
|
-
)
|
123
|
-
end
|
124
|
-
# :nocov:
|
124
|
+
ScanHelper.print_scan_parameters(values)
|
125
125
|
|
126
126
|
remove_preexisting_xctestrun_files
|
127
127
|
Scan::Runner.new.run
|
@@ -146,21 +146,30 @@ module Fastlane
|
|
146
146
|
end
|
147
147
|
|
148
148
|
def self.update_xctestrun_after_build(scan_options)
|
149
|
-
|
149
|
+
xctestrun_files = Dir.glob("#{Scan.config[:derived_data_path]}/Build/Products/*.xctestrun")
|
150
|
+
UI.verbose("After building, found xctestrun files #{xctestrun_files} (choosing 1st)")
|
151
|
+
scan_options[:xctestrun] = xctestrun_files.first
|
150
152
|
end
|
151
153
|
|
152
154
|
def self.remove_preexisting_xctestrun_files
|
153
155
|
xctestrun_files = Dir.glob("#{Scan.config[:derived_data_path]}/Build/Products/*.xctestrun")
|
156
|
+
UI.verbose("Before building, removing pre-existing xctestrun files: #{xctestrun_files}")
|
154
157
|
FileUtils.rm_rf(xctestrun_files)
|
155
158
|
end
|
156
159
|
|
157
160
|
def self.remove_build_report_files
|
161
|
+
# When Scan builds, it generates empty report files. Trying to collate
|
162
|
+
# subsequent, valid, report files with the empty report file will fail
|
163
|
+
# because there is no shared XML elements
|
158
164
|
report_options = Scan::XCPrettyReporterOptionsGenerator.generate_from_scan_config
|
159
165
|
output_files = report_options.instance_variable_get(:@output_files)
|
160
166
|
output_directory = report_options.instance_variable_get(:@output_directory)
|
161
167
|
|
168
|
+
UI.verbose("Removing report files generated by the build")
|
162
169
|
output_files.each do |output_file|
|
163
|
-
|
170
|
+
report_file = File.join(output_directory, output_file)
|
171
|
+
UI.verbose(" #{report_file}")
|
172
|
+
FileUtils.rm_f(report_file)
|
164
173
|
end
|
165
174
|
end
|
166
175
|
|
@@ -198,6 +207,8 @@ module Fastlane
|
|
198
207
|
end
|
199
208
|
|
200
209
|
def self.scan_options
|
210
|
+
# multi_scan has its own enhanced version of `output_types` and we want to provide
|
211
|
+
# the help and validation for that new version.
|
201
212
|
ScanAction.available_options.reject { |config| %i[output_types].include?(config.key) }
|
202
213
|
end
|
203
214
|
|
@@ -234,7 +245,7 @@ module Fastlane
|
|
234
245
|
conflict_block: proc do |value|
|
235
246
|
UI.user_error!(
|
236
247
|
"Error: Can't use 'invocation_based_tests' and 'batch_count' options in one run, "\
|
237
|
-
"because the number of tests is
|
248
|
+
"because the number of tests is unknown")
|
238
249
|
end
|
239
250
|
),
|
240
251
|
FastlaneCore::ConfigItem.new(
|
@@ -272,7 +283,7 @@ module Fastlane
|
|
272
283
|
),
|
273
284
|
FastlaneCore::ConfigItem.new(
|
274
285
|
key: :testrun_completed_block,
|
275
|
-
description: 'A block invoked each time a test run completes',
|
286
|
+
description: 'A block invoked each time a test run completes. When combined with :parallel_testrun_count, will be called separately in each child process',
|
276
287
|
optional: true,
|
277
288
|
is_string: false,
|
278
289
|
default_value: nil,
|
@@ -1,3 +1,10 @@
|
|
1
|
+
require_relative 'multi_scan_manager/device_manager'
|
2
|
+
require_relative 'multi_scan_manager/parallel_test_batch_worker'
|
1
3
|
require_relative 'multi_scan_manager/report_collator'
|
4
|
+
require_relative 'multi_scan_manager/retrying_scan_helper.rb'
|
5
|
+
require_relative 'multi_scan_manager/retrying_scan'
|
2
6
|
require_relative 'multi_scan_manager/runner'
|
7
|
+
require_relative 'multi_scan_manager/simulator_helper'
|
8
|
+
require_relative 'multi_scan_manager/test_batch_worker_pool'
|
9
|
+
require_relative 'multi_scan_manager/test_batch_worker'
|
3
10
|
require_relative 'xctestrun_info'
|
data/lib/fastlane/plugin/test_center/helper/multi_scan_manager/parallel_test_batch_worker.rb
CHANGED
@@ -1,13 +1,20 @@
|
|
1
1
|
module TestCenter
|
2
2
|
module Helper
|
3
3
|
module MultiScanManager
|
4
|
-
|
4
|
+
require 'colorize'
|
5
5
|
|
6
|
+
|
7
|
+
class ParallelTestBatchWorker < TestBatchWorker
|
8
|
+
|
6
9
|
attr_reader :pid
|
7
|
-
|
10
|
+
|
8
11
|
def initialize(options)
|
9
12
|
super(options)
|
10
13
|
@pipe_endpoint = nil
|
14
|
+
|
15
|
+
@@colors ||= String.colors - %i[white black light_green default]
|
16
|
+
@color = @@colors.sample
|
17
|
+
@@colors = @@colors - [@color]
|
11
18
|
end
|
12
19
|
|
13
20
|
def state=(new_state)
|
@@ -15,9 +22,16 @@ module TestCenter
|
|
15
22
|
end
|
16
23
|
|
17
24
|
def process_results
|
25
|
+
# This is performed in the Parent process
|
18
26
|
@pid = nil
|
27
|
+
|
28
|
+
worker_prefix = "[worker #{@options[:batch_index] + 1}] "
|
19
29
|
File.foreach(@log_filepath) do |line|
|
20
|
-
|
30
|
+
unless FastlaneCore::Helper.colors_disabled?
|
31
|
+
worker_prefix = worker_prefix.colorize(@color)
|
32
|
+
end
|
33
|
+
print worker_prefix
|
34
|
+
print line
|
21
35
|
end
|
22
36
|
state = :ready_to_work
|
23
37
|
@options[:test_batch_results] << (@reader.gets == 'true')
|
@@ -44,6 +58,11 @@ module TestCenter
|
|
44
58
|
end
|
45
59
|
|
46
60
|
def open_interprocess_communication
|
61
|
+
# This is performed in the Parent process in preparation to setup
|
62
|
+
# the STDOUT and STDOUT for printing messages from the Child process
|
63
|
+
# to a file. This is done so that when multiple processes write
|
64
|
+
# messages, they will not be written to the console in a broken
|
65
|
+
# interlaced manner.
|
47
66
|
@reader, @writer = IO.pipe
|
48
67
|
@log_filepath = File.join(
|
49
68
|
Dir.mktmpdir,
|
@@ -52,7 +71,8 @@ module TestCenter
|
|
52
71
|
end
|
53
72
|
|
54
73
|
def reroute_stdout_to_logfile
|
55
|
-
@reader.close # we are now in the subprocess
|
74
|
+
@reader.close # we are now in the subprocess. Write all stdout to the
|
75
|
+
# log file to prevent interlaced messages
|
56
76
|
@logfile = File.open(@log_filepath, 'w')
|
57
77
|
@logfile.sync = true
|
58
78
|
$stdout.reopen(@logfile)
|
@@ -60,6 +80,7 @@ module TestCenter
|
|
60
80
|
end
|
61
81
|
|
62
82
|
def handle_child_process_results(tests_passed)
|
83
|
+
# as suggested by the method name, this is done in the Child process
|
63
84
|
@logfile.close
|
64
85
|
@writer.puts tests_passed.to_s
|
65
86
|
@writer.close
|
@@ -72,5 +93,3 @@ module TestCenter
|
|
72
93
|
end
|
73
94
|
end
|
74
95
|
end
|
75
|
-
|
76
|
-
|
@@ -17,6 +17,7 @@ module TestCenter
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def collate
|
20
|
+
FastlaneCore::UI.verbose("ReportCollator collating")
|
20
21
|
collate_junit_reports
|
21
22
|
collate_html_reports
|
22
23
|
collate_json_reports
|
@@ -46,6 +47,7 @@ module TestCenter
|
|
46
47
|
report_files = sort_globbed_files(glob)
|
47
48
|
collated_file = File.absolute_path(File.join(@output_directory, @reportnamer.junit_reportname(@suffix)))
|
48
49
|
if report_files.size > 1
|
50
|
+
FastlaneCore::UI.verbose("Collating junit report files #{report_files}")
|
49
51
|
config = create_config(
|
50
52
|
CollateJunitReportsAction,
|
51
53
|
{
|
@@ -56,6 +58,7 @@ module TestCenter
|
|
56
58
|
CollateJunitReportsAction.run(config)
|
57
59
|
FileUtils.rm_rf(report_files - [collated_file])
|
58
60
|
elsif report_files.size == 1 && report_files.first != collated_file
|
61
|
+
FastlaneCore::UI.verbose("Copying junit report file #{report_files.first}")
|
59
62
|
FileUtils.mkdir_p(File.dirname(collated_file))
|
60
63
|
FileUtils.mv(report_files.first, collated_file)
|
61
64
|
end
|
@@ -67,6 +70,7 @@ module TestCenter
|
|
67
70
|
report_files = sort_globbed_files("#{@source_reports_directory_glob}/#{@reportnamer.html_fileglob}")
|
68
71
|
collated_file = File.absolute_path(File.join(@output_directory, @reportnamer.html_reportname(@suffix)))
|
69
72
|
if report_files.size > 1
|
73
|
+
FastlaneCore::UI.verbose("Collating html report files #{report_files}")
|
70
74
|
config = create_config(
|
71
75
|
CollateJunitReportsAction,
|
72
76
|
{
|
@@ -77,6 +81,7 @@ module TestCenter
|
|
77
81
|
CollateHtmlReportsAction.run(config)
|
78
82
|
FileUtils.rm_rf(report_files - [collated_file])
|
79
83
|
elsif report_files.size == 1 && report_files.first != collated_file
|
84
|
+
FastlaneCore::UI.verbose("Copying html report file #{report_files.first}")
|
80
85
|
FileUtils.mkdir_p(File.dirname(collated_file))
|
81
86
|
FileUtils.mv(report_files.first, collated_file)
|
82
87
|
end
|
@@ -88,6 +93,7 @@ module TestCenter
|
|
88
93
|
report_files = sort_globbed_files("#{@source_reports_directory_glob}/#{@reportnamer.json_fileglob}")
|
89
94
|
collated_file = File.absolute_path(File.join(@output_directory, @reportnamer.json_reportname(@suffix)))
|
90
95
|
if report_files.size > 1
|
96
|
+
FastlaneCore::UI.verbose("Collating json report files #{report_files}")
|
91
97
|
config = create_config(
|
92
98
|
CollateJsonReportsAction,
|
93
99
|
{
|
@@ -98,6 +104,7 @@ module TestCenter
|
|
98
104
|
CollateJsonReportsAction.run(config)
|
99
105
|
FileUtils.rm_rf(report_files - [collated_file])
|
100
106
|
elsif report_files.size == 1 && report_files.first != collated_file
|
107
|
+
FastlaneCore::UI.verbose("Copying json report file #{report_files.first}")
|
101
108
|
FileUtils.mkdir_p(File.dirname(collated_file))
|
102
109
|
FileUtils.mv(report_files.first, collated_file)
|
103
110
|
end
|
@@ -109,6 +116,7 @@ module TestCenter
|
|
109
116
|
test_result_bundlepaths = sort_globbed_files("#{@source_reports_directory_glob}/#{@scheme}*.test_result")
|
110
117
|
collated_test_result_bundlepath = File.absolute_path("#{File.join(@output_directory, @scheme)}.test_result")
|
111
118
|
if test_result_bundlepaths.size > 1
|
119
|
+
FastlaneCore::UI.verbose("Collating test_result bundles #{test_result_bundlepaths}")
|
112
120
|
config = create_config(
|
113
121
|
CollateTestResultBundlesAction,
|
114
122
|
{
|
@@ -119,6 +127,7 @@ module TestCenter
|
|
119
127
|
CollateTestResultBundlesAction.run(config)
|
120
128
|
FileUtils.rm_rf(test_result_bundlepaths - [collated_test_result_bundlepath])
|
121
129
|
elsif test_result_bundlepaths.size == 1 && test_result_bundlepaths.first != collated_test_result_bundlepath
|
130
|
+
FastlaneCore::UI.verbose("Copying test_result bundle #{test_result_bundlepaths.first}")
|
122
131
|
FileUtils.mkdir_p(File.dirname(collated_test_result_bundlepath))
|
123
132
|
FileUtils.mv(test_result_bundlepaths.first, collated_test_result_bundlepath)
|
124
133
|
end
|
@@ -44,28 +44,21 @@ module TestCenter
|
|
44
44
|
def run
|
45
45
|
try_count = @options[:try_count] || 1
|
46
46
|
begin
|
47
|
-
# TODO move delete_xcresults to `before_testrun`
|
48
47
|
@retrying_scan_helper.before_testrun
|
49
48
|
update_scan_options
|
50
49
|
|
51
50
|
values = scan_config.values(ask: false)
|
52
51
|
values[:xcode_path] = File.expand_path("../..", FastlaneCore::Helper.xcode_path)
|
53
|
-
|
54
|
-
config: values,
|
55
|
-
hide_keys: [:destination, :slack_url],
|
56
|
-
title: "Summary for scan #{Fastlane::VERSION}"
|
57
|
-
) unless FastlaneCore::Helper.test?
|
52
|
+
ScanHelper.print_scan_parameters(values)
|
58
53
|
|
59
54
|
Scan::Runner.new.run
|
60
55
|
@retrying_scan_helper.after_testrun
|
61
56
|
true
|
62
57
|
rescue FastlaneCore::Interface::FastlaneTestFailure => e
|
63
|
-
FastlaneCore::UI.message("retrying_scan after test failure")
|
64
58
|
@retrying_scan_helper.after_testrun(e)
|
65
59
|
retry if @retrying_scan_helper.testrun_count < try_count
|
66
60
|
false
|
67
61
|
rescue FastlaneCore::Interface::FastlaneBuildFailure => e
|
68
|
-
FastlaneCore::UI.message("retrying_scan after build failure")
|
69
62
|
@retrying_scan_helper.after_testrun(e)
|
70
63
|
retry if @retrying_scan_helper.testrun_count < try_count
|
71
64
|
false
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module TestCenter
|
2
2
|
module Helper
|
3
3
|
module MultiScanManager
|
4
|
-
require_relative 'device_manager'
|
5
|
-
|
6
4
|
class RetryingScanHelper
|
7
5
|
|
8
6
|
attr_reader :testrun_count
|
@@ -19,7 +17,7 @@ module TestCenter
|
|
19
17
|
@options[:custom_report_file_name]
|
20
18
|
)
|
21
19
|
end
|
22
|
-
|
20
|
+
|
23
21
|
def before_testrun
|
24
22
|
delete_xcresults # has to be performed _after_ moving a *.test_result
|
25
23
|
quit_simulator
|
@@ -32,7 +30,9 @@ module TestCenter
|
|
32
30
|
|
33
31
|
@options.fetch(:destination).each do |destination|
|
34
32
|
if /id=(?<udid>\w+),?/ =~ destination
|
33
|
+
FastlaneCore::UI.verbose("Restarting Simulator #{udid}")
|
35
34
|
`xcrun simctl shutdown #{udid} 2>/dev/null`
|
35
|
+
`xcrun simctl boot #{udid} 2>/dev/null`
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -40,7 +40,10 @@ module TestCenter
|
|
40
40
|
def delete_xcresults
|
41
41
|
derived_data_path = File.expand_path(@options[:derived_data_path] || Scan.config[:derived_data_path])
|
42
42
|
xcresults = Dir.glob("#{derived_data_path}/Logs/Test/*.xcresult")
|
43
|
-
FastlaneCore::UI.
|
43
|
+
FastlaneCore::UI.verbose("Deleting xcresults:")
|
44
|
+
xcresults.each do |xcresult|
|
45
|
+
FastlaneCore::UI.verbose(" #{xcresult}")
|
46
|
+
end
|
44
47
|
FileUtils.rm_rf(xcresults)
|
45
48
|
end
|
46
49
|
|
@@ -61,10 +64,12 @@ module TestCenter
|
|
61
64
|
def set_json_env
|
62
65
|
return unless @reportnamer.includes_json?
|
63
66
|
|
64
|
-
|
67
|
+
xcpretty_json_file_output = File.join(
|
65
68
|
output_directory,
|
66
69
|
@reportnamer.json_last_reportname
|
67
70
|
)
|
71
|
+
FastlaneCore::UI.verbose("Setting the XCPRETTY_JSON_FILE_OUTPUT to #{xcpretty_json_file_output}")
|
72
|
+
ENV['XCPRETTY_JSON_FILE_OUTPUT'] = xcpretty_json_file_output
|
68
73
|
end
|
69
74
|
|
70
75
|
def reset_json_env
|
@@ -91,10 +96,22 @@ module TestCenter
|
|
91
96
|
def after_testrun(exception = nil)
|
92
97
|
@testrun_count = @testrun_count + 1
|
93
98
|
if exception.kind_of?(FastlaneCore::Interface::FastlaneTestFailure)
|
99
|
+
after_testrun_message = "Scan found failing tests"
|
100
|
+
after_testrun_message << " for batch ##{@options[:batch]}" unless @options[:batch].nil?
|
101
|
+
FastlaneCore::UI.verbose(after_testrun_message)
|
102
|
+
|
94
103
|
handle_test_failure
|
95
104
|
elsif exception.kind_of?(FastlaneCore::Interface::FastlaneBuildFailure)
|
105
|
+
after_testrun_message = "Scan unable to test"
|
106
|
+
after_testrun_message << " for batch ##{@options[:batch]}" unless @options[:batch].nil?
|
107
|
+
FastlaneCore::UI.verbose(after_testrun_message)
|
108
|
+
|
96
109
|
handle_build_failure(exception)
|
97
110
|
else
|
111
|
+
after_testrun_message = "Scan passed the tests"
|
112
|
+
after_testrun_message << " for batch ##{@options[:batch]}" unless @options[:batch].nil?
|
113
|
+
FastlaneCore::UI.verbose(after_testrun_message)
|
114
|
+
|
98
115
|
handle_success
|
99
116
|
end
|
100
117
|
collate_reports
|
@@ -130,18 +147,7 @@ module TestCenter
|
|
130
147
|
return unless @options[:testrun_completed_block]
|
131
148
|
|
132
149
|
report_filepath = nil
|
133
|
-
junit_results =
|
134
|
-
unless additional_info.key?(:test_operation_failure)
|
135
|
-
report_filepath = File.join(output_directory, @reportnamer.junit_last_reportname)
|
136
|
-
|
137
|
-
config = FastlaneCore::Configuration.create(
|
138
|
-
Fastlane::Actions::TestsFromJunitAction.available_options,
|
139
|
-
{
|
140
|
-
junit: File.absolute_path(report_filepath)
|
141
|
-
}
|
142
|
-
)
|
143
|
-
junit_results = Fastlane::Actions::TestsFromJunitAction.run(config)
|
144
|
-
end
|
150
|
+
junit_results, report_filepath = failure_details(additional_info)
|
145
151
|
|
146
152
|
info = {
|
147
153
|
failed: junit_results[:failed],
|
@@ -151,23 +157,51 @@ module TestCenter
|
|
151
157
|
report_filepath: report_filepath
|
152
158
|
}.merge(additional_info)
|
153
159
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
if @reportnamer.includes_json?
|
159
|
-
json_report_filepath = File.join(output_directory, @reportnamer.json_last_reportname)
|
160
|
-
info[:json_report_filepath] = json_report_filepath
|
161
|
-
end
|
162
|
-
if @options[:result_bundle]
|
163
|
-
test_result_suffix = '.test_result'
|
164
|
-
test_result_suffix.prepend("-#{@reportnamer.report_count}") unless @reportnamer.report_count.zero?
|
165
|
-
test_result_bundlepath = File.join(output_directory, @options[:scheme]) + test_result_suffix
|
166
|
-
info[:test_result_bundlepath] = test_result_bundlepath
|
167
|
-
end
|
160
|
+
update_html_failure_details(info)
|
161
|
+
update_json_failure_details(info)
|
162
|
+
update_test_result_bundle_details(info)
|
163
|
+
|
168
164
|
@options[:testrun_completed_block].call(info)
|
169
165
|
end
|
170
166
|
|
167
|
+
def failure_details(additional_info)
|
168
|
+
return [{}, nil] if additional_info.key?(:test_operation_failure)
|
169
|
+
|
170
|
+
report_filepath = File.join(output_directory, @reportnamer.junit_last_reportname)
|
171
|
+
config = FastlaneCore::Configuration.create(
|
172
|
+
Fastlane::Actions::TestsFromJunitAction.available_options,
|
173
|
+
{
|
174
|
+
junit: File.absolute_path(report_filepath)
|
175
|
+
}
|
176
|
+
)
|
177
|
+
junit_results = Fastlane::Actions::TestsFromJunitAction.run(config)
|
178
|
+
|
179
|
+
[junit_results, report_filepath]
|
180
|
+
end
|
181
|
+
|
182
|
+
def update_html_failure_details(info)
|
183
|
+
return unless @reportnamer.includes_html?
|
184
|
+
|
185
|
+
html_report_filepath = File.join(output_directory, @reportnamer.html_last_reportname)
|
186
|
+
info[:html_report_filepath] = html_report_filepath
|
187
|
+
end
|
188
|
+
|
189
|
+
def update_json_failure_details(info)
|
190
|
+
return unless @reportnamer.includes_json?
|
191
|
+
|
192
|
+
json_report_filepath = File.join(output_directory, @reportnamer.json_last_reportname)
|
193
|
+
info[:json_report_filepath] = json_report_filepath
|
194
|
+
end
|
195
|
+
|
196
|
+
def update_test_result_bundle_details(info)
|
197
|
+
return unless @options[:result_bundle]
|
198
|
+
|
199
|
+
test_result_suffix = '.test_result'
|
200
|
+
test_result_suffix.prepend("-#{@reportnamer.report_count}") unless @reportnamer.report_count.zero?
|
201
|
+
test_result_bundlepath = File.join(output_directory, @options[:scheme]) + test_result_suffix
|
202
|
+
info[:test_result_bundlepath] = test_result_bundlepath
|
203
|
+
end
|
204
|
+
|
171
205
|
def update_scan_options
|
172
206
|
update_only_testing
|
173
207
|
turn_off_code_coverage
|
@@ -193,30 +227,32 @@ module TestCenter
|
|
193
227
|
end
|
194
228
|
end
|
195
229
|
|
196
|
-
def handle_build_failure(exception)
|
197
|
-
test_operation_failure = ''
|
198
|
-
|
230
|
+
def handle_build_failure(exception)
|
199
231
|
test_session_last_messages = last_lines_of_test_session_log
|
200
|
-
|
201
|
-
|
202
|
-
test_operation_failure = 'Unknown test operation failure'
|
203
|
-
end
|
204
|
-
|
205
|
-
case test_operation_failure
|
232
|
+
failure = retrieve_test_operation_failure(test_session_last_messages)
|
233
|
+
case failure
|
206
234
|
when /Test runner exited before starting test execution/
|
207
|
-
FastlaneCore::UI.error(
|
235
|
+
FastlaneCore::UI.error(failure)
|
208
236
|
when /Lost connection to testmanagerd/
|
209
|
-
FastlaneCore::UI.error(
|
237
|
+
FastlaneCore::UI.error(failure)
|
210
238
|
FastlaneCore::UI.important("com.apple.CoreSimulator.CoreSimulatorService may have become corrupt, consider quitting it")
|
211
239
|
if @options[:quit_core_simulator_service]
|
212
240
|
Fastlane::Actions::RestartCoreSimulatorServiceAction.run
|
213
241
|
end
|
214
242
|
else
|
215
243
|
FastlaneCore::UI.error(test_session_last_messages)
|
216
|
-
send_callback_testrun_info(test_operation_failure:
|
244
|
+
send_callback_testrun_info(test_operation_failure: failure)
|
217
245
|
raise exception
|
218
246
|
end
|
219
|
-
send_callback_testrun_info(test_operation_failure:
|
247
|
+
send_callback_testrun_info(test_operation_failure: failure)
|
248
|
+
end
|
249
|
+
|
250
|
+
def retrieve_test_operation_failure(test_session_last_messages)
|
251
|
+
test_operation_failure_match = /Test operation failure: (?<test_operation_failure>.*)$/ =~ test_session_last_messages
|
252
|
+
if test_operation_failure_match.nil?
|
253
|
+
test_operation_failure = 'Unknown test operation failure'
|
254
|
+
end
|
255
|
+
test_operation_failure
|
220
256
|
end
|
221
257
|
|
222
258
|
def last_lines_of_test_session_log
|
@@ -44,7 +44,7 @@ module TestCenter
|
|
44
44
|
|
45
45
|
tests_passed = false
|
46
46
|
if @options[:invocation_based_tests] && @options[:only_testing].nil?
|
47
|
-
tests_passed =
|
47
|
+
tests_passed = run_first_run_of_invocation_based_tests
|
48
48
|
end
|
49
49
|
|
50
50
|
unless tests_passed || @options[:try_count] < 1
|
@@ -58,14 +58,24 @@ module TestCenter
|
|
58
58
|
|
59
59
|
glob_pattern = "#{output_directory}/**/*.test_result"
|
60
60
|
preexisting_test_result_bundles = Dir.glob(glob_pattern)
|
61
|
-
|
61
|
+
if preexisting_test_result_bundles.size > 0
|
62
|
+
FastlaneCore::UI.verbose("Removing pre-existing test_result bundles: ")
|
63
|
+
preexisting_test_result_bundles.each do |test_result_bundle|
|
64
|
+
FastlaneCore::UI.verbose(" #{test_result_bundle}")
|
65
|
+
end
|
66
|
+
FileUtils.rm_rf(preexisting_test_result_bundles)
|
67
|
+
end
|
62
68
|
end
|
63
69
|
|
64
|
-
def
|
70
|
+
def run_first_run_of_invocation_based_tests
|
71
|
+
FastlaneCore::UI.verbose("Running invocation tests")
|
65
72
|
@options[:skip_testing] = @options[:skip_testing]&.map(&:strip_testcase)&.uniq
|
66
73
|
@options[:output_directory] = output_directory
|
67
74
|
@options[:destination] = Scan.config[:destination]
|
68
75
|
|
76
|
+
# We do not want Scan.config to _not_ have :device :devices, we want to
|
77
|
+
# use :destination. We remove :force_quit_simulator as we do not want
|
78
|
+
# Scan to handle it as multi_scan takes care of it in its own way
|
69
79
|
options = @options.reject { |key| %i[device devices force_quit_simulator].include?(key) }
|
70
80
|
options[:try_count] = 1
|
71
81
|
|
@@ -84,12 +94,28 @@ module TestCenter
|
|
84
94
|
junit: File.absolute_path(report_filepath)
|
85
95
|
}
|
86
96
|
)
|
87
|
-
@options[:only_testing] =
|
97
|
+
@options[:only_testing] = retrieve_failed_invocation_tests[:failed]
|
88
98
|
@options[:only_testing] = @options[:only_testing].map(&:strip_testcase).uniq
|
89
99
|
|
90
100
|
tests_passed
|
91
101
|
end
|
92
102
|
|
103
|
+
def retrieve_failed_invocation_tests
|
104
|
+
reportnamer = ReportNameHelper.new(
|
105
|
+
@options[:output_types],
|
106
|
+
@options[:output_files],
|
107
|
+
@options[:custom_report_file_name]
|
108
|
+
)
|
109
|
+
report_filepath = File.join(output_directory, reportnamer.junit_last_reportname)
|
110
|
+
config = FastlaneCore::Configuration.create(
|
111
|
+
Fastlane::Actions::TestsFromJunitAction.available_options,
|
112
|
+
{
|
113
|
+
junit: File.absolute_path(report_filepath)
|
114
|
+
}
|
115
|
+
)
|
116
|
+
Fastlane::Actions::TestsFromJunitAction.run(config)
|
117
|
+
end
|
118
|
+
|
93
119
|
def run_test_batches
|
94
120
|
test_batch_results = []
|
95
121
|
pool_options = @options.reject { |key| %i[device devices force_quit_simulator].include?(key) }
|
@@ -141,6 +167,8 @@ module TestCenter
|
|
141
167
|
end
|
142
168
|
|
143
169
|
def collate_batched_reports_for_testable(testable)
|
170
|
+
FastlaneCore::UI.verbose("Collating results for all batches")
|
171
|
+
|
144
172
|
absolute_output_directory = File.join(
|
145
173
|
File.absolute_path(output_directory),
|
146
174
|
testable
|
@@ -169,4 +197,3 @@ module TestCenter
|
|
169
197
|
end
|
170
198
|
end
|
171
199
|
end
|
172
|
-
|
@@ -19,7 +19,7 @@ module TestCenter
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def setup_cloned_simulators
|
22
|
-
return [] unless @options[:platform] == :
|
22
|
+
return [] unless @options[:platform] == :ios_simulator
|
23
23
|
|
24
24
|
@simhelper = SimulatorHelper.new(
|
25
25
|
parallel_testrun_count: @options[:parallel_testrun_count]
|
@@ -38,7 +38,7 @@ module TestCenter
|
|
38
38
|
|
39
39
|
def destination_for_worker(worker_index)
|
40
40
|
# each worker has its own simulators to work with
|
41
|
-
return @options[:destination] unless @options[:platform] == :
|
41
|
+
return @options[:destination] unless @options[:platform] == :ios_simulator
|
42
42
|
|
43
43
|
@clones[worker_index].map do |simulator|
|
44
44
|
"platform=iOS Simulator,id=#{simulator.udid}"
|
@@ -85,9 +85,7 @@ module TestCenter
|
|
85
85
|
def setup_serial_workers
|
86
86
|
serial_scan_options = @options.reject { |key| %i[device devices].include?(key) }
|
87
87
|
serial_scan_options[:destination] ||= Scan&.config&.fetch(:destination)
|
88
|
-
@workers = [
|
89
|
-
TestBatchWorker.new(serial_scan_options)
|
90
|
-
]
|
88
|
+
@workers = [ TestBatchWorker.new(serial_scan_options) ]
|
91
89
|
end
|
92
90
|
|
93
91
|
def wait_for_worker
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ScanHelper
|
2
|
+
def self.print_scan_parameters(params)
|
3
|
+
return if FastlaneCore::Helper.test?
|
4
|
+
|
5
|
+
# :nocov:
|
6
|
+
FastlaneCore::PrintTable.print_values(
|
7
|
+
config: params,
|
8
|
+
hide_keys: [:destination, :slack_url],
|
9
|
+
title: "Summary for scan #{Fastlane::VERSION}"
|
10
|
+
)
|
11
|
+
# :nocov:
|
12
|
+
end
|
13
|
+
end
|
@@ -31,8 +31,7 @@ module TestCenter
|
|
31
31
|
|
32
32
|
def derived_testrun_path(derived_data_path, scheme)
|
33
33
|
xctestrun_files = Dir.glob("#{derived_data_path}/Build/Products/*.xctestrun")
|
34
|
-
xctestrun_files.sort { |f1, f2| File.mtime(f1) <=> File.mtime(f2) }
|
35
|
-
.last
|
34
|
+
xctestrun_files.sort { |f1, f2| File.mtime(f1) <=> File.mtime(f2) }.last
|
36
35
|
end
|
37
36
|
|
38
37
|
def testables
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-test_center
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.8.0.parallelizing.beta.
|
4
|
+
version: 3.8.0.parallelizing.beta.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lyndsey Ferguson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-07-
|
11
|
+
date: 2019-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -267,6 +267,7 @@ files:
|
|
267
267
|
- lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker.rb
|
268
268
|
- lib/fastlane/plugin/test_center/helper/multi_scan_manager/test_batch_worker_pool.rb
|
269
269
|
- lib/fastlane/plugin/test_center/helper/reportname_helper.rb
|
270
|
+
- lib/fastlane/plugin/test_center/helper/scan_helper.rb
|
270
271
|
- lib/fastlane/plugin/test_center/helper/test_collector.rb
|
271
272
|
- lib/fastlane/plugin/test_center/helper/xcodebuild_string.rb
|
272
273
|
- lib/fastlane/plugin/test_center/helper/xctestrun_info.rb
|