Trim the harness to what it needs to keep going
Host: - test first: a new version is tested where it lies; only an installed version goes to versions/, and instances run from there - data/ and public/ are shared by all versions; no snapshots; rollback restores code only - no re-delivery, status.json, list, remove/archive, smoke test, data/ hiding, or stdin timeout; rollback needs a version - supervisor.rs split out; one place for installing a version - init only writes the agent folder; run installs it like any actor - console: @actor, text to the agent, /help, /quit Agent: - every text goes out as a broadcast; 5-line prompt; 5 tools that describe themselves; turn.json only marks an active turn Docs: PROTOCOL.md, README.md, DECISIONS.md, AGENTS.md rewritten. Examples: only notes and notes-v2.
This commit is contained in:
+11
-39
@@ -18,8 +18,8 @@
|
||||
//! also go to that recipient.
|
||||
//!
|
||||
//! Each file runs in a fresh instance on a copy of the actor's `/data` and
|
||||
//! `/public` (empty folders for a new actor). The candidate has no HTTP access. Without test files, the
|
||||
//! candidate must start and stay up for `SMOKE_TIME`.
|
||||
//! `/public` (empty folders for a new actor), without HTTP. A version
|
||||
//! without test files passes.
|
||||
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
@@ -33,7 +33,6 @@ use crate::fs::Mount;
|
||||
use crate::runtime::{Instance, InstanceConfig};
|
||||
use crate::world;
|
||||
|
||||
const SMOKE_TIME: Duration = Duration::from_secs(2);
|
||||
const EXPECT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
|
||||
/// `expected` matches `actual` if every key of an expected object exists in
|
||||
@@ -66,50 +65,22 @@ fn stderr_tail(path: &Path) -> String {
|
||||
text[s..].to_string()
|
||||
}
|
||||
|
||||
/// The version under test and the state that its tests start from.
|
||||
/// The version under test, which starts from a copy of the actor's state.
|
||||
struct Candidate<'a> {
|
||||
broker: &'a Broker,
|
||||
id: &'a str,
|
||||
version: u64,
|
||||
component: &'a Component,
|
||||
data: &'a Path,
|
||||
public: &'a Path,
|
||||
}
|
||||
|
||||
pub async fn test(
|
||||
broker: &Broker,
|
||||
id: &str,
|
||||
version: u64,
|
||||
component: &Component,
|
||||
source: &Path,
|
||||
data: &Path,
|
||||
public: &Path,
|
||||
) -> Result<Value> {
|
||||
let candidate = Candidate { broker, id, version, component, data, public };
|
||||
/// Run every test file of `<source>/tests/`.
|
||||
pub async fn test(broker: &Broker, id: &str, version: u64, component: &Component, source: Option<&Path>) -> Result<Value> {
|
||||
let candidate = Candidate { broker, id, version, component };
|
||||
let Some(source) = source else { return Ok(json!({"passed": []})) };
|
||||
let mut files: Vec<_> = std::fs::read_dir(source.join("tests"))
|
||||
.map(|rd| {
|
||||
rd.filter_map(|e| e.ok())
|
||||
.map(|e| e.path())
|
||||
.filter(|p| p.extension().is_some_and(|x| x == "json"))
|
||||
.collect()
|
||||
})
|
||||
.map(|rd| rd.filter_map(|e| Some(e.ok()?.path())).filter(|p| p.extension().is_some_and(|x| x == "json")).collect())
|
||||
.unwrap_or_default();
|
||||
files.sort();
|
||||
|
||||
if files.is_empty() {
|
||||
let (mut inst, scratch) = candidate.start()?;
|
||||
tokio::time::sleep(SMOKE_TIME).await;
|
||||
if inst.is_finished() {
|
||||
let exit = inst.wait().await;
|
||||
bail!(
|
||||
"candidate ended during the smoke test ({exit}). stderr:\n{}",
|
||||
stderr_tail(&scratch.dir.join("stderr.log"))
|
||||
);
|
||||
}
|
||||
inst.stop(&shutdown_line(), SHUTDOWN_DEADLINE, |_| {}).await;
|
||||
return Ok(json!({"smoke_test": "passed", "files": 0}));
|
||||
}
|
||||
|
||||
let mut passed = Vec::new();
|
||||
for file in &files {
|
||||
let name = file.file_name().unwrap().to_string_lossy().to_string();
|
||||
@@ -126,10 +97,11 @@ impl Candidate<'_> {
|
||||
let n = N.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
let dir = self.broker.world.scratch_dir().join(format!("{}-{}-{n}", self.id, std::process::id()));
|
||||
let scratch = Scratch { dir: dir.clone() };
|
||||
for (from, name) in [(self.data, "data"), (self.public, "public")] {
|
||||
let world = &self.broker.world;
|
||||
for (from, name) in [(world.data_dir(self.id), "data"), (world.public_dir(self.id), "public")] {
|
||||
std::fs::create_dir_all(dir.join(name))?;
|
||||
if from.is_dir() {
|
||||
world::copy_tree(from, &dir.join(name))?;
|
||||
world::copy_tree(&from, &dir.join(name))?;
|
||||
}
|
||||
}
|
||||
let cfg = InstanceConfig {
|
||||
|
||||
Reference in New Issue
Block a user