fastlane-plugin-test_center 3.14.8 → 3.15.0

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: 290ab3e6fb5932555e74d834784e80cb441dc4b7e4feb49eda479382a603a1e5
4
- data.tar.gz: f46250359e1d156d283dd033e6e8db8c851297ea7a6385d78da4e72a014d0ebd
3
+ metadata.gz: '09ff419b88b430de488e1e2b4053a89b474f355f903c4cc3cfc4df69286da6f8'
4
+ data.tar.gz: 80114cde688e0efa5f1f5d6b6ee1f0167bd7cc8119598452fb53acd62945c60b
5
5
  SHA512:
6
- metadata.gz: aaf987944f48d6511755077c7e4e1c564f722ad8c7f69f8c4e0f24b7c5db62590edc9fc69372e98d19e0cc8b7466f8b3fd2ef2a1ddba472b37bc45c3ee0b12a5
7
- data.tar.gz: e1eb52e0b8b396019fe9727af6895948ad675c574b80293c866dfd627752d0e2dc3c8dd11b3e8f7508a40f1f64732a4b2987b1f92938aa6cf21b98d9c0d731d7
6
+ metadata.gz: b97fe2075ff7a24dead50f00d3a25028566ead76bb1f01ad95d3dd702ebdf33bff942fad7eff475a82c21a4b3caf892af197300ae8d3f4c8a768bb137f9eba35
7
+ data.tar.gz: 84fc593aee44b48ca43709ae6401e85546867b3b2502cf8000db752738a40fb24410645fb0243f85797e51f8190e46e9c1e9a69b72610342d4d618fb2f597ff2
@@ -13,12 +13,7 @@ module Fastlane
13
13
 
14
14
  class MultiScanAction < Action
15
15
  def self.run(params)
16
- params[:quit_simulators] = params._values[:force_quit_simulator] if params._values[:force_quit_simulator]
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
20
- end
21
-
16
+ update_interdependent_params(params)
22
17
  strip_leading_and_trailing_whitespace_from_output_types(params)
23
18
 
24
19
  warn_of_xcode11_result_bundle_incompatability(params)
@@ -53,6 +48,14 @@ module Fastlane
53
48
  summary
54
49
  end
55
50
 
51
+ def self.update_interdependent_params(params)
52
+ params[:quit_simulators] = params._values[:force_quit_simulator] if params._values[:force_quit_simulator]
53
+ if params[:try_count] < 1
54
+ UI.important('multi_scan will not test any if :try_count < 0, setting to 1')
55
+ params[:try_count] = 1
56
+ end
57
+ end
58
+
56
59
  def self.warn_of_parallelism_with_circle_ci(params)
57
60
  if params[:parallel_testrun_count] > 1 && Helper.is_circle_ci?
58
61
  UI.important("Warning: problems have occurreed when running parallel simulators on Circle CI.")
@@ -456,6 +459,22 @@ module Fastlane
456
459
  is_string: false,
457
460
  default_value: true
458
461
  ),
462
+ FastlaneCore::ConfigItem.new(
463
+ key: :override_scan_options_block,
464
+ description: 'A block invoked with a Hash of the scan options that will be used when test run is about to start. This allows your code to modify the arguments that will be sent to scan',
465
+ optional: true,
466
+ is_string: false,
467
+ default_value: nil,
468
+ type: Proc
469
+ ),
470
+ FastlaneCore::ConfigItem.new(
471
+ key: :reuse_simulators_for_parallel_testruns,
472
+ description: 'Find simulators (or clone new ones) that match the requested device for the parallel test runs. This option sets :pre_delete_cloned_simulators to false',
473
+ optional: true,
474
+ is_string: false,
475
+ type: Boolean,
476
+ default_value: false
477
+ ),
459
478
  FastlaneCore::ConfigItem.new(
460
479
  key: :testrun_completed_block,
461
480
  description: 'A block invoked each time a test run completes. When combined with :parallel_testrun_count, will be called separately in each child process. Return a Hash with :continue set to false to stop retrying tests, or :only_testing to change which tests will be run in the next try',
@@ -463,6 +482,14 @@ module Fastlane
463
482
  is_string: false,
464
483
  default_value: nil,
465
484
  type: Proc
485
+ ),
486
+ FastlaneCore::ConfigItem.new(
487
+ key: :simulator_started_callback,
488
+ description: 'A block invoked after the iOS simulators have started',
489
+ optional: true,
490
+ is_string: false,
491
+ default_value: nil,
492
+ type: Proc
466
493
  )
