fastlane-plugin-test_center 3.9.0 → 3.10.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7dd99b394133508622e5daab51025772002b0b0369e6b7cfd04055dbb51cc0aa
4
- data.tar.gz: 30abd18975a3259a86ded79a1e466b386f86ef5f56cab4fefa04397bc80fa25a
3
+ metadata.gz: '098e845a533aae1482f49c2265234f95e6b6415a6f389fca3956851f009841da'
4
+ data.tar.gz: 612fa05cd1d3c550ed344ecc34f9f7a54a4d50a701711e33c7154f496d05104e
5
5
  SHA512:
6
- metadata.gz: 225ffa3158f7bf9b8bea8c6d47c897d4926e003a90f4eae9cd4f6cb1074e5de3943bcaf4111d2d819b611260503f9c2fb537cb334fd8d0ee07c0f501dc75b136
7
- data.tar.gz: 449cb428920924775c5aa28c236d367c34453e0ef68d534981c03f8292eb0e8a582043c4992b28e3dff4d21dee6fd96957d2280d39322f34c19a26845aa0e3df
6
+ metadata.gz: cd691d0fd30fc8a3a06d082f9a751a7101c1de6843819136d1fb18b66051435412bf8fe41606012ce65552096337a844ea1536896394b9ce6d679b3e80f00014
7
+ data.tar.gz: 25354716d6138969a45954a0f77429be98ea188e1a8fb9c4bda0b92300ea1d85df128526b65c4ef9e76575561f1aeddcb9c7fd9a9dd1133a6dbed3031af9dd21
data/README.md CHANGED
@@ -91,6 +91,10 @@ For more information about how the `fastlane` plugin system works, check out the
91
91
 
92
92
  _fastlane_ is the easiest way to automate beta deployments and releases for your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
93
93
 
94
+ ## Supporter
95
+
96
+ I'm grateful to all of the people who contributed back to `test_center`, all the people who helped test for new features or bug fixes, but most importantly I am grateful to my wife who supports my crazy passion for making software.
97
+
94
98
  ## License
95
99
 
96
100
  MIT
@@ -14,25 +14,21 @@ module Fastlane
14
14
  class MultiScanAction < Action
15
15
  def self.run(params)
16
16
  params[:quit_simulators] = params._values[:force_quit_simulator] if params._values[:force_quit_simulator]
17
- if params[:output_types]
18
- params[:output_types] = params[:output_types].split(',').map(&:strip).join(',')
19
- end
20
- if params[:output_files]
21
- params[:output_files] = params[:output_files].split(',').map(&:strip).join(',')
17
+ if params[:try_count] < 1
18
+ UI.important('multi_scan will not test any if :try_count < 0, setting to 1')
19
+ params[:try_count] = 1
22
20
  end
23
21
 
24
- if FastlaneCore::Helper.xcode_at_least?('11.0.0')
25
- if params[:result_bundle]
26
- UI.important('As of Xcode 11, test_result bundles created in the output directory are actually symbolic links to an xcresult bundle')
27
- end
28
- elsif params[:output_types]&.include?('xcresult')
29
- UI.important("The 'xcresult' :output_type is only supported for Xcode 11 and greater. You are using #{FastlaneCore::Helper.xcode_version}.")
30
- end
22
+ strip_leading_and_trailing_whitespace_from_output_types(params)
23
+
24
+ warn_of_xcode11_result_bundle_incompatability(params)
25
+ warn_of_parallelism_with_circle_ci(params)
26
+
31
27
  print_multi_scan_parameters(params)
32
28
  force_quit_simulator_processes if params[:quit_simulators]
33
29
 
34
30
  prepare_for_testing(params.values)
35
-
31
+
36
32
  coerce_destination_to_array(params)
37
33
  platform = :mac
38
34
  platform = :ios_simulator if Scan.config[:destination].any? { |d| d.include?('platform=iOS Simulator') }
@@ -43,17 +39,43 @@ module Fastlane
43
39
 
44
40
  summary = run_summary(params, tests_passed)
45
41
  print_run_summary(summary)
