stack_profile/
device_identity.rs1use serde::{Deserialize, Serialize};
2use uuid::Uuid;
3
4use crate::{ProfileData, ProfileError, ProfileStore};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct DeviceIdentity {
14 pub device_instance_id: Uuid,
16 pub device_name: String,
18}
19
20impl ProfileData for DeviceIdentity {
21 const FILENAME: &'static str = "device.json";
22 const MODE: Option<u32> = Some(0o600);
23}
24
25impl DeviceIdentity {
26 pub fn load_or_create(store: &ProfileStore) -> Result<Self, ProfileError> {
32 match store.load_profile::<Self>() {
33 Ok(identity) => Ok(identity),
34 Err(ProfileError::NotFound { .. }) => {
35 let identity = Self {
36 device_instance_id: Uuid::new_v4(),
37 device_name: gethostname::gethostname().to_string_lossy().into_owned(),
38 };
39 store.save_profile(&identity)?;
40 Ok(identity)
41 }
42 Err(e) => Err(e),
43 }
44 }
45
46 pub fn load(store: &ProfileStore) -> Result<Self, ProfileError> {
50 store.load_profile()
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn load_or_create_generates_new_identity() {
60 let dir = tempfile::tempdir().unwrap();
61 let store = ProfileStore::new(dir.path());
62
63 let identity = DeviceIdentity::load_or_create(&store).unwrap();
64 assert!(!identity.device_instance_id.is_nil());
65 assert!(!identity.device_name.is_empty());
66 }
67
68 #[test]
69 fn load_or_create_reuses_existing() {
70 let dir = tempfile::tempdir().unwrap();
71 let store = ProfileStore::new(dir.path());
72
73 let first = DeviceIdentity::load_or_create(&store).unwrap();
74 let second = DeviceIdentity::load_or_create(&store).unwrap();
75 assert_eq!(first.device_instance_id, second.device_instance_id);
76 assert_eq!(first.device_name, second.device_name);
77 }
78
79 #[test]
80 fn load_returns_not_found_for_missing_file() {
81 let dir = tempfile::tempdir().unwrap();
82 let store = ProfileStore::new(dir.path());
83 let err = DeviceIdentity::load(&store).unwrap_err();
84 assert!(matches!(err, ProfileError::NotFound { .. }));
85 }
86
87 #[test]
88 fn round_trip_serialization() {
89 let dir = tempfile::tempdir().unwrap();
90 let store = ProfileStore::new(dir.path());
91
92 let original = DeviceIdentity {
93 device_instance_id: Uuid::new_v4(),
94 device_name: "test-host".to_string(),
95 };
96 store.save("device.json", &original).unwrap();
97
98 let loaded = DeviceIdentity::load(&store).unwrap();
99 assert_eq!(original.device_instance_id, loaded.device_instance_id);
100 assert_eq!(original.device_name, loaded.device_name);
101 }
102}