Skip to main content

HttpRunnerClient

Struct HttpRunnerClient 

Source
pub struct HttpRunnerClient { /* private fields */ }
Expand description

HTTP client to the swift-side SmixRunnerCore. Async (tokio-based). Constructed once per Cell; ensure_reachable memoizes a successful /health probe so subsequent calls don’t re-probe.

Implementations§

Source§

impl HttpRunnerClient

Source

pub fn new(port: u16) -> Self

Construct a client targeting http://127.0.0.1:{port}.

Source

pub fn with_base<S: Into<String>>(base: S) -> Self

Construct with an explicit base URL (test / non-localhost cases).

Source

pub fn attach_session_state(&self, state: Arc<AtomicU8>)

v1.0.4 §D7 — attach the SDK Session’s state atomic so the client updates it on every response by parsing X-Sim-Health. Called by App::open_session. External callers rarely need this directly.

Source

pub fn with_target_bundle_id<S: Into<String>>(self, bundle: S) -> Self

Set the target bundle id sent as App-Bundle-Id header on every subsequent request. Runner rebinds XCUIApplication(bundleIdentifier:) per request if this differs from its boot-time default.

Source

pub fn set_target_bundle_id<S: Into<String>>(&mut self, bundle: S)

Mutable variant of Self::with_target_bundle_id. Used from the driver-trait pass-through where the driver holds the client by value and can’t easily use the builder shape.

Source

pub fn with_auto_activate(self, activate: bool) -> Self

When set, every subsequent request sends App-Activate: true, causing the runner to .activate() the resolved target before operating.

Source

pub fn set_auto_activate(&mut self, activate: bool)

Mutable variant of Self::with_auto_activate.

Source

pub fn with_input_dispatch_mode(self, mode: InputDispatchMode) -> Self

Set the input dispatch mode header. Sent as Input-Dispatch-Mode: <mode> on every request that touches text input (currently /fill + /clear). Runner routes:

  • a11y (default) — resolve focus via a11y tree, dispatch to XCUIElement.typeText
  • key-events — skip a11y-focus resolution, send raw key events via IOHID / daemon
  • auto — try a11y first, fall back to key-events on ElementNotFound

--force-key-events on smix run sets this to key-events.

Source

pub fn set_input_dispatch_mode(&mut self, mode: InputDispatchMode)

Mutable variant.

Source

pub fn target_bundle_id(&self) -> Option<&str>

Accessor for the current target bundle. Used by callers that want to log or diagnose.

Source

pub fn auto_activate(&self) -> bool

Accessor for the current auto-activate flag.

Source

pub fn set_session_id<S: Into<String>>(&mut self, id: S)

Attach a session id sent as the Session-Id header on every subsequent request. When the runner sees this header it looks up the session’s cached XCUIApplication and skips the per-request .activate(), eliminating the activation storm on long-running gates. Typically not called directly — use open_session() + a session wrapper instead.

Source

pub fn clear_session_id(&mut self)

Clear a previously-set session id, reverting to legacy per-request resolveApp() (now itself rate-limited to at most one .activate() per 5 s per bundle-id).

Source

pub fn session_id(&self) -> Option<&str>

The session id in force for outgoing requests, or None if the legacy per-request rebind path is in use.

Source

pub fn with_liveness_window(self, window: usize) -> Self

Enable liveness observability. The client tracks the last window request outcomes; if a majority are non-success (5xx, unreachable, connection-refused), subsequent calls surface RunnerTransportError::RunnerDegraded instead of returning silent stale data. On any is_connect() failure the client also probes /health; if that fails within 1 s the next call surfaces RunnerTransportError::RunnerDied.

Idempotent; safe to call more than once (last window size wins). Default is disabled (behavior identical to v1.0.1).

Source

pub fn with_sim_health(self, monitor: SimHealthMonitor) -> Self

Attach a smix_sim_health::SimHealthMonitor that receives /health outcome observations. Every health(), health_detail() and internal probe_death() call feeds SimHealthMonitor::record_health_ok / record_health_fail, and subscribers get a Degraded / Dead transition without polling.