46
-
42
+
47
43
  if params[:fail_build] && !tests_passed
48
44
  raise UI.test_failure!('Tests have failed')
49
45
  end
50
46
  summary
51
47
  end
52
48
 
49
+ def self.warn_of_parallelism_with_circle_ci(params)
50
+ if params[:parallel_testrun_count] > 1 && Helper.is_circle_ci?
51
+ UI.important("Warning: problems have occurreed when running parallel simulators on Circle CI.")
52
+ UI.message(" See https://github.com/lyndsey-ferguson/fastlane-plugin-test_center/issues/179")
53
+ end
54
+ end
55
+
56
+ def self.strip_leading_and_trailing_whitespace_from_output_types(params)
57
+ if params[:output_types]
58
+ params[:output_types] = params[:output_types].split(',').map(&:strip).join(',')
59
+ end
60
+ if params[:output_files]
61
+ params[:output_files] = params[:output_files].split(',').map(&:strip).join(',')
62
+ end
63
+ end
64
+
65
+ def self.warn_of_xcode11_result_bundle_incompatability(params)
66
+ if FastlaneCore::Helper.xcode_at_least?('11.0.0')
67
+ if params[:result_bundle]
68
+ UI.important('As of Xcode 11, test_result bundles created in the output directory are actually symbolic links to an xcresult bundle')
69
+ end
70
+ elsif params[:output_types]&.include?('xcresult')
71
+ UI.important("The 'xcresult' :output_type is only supported for Xcode 11 and greater. You are using #{FastlaneCore::Helper.xcode_version}.")
72
+ end
73
+ end
74
+
53
75
  def self.coerce_destination_to_array(params)
54
76
  destination = params[:destination] || Scan.config[:destination] || []
55
77
  unless destination.kind_of?(Array)
56
- params[:destination] = Scan.config[:destination] = [destination]
78
+ params[:destination] = Scan.config[:destination] = [destination]
57
79
  end
58
80
  end
59
81
 
@@ -68,7 +90,7 @@ module Fastlane
68
90
  # :nocov:
69
91
  end
70
92
 
71
- def self.print_run_summary(summary)
93
+ def self.print_run_summary(summary)
72
94
  return if Helper.test?
73
95
 
74
96
  # :nocov:
@@ -147,6 +169,7 @@ module Fastlane
147
169
  def self.prepare_for_testing(scan_options)
148
170
  reset_scan_config_to_defaults
149
171
  use_scanfile_to_override_settings(scan_options)
172
+ turn_off_concurrent_workers(scan_options)
150
173
  ScanHelper.remove_preexisting_simulator_logs(scan_options)
151
174
  if scan_options[:test_without_building] || scan_options[:skip_build]
152
175
  UI.verbose("Preparing Scan config options for multi_scan testing")
@@ -157,6 +180,12 @@ module Fastlane
157
180
  end
158
181
  end
159
182
 
183
+ def self.turn_off_concurrent_workers(scan_options)
184
+ if Gem::Version.new(Fastlane::VERSION) >= Gem::Version.new('2.142.0')
185
+ scan_options.delete(:concurrent_workers) if scan_options[:concurrent_workers].to_i > 0
186
+ end
187
+ end
188
+
160
189
  def self.reset_scan_config_to_defaults
161
190
  return unless Scan.config
162
191
 
@@ -173,7 +202,7 @@ module Fastlane
173
202
  overridden_options = ScanHelper.options_from_configuration_file(
174
203
  ScanHelper.scan_options_from_multi_scan_options(scan_options)
175
204
  )
176
-
205
+
177
206
  unless overridden_options.empty?
178
207
  FastlaneCore::UI.important("Scanfile found: overriding multi_scan options with it's values.")
179
208
  overridden_options.each do |k,v|
@@ -303,6 +332,13 @@ module Fastlane
303
332
  UI.user_error!("Error: Batch counts must be greater than zero") unless count > 0
304
333
  end
305
334
  ),
