mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-04 12:07:09 +00:00
fix(ios): the device path clears before its runner session too
This commit is contained in:
1 parent
aed65976e3
commit
67da9313dd
2 files changed
+55
-6
No files matched your search
@@ -31,17 +31,22 @@ type DeviceOptions struct {
|
|||||||
BundleID string
|
BundleID string
|
||||||
// AppPath is the .app bundle installed via devicectl for clear-state.
|
// AppPath is the .app bundle installed via devicectl for clear-state.
|
||||||
AppPath string
|
AppPath string
|
||||||
|
// ClearState reinstalls the app while NewDevice runs, before the runner's
|
||||||
|
// test session exists. Clear state is a property of the driver rather than
|
||||||
|
// of a launch: see Launch.
|
||||||
|
ClearState bool
|
||||||
// Output receives the runner session log path and driver warnings.
|
// Output receives the runner session log path and driver warnings.
|
||||||
Output io.Writer
|
Output io.Writer
|
||||||
// DoubleTapGapMilliseconds overrides the synthesized double-tap gap.
|
// DoubleTapGapMilliseconds overrides the synthesized double-tap gap.
|
||||||
DoubleTapGapMilliseconds float64
|
DoubleTapGapMilliseconds float64
|
||||||
|
|
||||||
// Test seams. Production leaves them nil and NewDevice wires the real
|
// Test seams. Production leaves them nil and NewDevice wires the real
|
||||||
// build/spawn/tunnel/dial.
|
// build/spawn/tunnel/dial/devicectl.
|
||||||
spawnRunner func(ctx context.Context, address string) (*exec.Cmd, error)
|
spawnRunner func(ctx context.Context, address string) (*exec.Cmd, error)
|
||||||
startTunnel func(ctx context.Context, hardwareUDID, localAddress, devicePort string) (io.Closer, error)
|
startTunnel func(ctx context.Context, hardwareUDID, localAddress, devicePort string) (io.Closer, error)
|
||||||
dialRunner func(address string) (transport.Companion, error)
|
dialRunner func(address string) (transport.Companion, error)
|
||||||
pickAddress func() (string, error)
|
pickAddress func() (string, error)
|
||||||
|
reinstallApp func(ctx context.Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// deviceStartupTimeout bounds the runner's startup once its hosting test
|
// deviceStartupTimeout bounds the runner's startup once its hosting test
|
||||||
@@ -61,6 +66,9 @@ func NewDevice(ctx context.Context, options DeviceOptions) (*Driver, error) {
|
|||||||
if options.CoreDeviceID == "" {
|
if options.CoreDeviceID == "" {
|
||||||
return nil, errors.New("ios device: CoreDeviceID is required")
|
return nil, errors.New("ios device: CoreDeviceID is required")
|
||||||
}
|
}
|
||||||
|
if options.ClearState && options.BundleID == "" {
|
||||||
|
return nil, errors.New("ios device: clear-state needs BundleID: there is nothing to uninstall without it")
|
||||||
|
}
|
||||||
output := options.Output
|
output := options.Output
|
||||||
if output == nil {
|
if output == nil {
|
||||||
output = io.Discard
|
output = io.Discard
|
||||||
@@ -75,6 +83,7 @@ func NewDevice(ctx context.Context, options DeviceOptions) (*Driver, error) {
|
|||||||
coreDeviceID: options.CoreDeviceID,
|
coreDeviceID: options.CoreDeviceID,
|
||||||
bundleID: options.BundleID,
|
bundleID: options.BundleID,
|
||||||
appPath: options.AppPath,
|
appPath: options.AppPath,
|
||||||
|
clearStateAtStartup: options.ClearState,
|
||||||
output: output,
|
output: output,
|
||||||
doubleTapGapMilliseconds: gap,
|
doubleTapGapMilliseconds: gap,
|
||||||
deviceMode: true,
|
deviceMode: true,
|
||||||
@@ -103,7 +112,10 @@ func NewDevice(ctx context.Context, options DeviceOptions) (*Driver, error) {
|
|||||||
// Device seams: clear-state reinstalls via devicectl; the container reset and
|
// Device seams: clear-state reinstalls via devicectl; the container reset and
|
||||||
// paste grant are simulator-only and become no-ops. The runner types
|
// paste grant are simulator-only and become no-ops. The runner types
|
||||||
// natively, so no paste prompt is ever hit.
|
// natively, so no paste prompt is ever hit.
|
||||||
d.reinstallApp = d.devicectlReinstall
|
d.reinstallApp = options.reinstallApp
|
||||||
|
if d.reinstallApp == nil {
|
||||||
|
d.reinstallApp = d.devicectlReinstall
|
||||||
|
}
|
||||||
d.resetContainer = d.deviceResetContainerUnsupported
|
d.resetContainer = d.deviceResetContainerUnsupported
|
||||||
d.grantPaste = func(context.Context) error { return nil }
|
d.grantPaste = func(context.Context) error { return nil }
|
||||||
d.restart = d.respawnDevice
|
d.restart = d.respawnDevice
|
||||||
@@ -116,6 +128,13 @@ func NewDevice(ctx context.Context, options DeviceOptions) (*Driver, error) {
|
|||||||
}
|
}
|
||||||
d.deviceLock = lock
|
d.deviceLock = lock
|
||||||
|
|
||||||
|
if options.ClearState {
|
||||||
|
if err := d.clearAppState(ctx); err != nil {
|
||||||
|
d.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := d.bringUpDevice(ctx); err != nil {
|
if err := d.bringUpDevice(ctx); err != nil {
|
||||||
d.Close()
|
d.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/priyanshujain/sanderling/internal/driver/ioscompanion/transport"
|
"github.com/priyanshujain/sanderling/internal/driver/ioscompanion/transport"
|
||||||
@@ -152,6 +153,35 @@ func TestDeviceEraseAndPressKeyRouteThroughEditor(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewDeviceReinstallsOnceBeforeTheRunnerSession(t *testing.T) {
|
||||||
|
address := startLoopbackListener(t)
|
||||||
|
probe := &clearStateProbe{}
|
||||||
|
options := testDeviceOptions(address, newDeviceCompanion())
|
||||||
|
options.HardwareUDID = "00008140-CLEAR"
|
||||||
|
options.AppPath = "/tmp/Sample.app"
|
||||||
|
options.ClearState = true
|
||||||
|
options.reinstallApp = func(context.Context) error { probe.record("reinstall"); return nil }
|
||||||
|
spawn := options.spawnRunner
|
||||||
|
options.spawnRunner = func(ctx context.Context, runnerAddress string) (*exec.Cmd, error) {
|
||||||
|
probe.record("runner session")
|
||||||
|
return spawn(ctx, runnerAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
d, err := NewDevice(context.Background(), options)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewDevice: %v", err)
|
||||||
|
}
|
||||||
|
defer d.Close()
|
||||||
|
if err := d.Launch(context.Background(), "", true, nil); err != nil {
|
||||||
|
t.Fatalf("Launch: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := []string{"reinstall", "runner session"}
|
||||||
|
if got := probe.recorded(); !slices.Equal(got, want) {
|
||||||
|
t.Fatalf("calls = %v, want %v: devicectl must reinstall once, before the runner's test session attaches", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDeviceClearStateWithoutAppPathWarnsOnce(t *testing.T) {
|
func TestDeviceClearStateWithoutAppPathWarnsOnce(t *testing.T) {
|
||||||
output := &bytes.Buffer{}
|
output := &bytes.Buffer{}
|
||||||
d := &Driver{output: output, deviceMode: true}
|
d := &Driver{output: output, deviceMode: true}
|
||||||
|
|||||||
Reference in new issue
Block a user