Additive over with_liveness_window; both may be enabled at the same time — the liveness window handles per-call transport classification, the sim-health monitor aggregates across the wider observation surface (screenshot wall time, watched processes) fed by other crates.

Since smix 1.0.4.

Source

pub fn set_sim_health(&mut self, monitor: SimHealthMonitor)

Mutable variant of Self::with_sim_health.

Source

pub fn sim_health(&self) -> Option<&SimHealthMonitor>

Accessor for the attached sim-health monitor, or None if the caller opted out. Used by driver / SDK layers that need to subscribe to state transitions or read the current classification.

Source

pub fn base(&self) -> &str

Base URL accessor.

Source

pub async fn health(&self) -> bool

GET /health — bare alive probe (no memoization). Returns true on 2xx.

Source

pub async fn ensure_reachable(&self) -> Result<(), RunnerTransportError>

GET /health memoized — first call probes; subsequent are no-ops after one success. Failure raises RunnerTransportError::Unreachable. Mirrors TS ensureReachable.

Source

pub async fn health_detail( &self, ) -> Result<HealthResponse, RunnerTransportError>

GET /health extended — parses the v1.0.2+ JSON body carrying uptime / activation counters / open-session count. On pre-v1.0.2 runners returning a bare 200 with no body, returns a default smix_runner_wire::HealthResponse with only ok = true set.

Source

pub async fn open_session( &self, req: &SessionOpenRequest, ) -> Result<SessionOpenResponse, RunnerTransportError>

POST /session/open — reserve a runner-side XCUIApplication binding and (optionally) activate it once. The returned session id becomes the Session-Id header on subsequent requests via Self::set_session_id or a session wrapper.

Source

pub async fn close_session( &self, req: &SessionCloseRequest, ) -> Result<SessionCloseResponse, RunnerTransportError>

POST /session/close — release a previously-opened session. Idempotent; closing an unknown session returns ok = true.

Source

pub async fn renew_session_activation( &self, req: &SessionRenewActivationRequest, ) -> Result<SessionRenewActivationResponse, RunnerTransportError>

POST /session/renew-activation — re-issue .activate() on the session’s cached binding, subject to the runner-side per-session 5 s rate limit. Escape hatch for consumers that detect drift.

Source

pub async fn close_all_sessions( &self, ) -> Result<SessionCloseAllResponse, RunnerTransportError>

v1.0.4 §D5 — POST /session/close-all — clear every open session on the runner. Used by smix runner cycle and the runner-side supervisor to drop stale bindings after a cycle. Idempotent — closing an empty session table returns {ok:true, closed:0}.

Source

pub async fn relaunch_session_app( &self, req: &SessionRelaunchAppRequest, ) -> Result<SessionRelaunchAppResponse, RunnerTransportError>

v1.0.4 §D14 — POST /session/relaunch-app — instruct the runner to terminate() + launch() the session’s cached XCUIApplication binding IN PLACE. Preserves session id and XCUITest binding; recovers from a downstream app crash without cycling the runner.

Source

pub async fn list_sessions( &self, ) -> Result<SessionListResponse, RunnerTransportError>

v1.0.5 §D1 — POST /session/list — enumerate every session currently known to the runner. Useful for diagnostics + the supervisor + SDK Session::still_valid() probe after a cycle.

Source

pub async fn terminate_session_app( &self, req: &SessionAppLifecycleRequest, ) -> Result<SessionAppLifecycleResponse, RunnerTransportError>

v1.0.8 §D1 — POST /session/terminate-app — cooperative XCUIApplication.terminate() on the session’s cached binding via testmanagerd (NOT simctl terminate SIGKILL). Does not signal com.apple.ReportCrash. Paired with Self::launch_session_app and a host-side SimctlClient::clear_app_sandbox invocation to implement the Session::reset_app_data orchestration that eliminates the “Insight quit unexpectedly” system dialog.

Source

pub async fn launch_session_app( &self, req: &SessionAppLifecycleRequest, ) -> Result<SessionAppLifecycleResponse, RunnerTransportError>

v1.0.8 §D1 — POST /session/launch-app — cooperative XCUIApplication.launch() on the session’s cached binding. Companion of Self::terminate_session_app.

