Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/nexum-module-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,17 +432,20 @@ mod tests {
#[test]
fn empty_subscribes_is_rejected() {
let err = parse_args(quote! { subscribes() }).err().unwrap();
// Foreign syn::Error; pins our macro message.
assert!(err.to_string().contains("at least one event type"), "{err}");
}

#[test]
fn unknown_argument_is_rejected() {
let err = parse_args(quote! { emits(Foo) }).err().unwrap();
// Foreign syn::Error; pins our macro message.
assert!(
err.to_string().contains("subscribes(EventType, ...)"),
"{err}"
);
let err = parse_args(quote! { subscribes(Foo), extra }).err().unwrap();
// Foreign syn::Error; pins our macro message.
assert!(err.to_string().contains("unexpected tokens"), "{err}");
}

Expand Down
5 changes: 4 additions & 1 deletion crates/nexum-runtime/src/addons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ impl RuntimeAddOn for PrometheusAddOn {
mod tests {
use super::*;
use crate::engine_config::MetricsSection;
use crate::test_utils::Refusal;

/// An enabled exporter with an unparseable bind address fails at install.
#[test]
Expand All @@ -103,6 +104,8 @@ mod tests {
Ok(_) => panic!("invalid bind_addr must not install"),
Err(err) => err,
};
assert!(err.to_string().contains("bind_addr"), "{err}");
Refusal::from(err).variant::<PrometheusError>(
|e| matches!(e, PrometheusError::BindAddr { addr, .. } if addr == "not-a-socket-addr"),
);
}
}
31 changes: 17 additions & 14 deletions crates/nexum-runtime/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -676,9 +676,12 @@ mod tests {
use crate::host::state::HostState;
use crate::manifest::NamespaceCaps;
use crate::preset::{CoreRuntime, Runtime as RuntimePreset};
use crate::supervisor::prepass::BootRefusal;
use crate::test_utils::clock::ManualClock;
use crate::test_utils::wasm::workspace_root;
use crate::test_utils::{Prebuilt, TestManifest, example_wasm_or_skip, module_wasm_or_skip};
use crate::test_utils::{
Prebuilt, Refusal, TestManifest, example_wasm_or_skip, module_wasm_or_skip,
};
use wasmtime::component::Linker;

/// The preset shortcut reaches the supervisor boot, which bails on the
Expand All @@ -697,7 +700,7 @@ mod tests {
Ok(_) => panic!("default config declares no modules; launch must bail"),
Err(err) => err,
};
assert!(err.to_string().contains("no modules to run"), "{err}");
Refusal::from(err).variant::<LaunchRefusal>(|e| matches!(e, LaunchRefusal::NothingToRun));
}

/// Counts linker hook runs.
Expand Down Expand Up @@ -779,7 +782,7 @@ mod tests {
Ok(_) => panic!("default config declares no modules; launch must bail"),
Err(err) => err,
};
assert!(err.to_string().contains("no modules to run"), "{err}");
Refusal::from(err).variant::<LaunchRefusal>(|e| matches!(e, LaunchRefusal::NothingToRun));
assert_eq!(preset_linked.load(Ordering::SeqCst), 1, "preset extension");
assert_eq!(
appended_linked.load(Ordering::SeqCst),
Expand Down Expand Up @@ -839,7 +842,7 @@ mod tests {
Ok(_) => panic!("default config declares no modules; launch must bail"),
Err(err) => err,
};
assert!(err.to_string().contains("no modules to run"), "{err}");
Refusal::from(err).variant::<LaunchRefusal>(|e| matches!(e, LaunchRefusal::NothingToRun));
seen.get().expect("clock attached before boot").clone()
}

Expand Down Expand Up @@ -979,7 +982,7 @@ mod tests {
Ok(_) => panic!("default config declares no modules; launch must bail"),
Err(err) => err,
};
assert!(err.to_string().contains("no modules to run"), "{err}");
Refusal::from(err).variant::<LaunchRefusal>(|e| matches!(e, LaunchRefusal::NothingToRun));
assert_eq!(
built.load(Ordering::SeqCst),
1,
Expand Down Expand Up @@ -1059,7 +1062,9 @@ mod tests {
Ok(_) => panic!("init-failing module must abort launch"),
Err(err) => err,
};
assert!(err.to_string().contains("failed initialisation"), "{err}");
Refusal::from(err).variant::<LaunchRefusal>(|e| {
matches!(e, LaunchRefusal::AllDeadOverride { modules: 1 })
});
}

#[tokio::test]
Expand Down Expand Up @@ -1091,12 +1096,10 @@ mod tests {
Ok(_) => panic!("an unconfigured chain subscription must abort launch"),
Err(err) => err,
};
let msg = format!("{err:#}");
assert!(
msg.contains("module example subscribes to chain 424242")
&& msg.contains("[chains.424242]"),
"the launch error is the boot-time chain refusal: {msg}",
);
Refusal::from(err).variant::<BootRefusal>(|e| {
matches!(e, BootRefusal::UnconfiguredChain { noun: "module", name, chain_id: 424_242, .. }
if name == "example")
});
}

