feat: identity lifecycle tests and ADR-011 DWN deprioritization
Added 8 integration tests for identity manager covering create, sign/verify, list, delete, default management, and Nostr key gen. Documented DWN deprioritization decision. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -215,6 +215,17 @@ impl IdentityManager {
|
||||
self.load_signing_key(id).await
|
||||
}
|
||||
|
||||
/// Get the default identity ID, if one is set.
|
||||
pub async fn get_default_id(&self) -> Result<Option<String>> {
|
||||
let marker = self.identities_dir.join(DEFAULT_MARKER);
|
||||
if marker.exists() {
|
||||
let id = fs::read_to_string(&marker).await?;
|
||||
Ok(Some(id.trim().to_string()))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sign data with a specific identity.
|
||||
pub async fn sign(&self, id: &str, data: &[u8]) -> Result<String> {
|
||||
let signing_key = self.load_signing_key(id).await?;
|
||||
@@ -415,3 +426,100 @@ impl IdentityManager {
|
||||
Ok(SigningKey::from_bytes(&arr))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_identity_did_key_format() {
|
||||
let dir = tempdir().unwrap();
|
||||
let mgr = IdentityManager::new(dir.path()).await.unwrap();
|
||||
let record = mgr.create("Test".to_string(), IdentityPurpose::Personal).await.unwrap();
|
||||
assert!(record.did.starts_with("did:key:z6Mk"), "DID should be did:key:z6Mk..., got {}", record.did);
|
||||
assert!(!record.id.is_empty());
|
||||
assert_eq!(record.name, "Test");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_nostr_key_npub_format() {
|
||||
let dir = tempdir().unwrap();
|
||||
let mgr = IdentityManager::new(dir.path()).await.unwrap();
|
||||
let record = mgr.create("Nostr".to_string(), IdentityPurpose::Personal).await.unwrap();
|
||||
let npub = mgr.create_nostr_key(&record.id).await.unwrap();
|
||||
assert!(npub.starts_with("npub1"), "npub should start with npub1, got {}", npub);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_sign_and_verify() {
|
||||
let dir = tempdir().unwrap();
|
||||
let mgr = IdentityManager::new(dir.path()).await.unwrap();
|
||||
let record = mgr.create("Signer".to_string(), IdentityPurpose::Personal).await.unwrap();
|
||||
let data = b"hello archipelago";
|
||||
let sig = mgr.sign(&record.id, data).await.unwrap();
|
||||
let valid = mgr.verify(&record.did, data, &sig).await.unwrap();
|
||||
assert!(valid, "Signature should verify");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_sign_verify_wrong_data() {
|
||||
let dir = tempdir().unwrap();
|
||||
let mgr = IdentityManager::new(dir.path()).await.unwrap();
|
||||
let record = mgr.create("Signer".to_string(), IdentityPurpose::Personal).await.unwrap();
|
||||
let sig = mgr.sign(&record.id, b"correct").await.unwrap();
|
||||
let valid = mgr.verify(&record.did, b"wrong", &sig).await.unwrap();
|
||||
assert!(!valid, "Signature should not verify with wrong data");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_list_identities() {
|
||||
let dir = tempdir().unwrap();
|
||||
let mgr = IdentityManager::new(dir.path()).await.unwrap();
|
||||
mgr.create("One".to_string(), IdentityPurpose::Personal).await.unwrap();
|
||||
mgr.create("Two".to_string(), IdentityPurpose::Business).await.unwrap();
|
||||
let (list, _) = mgr.list().await.unwrap();
|
||||
assert_eq!(list.len(), 2);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_delete_identity() {
|
||||
let dir = tempdir().unwrap();
|
||||
let mgr = IdentityManager::new(dir.path()).await.unwrap();
|
||||
let r1 = mgr.create("First".to_string(), IdentityPurpose::Personal).await.unwrap();
|
||||
let r2 = mgr.create("Second".to_string(), IdentityPurpose::Business).await.unwrap();
|
||||
mgr.delete(&r1.id).await.unwrap();
|
||||
let (list, _) = mgr.list().await.unwrap();
|
||||
assert_eq!(list.len(), 1);
|
||||
assert_eq!(list[0].id, r2.id);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_set_and_get_default() {
|
||||
let dir = tempdir().unwrap();
|
||||
let mgr = IdentityManager::new(dir.path()).await.unwrap();
|
||||
let r1 = mgr.create("First".to_string(), IdentityPurpose::Personal).await.unwrap();
|
||||
let r2 = mgr.create("Second".to_string(), IdentityPurpose::Business).await.unwrap();
|
||||
mgr.set_default(&r2.id).await.unwrap();
|
||||
let default_id = mgr.get_default_id().await.unwrap();
|
||||
assert_eq!(default_id, Some(r2.id.clone()));
|
||||
// First is no longer default
|
||||
assert_ne!(default_id, Some(r1.id));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_delete_default_shifts() {
|
||||
let dir = tempdir().unwrap();
|
||||
let mgr = IdentityManager::new(dir.path()).await.unwrap();
|
||||
let r1 = mgr.create("First".to_string(), IdentityPurpose::Personal).await.unwrap();
|
||||
mgr.create("Second".to_string(), IdentityPurpose::Business).await.unwrap();
|
||||
mgr.set_default(&r1.id).await.unwrap();
|
||||
mgr.delete(&r1.id).await.unwrap();
|
||||
let (list, default_id) = mgr.list().await.unwrap();
|
||||
assert_eq!(list.len(), 1);
|
||||
// Default should have shifted or be cleared
|
||||
if let Some(def) = default_id {
|
||||
assert_ne!(def, r1.id, "Default should not point to deleted identity");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user