Source

pub async fn diagnostic_dump( &self, ) -> Result<DiagnosticDumpResponse, RunnerTransportError>

v1.0.7 §D5 — POST /diagnostic/dump — one-shot post-mortem snapshot of the runner’s runtime state. Bundles the recent subprocess ring buffer, open sessions, sim-health state, supervisor pid, and uptime. smix diagnostic dump calls this then pretty-prints.

Legacy runners (v1.0.6 and earlier) return 404; consumers can gracefully fall back to the client-side ring buffer only.

Source

pub async fn get_tree( &self, include: Option<IncludeScope>, ) -> Result<A11yNode, RunnerTransportError>

GET /tree?include= — full a11y tree dump.

Post-deser pass derive_roles_recursive fills A11yNode.role from raw_type because the Swift /tree route only emits rawType on the wire. Without this, Selector::Role would never match real-sim payloads.

Source

pub async fn system_popups( &self, include: Option<IncludeScope>, ) -> Result<Vec<SystemPopup>, RunnerTransportError>

GET /system-popups?include= — list system popups.

Source

pub async fn system_popup_action( &self, popup_id: &str, button_id: &str, ) -> Result<bool, RunnerTransportError>

POST /system-popup-action. Tap a button on a previously enumerated popup. popup_id and button_id are the Popup.id / PopupButton.id strings returned by Self::system_popups; the runner walks the same scan order so the round-trip does not need a host-side id map.

Returns Ok(true) when the runner matched both ids and dispatched the tap, Ok(false) when the runner returned a 404 not_found (popup id, button id, or synthesize dispatch missed). Transport errors and non-2xx-non-404 statuses surface as RunnerTransportError.

Source

pub async fn tap( &self, selector: &Selector, mode: TapMode, include: Option<IncludeScope>, ) -> Result<TapResult, RunnerTransportError>

POST /tap — selector → element tap. Errors:

  • 404 → TapNotFoundError returned via Err(.. Other ..). We keep the simple RunnerTransportError + body inspection pattern. Driver layer wraps with ExpectationFailure.
Source

pub async fn tap_at_norm_coord( &self, nx: f64, ny: f64, ) -> Result<(), RunnerTransportError>

POST /tap-at-norm-coord — Apple native UI event coord tap.

Source

pub async fn double_tap_at_norm_coord( &self, nx: f64, ny: f64, ) -> Result<(), RunnerTransportError>

POST /double-tap-at-norm-coord — double-tap at viewport-normalized coord. Android-specific endpoint backing AndroidDriver::double_tap after host-resolve. iOS path uses selector-based /double-tap; this exists for Android where the runner does its own host-resolve via tree dump.

Source

pub async fn long_press_at_norm_coord( &self, nx: f64, ny: f64, duration_ms: u64, ) -> Result<(), RunnerTransportError>

POST /long-press-at-norm-coord — long-press at coord with explicit duration. Android-specific.

Source

pub async fn input_text(&self, text: &str) -> Result<(), RunnerTransportError>

POST /input-text — type text into currently-focused input. Caller must tap to focus the field first (AndroidDriver orchestrates). Android-specific.

Source

pub async fn tap_by_id(&self, id: &str) -> Result<bool, RunnerTransportError>

POST /tap-by-idXCUIElement.tap() via the XCTest gesture-recognizer chain. Drives SwiftUI .sheet / .alert / .confirmationDialog / .fullScreenCover dismiss bindings that the default host-HID-at-coord path can’t trigger. Returns Ok(true) when the element was found and tapped, Ok(false) when the runner reported ok=false (element not found / NSException surfaced through smixGuarded). Parallel to tap_at_norm_coord; the existing /tap envelope stays untouched.

Source

pub async fn find_text_by_ocr( &self, text: &str, locales: &[String], recognition_level: &str, ) -> Result<Option<OcrFrame>, RunnerTransportError>

POST /find-text-by-ocr — Apple Vision OCR over the current XCUIScreen screenshot. Returns the matching text observation’s bounding box normalized to [0, 1] in UIKit coord space (top-left origin, y-down). Ok(None) when no observation matches the keyword. Sense layer covering “lib without testID but with visible text” scenarios.

