Skip to content

Commit

Permalink
[scan] Filter simulators with version greater than SDK version of act…
Browse files Browse the repository at this point in the history
…ive Xcode installation when choosing default (#21677)

* [scan] Filter simulators with version greater than currently installed SDK

* addressing feedback

* redo implementation using suggested CLI invocations

* better description for test case

* addressing feedback

* move runtime_build_os_versions into own function

* fix odd indentation
  • Loading branch information
wuaar1003 committed Dec 14, 2023
1 parent eafe646 commit 3d51313
Show file tree
Hide file tree
Showing 14 changed files with 3,841 additions and 91 deletions.
28 changes: 15 additions & 13 deletions fastlane_core/lib/fastlane_core/device_manager.rb
Expand Up @@ -11,6 +11,19 @@ def all(requested_os_type = "")
return connected_devices(requested_os_type) + simulators(requested_os_type)
end

def runtime_build_os_versions
@runtime_build_os_versions ||= begin
output, status = Open3.capture2('xcrun simctl list runtimes -j')
raise status unless status.success?
json = JSON.parse(output)
json['runtimes'].map { |h| [h['buildversion'], h['version']] }.to_h
rescue StandardError => e
UI.error(e)
UI.error('xcrun simctl CLI broken; cun `xcrun simctl list runtimes` and make sure it works')
UI.user_error!('xcrun simctl not working')
end
end

def simulators(requested_os_type = "")
UI.verbose("Fetching available simulator devices")

Expand All @@ -22,18 +35,6 @@ def simulators(requested_os_type = "")
output = stdout.read
end

runtime_info = ''
Open3.popen3('xcrun simctl list runtimes') do |stdin, stdout, stderr, wait_thr|
# This regex outputs the version info in the format "<platform> <version><exact version>"
runtime_info = stdout.read.lines.map { |v| v.sub(/(\w+ \S+)\s*\((\S+)\s[\S\s]*/, "\\1 \\2") }.drop(1)
end
exact_versions = Hash.new({})
runtime_info.each do |r|
platform, general, exact = r.split
exact_versions[platform] = {} unless exact_versions.include?(platform)
exact_versions[platform][general] = exact
end

unless output.include?("== Devices ==")
UI.error("xcrun simctl CLI broken, run `xcrun simctl list devices` and make sure it works")
UI.user_error!("xcrun simctl not working.")
Expand All @@ -57,7 +58,7 @@ def simulators(requested_os_type = "")

if matches.count && (os_type == requested_os_type || requested_os_type == "")
# This is disabled here because the Device is defined later in the file, and that's a problem for the cop
@devices << Device.new(name: name, os_type: os_type, os_version: (exact_versions[os_type][os_version] || os_version), udid: udid, state: state, is_simulator: true)
@devices << Device.new(name: name, os_type: os_type, os_version: os_version, udid: udid, state: state, is_simulator: true)
end
end
end
Expand Down Expand Up @@ -289,6 +290,7 @@ def disable_slide_to_type(udid: nil, name: nil, os_version: nil)

def clear_cache
@devices = nil
@runtime_build_os_versions = nil
end

def launch(device)
Expand Down
71 changes: 19 additions & 52 deletions fastlane_core/spec/device_manager_spec.rb
Expand Up @@ -12,26 +12,29 @@
FastlaneCore::Simulator.clear_cache
end

it "raises an error if xcrun CLI prints garbage simulator" do
response = "response"
s = StringIO.new
s.puts(response)
expect(Open3).to receive(:popen3).with("xcrun simctl list devices").and_yield(nil, s, nil, nil)
allow(Open3).to receive(:popen3).with("xcrun simctl list runtimes").and_yield(nil, s, nil, nil)
it 'raises an error if broken xcrun simctl list devices' do
response = double('xcrun simctl list devices', read: 'garbage')
expect(Open3).to receive(:popen3).with("xcrun simctl list devices").and_yield(nil, response, nil, nil)

expect do
devices = FastlaneCore::Simulator.all
end.to raise_error("xcrun simctl not working.")
end

it 'raises an error if broken xcrun simctl list runtimes' do
status = double('status', "success?": true)
expect(Open3).to receive(:capture2).with("xcrun simctl list runtimes -j").and_return(['garbage', status])

expect do
FastlaneCore::DeviceManager.runtime_build_os_versions
end.to raise_error(FastlaneCore::Interface::FastlaneError)
end

describe "properly parses the simctl output and generates Device objects for iOS simulator" do
it "Xcode 7" do
response = "response"
expect(response).to receive(:read).and_return(@simctl_output)
expect(Open3).to receive(:popen3).with("xcrun simctl list devices").and_yield(nil, response, nil, nil)
thing = {}
expect(thing).to receive(:read).and_return("line\n")
allow(Open3).to receive(:popen3).with("xcrun simctl list runtimes").and_yield(nil, thing, nil, nil)

devices = FastlaneCore::Simulator.all
expect(devices.count).to eq(6)
Expand Down Expand Up @@ -79,9 +82,6 @@
simctl_output = File.read('./fastlane_core/spec/fixtures/DeviceManagerSimctlOutputXcode8')
expect(response).to receive(:read).and_return(simctl_output)
expect(Open3).to receive(:popen3).with("xcrun simctl list devices").and_yield(nil, response, nil, nil)
thing = {}
expect(thing).to receive(:read).and_return("line\n")
allow(Open3).to receive(:popen3).with("xcrun simctl list runtimes").and_yield(nil, thing, nil, nil)

devices = FastlaneCore::Simulator.all
expect(devices.count).to eq(12)
Expand Down Expand Up @@ -111,9 +111,6 @@
simctl_output = File.read('./fastlane_core/spec/fixtures/DeviceManagerSimctlOutputXcode9')
expect(response).to receive(:read).and_return(simctl_output)
expect(Open3).to receive(:popen3).with("xcrun simctl list devices").and_yield(nil, response, nil, nil)
thing = {}
expect(thing).to receive(:read).and_return("line\n")
allow(Open3).to receive(:popen3).with("xcrun simctl list runtimes").and_yield(nil, thing, nil, nil)

devices = FastlaneCore::Simulator.all
expect(devices.count).to eq(15)
Expand Down Expand Up @@ -143,9 +140,6 @@
simctl_output = File.read('./fastlane_core/spec/fixtures/DeviceManagerSimctlOutputXcode11')
expect(response).to receive(:read).and_return(simctl_output)
expect(Open3).to receive(:popen3).with("xcrun simctl list devices").and_yield(nil, response, nil, nil)
thing = {}
expect(thing).to receive(:read).and_return("line\n")
allow(Open3).to receive(:popen3).with("xcrun simctl list runtimes").and_yield(nil, thing, nil, nil)

devices = FastlaneCore::Simulator.all
expect(devices.count).to eq(29)
Expand Down Expand Up @@ -175,9 +169,6 @@
response = "response"
expect(response).to receive(:read).and_return(@simctl_output)
expect(Open3).to receive(:popen3).with("xcrun simctl list devices").and_yield(nil, response, nil, nil)
thing = {}
expect(thing).to receive(:read).and_return("line\n")
allow(Open3).to receive(:popen3).with("xcrun simctl list runtimes").and_yield(nil, thing, nil, nil)

devices = FastlaneCore::SimulatorTV.all
expect(devices.count).to eq(1)
Expand All @@ -194,9 +185,6 @@
response = "response"
expect(response).to receive(:read).and_return(@simctl_output)
expect(Open3).to receive(:popen3).with("xcrun simctl list devices").and_yield(nil, response, nil, nil)
thing = {}
expect(thing).to receive(:read).and_return("line\n")
allow(Open3).to receive(:popen3).with("xcrun simctl list runtimes").and_yield(nil, thing, nil, nil)

devices = FastlaneCore::SimulatorWatch.all
expect(devices.count).to eq(2)
Expand All @@ -219,9 +207,6 @@
response = "response"
expect(response).to receive(:read).and_return(@simctl_output)
expect(Open3).to receive(:popen3).with("xcrun simctl list devices").and_yield(nil, response, nil, nil)
thing = {}
expect(thing).to receive(:read).and_return("line\n")
allow(Open3).to receive(:popen3).with("xcrun simctl list runtimes").and_yield(nil, thing, nil, nil)

devices = FastlaneCore::DeviceManager.simulators
expect(devices.count).to eq(9)
Expand Down Expand Up @@ -275,9 +260,6 @@
simctl_output = File.read('./fastlane_core/spec/fixtures/DeviceManagerSimctlOutputXcode10BootedUnavailable')
expect(response).to receive(:read).and_return(simctl_output)
expect(Open3).to receive(:popen3).with("xcrun simctl list devices").and_yield(nil, response, nil, nil)
thing = {}
expect(thing).to receive(:read).and_return("line\n")
allow(Open3).to receive(:popen3).with("xcrun simctl list runtimes").and_yield(nil, thing, nil, nil)

devices = FastlaneCore::DeviceManager.simulators
expect(devices.count).to eq(3)
Expand Down Expand Up @@ -384,9 +366,6 @@

expect(response).to receive(:read).and_return(@simctl_output)
expect(Open3).to receive(:popen3).with("xcrun simctl list devices").and_yield(nil, response, nil, nil)
thing = {}
expect(thing).to receive(:read).and_return("line\n")
allow(Open3).to receive(:popen3).with("xcrun simctl list runtimes").and_yield(nil, thing, nil, nil)

devices = FastlaneCore::DeviceManager.all('iOS')
expect(devices.count).to eq(8)
Expand Down Expand Up @@ -439,9 +418,6 @@

expect(response).to receive(:read).and_return(@simctl_output)
expect(Open3).to receive(:popen3).with("xcrun simctl list devices").and_yield(nil, response, nil, nil)
thing = {}
expect(thing).to receive(:read).and_return("line\n")
allow(Open3).to receive(:popen3).with("xcrun simctl list runtimes").and_yield(nil, thing, nil, nil)

devices = FastlaneCore::DeviceManager.all('tvOS')
expect(devices.count).to eq(2)
Expand All @@ -460,23 +436,14 @@
)
end

it "parses runtime information properly to get the exact version information" do
response = "response"
expect(response).to receive(:read).and_return(@simctl_output)
expect(Open3).to receive(:popen3).with("xcrun simctl list devices").and_yield(nil, response, nil, nil)
thing = {}
expect(thing).to receive(:read).and_return("== Runtimes ==\ntvOS 9.0 (9.0.1 - 13A345) - com.apple.CoreSimulator.SimRuntime.tvOS-9-0\n")
allow(Open3).to receive(:popen3).with("xcrun simctl list runtimes").and_yield(nil, thing, nil, nil)
it 'properly parses `xcrun simctl list runtimes` to associate runtime builds with their exact OS version' do
status = double('status', "success?": true)
runtime_output = File.read('./fastlane_core/spec/fixtures/XcrunSimctlListRuntimesOutput')
expect(Open3).to receive(:capture2).with("xcrun simctl list runtimes -j").and_return([runtime_output, status])

devices = FastlaneCore::SimulatorTV.all
expect(devices.count).to eq(1)

expect(devices[0]).to have_attributes(
name: "Apple TV 1080p", os_type: "tvOS", os_version: "9.0.1",
udid: "D239A51B-A61C-4B60-B4D6-B7EC16595128",
state: "Shutdown",
is_simulator: true
)
expect(FastlaneCore::DeviceManager.runtime_build_os_versions['21A328']).to eq('17.0')
expect(FastlaneCore::DeviceManager.runtime_build_os_versions['21A342']).to eq('17.0.1')
expect(FastlaneCore::DeviceManager.runtime_build_os_versions['21R355']).to eq('10.0')
end

describe FastlaneCore::DeviceManager::Device do
Expand Down

0 comments on commit 3d51313

Please sign in to comment.