#![allow(clippy::unwrap_used, clippy::expect_used)]
use matter_cert::MatterTime;
use matter_commissioning::SystemNocRng;
use matter_controller::snapshot::{deserialize, serialize};
use matter_controller::{create_fabric, ControllerState, ControllerStore, FabricConfig, FileStore};
use matter_crypto::Signer as _;
fn temp_path(name: &str) -> std::path::PathBuf {
use std::sync::atomic::{AtomicU32, Ordering};
static COUNTER: AtomicU32 = AtomicU32::new(0);
let uniq = COUNTER.fetch_add(1, Ordering::Relaxed);
let mut p = std::env::temp_dir();
p.push(format!(
"matter-controller-restart-{name}-{}-{uniq}",
std::process::id()
));
let _ = std::fs::remove_file(&p);
let _ = std::fs::remove_file(p.with_extension("tmp"));
p
}
#[test]
fn commissioner_identity_is_stable_across_restart() {
let cfg = FabricConfig::new(
0x0102_0304_0506_0708,
1,
0x0000_0000_0000_0001,
(
MatterTime::from_unix_secs(1_700_000_000),
MatterTime::NO_EXPIRY,
),
);
let fabric = create_fabric(&cfg, &SystemNocRng).expect("create_fabric");
let original_state = ControllerState::new(vec![fabric]);
let path = temp_path("identity");
let store = FileStore::new(&path);
store
.save(&serialize(&original_state).expect("serialize"))
.expect("save");
let loaded = store.load().expect("load").expect("snapshot present");
let restored = deserialize(&loaded).expect("deserialize");
let before = &original_state.fabrics[0];
let after = &restored.fabrics[0];
assert_eq!(after.commissioner.node_id, before.commissioner.node_id);
assert_eq!(
after.commissioner.noc.to_tlv().unwrap(),
before.commissioner.noc.to_tlv().unwrap(),
"commissioner NOC must survive restart byte-for-byte"
);
let signer = after
.commissioner_signer()
.expect("reload commissioner signer");
assert_eq!(
signer.public_key().as_bytes(),
after.commissioner.noc.public_key().as_bytes()
);
let sig_bytes = signer.sign_p256_sha256(b"post-restart").expect("sign");
let sig = matter_cert::Signature::new(sig_bytes);
signer
.public_key()
.verify(b"post-restart", &sig)
.expect("post-restart signature verifies");
let record = after.to_fabric_record().expect("to_fabric_record");
assert_eq!(record.fabric_id, cfg.fabric_id);
let _ = std::fs::remove_file(&path);
}