locales are BCP-47 language subtags (e.g. ["en"] / ["ja"]); empty defaults to ["en"] on the swift side. recognition_level is "accurate" (default, slower + higher accuracy) or "fast".

Source

pub async fn webview_eval( &self, js: &str, ) -> Result<Value, RunnerTransportError>

Eval JS against app-side WKWebView bridge. Does NOT use the XCUITest runner — POSTs directly to the app-side debug bridge on 127.0.0.1:28080/eval (iOS sim shares host loopback). Returns the JS eval result as JSON Value or runtime error from the bridge.

Scope: works for any app that exposes the SmixWebViewBridge. Bridge port is fixed at 28080 today.

Source

pub async fn double_tap( &self, selector: &Selector, include: Option<IncludeScope>, ) -> Result<TapResult, RunnerTransportError>

POST /double-tap — XCUIElement.doubleTap() public API. Mirrors /tap envelope but issues two-tap gesture on the resolved element. Same as Maestro doubleTapOn.

Source

pub async fn long_press( &self, selector: &Selector, duration_ms: u64, include: Option<IncludeScope>, ) -> Result<TapResult, RunnerTransportError>

POST /long-press — XCUIElement.press(forDuration:) public API. duration_ms comes from maestro yaml duration:, default 500. Same as Maestro longPressOn.

Source

pub async fn set_orientation( &self, orientation: &str, ) -> Result<(), RunnerTransportError>

POST /set-orientation — rotate sim via swift XCUIDevice.shared.orientation setter. orientation literal: “portrait” | “portraitUpsideDown” | “landscapeLeft” | “landscapeRight”.

Source

pub async fn swipe_at_norm_coord( &self, from: (f64, f64), to: (f64, f64), ) -> Result<(), RunnerTransportError>

POST /swipe-at-norm-coord — Apple native UI event from-to swipe. Sibling of Self::tap_at_norm_coord under §9 #3 escape hatch.

Source

pub async fn find( &self, selector: &Selector, include: Option<IncludeScope>, ) -> Result<bool, RunnerTransportError>

POST /find — boolean existence quick-probe.

Source

pub async fn fill( &self, selector: &Selector, text: &str, include: Option<IncludeScope>, ) -> Result<RunnerKeyboardResult, RunnerTransportError>

POST /fill — fill text into focused / matched input.

Source

pub async fn clear( &self, selector: &Selector, include: Option<IncludeScope>, ) -> Result<RunnerKeyboardResult, RunnerTransportError>

POST /clear — clear focused / matched input.

Source

pub async fn press_key( &self, key: KeyName, ) -> Result<RunnerKeyboardResult, RunnerTransportError>

POST /press-key — press named key (Return/Tab/Delete/etc.).

Source

pub async fn scroll( &self, selector: &RunnerScrollSelector, direction: SwipeDirection, include: Option<IncludeScope>, ) -> Result<u32, RunnerTransportError>

POST /scroll {selector, direction, include?} — scroll-until-visible.

Source

pub async fn swipe_once( &self, direction: SwipeDirection, ) -> Result<(), RunnerTransportError>

POST /swipe-once {direction} — single swipe, no probe.

Source

pub async fn foreground( &self, bundle_id: &str, ) -> Result<(), RunnerTransportError>

POST /foreground {bundleId} — bring app to foreground.

Source

pub async fn hide_keyboard(&self) -> Result<(), RunnerTransportError>

POST /hide-keyboard.

Source

pub async fn back(&self) -> Result<(), RunnerTransportError>

POST /back — back gesture.

Source

pub async fn start_record(&self) -> Result<(), RunnerTransportError>

POST /record/start — begin recording.

Source

pub async fn poll_record( &self, ) -> Result<Vec<RecordedEvent>, RunnerTransportError>

GET /record/poll — drain recorded events.

Source

pub async fn stop_record( &self, ) -> Result<Vec<RecordedEvent>, RunnerTransportError>

POST /record/stop — stop recording, drain final events.

Trait Implementations§

Source§

impl Debug for HttpRunnerClient

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more