/// Add-ons install before the supervisor boots, exactly once.
Expand Down Expand Up @@ -1145,7 +1148,7 @@ mod tests {
Ok(_) => panic!("no modules configured; launch must bail"),
Err(err) => err,
};
assert!(err.to_string().contains("no modules to run"), "{err}");
Refusal::from(err).variant::<LaunchRefusal>(|e| matches!(e, LaunchRefusal::NothingToRun));
assert_eq!(
calls.load(Ordering::SeqCst),
1,
Expand Down Expand Up @@ -1236,7 +1239,7 @@ mod tests {
.wait()
.await
.expect_err("aborted task surfaces an error");
assert!(err.to_string().contains("terminated abnormally"), "{err}");
Refusal::from(err).variant::<LaunchRefusal>(|e| matches!(e, LaunchRefusal::EventLoopGone));
}

/// Dropping the handle without `wait` still drains the event loop.
Expand Down
1 change: 1 addition & 0 deletions crates/nexum-runtime/src/digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ mod tests {
actual,
};
let msg = err.to_string();
// Operator wording pin.
assert!(msg.contains("modules/example.wasm"), "{msg}");
assert!(msg.contains(&declared.to_string()), "{msg}");
assert!(msg.contains(&actual.to_string()), "{msg}");
Expand Down
12 changes: 8 additions & 4 deletions crates/nexum-runtime/src/engine_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,7 @@ request_timeout_secs = 0
"#,
)
.expect_err("a zero timeout must not parse");
// Foreign toml::de::Error; pins our serde message threaded through it.
assert!(
err.to_string()
.contains("request_timeout_secs must not be 0"),
Expand All @@ -854,7 +855,8 @@ rpc_url = "wss://example.test/x"
"#,
)
.expect_err("bogus chain key must not parse");
assert!(!err.to_string().is_empty());
// Foreign toml::de::Error; pins that it names the offending key.
assert!(err.to_string().contains("bogus"), "{err}");
}

#[test]
Expand Down Expand Up @@ -1337,9 +1339,11 @@ key = "value"
// environment. Use a guaranteed-unique prefix.
let err =
substitute_env_vars(r#"x = "${NEXUM_TEST_DEFINITELY_UNSET_VAR_XYZ}""#).unwrap_err();
let msg = err.to_string();
assert!(msg.contains("NEXUM_TEST_DEFINITELY_UNSET_VAR_XYZ"));
assert!(msg.contains("not set"));
assert!(
matches!(&err, EnvVarError::Missing { name }
if name == "NEXUM_TEST_DEFINITELY_UNSET_VAR_XYZ"),
"{err}"
);
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion crates/nexum-runtime/src/host/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,6 @@ mod tests {
ext("acme", Arc::new(Clockwork)),
])
.expect_err("duplicate namespace");
assert!(err.to_string().contains("acme"), "{err}");
assert_eq!(err.namespace, "acme");
}
}
3 changes: 3 additions & 0 deletions crates/nexum-runtime/src/manifest/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ event_signature = "0x00000000000000000000000000000000000000000000000000000000dea
chain_id = 1\n{field}\n"
);
let err = toml::from_str::<Manifest>(&toml).expect_err("malformed hex");
// Foreign toml::de::Error; pins our hex message threaded through it.
assert!(err.to_string().contains(detail), "{err}");
}
}
Expand Down Expand Up @@ -322,6 +323,7 @@ kind = "acme-status"
scope = 7
"#;
let err = toml::from_str::<Manifest>(toml).expect_err("non-string filter");
// Foreign toml::de::Error; pins our filter message threaded through it.
assert!(err.to_string().contains("must be a string"), "{err}");
}

Expand Down Expand Up @@ -588,6 +590,7 @@ max_state_bytes = 52428800
let err = load(&path, &CapabilityRegistry::core()).unwrap_err();
assert!(matches!(err, ParseError::MissingCapabilities), "{err:?}");
let msg = err.to_string();
// Operator wording pin.
assert!(msg.contains("[capabilities]"), "{msg}");
assert!(msg.contains("required = []"), "{msg}");
}
Expand Down
2 changes: 1 addition & 1 deletion crates/nexum-runtime/src/supervisor/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use crate::runtime::dispatch_rate::TokenBucket;
/// Admission refusals ahead of instantiation; the wording is operator-pinned.
#[derive(Debug, ThisError, IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub(super) enum LoadRefusal {
pub(crate) enum LoadRefusal {
#[error("{owner} declares manifest section [{section}]; no wired extension claims it")]
SectionUnclaimed { owner: String, section: String },
#[error("extension namespace {namespace} is claimed twice")]
Expand Down
4 changes: 2 additions & 2 deletions crates/nexum-runtime/src/supervisor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ mod artifact;
mod cursors;
mod dispatch;
mod lifecycle;
mod load;
mod prepass;
pub(crate) mod load;
pub(crate) mod prepass;
mod role;
mod store;
mod subscriptions;
Expand Down
2 changes: 1 addition & 1 deletion crates/nexum-runtime/src/supervisor/prepass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::manifest::{self, CapabilityRegistry, LoadedManifest, ParseError, Subs
/// Refusals before any compile; the wording is operator-pinned.
#[derive(Debug, Error, IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub(super) enum BootRefusal {
pub(crate) enum BootRefusal {
#[error(
"name {name} is claimed twice: {held_role} {} and {role} {}; \
[module].name must be unique across [[modules]] and [[adapters]]",
Expand Down
Loading
Loading