mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 11:07:10 +00:00
fix(ios): a failed simctl uninstall must fail the reinstall
simctl install over an installed app carries its data container across, so discarding the uninstall error reported a clear-state that never happened. Uninstalling an app that is not installed exits 0 on a booted simulator, so every failure here is a real one.
This commit is contained in:
1 parent
1ec6eb3847
commit
abc5e7db3e
2 files changed
+69
-1
No files matched your search
@@ -615,8 +615,14 @@ func (d *Driver) clearAppState(ctx context.Context) error {
|
||||
// simctlReinstall uninstalls and reinstalls the app bundle via simctl. App
|
||||
// lifecycle stays with simctl: the companion's install RPC misreads current
|
||||
// simulator targets' architectures and rejects valid bundles.
|
||||
// A failed uninstall ends the reinstall: `simctl install` over an installed app
|
||||
// carries its data container across, so clear-state would be reported without
|
||||
// happening. Uninstalling an app that is not installed exits 0, so there is no
|
||||
// benign failure here to sort out from a real one.
|
||||
func (d *Driver) simctlReinstall(ctx context.Context) error {
|
||||
_ = exec.CommandContext(ctx, "xcrun", "simctl", "uninstall", d.udid, d.bundleID).Run()
|
||||
if output, err := exec.CommandContext(ctx, "xcrun", "simctl", "uninstall", d.udid, d.bundleID).CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("simctl uninstall %s: %w: %s", d.bundleID, err, strings.TrimSpace(string(output)))
|
||||
}
|
||||
output, err := exec.CommandContext(ctx, "xcrun", "simctl", "install", d.udid, d.appPath).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("simctl install: %w: %s", err, strings.TrimSpace(string(output)))
|
||||
|
||||
@@ -329,6 +329,68 @@ func TestNewRejectsClearStateWithoutBundleID(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// scriptedXcrun puts an xcrun on PATH that logs each invocation's arguments and
|
||||
// answers from replies, a `case "$*" in` body, so a reinstall runs its real
|
||||
// command sequence and the log holds what reached the tool.
|
||||
func scriptedXcrun(t *testing.T, replies string) string {
|
||||
t.Helper()
|
||||
directory := t.TempDir()
|
||||
log := filepath.Join(directory, "xcrun.log")
|
||||
script := "#!/bin/sh\necho \"$*\" >> " + log + "\ncase \"$*\" in\n" + replies + "\nesac\n"
|
||||
if err := os.WriteFile(filepath.Join(directory, "xcrun"), []byte(script), 0o755); err != nil {
|
||||
t.Fatalf("write xcrun: %v", err)
|
||||
}
|
||||
t.Setenv("PATH", directory)
|
||||
return log
|
||||
}
|
||||
|
||||
func xcrunCalls(t *testing.T, log string) []string {
|
||||
t.Helper()
|
||||
contents, err := os.ReadFile(log)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
t.Fatalf("read %s: %v", log, err)
|
||||
}
|
||||
return strings.Split(strings.TrimSpace(string(contents)), "\n")
|
||||
}
|
||||
|
||||
func TestSimctlReinstallStopsWhenTheUninstallFails(t *testing.T) {
|
||||
log := scriptedXcrun(t, `"simctl uninstall "*) echo "Simulator device failed to uninstall app.example."; echo "Uninstall prohibited."; exit 22;;
|
||||
"simctl install "*) :;;`)
|
||||
d := &Driver{udid: "SIM-UDID", bundleID: "app.example", appPath: "/tmp/Sample.app"}
|
||||
|
||||
err := d.simctlReinstall(context.Background())
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("simctlReinstall reported success while app.example kept the data clear-state was asked to remove")
|
||||
}
|
||||
for _, want := range []string{"app.example", "Uninstall prohibited."} {
|
||||
if !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("error %q does not quote %q", err, want)
|
||||
}
|
||||
}
|
||||
if calls := xcrunCalls(t, log); slices.Contains(calls, "simctl install SIM-UDID /tmp/Sample.app") {
|
||||
t.Errorf("xcrun calls = %v: installing over the app carries its data into the run", calls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimctlReinstallProceedsWhenNothingIsInstalled(t *testing.T) {
|
||||
log := scriptedXcrun(t, `"simctl uninstall "*) :;;
|
||||
"simctl install "*) :;;`)
|
||||
d := &Driver{udid: "SIM-UDID", bundleID: "app.example", appPath: "/tmp/Sample.app"}
|
||||
|
||||
if err := d.simctlReinstall(context.Background()); err != nil {
|
||||
t.Fatalf("simctlReinstall: %v", err)
|
||||
}
|
||||
|
||||
want := []string{"simctl uninstall SIM-UDID app.example", "simctl install SIM-UDID /tmp/Sample.app"}
|
||||
if got := xcrunCalls(t, log); !slices.Equal(got, want) {
|
||||
t.Fatalf("xcrun calls = %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLaunchRejectsEnvironment(t *testing.T) {
|
||||
d := newTestDriver(&fakeCompanion{accessibilityJSON: "[]"})
|
||||
err := d.Launch(context.Background(), "", false, map[string]string{"K": "V"})
|
||||
|
||||
Reference in new issue
Block a user