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
impl HttpRunnerClient
Sourcepub fn with_base<S: Into<String>>(base: S) -> Self
pub fn with_base<S: Into<String>>(base: S) -> Self
Construct with an explicit base URL (test / non-localhost cases).
Sourcepub fn attach_session_state(&self, state: Arc<AtomicU8>)
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.
Sourcepub fn with_target_bundle_id<S: Into<String>>(self, bundle: S) -> Self
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.
Sourcepub fn set_target_bundle_id<S: Into<String>>(&mut self, bundle: S)
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.
Sourcepub fn with_auto_activate(self, activate: bool) -> Self
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.
Sourcepub fn set_auto_activate(&mut self, activate: bool)
pub fn set_auto_activate(&mut self, activate: bool)
Mutable variant of Self::with_auto_activate.
Sourcepub fn with_input_dispatch_mode(self, mode: InputDispatchMode) -> Self
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.typeTextkey-events— skip a11y-focus resolution, send raw key events via IOHID / daemonauto— try a11y first, fall back to key-events on ElementNotFound
--force-key-events on smix run sets this to key-events.
Sourcepub fn set_input_dispatch_mode(&mut self, mode: InputDispatchMode)
pub fn set_input_dispatch_mode(&mut self, mode: InputDispatchMode)
Mutable variant.
Sourcepub fn target_bundle_id(&self) -> Option<&str>
pub fn target_bundle_id(&self) -> Option<&str>
Accessor for the current target bundle. Used by callers that want to log or diagnose.
Sourcepub fn auto_activate(&self) -> bool
pub fn auto_activate(&self) -> bool
Accessor for the current auto-activate flag.
Sourcepub fn set_session_id<S: Into<String>>(&mut self, id: S)
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.
Sourcepub fn clear_session_id(&mut self)
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).
Sourcepub fn session_id(&self) -> Option<&str>
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.
Sourcepub fn with_liveness_window(self, window: usize) -> Self
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).
Sourcepub fn with_sim_health(self, monitor: SimHealthMonitor) -> Self
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.
Sourcepub fn set_sim_health(&mut self, monitor: SimHealthMonitor)
pub fn set_sim_health(&mut self, monitor: SimHealthMonitor)
Mutable variant of Self::with_sim_health.
Sourcepub fn sim_health(&self) -> Option<&SimHealthMonitor>
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.
Sourcepub async fn health(&self) -> bool
pub async fn health(&self) -> bool
GET /health — bare alive probe (no memoization). Returns true on 2xx.
Sourcepub async fn ensure_reachable(&self) -> Result<(), RunnerTransportError>
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.
Sourcepub async fn health_detail(
&self,
) -> Result<HealthResponse, RunnerTransportError>
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.
Sourcepub async fn open_session(
&self,
req: &SessionOpenRequest,
) -> Result<SessionOpenResponse, RunnerTransportError>
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.
Sourcepub async fn close_session(
&self,
req: &SessionCloseRequest,
) -> Result<SessionCloseResponse, RunnerTransportError>
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.
Sourcepub async fn renew_session_activation(
&self,
req: &SessionRenewActivationRequest,
) -> Result<SessionRenewActivationResponse, RunnerTransportError>
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.
Sourcepub async fn close_all_sessions(
&self,
) -> Result<SessionCloseAllResponse, RunnerTransportError>
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}.
Sourcepub async fn relaunch_session_app(
&self,
req: &SessionRelaunchAppRequest,
) -> Result<SessionRelaunchAppResponse, RunnerTransportError>
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.
Sourcepub async fn list_sessions(
&self,
) -> Result<SessionListResponse, RunnerTransportError>
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.
Sourcepub async fn terminate_session_app(
&self,
req: &SessionAppLifecycleRequest,
) -> Result<SessionAppLifecycleResponse, RunnerTransportError>
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.
Sourcepub async fn launch_session_app(
&self,
req: &SessionAppLifecycleRequest,
) -> Result<SessionAppLifecycleResponse, RunnerTransportError>
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.
Sourcepub async fn diagnostic_dump(
&self,
) -> Result<DiagnosticDumpResponse, RunnerTransportError>
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.
Sourcepub async fn get_tree(
&self,
include: Option<IncludeScope>,
) -> Result<A11yNode, RunnerTransportError>
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.
Sourcepub async fn system_popups(
&self,
include: Option<IncludeScope>,
) -> Result<Vec<SystemPopup>, RunnerTransportError>
pub async fn system_popups( &self, include: Option<IncludeScope>, ) -> Result<Vec<SystemPopup>, RunnerTransportError>
GET /system-popups?include= — list system popups.
Sourcepub async fn system_popup_action(
&self,
popup_id: &str,
button_id: &str,
) -> Result<bool, RunnerTransportError>
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.
Sourcepub async fn tap(
&self,
selector: &Selector,
mode: TapMode,
include: Option<IncludeScope>,
) -> Result<TapResult, RunnerTransportError>
pub async fn tap( &self, selector: &Selector, mode: TapMode, include: Option<IncludeScope>, ) -> Result<TapResult, RunnerTransportError>
POST /tap — selector → element tap. Errors:
- 404 →
TapNotFoundErrorreturned viaErr(.. Other ..). We keep the simpleRunnerTransportError + body inspectionpattern. Driver layer wraps with ExpectationFailure.
Sourcepub async fn tap_at_norm_coord(
&self,
nx: f64,
ny: f64,
) -> Result<(), RunnerTransportError>
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.
Sourcepub async fn double_tap_at_norm_coord(
&self,
nx: f64,
ny: f64,
) -> Result<(), RunnerTransportError>
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.
Sourcepub async fn long_press_at_norm_coord(
&self,
nx: f64,
ny: f64,
duration_ms: u64,
) -> Result<(), RunnerTransportError>
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.
Sourcepub async fn input_text(&self, text: &str) -> Result<(), RunnerTransportError>
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.
Sourcepub async fn tap_by_id(&self, id: &str) -> Result<bool, RunnerTransportError>
pub async fn tap_by_id(&self, id: &str) -> Result<bool, RunnerTransportError>
POST /tap-by-id — XCUIElement.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.
Sourcepub async fn find_text_by_ocr(
&self,
text: &str,
locales: &[String],
recognition_level: &str,
) -> Result<Option<OcrFrame>, RunnerTransportError>
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".
Sourcepub async fn webview_eval(
&self,
js: &str,
) -> Result<Value, RunnerTransportError>
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.
Sourcepub async fn double_tap(
&self,
selector: &Selector,
include: Option<IncludeScope>,
) -> Result<TapResult, RunnerTransportError>
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.
Sourcepub async fn long_press(
&self,
selector: &Selector,
duration_ms: u64,
include: Option<IncludeScope>,
) -> Result<TapResult, RunnerTransportError>
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.
Sourcepub async fn set_orientation(
&self,
orientation: &str,
) -> Result<(), RunnerTransportError>
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”.
Sourcepub async fn swipe_at_norm_coord(
&self,
from: (f64, f64),
to: (f64, f64),
) -> Result<(), RunnerTransportError>
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.
Sourcepub async fn find(
&self,
selector: &Selector,
include: Option<IncludeScope>,
) -> Result<bool, RunnerTransportError>
pub async fn find( &self, selector: &Selector, include: Option<IncludeScope>, ) -> Result<bool, RunnerTransportError>
POST /find — boolean existence quick-probe.
Sourcepub async fn fill(
&self,
selector: &Selector,
text: &str,
include: Option<IncludeScope>,
) -> Result<RunnerKeyboardResult, RunnerTransportError>
pub async fn fill( &self, selector: &Selector, text: &str, include: Option<IncludeScope>, ) -> Result<RunnerKeyboardResult, RunnerTransportError>
POST /fill — fill text into focused / matched input.
Sourcepub async fn clear(
&self,
selector: &Selector,
include: Option<IncludeScope>,
) -> Result<RunnerKeyboardResult, RunnerTransportError>
pub async fn clear( &self, selector: &Selector, include: Option<IncludeScope>, ) -> Result<RunnerKeyboardResult, RunnerTransportError>
POST /clear — clear focused / matched input.
Sourcepub async fn press_key(
&self,
key: KeyName,
) -> Result<RunnerKeyboardResult, RunnerTransportError>
pub async fn press_key( &self, key: KeyName, ) -> Result<RunnerKeyboardResult, RunnerTransportError>
POST /press-key — press named key (Return/Tab/Delete/etc.).
Sourcepub async fn scroll(
&self,
selector: &RunnerScrollSelector,
direction: SwipeDirection,
include: Option<IncludeScope>,
) -> Result<u32, RunnerTransportError>
pub async fn scroll( &self, selector: &RunnerScrollSelector, direction: SwipeDirection, include: Option<IncludeScope>, ) -> Result<u32, RunnerTransportError>
POST /scroll {selector, direction, include?} — scroll-until-visible.
Sourcepub async fn swipe_once(
&self,
direction: SwipeDirection,
) -> Result<(), RunnerTransportError>
pub async fn swipe_once( &self, direction: SwipeDirection, ) -> Result<(), RunnerTransportError>
POST /swipe-once {direction} — single swipe, no probe.
Sourcepub async fn foreground(
&self,
bundle_id: &str,
) -> Result<(), RunnerTransportError>
pub async fn foreground( &self, bundle_id: &str, ) -> Result<(), RunnerTransportError>
POST /foreground {bundleId} — bring app to foreground.
Sourcepub async fn hide_keyboard(&self) -> Result<(), RunnerTransportError>
pub async fn hide_keyboard(&self) -> Result<(), RunnerTransportError>
POST /hide-keyboard.
Sourcepub async fn back(&self) -> Result<(), RunnerTransportError>
pub async fn back(&self) -> Result<(), RunnerTransportError>
POST /back — back gesture.
Sourcepub async fn start_record(&self) -> Result<(), RunnerTransportError>
pub async fn start_record(&self) -> Result<(), RunnerTransportError>
POST /record/start — begin recording.
Sourcepub async fn poll_record(
&self,
) -> Result<Vec<RecordedEvent>, RunnerTransportError>
pub async fn poll_record( &self, ) -> Result<Vec<RecordedEvent>, RunnerTransportError>
GET /record/poll — drain recorded events.
Sourcepub async fn stop_record(
&self,
) -> Result<Vec<RecordedEvent>, RunnerTransportError>
pub async fn stop_record( &self, ) -> Result<Vec<RecordedEvent>, RunnerTransportError>
POST /record/stop — stop recording, drain final events.