335
+ FastlaneCore::ConfigItem.new(
336
+ key: :retry_test_runner_failures,
337
+ description: "Set to true If you want to treat build failures during testing, like 'Test runner exited before starting test execution', as 'all tests failed'",
338
+ type: Boolean,
339
+ default_value: false,
340
+ optional: true
341
+ ),
306
342
  FastlaneCore::ConfigItem.new(
307
343
  key: :invocation_based_tests,
308
344
  description: "Set to true If your test suit have invocation based tests like Kiwi",
@@ -374,7 +410,7 @@ module Fastlane
374
410
  UI.important(
375
411
  'example: ' \\
376
412
  'split the tests into 4 batches and run each batch of tests in ' \\
377
- 'parallel up to 3 times if tests fail. Abort the testing early ' \\
413
+ 'parallel up to 3 times if tests fail. Abort the testing early ' \\
378
414
  'if there are too many failing tests by passing in a ' \\
379
415
  ':testrun_completed_block that is called by :multi_scan ' \\
380
416
  'after each run of tests.'
@@ -17,17 +17,23 @@ module Fastlane
17
17
  scheme_filepaths.each do |scheme_filepath|
18
18
  is_dirty = false
19
19
  xcscheme = Xcodeproj::XCScheme.new(scheme_filepath)
20
- xcscheme.test_action.testables.each do |testable|
21
- buildable_name = File.basename(testable.buildable_references[0].buildable_name, '.xctest')
22
-
23
- tests_to_skip = all_tests_to_skip.select { |test| test.start_with?(buildable_name) }
24
- .map { |test| test.sub("#{buildable_name}/", '') }
25
-
26
- tests_to_skip.each do |test_to_skip|
27
- skipped_test = Xcodeproj::XCScheme::TestAction::TestableReference::SkippedTest.new
28
- skipped_test.identifier = test_to_skip
29
- testable.add_skipped_test(skipped_test)
30
- is_dirty = true
20
+ testplans = xcscheme.test_action.test_plans
21
+ unless testplans.nil?
22
+ container_directory = File.absolute_path(File.dirname(params[:xcodeproj] || params[:workspace]))
23
+ update_testplans(container_directory, testplans, all_tests_to_skip)
24
+ else
25
+ xcscheme.test_action.testables.each do |testable|
26
+ buildable_name = File.basename(testable.buildable_references[0].buildable_name, '.xctest')
27
+
28
+ tests_to_skip = all_tests_to_skip.select { |test| test.start_with?(buildable_name) }
29
+ .map { |test| test.sub("#{buildable_name}/", '') }
30
+
31
+ tests_to_skip.each do |test_to_skip|
32
+ skipped_test = Xcodeproj::XCScheme::TestAction::TestableReference::SkippedTest.new
33
+ skipped_test.identifier = test_to_skip
34
+ testable.add_skipped_test(skipped_test)
35
+ is_dirty = true
36
+ end
31
37
  end
32
38
  end
33
39
  xcscheme.save! if is_dirty
@@ -35,6 +41,24 @@ module Fastlane
35
41
  nil
36
42
  end
37
43
 
44
+ def self.update_testplans(container_directory, testplans, all_tests_to_skip)
45
+ testplans.each do |testplan_reference|
46
+ testplan_filename = testplan_reference.target_referenced_container.sub('container:', '')
47
+ testplan_filepath = File.join(container_directory, testplan_filename)
48
+ file = File.read(testplan_filepath)
49
+ testplan = JSON.parse(file)
50
+ testplan['testTargets'].each do |test_target|
51
+ buildable_name = test_target.dig('target', 'name')
52
+ tests_to_skip = all_tests_to_skip.select { |test| test.start_with?(buildable_name) }
53
+ .map { |test| test.sub("#{buildable_name}/", '') }
54
+ test_target['selectedTests'].reject! { |t| tests_to_skip.include?(t) }
55
+ end
56
+ File.open(testplan_filepath, 'w') do |f|
57
+ f.write(JSON.pretty_generate(testplan).gsub('/', '\/'))
58
+ end
59
+ end
60
+ end
61
+
38
62
  def self.schemes_from_project(project_path, scheme)
39
63
  return nil unless project_path
40
64
 
@@ -2,6 +2,7 @@ module Fastlane
2
2
  module Actions
3
3
  class SuppressedTestsAction < Action
4
4
  require 'set'
5
+ require 'json'
5
6
 
6
7
  def self.run(params)
7
8
  scheme = params[:scheme]
@@ -15,13 +16,19 @@ module Fastlane
15
16
  skipped_tests = Set.new
16
17
  scheme_filepaths.each do |scheme_filepath|
17
18
  xcscheme = Xcodeproj::XCScheme.new(scheme_filepath)
18
- xcscheme.test_action.testables.each do |testable|
19
- buildable_name = testable.buildable_references[0]
20
- .buildable_name
19
+ testplans = xcscheme.test_action.test_plans
20
+ unless testplans.nil?
21
+ UI.important("Error: unable to read suppressed tests from Xcode Scheme #{File.basename(scheme_filepath)}.")
22
+ UI.message("The scheme is using a testplan which does not list skipped tests.")
23
+ else
24
+ xcscheme.test_action.testables.each do |testable|
25
+ buildable_name = testable.buildable_references[0]
26
+ .buildable_name
21
27
 
22
- buildable_name = File.basename(buildable_name, '.xctest')
23
- testable.skipped_tests.map do |skipped_test|
24
- skipped_tests.add("#{buildable_name}/#{skipped_test.identifier}")
28
+ buildable_name = File.basename(buildable_name, '.xctest')
29
+ testable.skipped_tests.map do |skipped_test|
30
+ skipped_tests.add("#{buildable_name}/#{skipped_test.identifier}")
31
+ end
25
32
  end
26
33
  end
27
34
  end
@@ -11,10 +11,26 @@ module Fastlane
11
11
  def self.xctestrun_tests(xctestrun_path, invocation_based_tests)
12
12
  xctestrun = Plist.parse_xml(xctestrun_path)
13
13
  xctestrun_rootpath = File.dirname(xctestrun_path)
14
- tests = Hash.new([])
15
- xctestrun.each do |testable_name, xctestrun_config|
16
- next if ignoredTestables.include? testable_name
14
+ xctestrun_version = xctestrun.fetch('__xctestrun_metadata__', Hash.new).fetch('FormatVersion', 1)
17
15
 
16
+ test_targets = []
17
+ if xctestrun_version == 1
18
+ xctestrun.each do |testable_name, test_target_config|
19
+ next if ignoredTestables.include? testable_name
20
+ test_targets << test_target_config
21
+ end
22
+ else
23
+ test_configurations = xctestrun['TestConfigurations']
24
+ test_configurations.each do |configuration|
25
+ configuration['TestTargets'].each do |test_target|
26
+ test_targets << test_target
27
+ end
28
+ end
29
+ end
30
+
31
+ tests = Hash.new([])
32
+ test_targets.each do |xctestrun_config|
33
+ testable_name = xctestrun_config['ProductModuleName']
18
34
  xctest_path = xctest_bundle_path(xctestrun_rootpath, xctestrun_config)
19
35
  test_identifiers = []
20
36
  if xctestrun_config.key?('OnlyTestIdentifiers')
@@ -17,11 +17,18 @@ module TestCenter
17
17
  end
18
18
  # :nocov:
19
19
 
20
- def prepare_scan_config_for_destination
20
+ def prepare_scan_config
21
21
  # this allows multi_scan's `destination` option to be picked up by `scan`
22
22
  scan_config._values.delete(:device)
23
+ ENV.delete('SCAN_DEVICE')
23
24
  scan_config._values.delete(:devices)
24
- scan_config._values.delete(:result_bundle) if ReportNameHelper.includes_xcresult?(@options[:output_types])
25
+ ENV.delete('SCAN_DEVICES')
26
+ # this prevents double -resultBundlePath args to xcodebuild
27
+ if ReportNameHelper.includes_xcresult?(@options[:output_types])
28
+ scan_config._values.delete(:result_bundle)
29
+ ENV.delete('SCAN_RESULT_BUNDLE')
30
+ end
31
+ scan_config._values.delete(:skip_testing)
25
32
  scan_cache.clear
26
33
  end
27
34
 
@@ -30,12 +37,13 @@ module TestCenter
30
37
  scan_options = @options.select { |k,v| valid_scan_keys.include?(k) }
31
38
  .merge(@retrying_scan_helper.scan_options)
32
39
 
33
- prepare_scan_config_for_destination
40
+ prepare_scan_config
34
41
  scan_options[:build_for_testing] = false
42
+ scan_options.delete(:skip_testing)
35
43
  FastlaneCore::UI.verbose("retrying_scan #update_scan_options")
36
44
  scan_options.each do |k,v|
37
45
  next if v.nil?
38
-
46
+
39
47
  scan_config.set(k,v) unless v.nil?
40
48
  FastlaneCore::UI.verbose("\tSetting #{k.to_s} to #{v}")
41
49
  end
@@ -52,7 +60,7 @@ module TestCenter
52
60
  begin
53
61
  @retrying_scan_helper.before_testrun
54
62
  update_scan_options
55
-
63
+
56
64
  values = scan_config.values(ask: false)
57
65
  values[:xcode_path] = File.expand_path("../..", FastlaneCore::Helper.xcode_path)
58
66
  ScanHelper.print_scan_parameters(values)
@@ -88,11 +88,16 @@ module TestCenter
88
88
 
89
89
  def scan_options
90
90
  valid_scan_keys = Fastlane::Actions::ScanAction.available_options.map(&:key)
91
- xcargs = @options[:xcargs]
91
+ xcargs = @options[:xcargs] || ''
92
92
  if xcargs&.include?('build-for-testing')
93
93
  FastlaneCore::UI.important(":xcargs, #{xcargs}, contained 'build-for-testing', removing it")
94
94
  xcargs.slice!('build-for-testing')
95
95
  end
96
+ if xcargs.include?('-quiet')
97
+ FastlaneCore::UI.important('Disabling -quiet as failing tests cannot be found with it enabled.')
98
+ xcargs.gsub!('-quiet', '')
99
+ end
100
+ xcargs.gsub!(/-parallel-testing-enabled(=|\s+)(YES|NO)/, '')
96
101
  retrying_scan_options = @reportnamer.scan_options.merge(
97
102
  {
98
103
  output_directory: output_directory,
@@ -125,7 +130,11 @@ module TestCenter
125
130
  after_testrun_message << " for batch ##{@options[:batch]}" unless @options[:batch].nil?
126
131
  FastlaneCore::UI.verbose(after_testrun_message)
127
132
 
128
- handle_build_failure(exception)
133
+ if @options[:retry_test_runner_failures]
134
+ continue_with_build_failure(exception)
135
+ else
136
+ handle_build_failure(exception)
137
+ end
129
138
  else
130
139
  after_testrun_message = "Scan passed the tests"
131
140
  after_testrun_message << " for batch ##{@options[:batch]}" unless @options[:batch].nil?
@@ -240,12 +249,27 @@ module TestCenter
240
249
  junit: File.absolute_path(report_filepath)
241
250
  }
242
251
  )
243
- @options[:only_testing] = Fastlane::Actions::TestsFromJunitAction.run(config)[:failed].map(&:shellsafe_testidentifier)
252
+ @options[:only_testing] = (@options[:only_testing] || []) - Fastlane::Actions::TestsFromJunitAction.run(config).fetch(:passing, Hash.new).map(&:shellsafe_testidentifier)
244
253
  if @options[:invocation_based_tests]
245
254
  @options[:only_testing] = @options[:only_testing].map(&:strip_testcase).uniq
246
255
  end
247
256
  end
248
257
 
258
+ def continue_with_build_failure(exception)
259
+ test_session_last_messages = last_lines_of_test_session_log
260
+ failure = retrieve_test_operation_failure(test_session_last_messages)
261
+ case failure
262
+ when /Lost connection to testmanagerd/
263
+ FastlaneCore::UI.important("com.apple.CoreSimulator.CoreSimulatorService may have become corrupt, consider quitting it")
264
+ if @options[:quit_core_simulator_service]
265
+ Fastlane::Actions::RestartCoreSimulatorServiceAction.run
266
+ end
267
+ else
268
+ FastlaneCore::UI.important(test_session_last_messages)
269
+ end
270
+ send_callback_testrun_info(test_operation_failure: failure)
271
+ end
272
+
249
273
  def handle_build_failure(exception)
250
274
  test_session_last_messages = last_lines_of_test_session_log
251
275
  failure = retrieve_test_operation_failure(test_session_last_messages)
@@ -262,11 +286,31 @@ module TestCenter
262
286
  FastlaneCore::UI.error(test_session_last_messages)
263
287
  send_callback_testrun_info(test_operation_failure: failure)
264
288
  raise exception
289
+ FastlaneCore::UI.important(test_session_last_messages)
265
290
  end
266
291
  send_callback_testrun_info(test_operation_failure: failure)
267
292
  end
268
293
 
269
294
  def retrieve_test_operation_failure(test_session_last_messages)
295
+ if FastlaneCore::Helper.xcode_at_least?(11)
296
+ retrieve_test_operation_failure_post_xcode11(test_session_last_messages)
297
+ else
298
+ retrieve_test_operation_failure_pre_xcode11(test_session_last_messages)
299
+ end
300
+ end
301
+
302
+ def retrieve_test_operation_failure_post_xcode11(test_session_last_messages)
303
+ if /Connection peer refused channel request/ =~ test_session_last_messages
304
+ test_operation_failure = 'Lost connection to testmanagerd'
305
+ elsif /Please unlock your device and reattach/ =~ test_session_last_messages
306
+ test_operation_failure = 'Test device locked'
307
+ elsif /Test runner exited before starting test execution/ =~ test_session_last_messages
308
+ test_operation_failure = 'Test runner exited before starting test execution'
309
+ end
310
+ test_operation_failure
311
+ end
312
+
313
+ def retrieve_test_operation_failure_pre_xcode11(test_session_last_messages)
270
314
  test_operation_failure_match = /Test operation failure: (?<test_operation_failure>.*)$/ =~ test_session_last_messages
271
315
  if test_operation_failure_match.nil?
272
316
  test_operation_failure = 'Unknown test operation failure'
@@ -7,7 +7,7 @@ module TestCenter
7
7
  require 'json'
8
8
  require 'shellwords'
9
9
  require 'snapshot/reset_simulators'
10
-
10
+
11
11
  class Runner
12
12
  attr_reader :retry_total_count
13
13
 
@@ -66,12 +66,12 @@ module TestCenter
66
66
  end
67
67
 
68
68
  unless tests_passed || @options[:try_count] < 1
69
- setup_testcollector
69
+ setup_testcollector
70
70
  tests_passed = run_test_batches
71
71
  end
72
72
  tests_passed
73
73
  end
74
-
74
+
75
75
  def should_run_tests_through_single_try?
76
76
  should_run_for_invocation_tests = @options[:invocation_based_tests] && @options[:only_testing].nil?
77
77
  should_run_for_skip_build = @options[:skip_build]
@@ -114,16 +114,16 @@ module TestCenter
114
114
  end
115
115
  @options[:output_directory] = output_directory
116
116
  @options[:destination] = Scan.config[:destination]
117
-
117
+
118
118
  # We do not want Scan.config to _not_ have :device :devices, we want to
119
119
  # use :destination. We remove :force_quit_simulator as we do not want
120
120
  # Scan to handle it as multi_scan takes care of it in its own way
121
121
  options = @options.reject { |key| %i[device devices force_quit_simulator].include?(key) }
122
122
  options[:try_count] = 1
123
-
123
+
124
124
  tests_passed = RetryingScan.run(options)
125
125
  @options[:try_count] -= 1
126
-
126
+
127
127
  reportnamer = ReportNameHelper.new(
128
128
  @options[:output_types],
129
129
  @options[:output_files],
@@ -138,12 +138,12 @@ module TestCenter
138
138
  )
139
139
  @options[:only_testing] = retrieve_failed_single_try_tests
140
140
  @options[:only_testing] = @options[:only_testing].map(&:strip_testcase).uniq
141
-
141
+
142
142
  symlink_result_bundle_to_xcresult(output_directory, reportnamer)
143
143
 
144
144
  tests_passed
145
145
  end
146
-
146
+
147
147
  def retrieve_failed_single_try_tests
148
148
  reportnamer = ReportNameHelper.new(
149
149
  @options[:output_types],
@@ -168,10 +168,10 @@ module TestCenter
168
168
 
169
169
  pool = TestBatchWorkerPool.new(pool_options)
170
170
  pool.setup_workers
171
-
171
+
172
172
  remaining_test_batches = @test_collector.test_batches.clone
173
173
  remaining_test_batches.each_with_index do |test_batch, current_batch_index|
174
- worker = pool.wait_for_worker
174
+ worker = pool.wait_for_worker
175
175
  FastlaneCore::UI.message("Starting test run #{current_batch_index + 1}")
176
176
  worker.run(scan_options_for_worker(test_batch, current_batch_index))
177
177
  end
@@ -189,7 +189,7 @@ module TestCenter
189
189
  batch: batch_index + 1
190
190
  }
191
191
  end
192
-
192
+
193
193
  def collate_batched_reports
194
194
  return unless @batch_count > 1
195
195
  return unless @options[:collate_reports]
@@ -207,10 +207,44 @@ module TestCenter
207
207
  File.absolute_path(output_directory),
208
208
  @test_collector.testables.first
209
209
  )
210
+ merge_single_testable_xcresult_with_final_xcresult(report_files_dir, File.absolute_path(output_directory))
210
211
  FileUtils.cp_r("#{report_files_dir}/.", File.absolute_path(output_directory))
211
212
  FileUtils.rm_rf(report_files_dir)
212
213
  end
213
214
 
215
+ def merge_single_testable_xcresult_with_final_xcresult(testable_output_dir, final_output_dir)
216
+ reportnamer = ReportNameHelper.new(
217
+ @options[:output_types],
218
+ @options[:output_files],
219
+ @options[:custom_report_file_name]
220
+ )
221
+ return unless reportnamer.includes_xcresult?
222
+
223
+ xcresult_bundlename = reportnamer.xcresult_bundlename
224
+ src_xcresult_bundlepath = File.join(testable_output_dir, xcresult_bundlename)
225
+ dst_xcresult_bundlepath = File.join(final_output_dir, xcresult_bundlename)
226
+
227
+ # We do not need to merge if one of these do not exist
228
+ return unless File.exist?(src_xcresult_bundlepath) || File.exist?(dst_xcresult_bundlepath)
229
+
230
+ config = FastlaneCore::Configuration.create(
231
+ Fastlane::Actions::CollateXcresultsAction.available_options,
232
+ {
233
+ xcresults: [src_xcresult_bundlepath, dst_xcresult_bundlepath],
234
+ collated_xcresult: dst_xcresult_bundlepath
235
+ }
236
+ )
237
+ FastlaneCore::UI.verbose("Merging xcresult '#{src_xcresult_bundlepath}' to '#{dst_xcresult_bundlepath}'")
238
+ Fastlane::Actions::CollateXcresultsAction.run(config)
239
+ FileUtils.rm_rf(src_xcresult_bundlepath)
240
+ if @result_bundle_desired
241
+ xcresult_bundlename = reportnamer.xcresult_bundlename
242
+ test_result_bundlename = File.basename(xcresult_bundlename, '.*') + '.test_result'
243
+ test_result_bundlename_path = File.join(testable_output_dir, test_result_bundlename)
244
+ FileUtils.rm_rf(test_result_bundlename_path)
245
+ end
246
+ end
247
+
214
248
  def symlink_result_bundle_to_xcresult(output_dir, reportname_helper)
215
249
  return unless @result_bundle_desired && reportname_helper.includes_xcresult?
216
250
 
@@ -16,11 +16,22 @@ module TestCenter
16
16
  cloned_simulators = []
17
17
 
18
18
  run_count = @options[:parallel_testrun_count] || 0
19
- destination_simulator_ids = Scan.config[:destination].map do |destination|
20
- destination.split(',id=').last
21
- end
22
19
  original_simulators = FastlaneCore::DeviceManager.simulators('iOS').find_all do |simulator|
23
- destination_simulator_ids.include?(simulator.udid)
20
+ found_match = false
21
+ Scan.config[:destination].each do |destination|
22
+ match = destination.match(/id=(?<udid>[^,]+)/)
23
+ if match
24
+ found_match = (match[:udid] == simulator.udid)
25
+ else
26
+ match = destination.match(/name=(?<name>[^,]+)/)
27
+ name = match[:name] || ''
28
+ match = destination.match(/OS=(?<os_version>[^,]+)/)
29
+ os_version = match[:os_version] || ''
30
+
31
+ found_match = (name == simulator.name && os_version == simulator.os_version)
32
+ end
33
+ end
34
+ found_match
24
35
  end
25
36
  original_simulators.each(&:shutdown)
26
37
  (0...run_count).each do |batch_index|
@@ -42,9 +42,7 @@ module TestCenter
42
42
  if @only_testing
43
43
  @testables ||= only_testing_to_testables_tests.keys
44
44
  else
45
- @testables ||= Plist.parse_xml(@xctestrun_path).keys.reject do |key|
46
- key == '__xctestrun_metadata__'
47
- end
45
+ @testables = xctestrun_known_tests.keys
48
46
  end
49
47
  end
50
48
  @testables
@@ -80,7 +78,7 @@ module TestCenter
80
78
  known_tests += xctestrun_known_tests[testable]
81
79
  test_components = test.split('/')
82
80
  testsuite = test_components.size == 1 ? test_components[0] : test_components[1]
83
- @testables_tests[testable][index] = known_tests.select { |known_test| known_test.include?(testsuite) }
81
+ @testables_tests[testable][index] = known_tests.select { |known_test| known_test.include?(testsuite) }
84
82
  end
85
83
  end
86
84
  @testables_tests[testable].flatten!
@@ -106,7 +104,7 @@ module TestCenter
106
104
  end
107
105
  end
108
106
  end
109
-
107
+
110
108
  @testables_tests
111
109
  end
112
110
 
@@ -0,0 +1,25 @@
1
+ module Xcodeproj
2
+ class XCScheme
3
+ class TestAction < AbstractSchemeAction
4
+ def test_plans
5
+ return [] unless @xml_element.elements['TestPlans']
6
+
7
+ @xml_element.elements['TestPlans'].get_elements('TestPlanReference').map do |node|
8
+ TestPlanReference.new(node)
9
+ end
10
+ end
11
+ end
12
+
13
+ class TestPlanReference < XMLElementWrapper
14
+ def initialize(node)
15
+ create_xml_element_with_fallback(node, 'TestPlanReference') do
16
+ end
17
+ end
18
+
19
+ def target_referenced_container
20
+ @xml_element.attributes['reference']
21
+ end
22
+ end
23
+ end
24
+ end
25
+
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module TestCenter
3
- VERSION = "3.9.0"
3
+ VERSION = "3.10.3"
4
4
  end
5
5
  end
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.9.0
4
+ version: 3.10.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lyndsey Ferguson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-20 00:00:00.000000000 Z
11
+ date: 2020-06-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -285,6 +285,7 @@ files:
285
285
  - lib/fastlane/plugin/test_center/helper/scan_helper.rb
286
286
  - lib/fastlane/plugin/test_center/helper/test_collector.rb
287
287
  - lib/fastlane/plugin/test_center/helper/xcodebuild_string.rb
288
+ - lib/fastlane/plugin/test_center/helper/xcodeproj/scheme/test_action.rb
288
289
  - lib/fastlane/plugin/test_center/helper/xctestrun_info.rb
289
290
  - lib/fastlane/plugin/test_center/version.rb
290
291
  homepage: https://github.com/lyndsey-ferguson/fastlane-plugin-test_center