467
494
  ]
468
495
  end
@@ -492,6 +519,10 @@ module Fastlane
492
519
  }
493
520
  end
494
521
 
522
+ sim_callback = lambda do |simulator_device_udid|
523
+ puts \"Start streaming system log for device \#{simulator_device_udid}\"
524
+ end
525
+
495
526
  multi_scan(
496
527
  project: File.absolute_path('../AtomicBoy/AtomicBoy.xcodeproj'),
497
528
  scheme: 'AtomicBoy',
@@ -499,7 +530,8 @@ module Fastlane
499
530
  batch_count: 4,
500
531
  fail_build: false,
501
532
  parallel_testrun_count: 4,
502
- testrun_completed_block: test_run_block
533
+ testrun_completed_block: test_run_block,
534
+ simulator_started_callback: sim_callback
503
535
  )
504
536
  ",
505
537
  "
@@ -139,25 +139,32 @@ module Fastlane
139
139
  "
140
140
  require 'fastlane/actions/scan'
141
141
 
142
- UI.important(
143
- 'example: ' \\
144
- 'get list of tests that are referenced from an xctestrun file'
145
- )
146
- # build the tests so that we have a xctestrun file to parse
147
- scan(
148
- build_for_testing: true,
149
- workspace: File.absolute_path('../AtomicBoy/AtomicBoy.xcworkspace'),
150
- scheme: 'AtomicBoy'
151
- )
152
-
153
- # find the xctestrun file
154
- derived_data_path = Scan.config[:derived_data_path]
155
- xctestrun_file = Dir.glob(\"\#{derived_data_path}/Build/Products/*.xctestrun\").first
142
+ lane :split_tests do
143
+ scan(
144
+ build_for_testing: true,
145
+ workspace: File.absolute_path('../AtomicBoy/AtomicBoy.xcworkspace'),
146
+ scheme: 'AtomicBoy'
147
+ )
148
+ derived_data_path = Scan.config[:derived_data_path]
149
+ xctestrun_file = Dir.glob(\"\#{derived_data_path}/Build/Products/*.xctestrun\").first
150
+ tests = tests_from_xctestrun(xctestrun: xctestrun_file).values.flatten.shuffle
151
+ slice_size = (tests.size/4.0).ceil
152
+ tests.each_slice(slice_size).each_with_index do |inner_array, index|
153
+ File.write(\"test_output/batch\#{index}.txt\", inner_array.join(','))
154
+ end
155
+ end
156
156
 
157
- # get the tests from the xctestrun file
158
- tests = tests_from_xctestrun(xctestrun: xctestrun_file)
159
- UI.header('xctestrun file contains the following tests')
160
- tests.values.flatten.each { |test_identifier| puts test_identifier }
157
+ lane :run_split_tests do |options|
158
+ batch_file = File.join('test_output', \"batch\#{options[:batch_index]}.txt\")
159
+ only_testing = File.read(batch_file).split(',')
160
+ multi_scan(
161
+ workspace: File.absolute_path('../AtomicBoy/AtomicBoy.xcworkspace'),
162
+ scheme: 'AtomicBoy',
163
+ try_count: 3,
164
+ fail_build: false,
165
+ only_testing: only_testing
166
+ )
167
+ end
161
168
  "
162
169
  ]
163
170
  end
@@ -8,6 +8,12 @@ module TestCenter
8
8
  FastlaneCore::UI.verbose(message)
9
9
  end
10
10
 
11
+ def self.error(message)
12
+ return if ENV.fetch('COLLATE_HTML_REPORTS_VERBOSITY', 1).to_i.zero?
13
+
14
+ FastlaneCore::UI.error(message)
15
+ end
16
+
11
17
  class Report
12
18
  require 'rexml/formatters/transitive'
13
19
 
@@ -18,6 +18,17 @@ module FastlaneCore
18
18
  self.name = newname
19
19
  end
20
20
 
21
+ def disable_hardware_keyboard
22
+ UI.verbose("Disabling hardware keyboard for #{self.udid}")
23
+ plist_filepath = File.expand_path("~/Library/Preferences/com.apple.iphonesimulator.plist")
24
+ keyboard_pref_key = ":DevicePreferences:#{self.udid}:ConnectHardwareKeyboard"
25
+
26
+ command = "/usr/libexec/PlistBuddy -c \"Set #{keyboard_pref_key} false\" #{plist_filepath} 2>/dev/null || "
27
+ command << "/usr/libexec/PlistBuddy -c \"Add #{keyboard_pref_key} bool false\" #{plist_filepath}"
28
+
29
+ `#{command}`
30
+ end
31
+
21
32
  def boot
22
33
  return unless is_simulator
23
34
  return unless os_type == "iOS"
@@ -7,57 +7,6 @@ module TestCenter
7
7
  @retrying_scan_helper = RetryingScanHelper.new(@options)
8
8
  end
9
9
 
10
- # :nocov:
11
- def scan_config
12
- Scan.config
13
- end
14
-
15
- def scan_cache
16
- Scan.cache
17
- end
18
- # :nocov:
19
-
20
- def prepare_scan_config
21
- # this allows multi_scan's `destination` option to be picked up by `scan`
22
- scan_config._values.delete(:device)
23
- ENV.delete('SCAN_DEVICE')
24
- scan_config._values.delete(:devices)
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)
32
- scan_cache.clear
33
- end
34
-
35
- def update_scan_options
36
- valid_scan_keys = Fastlane::Actions::ScanAction.available_options.map(&:key)
37
- scan_options = @options.select { |k,v| valid_scan_keys.include?(k) }
38
- .merge(@retrying_scan_helper.scan_options)
39
-
40
- prepare_scan_config
41
- scan_options[:build_for_testing] = false
42
- scan_options.delete(:skip_testing)
43
- FastlaneCore::UI.verbose("retrying_scan #update_scan_options")
44
- scan_options.each do |k,v|
45
- next if v.nil?
46
-
47
- scan_config.set(k,v) unless v.nil?
48
- FastlaneCore::UI.verbose("\tSetting #{k.to_s} to #{v}")
49
- end
50
- if @options[:scan_devices_override]
51
- scan_device_names = @options[:scan_devices_override].map { |device| device.name }
52
- FastlaneCore::UI.verbose("\tSetting Scan.devices to #{scan_device_names}")
53
- if Scan.devices
54
- Scan.devices.replace(@options[:scan_devices_override])
55
- else
56
- Scan.devices = @options[:scan_devices_override]
57
- end
58
- end
59
- end
60
-
61
10
  # :nocov:
62
11
  def self.run(options)
63
12
  RetryingScan.new(options).run
@@ -68,12 +17,6 @@ module TestCenter
68
17
  try_count = @options[:try_count] || 1
69
18
  begin
70
19
  @retrying_scan_helper.before_testrun
71
- update_scan_options
72
-
73
- values = scan_config.values(ask: false)
74
- values[:xcode_path] = File.expand_path("../..", FastlaneCore::Helper.xcode_path)
75
- ScanHelper.print_scan_parameters(values)
76
-
77
20
  Scan::Runner.new.run
78
21
  @retrying_scan_helper.after_testrun
79
22
  true
@@ -23,9 +23,78 @@ module TestCenter
23
23
  delete_xcresults # has to be performed _after_ moving a *.test_result
24
24
  quit_simulator
25
25
  set_json_env
26
+ set_scan_config
26
27
  print_starting_scan_message
27
28
  end
28
29
 
30
+ def set_scan_config
31
+ valid_scan_keys = Fastlane::Actions::ScanAction.available_options.map(&:key)
32
+ new_scan_options = @options.select { |k,v| valid_scan_keys.include?(k) }
33
+ .merge(scan_options)
34
+
35
+ prepare_scan_config
36
+ new_scan_options[:build_for_testing] = false
37
+ new_scan_options.delete(:skip_testing)
38
+
39
+ new_scan_options = send_callback_override_scan_options_block(new_scan_options)
40
+
41
+ FastlaneCore::UI.verbose("retrying_scan #update_scan_options")
42
+ new_scan_options.each do |k,v|
43
+ next if v.nil?
44
+
45
+ scan_config.set(k,v) unless v.nil?
46
+ FastlaneCore::UI.verbose("\tSetting #{k.to_s} to #{v}")
47
+ end
48
+ if @options[:scan_devices_override]
49
+ scan_device_names = @options[:scan_devices_override].map { |device| device.name }
50
+ FastlaneCore::UI.verbose("\tSetting Scan.devices to #{scan_device_names}")
51
+ if Scan.devices
52
+ Scan.devices.replace(@options[:scan_devices_override])
53
+ else
54
+ Scan.devices = @options[:scan_devices_override]
55
+ end
56
+ end
57
+
58
+ values = scan_config.values(ask: false)
59
+ values[:xcode_path] = File.expand_path("../..", FastlaneCore::Helper.xcode_path)
60
+ ScanHelper.print_scan_parameters(values)
61
+ end
62
+
63
+ # :nocov:
64
+ def scan_config
65
+ Scan.config
66
+ end
67
+
68
+ def scan_cache
69
+ Scan.cache
70
+ end
71
+ # :nocov:
72
+
73
+ def prepare_scan_config
74
+ # this allows multi_scan's `destination` option to be picked up by `scan`
75
+ scan_config._values.delete(:device)
76
+ ENV.delete('SCAN_DEVICE')
77
+ scan_config._values.delete(:devices)
78
+ ENV.delete('SCAN_DEVICES')
79
+ # this prevents double -resultBundlePath args to xcodebuild
80
+ if ReportNameHelper.includes_xcresult?(@options[:output_types])
81
+ scan_config._values.delete(:result_bundle)
82
+ ENV.delete('SCAN_RESULT_BUNDLE')
83
+ end
84
+ scan_config._values.delete(:skip_testing)
85
+ scan_cache.clear
86
+ end
87
+
88
+ def send_callback_override_scan_options_block(new_scan_options)
89
+ return new_scan_options unless @options[:override_scan_options_block]
90
+
91
+ callback_result = @options[:override_scan_options_block].call(new_scan_options)
92
+ if callback_result.kind_of?(Hash)
93
+ return callback_result
94
+ end
95
+ new_scan_options
96
+ end
97
+
29
98
  def quit_simulator
30
99
  return unless @options[:quit_simulators]
31
100
 
@@ -21,6 +21,8 @@ module TestCenter
21
21
  update_options_to_use_xcresult_output
22
22
  end
23
23
  @batch_count = 1 # default count. Will be updated by setup_testcollector
24
+ @options[:parallel_testrun_count] ||= 1
25
+ @initial_parallel_testrun_count = @options[:parallel_testrun_count]
24
26
  setup_testcollector
25
27
  setup_logcollection
26
28
  FastlaneCore::UI.verbose("< done in TestCenter::Helper::MultiScanManager.initialize")
@@ -67,6 +69,7 @@ module TestCenter
67
69
  @test_collector = TestCollector.new(@options)
68
70
  @options.reject! { |key| %i[testplan].include?(key) }
69
71
  @batch_count = @test_collector.batches.size
72
+ @options[:parallel_testrun_count] = @initial_parallel_testrun_count
70
73
  tests = @test_collector.batches.flatten
71
74
  if tests.size < @options[:parallel_testrun_count].to_i
72
75
  FastlaneCore::UI.important(":parallel_testrun_count greater than the number of tests (#{tests.size}). Reducing to that number.")
@@ -184,6 +187,8 @@ module TestCenter
184
187
  options = @options.reject { |key| %i[device devices force_quit_simulator].include?(key) }
185
188
  options[:try_count] = 1
186
189
 
190
+ SimulatorHelper.call_simulator_started_callback(@options, Scan.devices)
191
+
187
192
  tests_passed = RetryingScan.run(options)
188
193
  @options[:try_count] -= 1
189
194
 
@@ -229,6 +234,11 @@ module TestCenter
229
234
  pool_options[:test_batch_results] = test_batch_results
230
235
  pool_options[:xctestrun] = @test_collector.xctestrun_path
231
236
 
237
+ serial_test_batches = (@options.fetch(:parallel_testrun_count, 1) == 1)
238
+ if serial_test_batches && !@options[:invocation_based_tests]
239
+ SimulatorHelper.call_simulator_started_callback(@options, Scan.devices)
240
+ end
241
+
232
242
  pool = TestBatchWorkerPool.new(pool_options)
233
243
  pool.setup_workers
234
244
 
@@ -4,6 +4,8 @@ module TestCenter
4
4
  class SimulatorHelper
5
5
  def initialize(options)
6
6
  @options = options
7
+ # TODO: add byebug to make sure we're mocking this
8
+ @all_simulators = FastlaneCore::DeviceManager.simulators('iOS')
7
9
  end
8
10
 
9
11
  def setup
@@ -12,6 +14,38 @@ module TestCenter
12
14
  end
13
15
  end
14
16
 
17
+ def parallel_destination_simulators
18
+ remaining_desired_simulators = @options[:parallel_testrun_count] || 0
19
+
20
+ simulators = []
21
+ if @options[:reuse_simulators_for_parallel_testruns]
22
+ matching_simulators = find_matching_destination_simulators(remaining_desired_simulators)
23
+ remaining_desired_simulators -= matching_simulators.size
24
+ (0...matching_simulators.size).each do |s|
25
+ simulators << [matching_simulators[s]]
26
+ end
27
+ end
28
+
29
+ if remaining_desired_simulators > 0
30
+ simulators.concat(clone_destination_simulators(remaining_desired_simulators))
31
+ end
32
+ simulators
33
+ end
34
+
35
+ def find_matching_destination_simulators(remaining_desired_simulators)
36
+ destination = Scan.config[:destination].clone.first
37
+
38
+ desired_device = @all_simulators.find do |simulator|
39
+ match = destination.match(/id=(?<udid>[^,]+)/)
40
+ match && match[:udid] == simulator.udid
41
+ end
42
+
43
+ matching_simulators = @all_simulators.find_all do |simulator|
44
+ desired_device.os_version == simulator.os_version && simulator.name =~ /#{Regexp.escape(desired_device.name)} Clone \d #{self.class.name}<[^>]+>/
45
+ end
46
+ matching_simulators.first(remaining_desired_simulators)
47
+ end
48
+
15
49
  def simulator_matches_destination(simulator, destination)
16
50
  match = destination.match(/id=(?<udid>[^,]+)/)
17
51
  if match
@@ -27,12 +61,12 @@ module TestCenter
27
61
  found_match
28
62
  end
29
63
 
30
- def clone_destination_simulators
64
+ def clone_destination_simulators(remaining_desired_simulators)
31
65
  cloned_simulators = []
32
66
 
33
- run_count = @options[:parallel_testrun_count] || 0
67
+ run_count = remaining_desired_simulators
34
68
  destinations = Scan.config[:destination].clone
35
- original_simulators = FastlaneCore::DeviceManager.simulators('iOS').find_all do |simulator|
69
+ original_simulators = @all_simulators.find_all do |simulator|
36
70
  found_simulator = destinations.find do |destination|
37
71
  simulator_matches_destination(simulator, destination)
38
72
  end
@@ -63,6 +97,15 @@ module TestCenter
63
97
  simulator.delete if /#{self.class.name}<\d+>/ =~ simulator.name
64
98
  end
65
99
  end
100
+
101
+ def self.call_simulator_started_callback(options, devices)
102
+ return unless options[:simulator_started_callback]
103
+ return unless options[:platform] == :ios_simulator
104
+
105
+ devices.each do |device|
106
+ options[:simulator_started_callback].call(device.udid)
107
+ end
108
+ end
66
109
  end
67
110
  end
68
111
  end
@@ -23,17 +23,23 @@ module TestCenter
23
23
 
24
24
  @simhelper = SimulatorHelper.new(
25
25
  parallel_testrun_count: @options[:parallel_testrun_count],
26
- pre_delete_cloned_simulators: @options.fetch(:pre_delete_cloned_simulators, true)
26
+ pre_delete_cloned_simulators: @options.fetch(:pre_delete_cloned_simulators, true),
27
+ reuse_simulators_for_parallel_testruns: @options[:reuse_simulators_for_parallel_testruns] || false
27
28
  )
28
29
  @simhelper.setup
29
- @clones = @simhelper.clone_destination_simulators
30
+ @clones = @simhelper.parallel_destination_simulators
30
31
  main_pid = Process.pid
31
- at_exit do
32
- clean_up_cloned_simulators(@clones) if Process.pid == main_pid
32
+ unless @options[:reuse_simulators_for_parallel_testruns]
33
+ at_exit do
34
+ clean_up_cloned_simulators(@clones) if Process.pid == main_pid
35
+ end
33
36
  end
34
37
  # boot all the simulators _before_ calling `xcodebuilt test` to avoid
35
38
  # testmanagerd connection failures.
39
+ @clones.flatten.each(&:shutdown)
40
+ @clones.flatten.each(&:disable_hardware_keyboard)
36
41
  @clones.flatten.each(&:boot)
42
+ SimulatorHelper.call_simulator_started_callback(@options, @clones.flatten)
37
43
  @clones
38
44
  end
39
45
 
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module TestCenter
3
- VERSION = "3.14.8"
3
+ VERSION = "3.15.0"
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.14.8
4
+ version: 3.15.0
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-11-13 00:00:00.000000000 Z
11
+ date: 2020-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json