diff --git a/affinidi-did-resolver-cache-sdk/src/networking/request_queue.rs b/affinidi-did-resolver-cache-sdk/src/networking/request_queue.rs index b803663..989d35a 100644 --- a/affinidi-did-resolver-cache-sdk/src/networking/request_queue.rs +++ b/affinidi-did-resolver-cache-sdk/src/networking/request_queue.rs @@ -136,3 +136,205 @@ impl RequestList { self.list_full } } +#[cfg(test)] +mod tests { + + use std::collections::HashMap; + + use blake2::{Blake2s256, Digest}; + use rand::{distributions::Alphanumeric, Rng}; + use tokio::sync::oneshot::{self, Sender}; + + use crate::{ + config, + networking::{network::WSCommands, request_queue::RequestList}, + }; + const DID_KEY: &str = "did:key:z6MkiToqovww7vYtxm1xNM15u9JzqzUFZ1k7s7MazYJUyAxv"; + const DID_KEY_2: &str = "did:key:z6Mkp89diy1PZkbUBDTpiqZBotddb1VV7JnY8qiZMGErUbFe"; + + #[tokio::test] + async fn new_works() { + let config = config::ClientConfigBuilder::default().build(); + let request_list = RequestList::new(&config); + + assert_eq!(request_list.list_full, false); + assert_eq!(request_list.total_count, 0); + } + + #[tokio::test] + async fn insert_works_returns_true() { + let config = config::ClientConfigBuilder::default().build(); + let mut request_list = RequestList::new(&config); + + let (tx, _) = oneshot::channel::(); + + let unique_id: String = _unique_id(); + let did_hash = _hash_did(&DID_KEY); + + let insert_result = request_list.insert(did_hash.clone(), &unique_id, tx); + + assert!(insert_result); + } + + #[tokio::test] + async fn insert_works_returns_false_duplicates() { + let config = config::ClientConfigBuilder::default().build(); + let mut request_list = RequestList::new(&config); + + let (tx, _) = oneshot::channel::(); + let (tx2, _) = oneshot::channel::(); + + let unique_id: String = _unique_id(); + let did_hash = _hash_did(DID_KEY); + + let insert_result = request_list.insert(did_hash.clone(), &unique_id, tx); + let insert_result2 = request_list.insert(did_hash.clone(), &unique_id, tx2); + + assert!(insert_result); + assert_eq!(insert_result2, false); + } + + #[tokio::test] + async fn insert_list_becomes_full() { + let config = config::ClientConfigBuilder::default() + .with_network_cache_limit_count(1) + .build(); + let mut request_list = RequestList::new(&config); + + let (tx, _) = oneshot::channel::(); + let (tx2, _) = oneshot::channel::(); + + let unique_id: String = _unique_id(); + let unique_id_2: String = _unique_id(); + + let did_hash = _hash_did(DID_KEY); + let did_hash_2 = _hash_did(DID_KEY_2); + + let insert_result = request_list.insert(did_hash.clone(), &unique_id, tx); + let insert_result2 = request_list.insert(did_hash_2.clone(), &unique_id_2, tx2); + + assert!(insert_result); + assert!(insert_result2); + assert!(request_list.list_full); + + assert_eq!(request_list.total_count, 2); + } + + #[tokio::test] + async fn remove_key_not_found() { + let config = config::ClientConfigBuilder::default().build(); + let mut request_list = RequestList::new(&config); + + let result = request_list.remove(&_hash_did(DID_KEY), None); + assert!(result.is_none()); + } + + #[tokio::test] + async fn remove_key_not_found_passing_uuid() { + let config = config::ClientConfigBuilder::default().build(); + let mut request_list = RequestList::new(&config); + + let result = request_list.remove(&_hash_did(DID_KEY), Some("".to_string())); + assert!(result.is_none()); + } + + #[tokio::test] + async fn remove_key_not_found_passing_uuid_wrong_did() { + let config = config::ClientConfigBuilder::default().build(); + let mut request_list = RequestList::new(&config); + + let result = request_list.remove(&_hash_did("wrongdid"), Some("".to_string())); + assert!(result.is_none()); + } + + #[tokio::test] + async fn remove_passing_uuid_works() { + let (mut request_list, did_to_uuid) = _fill_request_list([DID_KEY].to_vec(), true, Some(1)); + + let num_of_channels_before_remove = + request_list.list.get(&_hash_did(DID_KEY)).unwrap().len(); + let total_count_before_remove = request_list.total_count; + let ids = did_to_uuid.get(DID_KEY).unwrap(); + + request_list + .remove(&_hash_did(DID_KEY), ids.first().cloned()) + .unwrap(); + + assert_eq!( + num_of_channels_before_remove - 1, + request_list.list.get(&_hash_did(DID_KEY)).unwrap().len() + ); + assert_eq!(total_count_before_remove, request_list.total_count); + } + + #[tokio::test] + async fn remove_without_passing_uuid_to_remove_all_works() { + let (mut request_list, _) = _fill_request_list([DID_KEY].to_vec(), true, Some(4)); + + request_list.remove(&_hash_did(DID_KEY), None).unwrap(); + + assert_eq!(request_list.total_count, 0); + } + + #[tokio::test] + async fn remove_works() { + let (mut request_list, _) = _fill_request_list([DID_KEY].to_vec(), false, None); + + request_list.remove(&_hash_did(DID_KEY), None).unwrap(); + } + + fn _hash_did(did: &str) -> String { + let mut hasher = Blake2s256::new(); + hasher.update(did); + format!("{:x}", hasher.clone().finalize()) + } + + fn _unique_id() -> String { + rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(8) + .map(char::from) + .collect() + } + + fn _fill_request_list( + dids: Vec<&str>, + fill_channels_for_key: bool, + fill_channels_for_key_number: Option, + ) -> (RequestList, HashMap>) { + fn get_hash_and_id(did: &str) -> (String, String, Sender) { + ( + _unique_id(), + _hash_did(&did), + oneshot::channel::().0, + ) + } + + let nested_channels_num = if let Some(nested_channels) = fill_channels_for_key_number { + nested_channels // This returns the u8 + } else { + 0 // Handle None case by returning 0 or some other u8 value + }; + + let mut did_to_uuid_map: HashMap> = HashMap::new(); + + let config = config::ClientConfigBuilder::default().build(); + let mut request_list = RequestList::new(&config); + + for did in dids { + let (unique_id, did_hash, tx) = get_hash_and_id(did); + let mut uuids_arr: Vec = [unique_id.clone()].to_vec(); + let insert_result = request_list.insert(did_hash.clone(), &unique_id, tx); + if insert_result && fill_channels_for_key { + for _i in 0..nested_channels_num { + let (unique_id, did_hash, tx) = get_hash_and_id(did); + uuids_arr.push(unique_id.clone()); + request_list.insert(did_hash.clone(), &unique_id, tx); + } + } + did_to_uuid_map.insert(did.to_string(), uuids_arr); + } + + (request_list, did_to_uuid_map) + } +} diff --git a/affinidi-did-resolver-cache-sdk/src/resolver/mod.rs b/affinidi-did-resolver-cache-sdk/src/resolver/mod.rs index c73d2ee..fdc9c6b 100644 --- a/affinidi-did-resolver-cache-sdk/src/resolver/mod.rs +++ b/affinidi-did-resolver-cache-sdk/src/resolver/mod.rs @@ -87,3 +87,139 @@ impl DIDCacheClient { } } } + +#[cfg(test)] +mod tests { + use crate::{config, DIDCacheClient}; + + const DID_ETHR: &str = "did:ethr:0x1:0xb9c5714089478a327f09197987f16f9e5d936e8a"; + const DID_JWK: &str= "did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6ImFjYklRaXVNczNpOF91c3pFakoydHBUdFJNNEVVM3l6OTFQSDZDZEgyVjAiLCJ5IjoiX0tjeUxqOXZXTXB0bm1LdG00NkdxRHo4d2Y3NEk1TEtncmwyR3pIM25TRSJ9"; + const DID_KEY: &str = "did:key:z6MkiToqovww7vYtxm1xNM15u9JzqzUFZ1k7s7MazYJUyAxv"; + const DID_PEER: &str = "did:peer:2.Vz6MkiToqovww7vYtxm1xNM15u9JzqzUFZ1k7s7MazYJUyAxv.EzQ3shQLqRUza6AMJFbPuMdvFRFWm1wKviQRnQSC1fScovJN4s.SeyJ0IjoiRElEQ29tbU1lc3NhZ2luZyIsInMiOnsidXJpIjoiaHR0cHM6Ly8xMjcuMC4wLjE6NzAzNyIsImEiOlsiZGlkY29tbS92MiJdLCJyIjpbXX19"; + const DID_PKH: &str = "did:pkh:solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ:CKg5d12Jhpej1JqtmxLJgaFqqeYjxgPqToJ4LBdvG9Ev"; + + #[tokio::test] + async fn local_resolve_ethr() { + let config = config::ClientConfigBuilder::default().build(); + let client = DIDCacheClient::new(config).await.unwrap(); + + let parts: Vec<&str> = DID_ETHR.split(':').collect(); + let did_document = client.local_resolve(DID_ETHR, &parts).await.unwrap(); + let verification_relationships = did_document.verification_relationships; + + assert_eq!(did_document.id, DID_ETHR); + + assert_eq!(verification_relationships.authentication.len(), 2); + assert_eq!(verification_relationships.assertion_method.len(), 2); + + assert_eq!(did_document.verification_method.len(), 2,); + } + + #[tokio::test] + async fn local_resolve_jwk() { + let config = config::ClientConfigBuilder::default().build(); + let client = DIDCacheClient::new(config).await.unwrap(); + + let parts: Vec<&str> = DID_JWK.split(':').collect(); + let did_document = client.local_resolve(DID_JWK, &parts).await.unwrap(); + let verification_relationships = did_document.verification_relationships; + + assert_eq!(did_document.id, DID_JWK); + + assert_eq!(verification_relationships.authentication.len(), 1); + assert_eq!(verification_relationships.assertion_method.len(), 1); + assert_eq!(verification_relationships.key_agreement.len(), 1); + assert_eq!(verification_relationships.capability_invocation.len(), 1); + assert_eq!(verification_relationships.capability_delegation.len(), 1); + + assert_eq!(did_document.verification_method.len(), 1); + assert_eq!( + did_document.verification_method.first().unwrap().properties["publicKeyMultibase"], + "zDnaepnC2eBkx4oZkNLGDnVK8ofKzoGk1Yui8fzC6FLoV1F1e" + ); + } + + #[tokio::test] + async fn local_resolve_key() { + let config = config::ClientConfigBuilder::default().build(); + let client = DIDCacheClient::new(config).await.unwrap(); + + let parts: Vec<&str> = DID_KEY.split(':').collect(); + let did_document = client.local_resolve(DID_KEY, &parts).await.unwrap(); + let verification_relationships = did_document.verification_relationships; + + assert_eq!(did_document.id, DID_KEY); + + assert_eq!(verification_relationships.authentication.len(), 1); + assert_eq!(verification_relationships.assertion_method.len(), 1); + + assert_eq!(did_document.verification_method.len(), 1); + assert_eq!( + did_document.verification_method.first().unwrap().properties["publicKeyMultibase"], + parts.last().unwrap().to_string() + ); + } + #[tokio::test] + async fn local_resolve_peer() { + let config = config::ClientConfigBuilder::default().build(); + let client = DIDCacheClient::new(config).await.unwrap(); + + let parts: Vec<&str> = DID_PEER.split(':').collect(); + let did_document = client.local_resolve(DID_PEER, &parts).await.unwrap(); + let verification_relationships = did_document.verification_relationships; + let verification_method = did_document.verification_method; + let service = did_document.service; + + assert_eq!(did_document.id, DID_PEER); + + assert_eq!(verification_relationships.authentication.len(), 1); + assert_eq!(verification_relationships.assertion_method.len(), 1); + assert_eq!(verification_relationships.key_agreement.len(), 1); + + assert_eq!(verification_method.len(), 2); + assert_eq!( + verification_method.first().unwrap().properties["publicKeyMultibase"], + "z6MkiToqovww7vYtxm1xNM15u9JzqzUFZ1k7s7MazYJUyAxv" + ); + assert_eq!( + verification_method.last().unwrap().properties["publicKeyMultibase"], + "zQ3shQLqRUza6AMJFbPuMdvFRFWm1wKviQRnQSC1fScovJN4s" + ); + + assert_eq!(service.len(), 1); + assert_eq!(service.first().unwrap().id, "did:peer:#service"); + } + + #[tokio::test] + async fn local_resolve_pkh() { + let config = config::ClientConfigBuilder::default().build(); + let client = DIDCacheClient::new(config).await.unwrap(); + let parts: Vec<&str> = DID_PKH.split(':').collect(); + + let did_document = client.local_resolve(DID_PKH, &parts).await.unwrap(); + let verification_relationships = did_document.verification_relationships; + let verification_method = did_document.verification_method; + let vm_properties_first = verification_method.first().unwrap().properties.clone(); + let vm_properties_last = verification_method.last().unwrap().properties.clone(); + + assert_eq!(did_document.id, DID_PKH); + + assert_eq!(verification_relationships.authentication.len(), 2); + assert_eq!(verification_relationships.assertion_method.len(), 2); + + assert_eq!(verification_method.len(), 2); + assert_eq!( + vm_properties_first["publicKeyBase58"], + parts.last().unwrap().to_string() + ); + assert_eq!( + vm_properties_first["blockchainAccountId"], + parts[2..parts.len()].join(":") + ); + assert_eq!( + vm_properties_last["blockchainAccountId"], + parts[2..parts.len()].join(":") + ); + assert!(vm_properties_last["publicKeyJwk"].is_object(),); + } +}