class Snapshot::SimulatorLauncher
Public Instance Methods
cleanup_after_failure(devices, language, locale, launch_args, return_code)
click to toggle source
# File snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb, line 141 def cleanup_after_failure(devices, language, locale, launch_args, return_code) copy_screenshots(language: language, locale: locale, launch_args: launch_args) UI.important("Tests failed while running on: #{devices.join(', ')}") UI.important("For more detail about the test failures, check the logs here:") UI.important(xcodebuild_log_path(language: language, locale: locale)) UI.important(" ") UI.important("You can also find the test result data here:") UI.important(test_results_path) UI.important(" ") UI.important("You can find the incomplete screenshots here:") UI.important(SCREENSHOTS_DIR) UI.important(launcher_config.output_directory) end
copy_screenshots(language: nil, locale: nil, launch_args: nil)
click to toggle source
# File snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb, line 171 def copy_screenshots(language: nil, locale: nil, launch_args: nil) raw_output = File.read(xcodebuild_log_path(language: language, locale: locale)) dir_name = locale || language return Collector.fetch_screenshots(raw_output, dir_name, '', launch_args.first) end
default_number_of_simultaneous_simulators()
click to toggle source
With Xcode 9's ability to run tests on multiple concurrent simulators, this method sets the maximum number of simulators to run simultaneously to avoid overloading your machine.
# File snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb, line 34 def default_number_of_simultaneous_simulators cpu_count = CPUInspector.cpu_count if cpu_count <= 2 return cpu_count end return cpu_count - 1 end
execute(retries = 0, command: nil, language: nil, locale: nil, launch_args: nil, devices: nil)
click to toggle source
# File snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb, line 103 def execute(retries = 0, command: nil, language: nil, locale: nil, launch_args: nil, devices: nil) prefix_hash = [ { prefix: "Running Tests: ", block: proc do |value| value.include?("Touching") end } ] FastlaneCore::CommandExecutor.execute(command: command, print_all: true, print_command: true, prefix: prefix_hash, loading: "Loading...", error: proc do |output, return_code| self.collected_errors.concat(failed_devices.map do |device, messages| "#{device}: #{messages.join(', ')}" end) cleanup_after_failure(devices, language, locale, launch_args, return_code) # no exception raised... that means we need to retry UI.error("Caught error... #{return_code}") self.current_number_of_retries_due_to_failing_simulator += 1 if self.current_number_of_retries_due_to_failing_simulator < 20 && return_code != 65 # If the return code is not 65, we should assume its a simulator failure and retry launch_simultaneously(devices, language, locale, launch_args) elsif retries < launcher_config.number_of_retries # If there are retries remaining, run the tests again retry_tests(retries, command, language, locale, launch_args, devices) else # It's important to raise an error, as we don't want to collect the screenshots UI.crash!("Too many errors... no more retries...") if launcher_config.stop_after_first_error end end) end
failed_devices()
click to toggle source
This method returns a hash of { device name => [failure messages] } {
'iPhone 7': [], # this empty array indicates success 'iPhone 7 Plus': ["No tests were executed"], 'iPad Air': ["Launch session expired", "Array out of bounds"]
}
# File snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb, line 188 def failed_devices test_summaries = Dir["#{test_results_path}/*_TestSummaries.plist"] test_summaries.each_with_object({}) do |plist, hash| summary = FastlaneCore::TestParser.new(plist) name = summary.data.first[:run_destination_name] if summary.data.first[:number_of_tests] == 0 hash[name] = ["No tests were executed"] else tests = Array(summary.data.first[:tests]) hash[name] = tests.flat_map { |test| Array(test[:failures]).map { |failure| failure[:failure_message] } } end end end
launch_simultaneously(devices, language, locale, launch_arguments)
click to toggle source
# File snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb, line 79 def launch_simultaneously(devices, language, locale, launch_arguments) prepare_for_launch(devices, language, locale, launch_arguments) add_media(devices, :photo, launcher_config.add_photos) if launcher_config.add_photos add_media(devices, :video, launcher_config.add_videos) if launcher_config.add_videos command = TestCommandGenerator.generate( devices: devices, language: language, locale: locale, log_path: xcodebuild_log_path(language: language, locale: locale) ) devices.each { |device_type| override_status_bar(device_type, launcher_config.override_status_bar_arguments) } if launcher_config.override_status_bar UI.important("Running snapshot on: #{devices.join(', ')}") execute(command: command, language: language, locale: locale, launch_args: launch_arguments, devices: devices) devices.each { |device_type| clear_status_bar(device_type) } if launcher_config.override_status_bar return copy_screenshots(language: language, locale: locale, launch_args: launch_arguments) end
retry_tests(retries, command, language, locale, launch_args, devices)
click to toggle source
# File snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb, line 156 def retry_tests(retries, command, language, locale, launch_args, devices) UI.important("Retrying on devices: #{devices.join(', ')}") UI.important("Number of retries remaining: #{launcher_config.number_of_retries - retries - 1}") # Make sure all needed directories exist for next retry # `copy_screenshots` in `cleanup_after_failure` can delete some needed directories # https://github.com/fastlane/fastlane/issues/10786 prepare_directories_for_launch(language: language, locale: locale, launch_arguments: launch_args) # Clear errors so a successful retry isn't reported as an over failure self.collected_errors = [] execute(retries + 1, command: command, language: language, locale: locale, launch_args: launch_args, devices: devices) end
take_screenshots_simultaneously()
click to toggle source
# File snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb, line 43 def take_screenshots_simultaneously languages_finished = {} launcher_config.launch_args_set.each do |launch_args| launcher_config.languages.each_with_index do |language, language_index| locale = nil if language.kind_of?(Array) locale = language[1] language = language[0] end # Clear logs so subsequent xcodebuild executions don't append to old ones log_path = xcodebuild_log_path(language: language, locale: locale) File.delete(log_path) if File.exist?(log_path) # Break up the array of devices into chunks that can # be run simultaneously. if launcher_config.concurrent_simulators? all_devices = launcher_config.devices # We have to break up the concurrent simulators by device version too, otherwise there is an error (see #10969) by_simulator_version = all_devices.group_by { |d| FastlaneCore::DeviceManager.latest_simulator_version_for_device(d) }.values device_batches = by_simulator_version.flat_map { |a| a.each_slice(default_number_of_simultaneous_simulators).to_a } else # Put each device in it's own array to run tests one at a time device_batches = launcher_config.devices.map { |d| [d] } end device_batches.each do |devices| languages_finished[language] = launch_simultaneously(devices, language, locale, launch_args) end end end launcher_config.devices.each_with_object({}) do |device, results_hash| results_hash[device] = languages_finished end end
test_results_path()
click to toggle source
# File snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb, line 177 def test_results_path derived_data_path = TestCommandGenerator.derived_data_path return File.join(derived_data_path, 'Logs/Test') end
xcodebuild_log_path(language: nil, locale: nil)
click to toggle source
# File snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb, line 202 def xcodebuild_log_path(language: nil, locale: nil) name_components = [Snapshot.project.app_name, Snapshot.config[:scheme]] if Snapshot.config[:namespace_log_files] name_components << launcher_config.devices.join('-') if launcher_config.devices.count >= 1 name_components << language if language name_components << locale if locale end file_name = "#{name_components.join('-')}.log" containing = File.expand_path(Snapshot.config[:buildlog_path]) FileUtils.mkdir_p(containing) return File.join(containing, file_name) end