Skip to main content

stackless_core/
names.rs

1//! Default instance name composition (`{stack.name}-{uuid}`).
2
3use uuid::Uuid;
4
5use crate::types::{DnsName, TypeError};
6
7/// A DNS-safe instance name: `{stack}-{uuid}`.
8pub fn compose_instance_name(stack: &str) -> Result<String, TypeError> {
9    let id = Uuid::new_v4().hyphenated().to_string();
10    let name = format!("{stack}-{id}");
11    DnsName::try_new(name).map(DnsName::into_inner)
12}
13
14#[cfg(test)]
15mod tests {
16    use super::*;
17
18    #[test]
19    fn typical_stack_name_is_valid() {
20        let name = compose_instance_name("hello").expect("hello + uuid");
21        assert!(name.starts_with("hello-"));
22        assert!(DnsName::try_new(&name).is_ok());
23    }
24
25    #[test]
26    fn uuid_segment_matches_hyphenated_form() {
27        let name = compose_instance_name("atto").expect("atto + uuid");
28        let Some((stack, uuid)) = name.split_once('-') else {
29            panic!("expected stack-uuid form, got {name:?}");
30        };
31        assert_eq!(stack, "atto");
32        let parts: Vec<_> = uuid.split('-').collect();
33        assert_eq!(parts.len(), 5);
34        assert_eq!(parts[0].len(), 8);
35        assert_eq!(parts[1].len(), 4);
36        assert_eq!(parts[2].len(), 4);
37        assert_eq!(parts[3].len(), 4);
38        assert_eq!(parts[4].len(), 12);
39    }
40
41    #[test]
42    fn overlong_stack_name_rejected() {
43        let stack = "a".repeat(27);
44        let err = compose_instance_name(&stack).expect_err("stack name too long for uuid suffix");
45        assert!(matches!(err, TypeError::InvalidDnsName { .. }));
46    }
47}