pub struct MockWorkerFacade {
pub callers: Mutex<HashMap<SessionSlot, CallerProject>>,
pub workers: Mutex<HashMap<String, Vec<WorkerStatus>>>,
pub spawn_calls: Mutex<Vec<(SessionSlot, String, String, Option<String>, Option<String>, bool, bool, Option<Vec<String>>, Option<String>)>>,
pub spawn_reply: Mutex<Option<Result<WorkerSpawnReply, WorkerSpawnError>>>,
pub update_calls: Mutex<Vec<(SessionSlot, String, Option<String>, Option<String>, Option<String>, Option<Vec<String>>)>>,
pub update_result: Mutex<Option<Result<(), WorkerUpdateError>>>,
pub deliver_calls: Mutex<Vec<(SessionSlot, String, WrappedPrompt)>>,
pub deliver_to_project_calls: Mutex<Vec<RecordedProjectDelivery>>,
pub despawn_calls: Mutex<Vec<(SessionSlot, String, bool)>>,
pub despawn_outcome: Mutex<Option<DespawnOutcome>>,
pub capacity_reply: Mutex<Option<WorkerCapacity>>,
}Expand description
Mock for unit-testing the four Tool impls. Captures every dispatched call into a Vec so tests can assert “tool X dispatched spawn with these args” without spinning up a real Workspace.
Fields§
§callers: Mutex<HashMap<SessionSlot, CallerProject>>Pre-loaded caller -> project mapping. Tests insert entries before invoking the tool.
workers: Mutex<HashMap<String, Vec<WorkerStatus>>>Pre-loaded live_workers snapshot per project_key string.
list_workers and deliver_worker_prompt both read from
this.
spawn_calls: Mutex<Vec<(SessionSlot, String, String, Option<String>, Option<String>, bool, bool, Option<Vec<String>>, Option<String>)>>Captured spawn_worker calls.
spawn_reply: Mutex<Option<Result<WorkerSpawnReply, WorkerSpawnError>>>Pre-loaded reply for spawn_worker. When None, the mock
returns DispatchFailed { message: "no preloaded reply" }.
update_calls: Mutex<Vec<(SessionSlot, String, Option<String>, Option<String>, Option<String>, Option<Vec<String>>)>>Captured update_worker calls.
update_result: Mutex<Option<Result<(), WorkerUpdateError>>>Pre-loaded result for update_worker. When None, the mock
reports success, so a test that cares only about the args passed
through does not have to set it.
deliver_calls: Mutex<Vec<(SessionSlot, String, WrappedPrompt)>>Captured deliver_worker_prompt calls.
deliver_to_project_calls: Mutex<Vec<RecordedProjectDelivery>>Captured deliver_worker_prompt_to_project calls.
despawn_calls: Mutex<Vec<(SessionSlot, String, bool)>>Captured despawn_worker calls: (caller, label, force).
despawn_outcome: Mutex<Option<DespawnOutcome>>Pre-loaded outcome for despawn_worker on a known label. When
None, the mock reports Despawned with neither warning set.
capacity_reply: Mutex<Option<WorkerCapacity>>Pre-loaded reply for capacity. When None, the mock derives
it from the workers map: default cap, live count from the
caller’s project’s entries.
Implementations§
Trait Implementations§
Source§impl Default for MockWorkerFacade
impl Default for MockWorkerFacade
Source§impl WorkerFacade for MockWorkerFacade
impl WorkerFacade for MockWorkerFacade
Source§fn caller_project(&self, caller: &SessionSlot) -> Option<CallerProject>
fn caller_project(&self, caller: &SessionSlot) -> Option<CallerProject>
None when caller matches no known session.Source§fn spawn_worker<'life0, 'life1, 'async_trait>(
&'life0 self,
caller: &'life1 SessionSlot,
label: String,
charter: String,
kick: Option<String>,
resume_kick: Option<String>,
interactive: bool,
resume_session: bool,
mcp_families: Option<Vec<String>>,
cwd: Option<String>,
) -> Pin<Box<dyn Future<Output = Result<WorkerSpawnReply, WorkerSpawnError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn spawn_worker<'life0, 'life1, 'async_trait>(
&'life0 self,
caller: &'life1 SessionSlot,
label: String,
charter: String,
kick: Option<String>,
resume_kick: Option<String>,
interactive: bool,
resume_session: bool,
mcp_families: Option<Vec<String>>,
cwd: Option<String>,
) -> Pin<Box<dyn Future<Output = Result<WorkerSpawnReply, WorkerSpawnError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Command::SpawnWorker and await its synchronous
reply. Gating (lead-only, non-empty label, non-empty charter)
happens before dispatch. resume_kick is persisted rather than
delivered now; it replaces the generic restart note when this
worker resumes after a forge restart with a turn that was cut off.
A worker that was idle when forge stopped resumes with nothing
delivered. interactive keeps the built-in
AskUserQuestion tool, which every other worker is denied.
resume_session resumes the label’s most recent prior session
instead of starting fresh. A label with none resolves to
ResumeTarget::None, which starts a fresh session and says so in
the reply’s SessionChoice; only a lookup that failed is an
error. Read moreSource§fn update_worker(
&self,
caller: &SessionSlot,
label: &str,
charter: Option<String>,
kick: Option<String>,
resume_kick: Option<String>,
mcp_families: Option<Vec<String>>,
) -> Result<(), WorkerUpdateError>
fn update_worker( &self, caller: &SessionSlot, label: &str, charter: Option<String>, kick: Option<String>, resume_kick: Option<String>, mcp_families: Option<Vec<String>>, ) -> Result<(), WorkerUpdateError>
label in the caller’s project, leaving a None field at its
stored value. Errors with NoSuchWorker when no row exists:
update revises an existing worker, it never creates one. Takes
effect on that worker’s next respawn, since a session’s system
prompt and tool list are fixed when the session spawns.
mcp_families follows the same contract: None leaves the
stored selection alone, Some(names) replaces it - canonicalised
by the tool - and Some(empty) resets it to every family.Source§fn despawn_worker<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
caller: &'life1 SessionSlot,
label: &'life2 str,
force: bool,
) -> Pin<Box<dyn Future<Output = Result<DespawnOutcome, WorkerDespawnError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn despawn_worker<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
caller: &'life1 SessionSlot,
label: &'life2 str,
force: bool,
) -> Pin<Box<dyn Future<Output = Result<DespawnOutcome, WorkerDespawnError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Command::DespawnWorker and await its result.
Gating (lead-only, non-empty label) happens before dispatch.
force removes a dirty worktree; without it a dirty worktree
blocks the despawn (DespawnOutcome::Blocked).Source§fn list_workers(&self, caller: &SessionSlot) -> Vec<WorkerStatus>
fn list_workers(&self, caller: &SessionSlot) -> Vec<WorkerStatus>
Source§fn list_all_workers(&self) -> Vec<WorkerStatus>
fn list_all_workers(&self) -> Vec<WorkerStatus>
list_projects in config order, the mock sorts its project keys.Source§fn capacity(&self, caller: &SessionSlot) -> Option<WorkerCapacity>
fn capacity(&self, caller: &SessionSlot) -> Option<WorkerCapacity>
max_workers in the project’s [[orgs.projects]]
entry, else DEFAULT_MAX_WORKERS_PER_PROJECT) paired with the
live count.
A plain data read - the same one the spawn path’s cap check
performs. Returns None when the caller resolves to no
project.Source§fn deliver_worker_prompt<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
caller: &'life1 SessionSlot,
target_label: &'life2 str,
wrapped: WrappedPrompt,
) -> Pin<Box<dyn Future<Output = Result<WorkerTargetStatus, WorkerDeliverError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn deliver_worker_prompt<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
caller: &'life1 SessionSlot,
target_label: &'life2 str,
wrapped: WrappedPrompt,
) -> Pin<Box<dyn Future<Output = Result<WorkerTargetStatus, WorkerDeliverError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Delivered means the
prompt was accepted - handed to the target’s session queue, held
for its turn end, or parked for its connect - which is the whole
claim the sender’s ack makes; anything that reached no session is
an error. UnknownLabel when no live worker matches.Source§fn deliver_worker_prompt_to_project<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
caller: &'life1 SessionSlot,
org: &'life2 str,
project: &'life3 str,
target_label: &'life4 str,
wrapped: WrappedPrompt,
) -> Pin<Box<dyn Future<Output = Result<WorkerTargetStatus, WorkerDeliverError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn deliver_worker_prompt_to_project<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
caller: &'life1 SessionSlot,
org: &'life2 str,
project: &'life3 str,
target_label: &'life4 str,
wrapped: WrappedPrompt,
) -> Pin<Box<dyn Future<Output = Result<WorkerTargetStatus, WorkerDeliverError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
(org, project) pair rather than the caller’s own. The
caller lives in another project, so the target cannot be
resolved from it. Mirrors deliver_worker_prompt otherwise:
an unknown label is an error and a sleeping target is not
auto-spawned.Source§fn deliver_prompt_to_lead<'life0, 'life1, 'async_trait>(
&'life0 self,
caller: &'life1 SessionSlot,
wrapped: WrappedPrompt,
) -> Pin<Box<dyn Future<Output = Result<WorkerTargetStatus, WorkerLeadDeliverError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn deliver_prompt_to_lead<'life0, 'life1, 'async_trait>(
&'life0 self,
caller: &'life1 SessionSlot,
wrapped: WrappedPrompt,
) -> Pin<Box<dyn Future<Output = Result<WorkerTargetStatus, WorkerLeadDeliverError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
WorkerEntry::spawned_by_session_id. Same
wire-shape contract as deliver_worker_prompt: Delivered
means the lead’s session accepted it, and one the session could
not take is an error.Auto Trait Implementations§
impl !Freeze for MockWorkerFacade
impl !RefUnwindSafe for MockWorkerFacade
impl Send for MockWorkerFacade
impl Sync for MockWorkerFacade
impl Unpin for MockWorkerFacade
impl UnsafeUnpin for MockWorkerFacade
impl UnwindSafe for MockWorkerFacade
Blanket Implementations§
§impl<T> AnySync for T
impl<T> AnySync for T
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more