pub struct Fleet {
surface: Arc<ViewSurface>,
workspace: Arc<Workspace>,
config_dir: PathBuf,
owned_dir: Option<TempDir>,
}Expand description
A view surface over a stub workspace, plus the seeding a test needs to put a roster in front of it.
Fields§
§surface: Arc<ViewSurface>§workspace: Arc<Workspace>§config_dir: PathBufWhere the workspace’s store and the CLI’s transcripts live, which a transcript fixture has to write into.
owned_dir: Option<TempDir>Declared last, so the directory goes after the store this fixture opened under it has closed - unless a surface is cloned into something that outlives the fleet, which unlinks the file while it is still open.
Implementations§
Source§impl Fleet
impl Fleet
Sourcepub fn new(orgs: &[(&str, &[&str])]) -> Result<Self, FixtureError>
pub fn new(orgs: &[(&str, &[&str])]) -> Result<Self, FixtureError>
A fleet over a config directory of its own, removed with the fleet.
Sourcepub fn in_dir(
config_dir: &Path,
orgs: &[(&str, &[&str])],
) -> Result<Self, FixtureError>
pub fn in_dir( config_dir: &Path, orgs: &[(&str, &[&str])], ) -> Result<Self, FixtureError>
A fleet whose forge.toml declares one project per name under each
(org, projects) entry, in the order given. config_dir has to
outlive the fleet - the workspace’s store lives under it, and each
project’s path is a directory of its own under it.
The project directories are not created. A fixture that makes one
itself moves the key project_key answers, because that derivation
canonicalises a path that now resolves - and everything the fixture
registered before it appeared is registered under a key nothing looks
up again. Read project_key before creating one.
Sourcepub fn in_dir_with_server(
config_dir: &Path,
orgs: &[(&str, &[&str])],
server: &str,
) -> Result<Self, FixtureError>
pub fn in_dir_with_server( config_dir: &Path, orgs: &[(&str, &[&str])], server: &str, ) -> Result<Self, FixtureError>
Self::in_dir with a [server] block of the caller’s own, for a
test that pins what a key DOES rather than that it parses.
Sourcepub fn in_dir_with_server_and_env(
config_dir: &Path,
orgs: &[(&str, &[&str])],
server: &str,
env: &[(&str, &str)],
) -> Result<Self, FixtureError>
pub fn in_dir_with_server_and_env( config_dir: &Path, orgs: &[(&str, &[&str])], server: &str, env: &[(&str, &str)], ) -> Result<Self, FixtureError>
Self::in_dir_with_server with each project’s own
[orgs.projects.env], which is the identity a scan’s git and gh
children carry - a fixture that pins a lookup needs its own PATH.
Sourcepub fn new_with_tts(orgs: &[(&str, &[&str])]) -> Result<Self, FixtureError>
pub fn new_with_tts(orgs: &[(&str, &[&str])]) -> Result<Self, FixtureError>
A fleet with [tts] enabled, for a test that drives the voice
service: the fixture’s own section stays off so no other test
synthesises.
fn open(config_dir: &Path) -> Result<Self, FixtureError>
Sourcepub fn surface(&self) -> Arc<ViewSurface> ⓘ
pub fn surface(&self) -> Arc<ViewSurface> ⓘ
The surface, which keeps the workspace alive on its own.
Sourcepub fn workspace(&self) -> Arc<Workspace> ⓘ
pub fn workspace(&self) -> Arc<Workspace> ⓘ
The workspace under the fixture, for a test that has to build something FROM it - the transport a binary builds, above all, whose browser relay has to be this workspace’s own.
Sourcepub fn arm_dictation(&self, key: &SessionSlot) -> Result<TempDir, FixtureError>
pub fn arm_dictation(&self, key: &SessionSlot) -> Result<TempDir, FixtureError>
Arm dictation for key: an engine over a temp models directory
whose weights are absent, and the seat marked live, so a test can
drive a take without hardware, a model or a CLI. The returned
directory has to outlive the engine.
Sourcepub fn emit(&self, update: SessionUpdate)
pub fn emit(&self, update: SessionUpdate)
Push one update onto the core’s stream, so a test can watch a view react to it without driving a whole session.
Sourcepub fn seed_task(&self, task: Task)
pub fn seed_task(&self, task: Task)
Give a project a task, so a fixture can read one back rather than answering with an empty list a reader cannot tell from a missing field.
Sourcepub fn emit_and_report(&self, update: SessionUpdate) -> bool
pub fn emit_and_report(&self, update: SessionUpdate) -> bool
Self::emit, reporting whether a subscriber was there to take it.
false once nothing is listening, which is how a test tells a
subscription still attached from one that went with its socket.
Sourcepub fn park_slack_draft(&self, key: &SessionSlot, draft: SlackDraft)
pub fn park_slack_draft(&self, key: &SessionSlot, draft: SlackDraft)
Park a Slack draft on key as a blocked Slack call would, so a
transport test can answer it from the socket without a session agent
driving the tool. The draft’s own id is the one to answer.
Sourcepub fn subscriber_count(&self) -> usize
pub fn subscriber_count(&self) -> usize
How many subscribers are attached right now, the transport’s own fold included. A test that watches a socket’s subscription arrive and leave reads this rather than asking whether an emit landed: the fold makes every emit land, whether or not a client is there.
Sourcepub fn answering_count(&self) -> usize
pub fn answering_count(&self) -> usize
How many subscribers could answer a prompt right now. The role decides
whether the core parks a turn on a reply rather than resolving it
Cancelled, and nothing on the wire reports it - so a test that watches
a client declare answering reads this.
Sourcepub fn set_cli_version(&self, installed: Option<&str>, latest: Option<&str>)
pub fn set_cli_version(&self, installed: Option<&str>, latest: Option<&str>)
Hold a claude version snapshot, so a view test renders a version
line without a real claude --version and npm probe.
Sourcepub fn set_fatal_error(&self, error: AppError)
pub fn set_fatal_error(&self, error: AppError)
Hold the core’s last fatal, as the boot spawn’s failure records it, so a test can read the home’s encoding without a dying spawn.
Sourcepub fn set_user_preferences(&self, preferences: Value)
pub fn set_user_preferences(&self, preferences: Value)
Hold the CLI’s per-user preferences document, so a view test reads a preference of its own rather than the machine’s.
Sourcepub fn start(&self, org: &str, project: &str) -> Result<(), FixtureError>
pub fn start(&self, org: &str, project: &str) -> Result<(), FixtureError>
Give project a live lead session, registering the domain a spawn
would.
Sourcepub fn add_worker(
&self,
org: &str,
project: &str,
label: &str,
) -> Result<(), FixtureError>
pub fn add_worker( &self, org: &str, project: &str, label: &str, ) -> Result<(), FixtureError>
Put label under project as a worker that has run before: a
persisted row, so it is offered, plus a live entry, so it is not
asleep.
Sourcepub fn add_despawned_worker(
&self,
project: &str,
label: &str,
) -> Result<(), FixtureError>
pub fn add_despawned_worker( &self, project: &str, label: &str, ) -> Result<(), FixtureError>
A worker label with no live registry entry: the row a despawned worker leaves behind, which is drawn until the label is despawned.
The project’s directory has to exist for the label to be offered at
all - worker_row_can_start asks whether the tree it would start in
is there.
Sourcepub fn add_git_worker(
&self,
org: &str,
project: &str,
label: &str,
) -> Result<(), FixtureError>
pub fn add_git_worker( &self, org: &str, project: &str, label: &str, ) -> Result<(), FixtureError>
Self::add_worker for a worker spawned in a git repo, whose tree
is the worktree under the project rather than the project root.
The two reads differ, which is the whole point: a fixture that puts every worker in the project’s own tree cannot tell a per-seat read from a per-project one.
Sourcepub fn seed_transcript(
&self,
org: &str,
project: &str,
label: &str,
rows: &[&str],
) -> Result<(), FixtureError>
pub fn seed_transcript( &self, org: &str, project: &str, label: &str, rows: &[&str], ) -> Result<(), FixtureError>
Write a session’s transcript, where the CLI would have left it, and
register slot as the session that owns it. rows are the JSONL
lines themselves, so a fixture writes the wire shapes it means.
Sourcepub fn seed_asleep_transcript(
&self,
org: &str,
project: &str,
label: &str,
rows: &[&str],
) -> Result<(), FixtureError>
pub fn seed_asleep_transcript( &self, org: &str, project: &str, label: &str, rows: &[&str], ) -> Result<(), FixtureError>
Self::seed_transcript for a seat nothing is running behind: the id
lives in the store’s own row - which is what a wake resumes, and the
other place a transcript read is looked up by - and no live entry
names it.
Sourcefn write_transcript(
&self,
org: &str,
project: &str,
label: &str,
rows: &[&str],
) -> Result<SessionSlot, FixtureError>
fn write_transcript( &self, org: &str, project: &str, label: &str, rows: &[&str], ) -> Result<SessionSlot, FixtureError>
The row file at the path the CLI would have written it to, with the seat resolved; which of the two id sources names it is the caller’s.
Sourcepub fn hold_conversation(
&self,
state: &TransportState,
org: &str,
project: &str,
label: &str,
) -> Result<(), FixtureError>
pub fn hold_conversation( &self, state: &TransportState, org: &str, project: &str, label: &str, ) -> Result<(), FixtureError>
Hold the seat’s conversation on state, read from the transcript a
fixture just seeded.
This is the window a Connected carries, put there by hand: a
fixture that wants a seat to answer with a conversation the transport
is HANDED holds it this way, rather than leaning on the transport’s
own read of the file - which is a sleeping seat’s path, and firing it
here would make every held-window test pass through the other source.
So it reads the transcript RAW - the shape a Connected carries and a
resume answers with - and lets the conversation convert it. Not
through ViewSurface::conversation, which converts the task notices
on the way out: a fixture built on the converted shape would exercise
something production never seeds from, so a defect in the seed’s own
conversion could not be seen here.
Sourcepub fn install_agent(
&self,
org: &str,
project: &str,
label: &str,
) -> UnboundedReceiver<AgentCommand>
pub fn install_agent( &self, org: &str, project: &str, label: &str, ) -> UnboundedReceiver<AgentCommand>
Give slot a live agent, which is what makes a view treat the seat as
running rather than as one nothing is behind. A stub: nothing answers
the commands it is sent, and a caller that holds the receiver it hands
back reads what was asked.
Sourcepub fn park_terminal_hand_off(
&self,
slot: &SessionSlot,
terminal: u16,
) -> Result<String, String>
pub fn park_terminal_hand_off( &self, slot: &SessionSlot, terminal: u16, ) -> Result<String, String>
Park a terminal hand-off on slot as a blocked terminal__hand_off
call would, so a socket test can type through the hand-off’s door.
Sourcepub fn answer_terminal_hand_off(&self, id: &str, slot: &SessionSlot)
pub fn answer_terminal_hand_off(&self, id: &str, slot: &SessionSlot)
Answer that parked hand-off with Done, as the dock’s button would.
Sourcepub fn seed_queued_prompt(
&self,
slot: &SessionSlot,
uuid: &str,
source: PromptSource,
text: &str,
)
pub fn seed_queued_prompt( &self, slot: &SessionSlot, uuid: &str, source: PromptSource, text: &str, )
Put a prompt in a seat’s queue exactly as a dispatch leaves it: the row a client attaching mid-queue reads, with no dispatch to drive.
Sourcepub fn intercept_dispatch(&self)
pub fn intercept_dispatch(&self)
Catch every command the core is dispatched, so a test can assert what a view asked for without driving a session.
Sourcepub fn dispatched(&self) -> Vec<Command>
pub fn dispatched(&self) -> Vec<Command>
The commands caught since the last call.
Sourcepub fn fail_spawn(&self, org: &str, project: &str, label: &str, reason: &str)
pub fn fail_spawn(&self, org: &str, project: &str, label: &str, reason: &str)
Give slot the core’s own record of a spawn that failed, as the
connection-failure path leaves one.
Sourcepub fn seed_test_pending_interaction(
&self,
slot: &SessionSlot,
kind: PendingKind,
)
pub fn seed_test_pending_interaction( &self, slot: &SessionSlot, kind: PendingKind, )
Hold slot on a pending interaction, the way a session that has
asked a person for something reads.
Sourcepub fn clear_test_pending(&self, slot: &SessionSlot)
pub fn clear_test_pending(&self, slot: &SessionSlot)
Let go of everything parked on slot, which is the half of answering
that is the core’s.
Sourcepub fn await_login(&self, slot: &SessionSlot)
pub fn await_login(&self, slot: &SessionSlot)
Hold slot waiting to be let in, the way a session that cannot
authenticate reads.
Sourcepub fn add_starting_worker(
&self,
org: &str,
project: &str,
label: &str,
) -> Result<(), FixtureError>
pub fn add_starting_worker( &self, org: &str, project: &str, label: &str, ) -> Result<(), FixtureError>
Put label under project as a worker whose spawn has not
connected yet, so its row reads as starting rather than asleep.
Sourcepub fn seed_test_prompt_queue(
&self,
slot: &SessionSlot,
kind: PendingKind,
count: usize,
)
pub fn seed_test_prompt_queue( &self, slot: &SessionSlot, kind: PendingKind, count: usize, )
Hold slot on a queue of count unanswered prompts, so a view
test can render a depth a session holding several reads.
Sourcepub fn advertise(
&self,
slot: &SessionSlot,
commands: Vec<AvailableCommand>,
agents: Vec<AvailableAgent>,
)
pub fn advertise( &self, slot: &SessionSlot, commands: Vec<AvailableCommand>, agents: Vec<AvailableAgent>, )
Advertise commands and agents for slot, the way the CLI’s
init frame leaves them: what the composer’s / and & triggers
read.
Sourcepub fn add_task(
&self,
org: &str,
project: &str,
subject: &str,
owner: &str,
artifact: Option<&str>,
) -> Result<(), FixtureError>
pub fn add_task( &self, org: &str, project: &str, subject: &str, owner: &str, artifact: Option<&str>, ) -> Result<(), FixtureError>
Declare a task under project, held by the session labelled
owner, with artifact as what it produced.
Sourcepub fn add_cron(&self, project: &str, prompt: &str) -> Result<(), FixtureError>
pub fn add_cron(&self, project: &str, prompt: &str) -> Result<(), FixtureError>
Declare a durable cron under project, firing a day out so a view
renders it as a schedule rather than as an overdue one.
Sourcepub fn record_session(
&self,
project: &str,
session_id: &str,
) -> Result<(), FixtureError>
pub fn record_session( &self, project: &str, session_id: &str, ) -> Result<(), FixtureError>
Record a transcript row for project, as a session that ran and
ended would leave behind: a project whose session is gone but whose
history is not.
Sourcepub fn seed_view_facts(&self, slot: &SessionSlot, facts: ViewFacts)
pub fn seed_view_facts(&self, slot: &SessionSlot, facts: ViewFacts)
Hold facts on slot’s session, as the events that carry them
would: the header’s four, the MCP snapshot, the process walk, the
monitor set and the sub-agent attribution.
A field left out is a fact the session has not reported, which is its own state rather than an empty one.
fn project_view(&self, project: &str) -> Result<ProjectView, FixtureError>
Sourcefn project_key(&self, project: &str) -> Result<ProjectKey, FixtureError>
fn project_key(&self, project: &str) -> Result<ProjectKey, FixtureError>
The registry key for project.
The key is derived from the project’s PATH, and the derivation
canonicalises it, so the same project answers a different key before
and after its directory exists. in_dir writes the config without
creating the project directories, so a fixture that creates one itself
gets a key that moves under it: anything registered before it appeared
is registered under a key nothing looks up again, and the failure is
silent - an empty worker list rather than an error.
Auto Trait Implementations§
impl !RefUnwindSafe for Fleet
impl !UnwindSafe for Fleet
impl Freeze for Fleet
impl Send for Fleet
impl Sync for Fleet
impl Unpin for Fleet
impl UnsafeUnpin for Fleet
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