home-dirの整理

This commit is contained in:
2026-04-27 21:45:30 +09:00
parent 306b1cf942
commit 8658845b02
14 changed files with 635 additions and 260 deletions
+10 -10
View File
@@ -18,6 +18,8 @@
//! the user or overlay layers lay out their own paths:
//!
//! - user manifest: base = the directory holding the manifest file
//! (which is `manifest::paths::config_dir()` when loaded via the
//! `_auto` variant)
//! - project manifest: base = the **project root** (the parent of
//! `.insomnia/`, not `.insomnia/` itself) so that natural project
//! manifests with `target = "."` cover the whole workspace
@@ -29,7 +31,7 @@ use std::path::{Path, PathBuf};
use manifest::{
LayerLoadError, PodManifest, PodManifestConfig, ResolveError, find_project_manifest_from,
load_layer, user_manifest_path,
load_layer, paths,
};
use crate::prompt::loader::PromptLoader;
@@ -101,21 +103,19 @@ impl PodFactory {
Self::default()
}
/// Attempt to load the user manifest from the XDG config directory.
///
/// Looks at `$XDG_CONFIG_HOME/insomnia/manifest.toml` first, then
/// falls back to `$HOME/.config/insomnia/manifest.toml`. If neither
/// env var is set, or the resolved file does not exist, the call
/// is a no-op — user manifests are optional.
/// Attempt to load the user manifest from the user's config
/// directory (see [`manifest::paths::config_dir`] for how the path
/// is resolved). If the resolved file does not exist, the call is a
/// no-op — user manifests are optional.
pub fn with_user_manifest_auto(mut self) -> Result<Self, FactoryError> {
let Some(path) = user_manifest_path() else {
let Some(path) = paths::user_manifest_path() else {
return Ok(self);
};
if path.exists() {
let base = manifest_base(&path)?;
self.user = Some((load_layer(&path)?, base.clone()));
self.user_prompts_dir = Some(base.join("prompts"));
self.user_pack_file = Some(base.join("prompts.toml"));
self.user_prompts_dir = paths::user_prompts_dir();
self.user_pack_file = paths::user_pack_file();
}
Ok(self)
}
+12 -27
View File
@@ -2,6 +2,7 @@ use std::path::PathBuf;
use std::process::ExitCode;
use clap::Parser;
use manifest::paths;
use pod::{Pod, PodController, PodFactory};
use session_store::FsStore;
@@ -11,8 +12,8 @@ use session_store::FsStore;
about = "Spawn a Pod process from cascaded manifest layers"
)]
struct Cli {
/// User manifest TOML. Defaults to
/// `$XDG_CONFIG_HOME/insomnia/manifest.toml`.
/// User manifest TOML. Defaults to `<config_dir>/manifest.toml`
/// (see `manifest::paths`).
#[arg(long, value_name = "PATH")]
user_manifest: Option<PathBuf>,
@@ -28,7 +29,7 @@ struct Cli {
overlay: Option<String>,
/// Directory for session persistence. Defaults to
/// `~/.insomnia/sessions/`.
/// `<data_dir>/sessions/` (see `manifest::paths`).
#[arg(short, long)]
store: Option<PathBuf>,
@@ -44,25 +45,6 @@ struct Cli {
callback: Option<PathBuf>,
}
fn default_store_dir() -> Result<PathBuf, std::io::Error> {
let home = std::env::var("HOME")
.map_err(|_| std::io::Error::new(std::io::ErrorKind::NotFound, "HOME is not set"))?;
Ok(PathBuf::from(home).join(".insomnia").join("sessions"))
}
fn default_runtime_dir() -> Result<PathBuf, std::io::Error> {
if let Ok(runtime_dir) = std::env::var("XDG_RUNTIME_DIR") {
Ok(PathBuf::from(runtime_dir).join("insomnia"))
} else if let Ok(home) = std::env::var("HOME") {
Ok(PathBuf::from(home).join(".insomnia").join("run"))
} else {
Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"neither XDG_RUNTIME_DIR nor HOME is set",
))
}
}
async fn build_factory(cli: &Cli) -> Result<PodFactory, String> {
let mut factory = PodFactory::new();
@@ -115,7 +97,7 @@ async fn main() -> ExitCode {
// Initialize persistent store
let store_dir = cli.store.clone().unwrap_or_else(|| {
default_store_dir().unwrap_or_else(|_| PathBuf::from(".insomnia/sessions"))
paths::sessions_dir().unwrap_or_else(|| PathBuf::from(".insomnia/sessions"))
});
let store = match FsStore::new(&store_dir).await {
Ok(s) => s,
@@ -152,10 +134,13 @@ async fn main() -> ExitCode {
let pod_name = pod.manifest().pod.name.clone();
// Spawn the controller (starts socket server)
let runtime_base = match default_runtime_dir() {
Ok(d) => d,
Err(e) => {
eprintln!("error: {e}");
let runtime_base = match paths::runtime_dir() {
Some(d) => d,
None => {
eprintln!(
"error: could not resolve runtime directory \
(set INSOMNIA_HOME, INSOMNIA_RUNTIME_DIR, XDG_RUNTIME_DIR, or HOME)"
);
return ExitCode::FAILURE;
}
};
+13 -18
View File
@@ -1,7 +1,7 @@
use std::io;
use std::path::{Path, PathBuf};
use manifest::ScopeRule;
use manifest::{ScopeRule, paths};
use serde::{Deserialize, Serialize};
use tokio::fs;
@@ -28,7 +28,7 @@ pub struct SpawnedPodRecord {
/// Manages the Pod's runtime directory on tmpfs.
///
/// ```text
/// $XDG_RUNTIME_DIR/insomnia/{pod_name}/
/// <runtime_dir>/{pod_name}/
/// ├── pid
/// ├── status.json
/// ├── manifest.toml
@@ -36,6 +36,7 @@ pub struct SpawnedPodRecord {
/// └── sock (created by socket listener, not by RuntimeDir)
/// ```
///
/// `<runtime_dir>` is resolved via [`manifest::paths::runtime_dir`].
/// Files are written atomically (write tmp → rename).
/// The directory is removed on drop.
pub struct RuntimeDir {
@@ -54,10 +55,8 @@ impl RuntimeDir {
Ok(Self { path })
}
/// Create in the default base directory.
///
/// Uses `$XDG_RUNTIME_DIR/insomnia/` if available,
/// otherwise falls back to `~/.insomnia/run/`.
/// Create in the default base directory resolved via
/// [`manifest::paths::runtime_dir`].
pub async fn create_default(pod_name: &str) -> Result<Self, io::Error> {
let base = default_base()?;
Self::create(&base, pod_name).await
@@ -118,20 +117,16 @@ async fn atomic_write(target: &Path, content: &[u8]) -> Result<(), io::Error> {
/// Resolve the default base directory for runtime data.
///
/// Public so the scope-lock registry (which lives outside the
/// `RuntimeDir` instance lifecycle) can predict a Pod's socket path
/// without constructing a `RuntimeDir` first.
/// Thin wrapper over [`manifest::paths::runtime_dir`] that converts a
/// missing-env situation into an `io::Error`.
pub fn default_base() -> Result<PathBuf, io::Error> {
if let Ok(runtime_dir) = std::env::var("XDG_RUNTIME_DIR") {
Ok(PathBuf::from(runtime_dir).join("insomnia"))
} else if let Ok(home) = std::env::var("HOME") {
Ok(PathBuf::from(home).join(".insomnia").join("run"))
} else {
Err(io::Error::new(
paths::runtime_dir().ok_or_else(|| {
io::Error::new(
io::ErrorKind::NotFound,
"neither XDG_RUNTIME_DIR nor HOME is set",
))
}
"could not resolve runtime directory (no INSOMNIA_HOME / \
INSOMNIA_RUNTIME_DIR / XDG_RUNTIME_DIR / HOME)",
)
})
}
#[cfg(test)]
+72 -48
View File
@@ -1,9 +1,9 @@
//! Machine-wide scope allocation registry.
//!
//! A single JSON file at `$XDG_RUNTIME_DIR/insomnia/scope.lock` records
//! every live Pod's scope allocation. File-level `flock(2)` serialises
//! access across processes so spawn sequences from unrelated Pods can't
//! race.
//! A single JSON file at `<runtime_dir>/scope.lock` records every live
//! Pod's scope allocation (see [`manifest::paths::scope_lock_path`] for
//! how the path is resolved). File-level `flock(2)` serialises access
//! across processes so spawn sequences from unrelated Pods can't race.
//!
//! Each Pod, when starting, acquires the lock, reclaims stale entries
//! (Pods whose PID has died), checks that its requested write scope
@@ -19,7 +19,7 @@ use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt};
use std::path::{Path, PathBuf};
use fs4::fs_std::FileExt;
use manifest::{Permission, ScopeRule};
use manifest::{Permission, ScopeRule, paths};
use serde::{Deserialize, Serialize};
/// On-disk representation of the allocation table.
@@ -62,27 +62,18 @@ impl LockFile {
}
}
/// Default on-disk path: `$XDG_RUNTIME_DIR/insomnia/scope.lock`,
/// falling back to `~/.insomnia/run/scope.lock` when XDG is unset.
///
/// Honours `INSOMNIA_SCOPE_LOCK` as an explicit override, primarily so
/// tests can point at a tempdir without polluting the user's runtime
/// directory.
/// Default on-disk path: `<runtime_dir>/scope.lock` resolved via
/// [`manifest::paths::scope_lock_path`]. Tests should point this
/// elsewhere by setting `INSOMNIA_HOME` or `INSOMNIA_RUNTIME_DIR` to a
/// tempdir.
pub fn default_lock_path() -> io::Result<PathBuf> {
if let Ok(custom) = std::env::var("INSOMNIA_SCOPE_LOCK") {
return Ok(PathBuf::from(custom));
}
let base = if let Ok(dir) = std::env::var("XDG_RUNTIME_DIR") {
PathBuf::from(dir).join("insomnia")
} else if let Ok(home) = std::env::var("HOME") {
PathBuf::from(home).join(".insomnia").join("run")
} else {
return Err(io::Error::new(
paths::scope_lock_path().ok_or_else(|| {
io::Error::new(
io::ErrorKind::NotFound,
"neither XDG_RUNTIME_DIR nor HOME is set",
));
};
Ok(base.join("scope.lock"))
"could not resolve scope.lock path (no INSOMNIA_HOME / \
INSOMNIA_RUNTIME_DIR / XDG_RUNTIME_DIR / HOME)",
)
})
}
/// RAII guard over an exclusively-locked lock file.
@@ -555,15 +546,67 @@ pub enum ScopeLockError {
mod tests {
use super::*;
use manifest::Permission;
use std::sync::{LazyLock, Mutex};
use std::sync::{LazyLock, Mutex, MutexGuard};
use tempfile::TempDir;
/// Serialises tests that mutate `INSOMNIA_SCOPE_LOCK`. The test
/// Serialises tests that mutate runtime-dir env vars. The test
/// harness runs tests on multiple threads inside a single process,
/// so env-var writes from one test would otherwise leak into a
/// parallel test's `default_lock_path()` lookup.
static ENV_LOCK: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
/// Sandbox `INSOMNIA_RUNTIME_DIR` to a tempdir for the duration of
/// a test; restore the previous value (and any `INSOMNIA_HOME` /
/// `XDG_RUNTIME_DIR` that would otherwise outrank it) on drop.
struct RuntimeDirSandbox {
prev_runtime: Option<String>,
prev_home: Option<String>,
prev_xdg: Option<String>,
_guard: MutexGuard<'static, ()>,
}
impl RuntimeDirSandbox {
fn new(dir: &Path) -> Self {
let guard = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let prev_runtime = std::env::var("INSOMNIA_RUNTIME_DIR").ok();
let prev_home = std::env::var("INSOMNIA_HOME").ok();
let prev_xdg = std::env::var("XDG_RUNTIME_DIR").ok();
// SAFETY: ENV_LOCK serialises env writes across this test
// module; other modules that touch env vars rely on their
// own lock or `serial_test`.
unsafe {
std::env::remove_var("INSOMNIA_HOME");
std::env::remove_var("XDG_RUNTIME_DIR");
std::env::set_var("INSOMNIA_RUNTIME_DIR", dir);
}
Self {
prev_runtime,
prev_home,
prev_xdg,
_guard: guard,
}
}
}
impl Drop for RuntimeDirSandbox {
fn drop(&mut self) {
unsafe {
match &self.prev_runtime {
Some(v) => std::env::set_var("INSOMNIA_RUNTIME_DIR", v),
None => std::env::remove_var("INSOMNIA_RUNTIME_DIR"),
}
match &self.prev_home {
Some(v) => std::env::set_var("INSOMNIA_HOME", v),
None => std::env::remove_var("INSOMNIA_HOME"),
}
match &self.prev_xdg {
Some(v) => std::env::set_var("XDG_RUNTIME_DIR", v),
None => std::env::remove_var("XDG_RUNTIME_DIR"),
}
}
}
}
fn write_rule(path: &str, recursive: bool) -> ScopeRule {
ScopeRule {
target: PathBuf::from(path),
@@ -977,12 +1020,9 @@ mod tests {
#[test]
fn scope_allocation_guard_releases_on_drop() {
let _env = ENV_LOCK.lock().unwrap();
let dir = TempDir::new().unwrap();
let _sandbox = RuntimeDirSandbox::new(dir.path());
let lock_path = dir.path().join("scope.lock");
unsafe {
std::env::set_var("INSOMNIA_SCOPE_LOCK", &lock_path);
}
let guard = install_top_level(
"a".into(),
std::process::id(),
@@ -999,19 +1039,13 @@ mod tests {
let g = LockFileGuard::open(&lock_path).unwrap();
assert!(g.data().find("a").is_none());
}
unsafe {
std::env::remove_var("INSOMNIA_SCOPE_LOCK");
}
}
#[test]
fn adopt_allocation_rewrites_pid_and_releases_on_drop() {
let _env = ENV_LOCK.lock().unwrap();
let dir = TempDir::new().unwrap();
let _sandbox = RuntimeDirSandbox::new(dir.path());
let lock_path = dir.path().join("scope.lock");
unsafe {
std::env::set_var("INSOMNIA_SCOPE_LOCK", &lock_path);
}
// Pre-register an allocation under spawner's pid, as delegate_scope would.
{
let mut g = LockFileGuard::open(&lock_path).unwrap();
@@ -1029,24 +1063,14 @@ mod tests {
let g = LockFileGuard::open(&lock_path).unwrap();
assert!(g.data().find("child").is_none());
}
unsafe {
std::env::remove_var("INSOMNIA_SCOPE_LOCK");
}
}
#[test]
fn adopt_allocation_errors_on_unknown_pod() {
let _env = ENV_LOCK.lock().unwrap();
let dir = TempDir::new().unwrap();
let lock_path = dir.path().join("scope.lock");
unsafe {
std::env::set_var("INSOMNIA_SCOPE_LOCK", &lock_path);
}
let _sandbox = RuntimeDirSandbox::new(dir.path());
let err = adopt_allocation("ghost".into(), 42).unwrap_err();
assert!(matches!(err, ScopeLockError::UnknownPod(ref n) if n == "ghost"));
unsafe {
std::env::remove_var("INSOMNIA_SCOPE_LOCK");
}
}
/// Mimic what the spawner does before the child comes up: push an
+35 -14
View File
@@ -28,17 +28,47 @@ use tokio::net::UnixListener;
use tokio::task::JoinHandle;
/// Serialises env-mutating tests. The test harness runs tasks across
/// threads, and `INSOMNIA_SCOPE_LOCK` is a process-wide resource.
/// threads, and `INSOMNIA_RUNTIME_DIR` is a process-wide resource.
static ENV_LOCK: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
/// Take `ENV_LOCK` and clear any env vars that would outrank
/// `INSOMNIA_RUNTIME_DIR` in `paths::runtime_dir` resolution; restore
/// previous values on drop.
struct EnvGuard {
prev_home: Option<String>,
prev_xdg: Option<String>,
_lock: std::sync::MutexGuard<'static, ()>,
}
impl EnvGuard {
fn acquire() -> Self {
let lock = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let prev_home = std::env::var("INSOMNIA_HOME").ok();
let prev_xdg = std::env::var("XDG_RUNTIME_DIR").ok();
unsafe {
std::env::remove_var("INSOMNIA_HOME");
std::env::remove_var("XDG_RUNTIME_DIR");
}
Self {
_lock: ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner()),
prev_home,
prev_xdg,
_lock: lock,
}
}
}
impl Drop for EnvGuard {
fn drop(&mut self) {
unsafe {
match &self.prev_home {
Some(v) => std::env::set_var("INSOMNIA_HOME", v),
None => std::env::remove_var("INSOMNIA_HOME"),
}
match &self.prev_xdg {
Some(v) => std::env::set_var("XDG_RUNTIME_DIR", v),
None => std::env::remove_var("XDG_RUNTIME_DIR"),
}
std::env::remove_var("INSOMNIA_RUNTIME_DIR");
}
}
}
@@ -293,10 +323,10 @@ async fn read_pod_output_reports_stopped_on_dead_socket() {
async fn stop_pod_sends_shutdown_and_releases_scope() {
let _env = EnvGuard::acquire();
let (tmp, registry, rd) = setup_registry().await;
let lock_path = tmp.path().join("scope.lock");
unsafe {
std::env::set_var("INSOMNIA_SCOPE_LOCK", &lock_path);
std::env::set_var("INSOMNIA_RUNTIME_DIR", tmp.path());
}
let lock_path = tmp.path().join("scope.lock");
// Seed scope.lock with a top-level `spawner` allocation plus a
// delegated `child` allocation — mimics what SpawnPod would have
@@ -356,19 +386,14 @@ async fn stop_pod_sends_shutdown_and_releases_scope() {
let contents = std::fs::read_to_string(&spawned).unwrap();
let records: Vec<SpawnedPodRecord> = serde_json::from_str(&contents).unwrap();
assert!(records.is_empty());
unsafe {
std::env::remove_var("INSOMNIA_SCOPE_LOCK");
}
}
#[tokio::test]
async fn stop_pod_succeeds_even_when_child_unreachable() {
let _env = EnvGuard::acquire();
let (tmp, registry, _rd) = setup_registry().await;
let lock_path = tmp.path().join("scope.lock");
unsafe {
std::env::set_var("INSOMNIA_SCOPE_LOCK", &lock_path);
std::env::set_var("INSOMNIA_RUNTIME_DIR", tmp.path());
}
// No live listener — socket never bound. Registered record points
@@ -384,10 +409,6 @@ async fn stop_pod_succeeds_even_when_child_unreachable() {
// Registry no longer knows about the child.
assert!(registry.get("child").await.is_none());
unsafe {
std::env::remove_var("INSOMNIA_SCOPE_LOCK");
}
}
// ---------------------------------------------------------------------------
+48 -17
View File
@@ -18,30 +18,61 @@ use protocol::{Method, Permission, PodEvent, ScopeRule};
use tempfile::TempDir;
use tokio::net::UnixListener;
/// Serialises tests that mutate `INSOMNIA_SCOPE_LOCK`.
/// Serialises tests that mutate `INSOMNIA_RUNTIME_DIR`.
static ENV_LOCK: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
/// Take `ENV_LOCK` and clear any env vars that would outrank
/// `INSOMNIA_RUNTIME_DIR`; restore previous values on drop.
struct EnvGuard {
prev_home: Option<String>,
prev_xdg: Option<String>,
_lock: std::sync::MutexGuard<'static, ()>,
}
impl EnvGuard {
fn acquire() -> Self {
let lock = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let prev_home = std::env::var("INSOMNIA_HOME").ok();
let prev_xdg = std::env::var("XDG_RUNTIME_DIR").ok();
unsafe {
std::env::remove_var("INSOMNIA_HOME");
std::env::remove_var("XDG_RUNTIME_DIR");
}
Self {
_lock: ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner()),
prev_home,
prev_xdg,
_lock: lock,
}
}
}
fn set_scope_lock_path(path: &std::path::Path) {
unsafe {
std::env::set_var("INSOMNIA_SCOPE_LOCK", path);
impl Drop for EnvGuard {
fn drop(&mut self) {
unsafe {
match &self.prev_home {
Some(v) => std::env::set_var("INSOMNIA_HOME", v),
None => std::env::remove_var("INSOMNIA_HOME"),
}
match &self.prev_xdg {
Some(v) => std::env::set_var("XDG_RUNTIME_DIR", v),
None => std::env::remove_var("XDG_RUNTIME_DIR"),
}
std::env::remove_var("INSOMNIA_RUNTIME_DIR");
}
}
}
fn clear_scope_lock_path() {
/// Point `INSOMNIA_RUNTIME_DIR` at `dir`. The scope-lock then lives at
/// `<dir>/scope.lock` and Pod runtime sub-dirs at `<dir>/{pod_name}/`.
fn set_runtime_dir(dir: &std::path::Path) {
unsafe {
std::env::remove_var("INSOMNIA_SCOPE_LOCK");
std::env::set_var("INSOMNIA_RUNTIME_DIR", dir);
}
}
fn clear_runtime_dir() {
unsafe {
std::env::remove_var("INSOMNIA_RUNTIME_DIR");
}
}
@@ -133,7 +164,7 @@ async fn fresh_registry(runtime_base: &std::path::Path, pod_name: &str) -> Arc<S
async fn apply_shutdown_removes_from_registry_and_tolerates_missing() {
let _env = EnvGuard::acquire();
let scope_dir = TempDir::new().unwrap();
set_scope_lock_path(&scope_dir.path().join("scope.lock"));
set_runtime_dir(scope_dir.path());
let runtime_base = TempDir::new().unwrap();
let registry = fresh_registry(runtime_base.path(), "parent").await;
@@ -161,14 +192,14 @@ async fn apply_shutdown_removes_from_registry_and_tolerates_missing() {
apply_event_side_effects(&event, &registry, "parent", &None).await;
assert!(registry.get("child").await.is_none());
clear_scope_lock_path();
clear_runtime_dir();
}
#[tokio::test]
async fn apply_scope_sub_delegated_adds_grandchild_then_duplicate_is_noop() {
let _env = EnvGuard::acquire();
let scope_dir = TempDir::new().unwrap();
set_scope_lock_path(&scope_dir.path().join("scope.lock"));
set_runtime_dir(scope_dir.path());
let runtime_base = TempDir::new().unwrap();
let registry = fresh_registry(runtime_base.path(), "grandparent").await;
@@ -208,14 +239,14 @@ async fn apply_scope_sub_delegated_adds_grandchild_then_duplicate_is_noop() {
let gc2 = registry.get("grandchild").await.unwrap();
assert_eq!(gc2.socket_path, PathBuf::from("/tmp/grandchild.sock"));
clear_scope_lock_path();
clear_runtime_dir();
}
#[tokio::test]
async fn apply_scope_sub_delegated_reemits_to_own_parent() {
let _env = EnvGuard::acquire();
let scope_dir = TempDir::new().unwrap();
set_scope_lock_path(&scope_dir.path().join("scope.lock"));
set_runtime_dir(scope_dir.path());
let runtime_base = TempDir::new().unwrap();
let registry = fresh_registry(runtime_base.path(), "B").await;
@@ -268,14 +299,14 @@ async fn apply_scope_sub_delegated_reemits_to_own_parent() {
other => panic!("expected re-emitted ScopeSubDelegated, got {other:?}"),
}
clear_scope_lock_path();
clear_runtime_dir();
}
#[tokio::test]
async fn apply_turn_ended_and_errored_are_system_noops() {
let _env = EnvGuard::acquire();
let scope_dir = TempDir::new().unwrap();
set_scope_lock_path(&scope_dir.path().join("scope.lock"));
set_runtime_dir(scope_dir.path());
let runtime_base = TempDir::new().unwrap();
let registry = fresh_registry(runtime_base.path(), "parent").await;
@@ -312,7 +343,7 @@ async fn apply_turn_ended_and_errored_are_system_noops() {
.await;
assert!(registry.get("child").await.is_some());
clear_scope_lock_path();
clear_runtime_dir();
}
#[tokio::test]
@@ -320,7 +351,7 @@ async fn shutdown_releases_scope_allocation_when_present() {
let _env = EnvGuard::acquire();
let scope_dir = TempDir::new().unwrap();
let lock_path = scope_dir.path().join("scope.lock");
set_scope_lock_path(&lock_path);
set_runtime_dir(scope_dir.path());
// Install a top-level allocation for "kid" so ShutDown has
// something to release.
@@ -362,5 +393,5 @@ async fn shutdown_releases_scope_allocation_when_present() {
"ShutDown should have released the scope allocation"
);
clear_scope_lock_path();
clear_runtime_dir();
}
+14 -10
View File
@@ -23,7 +23,7 @@ use std::sync::Arc;
use tempfile::TempDir;
use tokio::net::UnixListener;
/// Serialises tests that mutate `INSOMNIA_SCOPE_LOCK` /
/// Serialises tests that mutate `INSOMNIA_RUNTIME_DIR` /
/// `INSOMNIA_POD_COMMAND` across the thread-pooled test harness.
static ENV_LOCK: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
@@ -39,22 +39,26 @@ impl EnvGuard {
}
}
/// Set up a tempdir, point `INSOMNIA_SCOPE_LOCK` + runtime-dir base at
/// it, and install a live top-level "spawner" allocation so the tool
/// has something to delegate from. Returns the tempdir (keeps it alive
/// for the test's lifetime), runtime base, spawner socket, and the
/// spawner's runtime dir.
/// Set up a tempdir, point `INSOMNIA_RUNTIME_DIR` at it (so
/// `scope.lock` and per-Pod runtime subdirs both land in the
/// sandbox), and install a live top-level "spawner" allocation so the
/// tool has something to delegate from. Returns the tempdir (keeps it
/// alive for the test's lifetime), runtime base, spawner socket, and
/// the spawner's runtime dir.
async fn setup_spawner(
spawner_name: &str,
allow_root: &Path,
) -> (TempDir, PathBuf, PathBuf, Arc<RuntimeDir>) {
let tmp = TempDir::new().unwrap();
let lock_path = tmp.path().join("scope.lock");
let runtime_base = tmp.path().to_path_buf();
unsafe {
std::env::set_var("INSOMNIA_SCOPE_LOCK", &lock_path);
// Outranking env vars must be cleared so `paths::runtime_dir`
// resolves to our sandbox instead of the developer's real one.
std::env::remove_var("INSOMNIA_HOME");
std::env::remove_var("XDG_RUNTIME_DIR");
std::env::set_var("INSOMNIA_RUNTIME_DIR", &runtime_base);
}
let runtime_base = tmp.path().join("runtime");
let spawner_rd = RuntimeDir::create(&runtime_base, spawner_name)
.await
.unwrap();
@@ -148,7 +152,7 @@ fn dummy_model() -> ModelManifest {
fn clear_env() {
unsafe {
std::env::remove_var("INSOMNIA_SCOPE_LOCK");
std::env::remove_var("INSOMNIA_RUNTIME_DIR");
std::env::remove_var("INSOMNIA_POD_COMMAND");
}
}