loopd: the memory block from memoryd, recall and memory as core tools
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
@@ -4,13 +4,13 @@
|
||||
|
||||
mod support;
|
||||
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::Path;
|
||||
use std::process::{Child, Command, Stdio};
|
||||
use std::time::Duration;
|
||||
|
||||
use loopd::baseline::Baseline;
|
||||
use loopd::broker_port::{not_configured_line, unavailable_line};
|
||||
use loopd::memory::{MemoryPort, MemorySource};
|
||||
use loopd::session::{Session, SessionError};
|
||||
use loopd::tools::Registry;
|
||||
use proto::SessionId;
|
||||
@@ -64,31 +64,37 @@ fn only_the_torn_error_points_at_the_damaged_log_entry() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_unreadable_core_memory_names_its_entry_and_a_missing_system_prompt_does_not() {
|
||||
fn memoryd_unreachable_or_refusing_names_the_memory_entry() {
|
||||
let home = Home::new();
|
||||
let cfg = home.config(Path::new("/tmp/unused.sock"));
|
||||
home.write("memory/core.md", "memory\n");
|
||||
let core = home.dir.join("memory/core.md");
|
||||
if !running_as_root() {
|
||||
std::fs::set_permissions(&core, std::fs::Permissions::from_mode(0o000)).unwrap();
|
||||
let result = Baseline::assemble(&cfg, &Registry::m3a());
|
||||
std::fs::set_permissions(&core, std::fs::Permissions::from_mode(0o644)).unwrap();
|
||||
let message = result.expect_err("unreadable core.md").to_string();
|
||||
assert!(message.contains("core.md"), "{message}");
|
||||
ends_with_pointer(&message, "see docs/runbook.md#core-memory-unreadable");
|
||||
}
|
||||
// The system prompt is a different file with a different remedy: no pointer to this entry.
|
||||
std::fs::remove_file(home.dir.join("system.md")).unwrap();
|
||||
let message = Baseline::assemble(&cfg, &Registry::m3a())
|
||||
.expect_err("no system.md")
|
||||
.to_string();
|
||||
assert!(!message.contains("core-memory-unreadable"), "{message}");
|
||||
}
|
||||
|
||||
fn running_as_root() -> bool {
|
||||
std::fs::read_to_string("/proc/self/status")
|
||||
.map(|s| s.lines().any(|l| l.starts_with("Uid:\t0\t")))
|
||||
.unwrap_or(false)
|
||||
let port = MemoryPort::new(
|
||||
home.dir.join("run/nobody/memory.sock"),
|
||||
Duration::from_secs(1),
|
||||
);
|
||||
let message = port.block().expect_err("nobody is listening");
|
||||
ends_with_pointer(&message, "see docs/runbook.md#memory-unavailable");
|
||||
// A refusal from memoryd itself (a file over its limit) ends with the same entry.
|
||||
let socket = home.dir.join("run/loop-memory/memory.sock");
|
||||
std::fs::create_dir_all(socket.parent().unwrap()).unwrap();
|
||||
let listener = std::os::unix::net::UnixListener::bind(&socket).unwrap();
|
||||
std::thread::spawn(move || {
|
||||
let (mut stream, _) = listener.accept().unwrap();
|
||||
let env = proto::read_frame(&mut stream).unwrap();
|
||||
let reply = proto::Envelope {
|
||||
v: 1,
|
||||
id: env.id,
|
||||
r#final: true,
|
||||
msg: proto::Message::Error(proto::WireError {
|
||||
code: proto::ErrorCode::Internal,
|
||||
detail: "memory/user.md: 1,376 characters; its limit is 1,375".to_string(),
|
||||
}),
|
||||
};
|
||||
proto::write_frame(&mut stream, &reply).unwrap();
|
||||
});
|
||||
let message = MemoryPort::new(socket, Duration::from_secs(5))
|
||||
.block()
|
||||
.expect_err("memoryd refused");
|
||||
assert!(message.contains("user.md: 1,376 characters"), "{message}");
|
||||
ends_with_pointer(&message, "see docs/runbook.md#memory-unavailable");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user