#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
use stackless_core::def::{self, DefError, Namespace, Node, StackDef};
use stackless_core::fault::{Fault, codes};
const KNOWN: &[&str] = &["local", "render", "vercel"];
fn fixture(name: &str) -> String {
let path = format!("{}/tests/fixtures/{name}", env!("CARGO_MANIFEST_DIR"));
std::fs::read_to_string(&path).unwrap_or_else(|err| panic!("read {path}: {err}"))
}
fn parse_valid(name: &str) -> def::StackDef {
let def = StackDef::parse(&fixture(name)).unwrap_or_else(|err| panic!("parse {name}: {err}"));
def.validate_hosts(KNOWN)
.unwrap_or_else(|err| panic!("validate {name}: {err}"));
def
}
#[test]
fn atto_parses_to_the_documented_model() {
let def = parse_valid("atto.toml");
assert_eq!(def.stack.name.as_str(), "atto");
let verify = def.stack.verify.as_ref().unwrap();
assert_eq!(verify.run.as_deref(), Some("bun e2e/smoke.ts"));
assert_eq!(verify.env["ATTO_STACKLESS"], "1");
assert_eq!(verify.env["ATTO_E2E_WEB_ORIGIN"], "${services.web.origin}");
assert_eq!(verify.env["ATTO_E2E_API_ORIGIN"], "${services.api.origin}");
assert_eq!(verify.env["ATTO_E2E_TENANT_SLUG"], "${instance.name}");
assert_eq!(
verify.env["CLERK_SECRET_KEY"],
"${integrations.clerk.secret_key}"
);
assert_eq!(
verify.env["VITE_CLERK_PUBLISHABLE_KEY"],
"${integrations.clerk.publishable_key}"
);
let render = def.stack.substrates["render"].as_table().unwrap();
assert_eq!(render["region"].as_str().unwrap(), "oregon");
assert_eq!(
def.stack
.projects
.stripe
.as_ref()
.and_then(|stripe| stripe.project.as_deref()),
Some("project_61UqVKJia4fs...")
);
assert_eq!(def.secrets.required, vec!["GITHUB_PACKAGES_TOKEN"]);
let clerk = &def.integrations["clerk"];
assert_eq!(clerk.provider, "clerk");
let clerk_config = clerk.effective_config("local", KNOWN);
assert_eq!(
clerk_config["app_name"].as_str(),
Some("${stack.name}-${instance.name}")
);
assert_eq!(clerk_config["credential_set"].as_str(), Some("development"));
assert_eq!(clerk_config["organizations"].as_bool(), Some(true));
let api = &def.services["api"];
assert_eq!(api.source.repo, "https://github.com/haaku-co/atto-server");
assert_eq!(api.source.reference, "main");
assert_eq!(api.setup.as_deref(), Some("mise install"));
assert_eq!(
api.prepare.as_deref(),
Some("just migrate-run && just seed")
);
assert!(api.secrets.is_empty());
assert_eq!(
api.env["CLERK_SECRET_KEY"],
"${integrations.clerk.secret_key}"
);
assert_eq!(api.health.path, "/health");
assert_eq!(api.health.status.get(), 200);
assert_eq!(api.health.contains.as_deref(), Some("ok"));
assert!(!api.root_origin);
let web = &def.services["web"];
assert!(web.root_origin);
assert_eq!(web.health.contains.as_deref(), Some(r#"id="root""#));
let api_render_env = api.effective_env("api", "render").unwrap();
assert_eq!(api_render_env["SQLX_OFFLINE"], "true");
assert_eq!(api_render_env["RUST_LOG"], "info");
let api_local_env = api.effective_env("api", "local").unwrap();
assert!(!api_local_env.contains_key("SQLX_OFFLINE"));
}
#[test]
fn minimal_stack_is_valid() {
let def = parse_valid("minimal.toml");
let graph = def::DependencyGraph::derive(&def).unwrap();
assert_eq!(graph.startup_order(), &[Node::Service("web".into())]);
assert!(graph.wiring().is_empty());
}
#[test]
fn atto_graph_orders_clerk_before_api_without_origin_cycles() {
let def = parse_valid("atto.toml");
let graph = def::DependencyGraph::derive(&def).unwrap();
let order = graph.startup_order();
let pos = |node: &Node| order.iter().position(|n| n == node).unwrap();
assert!(pos(&Node::Integration("clerk".into())) < pos(&Node::Service("api".into())));
assert!(pos(&Node::Integration("clerk".into())) < pos(&Node::Service("web".into())));
assert_eq!(order.len(), 3);
let wiring = graph.wiring();
assert!(wiring.contains(&(Node::Service("api".into()), Node::Service("web".into()))));
assert!(wiring.contains(&(Node::Service("web".into()), Node::Service("api".into()))));
assert!(wiring.contains(&(
Node::Service("api".into()),
Node::Integration("clerk".into())
)));
assert!(wiring.contains(&(
Node::Service("web".into()),
Node::Integration("clerk".into())
)));
}
#[test]
fn atto_plan_orders_integration_before_services() {
let def = parse_valid("atto.toml");
let steps = def.plan().unwrap();
let integration = steps
.iter()
.position(|step| step.id == "integration:clerk")
.unwrap();
let start_api = steps
.iter()
.position(|step| step.id == "start:api")
.unwrap();
assert!(integration < start_api);
}
#[test]
fn atto_validates_for_both_substrates() {
let def = parse_valid("atto.toml");
def.validate_for_substrate("local").unwrap();
def.validate_for_substrate("render").unwrap();
}
#[test]
fn minimal_lacks_render_config() {
let def = parse_valid("minimal.toml");
def.validate_for_substrate("local").unwrap();
let err = def.validate_for_substrate("render").unwrap_err();
assert_eq!(err.code(), codes::DEF_SUBSTRATE_CONFIG_MISSING);
assert!(!err.remediation().is_empty());
}
#[test]
fn api_env_resolves_against_a_namespace() {
let def = parse_valid("atto.toml");
let api = &def.services["api"];
let mut namespace = Namespace {
instance_name: stackless_core::types::DnsName::try_new("demo").unwrap(),
..Namespace::default()
};
namespace
.service_origins
.insert("web".into(), "http://web.demo.localhost:4444".into());
namespace
.service_origins
.insert("api".into(), "http://api.demo.localhost:4444".into());
let resolve = |value: &str| def::interp::resolve(value, &namespace, "test").unwrap();
assert_eq!(
resolve(&api.env["CORS_ALLOWED_ORIGINS"]),
"http://web.demo.localhost:4444"
);
assert_eq!(resolve(&api.env["TENANT_SLUG"]), "demo");
assert_eq!(resolve(&api.env["RUST_LOG"]), "info");
}
fn expect_invalid(name: &str, expected_code: &str) {
let text = fixture(&format!("invalid/{name}"));
let result = StackDef::parse(&text).and_then(|def| def.validate_hosts(KNOWN));
let err = result.unwrap_err();
assert_eq!(err.code(), expected_code, "fixture {name}: {err}");
assert!(
!err.remediation().is_empty(),
"fixture {name}: empty remediation"
);
}
#[test]
fn invalid_fixtures_produce_stable_codes() {
expect_invalid("undeclared_reference.toml", codes::DEF_UNDECLARED_REFERENCE);
expect_invalid("bad_name.toml", codes::DEF_NAME_INVALID);
expect_invalid("depends_on.toml", codes::DEF_DEPENDS_ON_REJECTED);
expect_invalid("unknown_key.toml", codes::DEF_UNKNOWN_KEY);
expect_invalid("secret_not_required.toml", codes::DEF_SECRET_NOT_REQUIRED);
expect_invalid("root_origin_conflict.toml", codes::DEF_ROOT_ORIGIN_CONFLICT);
expect_invalid("reference_syntax.toml", codes::DEF_REFERENCE_SYNTAX);
}
#[test]
fn missing_health_is_a_schema_error() {
let text = r#"
[stack]
name = "bad"
[services.web]
source = { repo = "https://example.invalid/web", ref = "main" }
[services.web.local]
run = "true"
"#;
let err = StackDef::parse(text).unwrap_err();
assert_eq!(err.code(), codes::DEF_PARSE_SCHEMA);
}
#[test]
fn toml_syntax_error_is_its_own_code() {
let err = StackDef::parse("[stack\nname = ").unwrap_err();
assert_eq!(err.code(), codes::DEF_PARSE_SYNTAX);
}
#[test]
fn unknown_top_level_section_is_rejected() {
let text = r#"
[stack]
name = "bad"
[volumes]
x = 1
[services.web]
source = { repo = "https://example.invalid/web", ref = "main" }
health = { path = "/" }
[services.web.local]
run = "true"
"#;
let err = StackDef::parse(text).unwrap_err();
assert_eq!(err.code(), codes::DEF_PARSE_SCHEMA);
}
#[test]
fn datastores_section_is_rejected_on_fresh_parse() {
let text = r#"
[stack]
name = "bad"
[datastores.db]
engine = "postgres"
version = "16"
[services.web]
source = { repo = "https://example.invalid/web", ref = "main" }
health = { path = "/" }
[services.web.local]
run = "true"
"#;
let err = StackDef::parse(text).unwrap_err();
assert_eq!(err.code(), codes::DEF_PARSE_SCHEMA);
}
#[test]
fn parse_snapshot_strips_legacy_datastores() {
let text = r#"
[stack]
name = "legacy"
[stack.verify]
run = "true"
env = { DATABASE_URL = "${datastores.db.url}" }
[datastores.db]
engine = "postgres"
version = "16"
[services.web]
source = { repo = "https://example.invalid/web", ref = "main" }
health = { path = "/" }
env = { DATABASE_URL = "${datastores.db.url}", ORIGIN = "${services.web.origin}" }
[services.web.local]
run = "true"
"#;
let def = StackDef::parse_snapshot(text).unwrap();
def.validate_hosts(KNOWN).unwrap();
assert_eq!(def.stack.name.as_str(), "legacy");
assert!(def.legacy_datastores.contains("db"));
assert!(def.services.contains_key("web"));
assert_eq!(
def.services["web"]
.env
.get("DATABASE_URL")
.map(String::as_str),
Some("${datastores.db.url}")
);
assert_eq!(
def.services["web"].env.get("ORIGIN").map(String::as_str),
Some("${services.web.origin}")
);
assert_eq!(
def.stack
.verify
.as_ref()
.and_then(|v| v.env.get("DATABASE_URL"))
.map(String::as_str),
Some("${datastores.db.url}")
);
}
#[test]
fn errors_are_reportable() {
let err = DefError::NoServices;
let report = stackless_core::fault::Report::from_fault(&err);
assert_eq!(report.code, codes::DEF_NO_SERVICES);
assert!(!report.remediation.is_empty());
}