From be8674da496e90c7ce5dfaf931c0396711d82834 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 7 Apr 2026 16:39:23 +0300 Subject: [PATCH 1/2] test(drive): improve coverage for identity fetch modules Add 67 new unit tests across the identity fetch subsystem targeting the lowest-coverage areas: queries, fetch_by_public_key_hashes, full_identity, balance, and contract_keys. Tests cover query construction (all branch variants), IdentityProveRequestType conversion, fetch with/without transactions, with-costs variants, negative balance/debt paths, estimated mode, public key hash lookups (unique and non-unique), batch fetches with missing identities, pagination with start_at (inclusive/exclusive, ascending/descending), and contract key fetches. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/drive/identity/fetch/balance/mod.rs | 260 +++++++ .../drive/identity/fetch/contract_keys/mod.rs | 111 +++ .../fetch/fetch_by_public_key_hashes/mod.rs | 685 ++++++++++++++++++ .../drive/identity/fetch/full_identity/mod.rs | 223 ++++++ .../rs-drive/src/drive/identity/fetch/mod.rs | 244 +++++++ .../src/drive/identity/fetch/queries/mod.rs | 336 +++++++++ 6 files changed, 1859 insertions(+) diff --git a/packages/rs-drive/src/drive/identity/fetch/balance/mod.rs b/packages/rs-drive/src/drive/identity/fetch/balance/mod.rs index 505984dc3a0..f53424d1757 100644 --- a/packages/rs-drive/src/drive/identity/fetch/balance/mod.rs +++ b/packages/rs-drive/src/drive/identity/fetch/balance/mod.rs @@ -306,4 +306,264 @@ mod tests { assert_eq!(negative_balance, 0); } } + + mod fetch_identity_balance_with_transaction { + use super::*; + use crate::config::DriveConfig; + use crate::util::test_helpers::setup::setup_drive; + + #[test] + fn should_return_balance_within_transaction() { + let drive = setup_drive(Some(DriveConfig { + batching_consistency_verification: true, + ..Default::default() + })); + let platform_version = PlatformVersion::latest(); + + let transaction = drive.grove.start_transaction(); + drive + .create_initial_state_structure(Some(&transaction), platform_version) + .expect("should create root tree"); + + let identity = Identity::random_identity(3, Some(42), platform_version) + .expect("expected a random identity"); + + let expected_balance = identity.balance(); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + Some(&transaction), + platform_version, + ) + .expect("expected to add identity"); + + let balance = drive + .fetch_identity_balance( + identity.id().to_buffer(), + Some(&transaction), + platform_version, + ) + .expect("should not error") + .expect("should have balance"); + + assert_eq!(balance, expected_balance); + + let balance_outside = drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("should not error"); + + assert!(balance_outside.is_none()); + } + } + + mod fetch_identity_balance_with_costs_applied { + use super::*; + + #[test] + fn should_return_actual_balance_with_costs_when_applied() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(42), platform_version) + .expect("expected a random identity"); + + let expected_balance = identity.balance(); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let block_info = BlockInfo::default(); + + let (balance, fee_result) = drive + .fetch_identity_balance_with_costs( + identity.id().to_buffer(), + &block_info, + true, + None, + platform_version, + ) + .expect("should return balance with costs"); + + assert_eq!(balance, Some(expected_balance)); + assert!(fee_result.processing_fee > 0); + } + + #[test] + fn should_return_none_with_costs_for_non_existent_identity() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let block_info = BlockInfo::default(); + + let (balance, fee_result) = drive + .fetch_identity_balance_with_costs( + [0u8; 32], + &block_info, + true, + None, + platform_version, + ) + .expect("should return none with costs"); + + assert!(balance.is_none()); + assert!(fee_result.processing_fee > 0); + } + } + + mod fetch_identity_balance_include_debt_with_costs { + use super::*; + use crate::fees::op::LowLevelDriveOperation; + + #[test] + fn should_return_balance_with_costs_estimated() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = create_test_identity(&drive, [0; 32], Some(1), None, platform_version) + .expect("expected an identity"); + + let added_balance = 1000; + drive + .add_to_identity_balance( + identity.id().to_buffer(), + added_balance, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("should add balance"); + + let block_info = BlockInfo::default(); + + let (balance, fee_result) = drive + .fetch_identity_balance_include_debt_with_costs( + identity.id().to_buffer(), + &block_info, + false, + None, + platform_version, + ) + .expect("should return with costs"); + + assert!(fee_result.processing_fee > 0); + assert!(balance.is_some()); + } + + #[test] + fn should_return_actual_balance_with_costs_when_applied() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = create_test_identity(&drive, [0; 32], Some(1), None, platform_version) + .expect("expected an identity"); + + let added_balance: u64 = 2000; + drive + .add_to_identity_balance( + identity.id().to_buffer(), + added_balance, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("should add balance"); + + let block_info = BlockInfo::default(); + + let (balance, fee_result) = drive + .fetch_identity_balance_include_debt_with_costs( + identity.id().to_buffer(), + &block_info, + true, + None, + platform_version, + ) + .expect("should return with costs"); + + assert_eq!(balance, Some(added_balance as i64)); + assert!(fee_result.processing_fee > 0); + } + + #[test] + fn should_return_negative_balance_with_costs_for_debt() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = create_test_identity(&drive, [0; 32], Some(1), None, platform_version) + .expect("expected an identity"); + + let negative_amount: u64 = 500; + + let batch = vec![drive + .update_identity_negative_credit_operation( + identity.id().to_buffer(), + negative_amount, + platform_version, + ) + .expect("expected operation")]; + + let mut drive_operations: Vec = vec![]; + drive + .apply_batch_low_level_drive_operations( + None, + None, + batch, + &mut drive_operations, + &platform_version.drive, + ) + .expect("should apply batch"); + + let block_info = BlockInfo::default(); + + let (balance, fee_result) = drive + .fetch_identity_balance_include_debt_with_costs( + identity.id().to_buffer(), + &block_info, + true, + None, + platform_version, + ) + .expect("should return with costs"); + + assert_eq!(balance, Some(-(negative_amount as i64))); + assert!(fee_result.processing_fee > 0); + } + } + + mod fetch_identity_negative_balance_estimated { + use super::*; + + #[test] + fn should_return_zero_in_estimated_mode_for_non_existent_identity() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let mut drive_operations = vec![]; + let result = drive + .fetch_identity_negative_balance_operations( + [0xffu8; 32], + false, + None, + &mut drive_operations, + platform_version, + ) + .expect("should not error in estimated mode"); + + assert_eq!(result, Some(0)); + } + } } diff --git a/packages/rs-drive/src/drive/identity/fetch/contract_keys/mod.rs b/packages/rs-drive/src/drive/identity/fetch/contract_keys/mod.rs index 20f41d6507b..9ec6a08416c 100644 --- a/packages/rs-drive/src/drive/identity/fetch/contract_keys/mod.rs +++ b/packages/rs-drive/src/drive/identity/fetch/contract_keys/mod.rs @@ -60,3 +60,114 @@ impl Drive { } } } + +#[cfg(feature = "server")] +#[cfg(test)] +mod tests { + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use dpp::identity::Purpose; + use dpp::version::PlatformVersion; + + mod fetch_identities_contract_keys { + use super::*; + + #[test] + fn should_return_empty_map_when_no_contract_keys_exist() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity_ids = [[1u8; 32]]; + let contract_id = [2u8; 32]; + let purposes = vec![Purpose::ENCRYPTION]; + + // When there are no contract keys bound, the query returns an + // empty result (the identity subtree exists but has no contract info). + let result = drive.fetch_identities_contract_keys( + &identity_ids, + &contract_id, + None, + purposes, + None, + platform_version, + ); + + // This may return an empty map or error depending on whether the identity + // exists. With no identity inserted, the path query should return empty results. + match result { + Ok(map) => assert!(map.is_empty()), + Err(_) => { + // Expected: path does not exist for non-existent identity + } + } + } + + #[test] + fn should_return_empty_for_existing_identity_without_contract_keys() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + use dpp::block::block_info::BlockInfo; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::Identity; + + let identity = Identity::random_identity(3, Some(42), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let identity_ids = [identity.id().to_buffer()]; + let contract_id = [0xabu8; 32]; + let purposes = vec![Purpose::ENCRYPTION]; + + // The identity exists but has no contract-bound keys, so the + // query should return an empty result or skip that identity. + let result = drive.fetch_identities_contract_keys( + &identity_ids, + &contract_id, + None, + purposes, + None, + platform_version, + ); + + match result { + Ok(map) => assert!(map.is_empty()), + Err(_) => { + // Also acceptable - contract info subtree may not exist + } + } + } + + #[test] + fn should_return_empty_for_empty_identity_ids() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity_ids: [[u8; 32]; 0] = []; + let contract_id = [3u8; 32]; + let purposes = vec![Purpose::ENCRYPTION]; + + let result = drive + .fetch_identities_contract_keys( + &identity_ids, + &contract_id, + None, + purposes, + None, + platform_version, + ) + .expect("should not error for empty ids"); + + assert!(result.is_empty()); + } + } +} diff --git a/packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes/mod.rs b/packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes/mod.rs index a1fe819c2d0..44970ec896e 100644 --- a/packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes/mod.rs +++ b/packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes/mod.rs @@ -81,4 +81,689 @@ mod tests { } } } + + mod fetch_identity_id_by_unique_public_key_hash { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + + #[test] + fn should_return_none_for_unknown_hash() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let unknown_hash = [0xabu8; 20]; + let result = drive + .fetch_identity_id_by_unique_public_key_hash(unknown_hash, None, platform_version) + .expect("should not error"); + + assert!(result.is_none()); + } + + #[test] + fn should_return_identity_id_for_known_hash() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(777), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let unique_key = identity + .public_keys() + .values() + .find(|k| k.key_type().is_unique_key_type()) + .expect("should have a unique key"); + + let hash = unique_key.public_key_hash().expect("should hash"); + + let fetched_id = drive + .fetch_identity_id_by_unique_public_key_hash(hash, None, platform_version) + .expect("should not error") + .expect("should find identity id"); + + assert_eq!(fetched_id, identity.id().to_buffer()); + } + } + + mod fetch_full_identity_by_unique_public_key_hash { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + + #[test] + fn should_return_none_for_unknown_hash() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let unknown_hash = [0xcdu8; 20]; + let result = drive + .fetch_full_identity_by_unique_public_key_hash(unknown_hash, None, platform_version) + .expect("should not error"); + + assert!(result.is_none()); + } + + #[test] + fn should_return_full_identity_for_known_unique_hash() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(888), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let unique_key = identity + .public_keys() + .values() + .find(|k| k.key_type().is_unique_key_type()) + .expect("should have a unique key"); + + let hash = unique_key.public_key_hash().expect("should hash"); + + let fetched = drive + .fetch_full_identity_by_unique_public_key_hash(hash, None, platform_version) + .expect("should not error") + .expect("should find identity"); + + assert_eq!(fetched, identity); + } + } + + mod has_unique_public_key_hash { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + + #[test] + fn should_return_false_for_unknown_hash() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let unknown_hash = [0xefu8; 20]; + let result = drive + .has_unique_public_key_hash(unknown_hash, None, &platform_version.drive) + .expect("should not error"); + + assert!(!result); + } + + #[test] + fn should_return_true_for_known_hash() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(999), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let unique_key = identity + .public_keys() + .values() + .find(|k| k.key_type().is_unique_key_type()) + .expect("should have a unique key"); + + let hash = unique_key.public_key_hash().expect("should hash"); + + let result = drive + .has_unique_public_key_hash(hash, None, &platform_version.drive) + .expect("should not error"); + + assert!(result); + } + } + + mod has_non_unique_public_key_hash { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + + #[test] + fn should_return_false_for_unknown_hash() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let unknown_hash = [0x11u8; 20]; + let result = drive + .has_non_unique_public_key_hash(unknown_hash, None, &platform_version.drive) + .expect("should not error"); + + assert!(!result); + } + + #[test] + fn should_return_true_for_identity_with_non_unique_key() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(5, Some(12345), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let non_unique_key = identity + .public_keys() + .values() + .find(|k| !k.key_type().is_unique_key_type()); + + if let Some(key) = non_unique_key { + let hash = key.public_key_hash().expect("should hash"); + let result = drive + .has_non_unique_public_key_hash(hash, None, &platform_version.drive) + .expect("should not error"); + assert!(result); + } + } + } + + mod has_any_of_unique_public_key_hashes { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + + #[test] + fn should_return_empty_for_unknown_hashes() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let hashes = vec![[0x22u8; 20], [0x33u8; 20]]; + let result = drive + .has_any_of_unique_public_key_hashes(hashes, None, platform_version) + .expect("should not error"); + + assert!(result.is_empty()); + } + + #[test] + fn should_return_matching_hashes_for_known_identity() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(555), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let mut hashes: Vec<[u8; 20]> = identity + .public_keys() + .values() + .filter(|k| k.key_type().is_unique_key_type()) + .map(|k| k.public_key_hash().expect("should hash")) + .collect(); + + hashes.push([0xffu8; 20]); + + let result = drive + .has_any_of_unique_public_key_hashes(hashes.clone(), None, platform_version) + .expect("should not error"); + + assert!(!result.is_empty()); + assert!(!result.contains(&[0xffu8; 20])); + } + } + + mod fetch_identity_ids_by_unique_public_key_hashes { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + + #[test] + fn should_return_none_for_unknown_hashes() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let hashes = [[0x44u8; 20], [0x55u8; 20]]; + let result = drive + .fetch_identity_ids_by_unique_public_key_hashes(&hashes, None, platform_version) + .expect("should not error"); + + assert_eq!(result.len(), 2); + for (_, id) in &result { + assert!(id.is_none()); + } + } + + #[test] + fn should_return_identity_ids_for_known_hashes() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(666), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let unique_hashes: Vec<[u8; 20]> = identity + .public_keys() + .values() + .filter(|k| k.key_type().is_unique_key_type()) + .map(|k| k.public_key_hash().expect("should hash")) + .collect(); + + let result = drive + .fetch_identity_ids_by_unique_public_key_hashes( + &unique_hashes, + None, + platform_version, + ) + .expect("should not error"); + + for hash in &unique_hashes { + let id = result + .get(hash) + .expect("hash should be in results") + .expect("identity id should be Some"); + assert_eq!(id, identity.id().to_buffer()); + } + } + + #[test] + fn should_handle_mix_of_known_and_unknown_hashes() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(667), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let known_hash = identity + .public_keys() + .values() + .find(|k| k.key_type().is_unique_key_type()) + .expect("should have unique key") + .public_key_hash() + .expect("should hash"); + + let unknown_hash = [0x77u8; 20]; + let hashes = vec![known_hash, unknown_hash]; + + let result = drive + .fetch_identity_ids_by_unique_public_key_hashes(&hashes, None, platform_version) + .expect("should not error"); + + assert_eq!(result.len(), 2); + assert!(result[&known_hash].is_some()); + assert!(result[&unknown_hash].is_none()); + } + } + + mod fetch_full_identities_by_unique_public_key_hashes { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + + #[test] + fn should_return_none_for_unknown_hashes() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let hashes = [[0x88u8; 20]]; + let result = drive + .fetch_full_identities_by_unique_public_key_hashes(&hashes, None, platform_version) + .expect("should not error"); + + assert_eq!(result.len(), 1); + assert!(result[&[0x88u8; 20]].is_none()); + } + + #[test] + fn should_return_identities_for_known_hashes() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(1111), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let unique_hashes: Vec<[u8; 20]> = identity + .public_keys() + .values() + .filter(|k| k.key_type().is_unique_key_type()) + .map(|k| k.public_key_hash().expect("should hash")) + .collect(); + + let result = drive + .fetch_full_identities_by_unique_public_key_hashes( + &unique_hashes, + None, + platform_version, + ) + .expect("should not error"); + + for hash in &unique_hashes { + let fetched = result + .get(hash) + .expect("hash should be in results") + .as_ref() + .expect("identity should be Some"); + assert_eq!(*fetched, identity); + } + } + } + + mod fetch_full_identity_by_non_unique_public_key_hash { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + + #[test] + fn should_return_none_for_unknown_non_unique_hash() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let unknown_hash = [0x99u8; 20]; + let result = drive + .fetch_full_identity_by_non_unique_public_key_hash( + unknown_hash, + None, + None, + platform_version, + ) + .expect("should not error"); + + assert!(result.is_none()); + } + + #[test] + fn should_return_identity_for_known_non_unique_hash() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(5, Some(2222), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let non_unique_key = identity + .public_keys() + .values() + .find(|k| !k.key_type().is_unique_key_type()); + + if let Some(key) = non_unique_key { + let hash = key.public_key_hash().expect("should hash"); + let result = drive + .fetch_full_identity_by_non_unique_public_key_hash( + hash, + None, + None, + platform_version, + ) + .expect("should not error"); + + assert!(result.is_some()); + assert_eq!(result.unwrap(), identity); + } + } + } + + mod fetch_identity_ids_by_non_unique_public_key_hash { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + + #[test] + fn should_return_empty_for_unknown_hash() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let unknown_hash = [0xaau8; 20]; + let result = drive + .fetch_identity_ids_by_non_unique_public_key_hash( + unknown_hash, + None, + None, + None, + platform_version, + ) + .expect("should not error"); + + assert!(result.is_empty()); + } + + #[test] + fn should_return_identity_id_for_known_hash() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(5, Some(3333), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let non_unique_key = identity + .public_keys() + .values() + .find(|k| !k.key_type().is_unique_key_type()); + + if let Some(key) = non_unique_key { + let hash = key.public_key_hash().expect("should hash"); + let result = drive + .fetch_identity_ids_by_non_unique_public_key_hash( + hash, + None, + None, + None, + platform_version, + ) + .expect("should not error"); + + assert!(!result.is_empty()); + assert!(result.contains(&identity.id().to_buffer())); + } + } + + #[test] + fn should_respect_limit() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(5, Some(4444), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let non_unique_key = identity + .public_keys() + .values() + .find(|k| !k.key_type().is_unique_key_type()); + + if let Some(key) = non_unique_key { + let hash = key.public_key_hash().expect("should hash"); + let result = drive + .fetch_identity_ids_by_non_unique_public_key_hash( + hash, + Some(1), + None, + None, + platform_version, + ) + .expect("should not error"); + + assert!(result.len() <= 1); + } + } + } + + mod has_non_unique_public_key_hash_already_for_identity { + use super::*; + use crate::fees::op::LowLevelDriveOperation; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + + #[test] + fn should_return_false_for_wrong_identity() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(5, Some(5555), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let non_unique_key = identity + .public_keys() + .values() + .find(|k| !k.key_type().is_unique_key_type()); + + if let Some(key) = non_unique_key { + let hash = key.public_key_hash().expect("should hash"); + let mut drive_operations: Vec = vec![]; + let result = drive + .has_non_unique_public_key_hash_already_for_identity_operations( + hash, + [0xffu8; 32], + None, + &mut drive_operations, + &platform_version.drive, + ) + .expect("should not error"); + + assert!(!result); + } + } + + #[test] + fn should_return_true_for_correct_identity() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(5, Some(6666), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let non_unique_key = identity + .public_keys() + .values() + .find(|k| !k.key_type().is_unique_key_type()); + + if let Some(key) = non_unique_key { + let hash = key.public_key_hash().expect("should hash"); + let mut drive_operations: Vec = vec![]; + let result = drive + .has_non_unique_public_key_hash_already_for_identity_operations( + hash, + identity.id().to_buffer(), + None, + &mut drive_operations, + &platform_version.drive, + ) + .expect("should not error"); + + assert!(result); + } + } + } } diff --git a/packages/rs-drive/src/drive/identity/fetch/full_identity/mod.rs b/packages/rs-drive/src/drive/identity/fetch/full_identity/mod.rs index ebfe8128a95..84a42adb9d4 100644 --- a/packages/rs-drive/src/drive/identity/fetch/full_identity/mod.rs +++ b/packages/rs-drive/src/drive/identity/fetch/full_identity/mod.rs @@ -51,6 +51,56 @@ mod tests { } } + mod fetch_full_identities_additional { + use super::*; + use dpp::block::block_info::BlockInfo; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::Identity; + use dpp::version::PlatformVersion; + + #[test] + fn should_return_none_for_non_existent_ids_in_batch() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + let non_existent_id = [0xffu8; 32]; + let ids = vec![identity.id().to_buffer(), non_existent_id]; + let fetched = drive + .fetch_full_identities(&ids, None, platform_version) + .expect("should get identities"); + + assert_eq!(fetched.len(), 2); + assert!(fetched[&identity.id().to_buffer()].is_some()); + assert!(fetched[&non_existent_id].is_none()); + } + + #[test] + fn should_return_empty_map_for_empty_input() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let fetched = drive + .fetch_full_identities(&[], None, platform_version) + .expect("should get empty result"); + + assert!(fetched.is_empty()); + } + } + mod fetch_full_identity { use super::*; use dpp::block::block_info::BlockInfo; @@ -105,4 +155,177 @@ mod tests { assert_eq!(identity, fetched_identity); } } + + mod fetch_full_identity_with_costs { + use super::*; + use dpp::block::block_info::BlockInfo; + use dpp::block::epoch::Epoch; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::Identity; + use dpp::version::PlatformVersion; + + #[test] + fn should_return_none_with_fee_for_non_existent_identity() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + let epoch = Epoch::new(0).expect("expected epoch"); + + let (identity, fee) = drive + .fetch_full_identity_with_costs([0u8; 32], &epoch, None, platform_version) + .expect("should return none with fee"); + + assert!(identity.is_none()); + assert!(fee.processing_fee > 0); + } + + #[test] + fn should_return_identity_with_fee_for_existing_identity() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + let epoch = Epoch::new(0).expect("expected epoch"); + + let identity = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + let (fetched_identity, fee) = drive + .fetch_full_identity_with_costs( + identity.id().to_buffer(), + &epoch, + None, + platform_version, + ) + .expect("should return identity with fee"); + + assert_eq!(fetched_identity.unwrap(), identity); + assert!(fee.processing_fee > 0); + } + } + + mod fetch_full_identity_operations { + use super::*; + use crate::fees::op::LowLevelDriveOperation; + use dpp::block::block_info::BlockInfo; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::Identity; + use dpp::version::PlatformVersion; + + #[test] + fn should_return_none_for_non_existent_identity_operations() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + let mut drive_operations: Vec = vec![]; + + let identity = drive + .fetch_full_identity_operations( + [0u8; 32], + None, + &mut drive_operations, + platform_version, + ) + .expect("should return none"); + + assert!(identity.is_none()); + assert!(!drive_operations.is_empty()); + } + + #[test] + fn should_return_identity_and_record_operations() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + let mut drive_operations: Vec = vec![]; + let fetched_identity = drive + .fetch_full_identity_operations( + identity.id().to_buffer(), + None, + &mut drive_operations, + platform_version, + ) + .expect("should return identity") + .expect("should have identity"); + + assert_eq!(fetched_identity, identity); + assert!(!drive_operations.is_empty()); + } + } + + mod fetch_full_identity_with_transaction { + use super::*; + use crate::config::DriveConfig; + use crate::util::test_helpers::setup::setup_drive; + use dpp::block::block_info::BlockInfo; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::Identity; + use dpp::version::PlatformVersion; + + #[test] + fn should_fetch_identity_within_transaction() { + let drive = setup_drive(Some(DriveConfig { + batching_consistency_verification: true, + ..Default::default() + })); + let platform_version = PlatformVersion::latest(); + + let transaction = drive.grove.start_transaction(); + drive + .create_initial_state_structure(Some(&transaction), platform_version) + .expect("should create root tree"); + + let identity = Identity::random_identity(3, Some(42), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + Some(&transaction), + platform_version, + ) + .expect("expected to add identity"); + + let fetched = drive + .fetch_full_identity( + identity.id().to_buffer(), + Some(&transaction), + platform_version, + ) + .expect("should not error") + .expect("should find identity in transaction"); + + assert_eq!(fetched, identity); + + let fetched_outside = drive + .fetch_full_identity(identity.id().to_buffer(), None, platform_version) + .expect("should not error"); + + assert!(fetched_outside.is_none()); + } + } } diff --git a/packages/rs-drive/src/drive/identity/fetch/mod.rs b/packages/rs-drive/src/drive/identity/fetch/mod.rs index 8b2cd2b4ffa..513fa184e8c 100644 --- a/packages/rs-drive/src/drive/identity/fetch/mod.rs +++ b/packages/rs-drive/src/drive/identity/fetch/mod.rs @@ -554,5 +554,249 @@ mod tests { assert_eq!(balances.len(), 2); } + + #[test] + fn should_fetch_balances_descending() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identities: Vec = + Identity::random_identities(5, 3, Some(42), platform_version) + .expect("expected random identities"); + + for identity in &identities { + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + } + + let balances: BTreeMap<[u8; 32], u64> = drive + .fetch_many_identity_balances_by_range::>( + None, + false, + 10, + None, + platform_version, + ) + .expect("should fetch balances by range descending"); + + assert_eq!(balances.len(), 5); + } + + #[test] + fn should_paginate_with_start_at_ascending() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identities: Vec = + Identity::random_identities(5, 3, Some(42), platform_version) + .expect("expected random identities"); + + for identity in &identities { + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + } + + // Get first 2 ascending + let first_page: BTreeMap<[u8; 32], u64> = drive + .fetch_many_identity_balances_by_range::>( + None, + true, + 2, + None, + platform_version, + ) + .expect("should fetch first page"); + + assert_eq!(first_page.len(), 2); + + // Get next page starting after the last key (exclusive) + let last_key = *first_page.keys().last().unwrap(); + let second_page: BTreeMap<[u8; 32], u64> = drive + .fetch_many_identity_balances_by_range::>( + Some((last_key, false)), + true, + 2, + None, + platform_version, + ) + .expect("should fetch second page"); + + assert_eq!(second_page.len(), 2); + + // Pages should not overlap + for key in first_page.keys() { + assert!(!second_page.contains_key(key), "pages should not overlap"); + } + } + + #[test] + fn should_paginate_with_start_at_included() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identities: Vec = + Identity::random_identities(5, 3, Some(42), platform_version) + .expect("expected random identities"); + + for identity in &identities { + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + } + + // Get first 2 + let first_page: BTreeMap<[u8; 32], u64> = drive + .fetch_many_identity_balances_by_range::>( + None, + true, + 2, + None, + platform_version, + ) + .expect("should fetch first page"); + + let last_key = *first_page.keys().last().unwrap(); + + // Get page starting at last_key inclusive + let inclusive_page: BTreeMap<[u8; 32], u64> = drive + .fetch_many_identity_balances_by_range::>( + Some((last_key, true)), + true, + 2, + None, + platform_version, + ) + .expect("should fetch inclusive page"); + + assert!(!inclusive_page.is_empty()); + // The first key of the inclusive page should be the last_key + assert!(inclusive_page.contains_key(&last_key)); + } + + #[test] + fn should_return_empty_when_no_identities_exist() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let balances: BTreeMap<[u8; 32], u64> = drive + .fetch_many_identity_balances_by_range::>( + None, + true, + 10, + None, + platform_version, + ) + .expect("should return empty"); + + assert!(balances.is_empty()); + } + + #[test] + fn should_paginate_descending_with_start_at() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identities: Vec = + Identity::random_identities(5, 3, Some(42), platform_version) + .expect("expected random identities"); + + for identity in &identities { + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + } + + // Get first 2 descending + let first_page: BTreeMap<[u8; 32], u64> = drive + .fetch_many_identity_balances_by_range::>( + None, + false, + 2, + None, + platform_version, + ) + .expect("should fetch first page descending"); + + assert_eq!(first_page.len(), 2); + + // Get next page descending, exclusive of the smallest key in the previous page + let smallest_key = *first_page.keys().next().unwrap(); + let second_page: BTreeMap<[u8; 32], u64> = drive + .fetch_many_identity_balances_by_range::>( + Some((smallest_key, false)), + false, + 2, + None, + platform_version, + ) + .expect("should fetch second page descending"); + + assert_eq!(second_page.len(), 2); + + for key in first_page.keys() { + assert!( + !second_page.contains_key(key), + "descending pages should not overlap" + ); + } + } + } + + mod identity_revision_query { + use super::*; + + #[test] + fn should_build_identity_revision_query() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(42), platform_version) + .expect("expected a random identity"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add identity"); + + let query = crate::drive::Drive::identity_revision_query(&identity.id().to_buffer()); + assert!(!query.path.is_empty()); + assert!(query.query.limit.is_none()); + } } } diff --git a/packages/rs-drive/src/drive/identity/fetch/queries/mod.rs b/packages/rs-drive/src/drive/identity/fetch/queries/mod.rs index 645e9de02f2..23f5ac96954 100644 --- a/packages/rs-drive/src/drive/identity/fetch/queries/mod.rs +++ b/packages/rs-drive/src/drive/identity/fetch/queries/mod.rs @@ -410,3 +410,339 @@ impl Drive { .unwrap() } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::drive::Drive; + use dpp::identity::Purpose; + use grovedb_version::version::GroveVersion; + + mod identity_prove_request_type { + use super::*; + + #[test] + fn should_convert_valid_values() { + assert!(matches!( + IdentityProveRequestType::try_from(0), + Ok(IdentityProveRequestType::FullIdentity) + )); + assert!(matches!( + IdentityProveRequestType::try_from(1), + Ok(IdentityProveRequestType::Balance) + )); + assert!(matches!( + IdentityProveRequestType::try_from(2), + Ok(IdentityProveRequestType::Keys) + )); + assert!(matches!( + IdentityProveRequestType::try_from(3), + Ok(IdentityProveRequestType::Revision) + )); + } + + #[test] + fn should_error_on_invalid_value() { + let result = IdentityProveRequestType::try_from(4); + assert!(result.is_err()); + + let result = IdentityProveRequestType::try_from(255); + assert!(result.is_err()); + } + } + + mod query_construction { + use super::*; + + #[test] + fn should_build_revision_for_identity_id_path_query() { + let identity_id = [1u8; 32]; + let pq = Drive::revision_for_identity_id_path_query(identity_id); + + assert!(!pq.path.is_empty()); + assert!(pq.query.limit.is_none()); + assert!(pq.query.offset.is_none()); + } + + #[test] + fn should_build_revision_and_balance_path_query() { + let identity_id = [2u8; 32]; + let grove_version = GroveVersion::latest(); + let pq = Drive::revision_and_balance_path_query(identity_id, grove_version) + .expect("should build merged query"); + + assert!(pq.query.limit.is_none()); + assert!(pq.query.offset.is_none()); + } + + #[test] + fn should_build_identity_id_by_unique_public_key_hash_query() { + let public_key_hash = [3u8; 20]; + let pq = Drive::identity_id_by_unique_public_key_hash_query(public_key_hash); + + assert!(!pq.path.is_empty()); + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_identity_id_by_non_unique_public_key_hash_query_without_after() { + let public_key_hash = [4u8; 20]; + let pq = Drive::identity_id_by_non_unique_public_key_hash_query(public_key_hash, None); + + assert!(!pq.path.is_empty()); + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_identity_id_by_non_unique_public_key_hash_query_with_after() { + let public_key_hash = [4u8; 20]; + let after_id = [5u8; 32]; + let pq = Drive::identity_id_by_non_unique_public_key_hash_query( + public_key_hash, + Some(after_id), + ); + + assert!(!pq.path.is_empty()); + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_identity_ids_by_unique_public_key_hash_query() { + let hashes = [[6u8; 20], [7u8; 20], [8u8; 20]]; + let pq = Drive::identity_ids_by_unique_public_key_hash_query(&hashes); + + assert!(!pq.path.is_empty()); + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_identity_ids_by_unique_public_key_hash_query_empty() { + let hashes: [[u8; 20]; 0] = []; + let pq = Drive::identity_ids_by_unique_public_key_hash_query(&hashes); + assert!(!pq.path.is_empty()); + } + + #[test] + fn should_build_full_identity_query() { + let identity_id = [9u8; 32]; + let grove_version = GroveVersion::latest(); + let pq = Drive::full_identity_query(&identity_id, grove_version) + .expect("should build full identity query"); + + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_identity_all_keys_query() { + let identity_id = [10u8; 32]; + let grove_version = GroveVersion::latest(); + let pq = Drive::identity_all_keys_query(&identity_id, grove_version) + .expect("should build all keys query"); + + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_balances_for_identity_ids_query() { + let ids = [[11u8; 32], [12u8; 32]]; + let pq = Drive::balances_for_identity_ids_query(&ids); + + assert!(!pq.path.is_empty()); + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_balances_for_range_query_ascending_no_start() { + let pq = Drive::balances_for_range_query(None, true, 10); + assert_eq!(pq.query.limit, Some(10)); + } + + #[test] + fn should_build_balances_for_range_query_ascending_with_start_included() { + let start = [13u8; 32]; + let pq = Drive::balances_for_range_query(Some((start, true)), true, 5); + assert_eq!(pq.query.limit, Some(5)); + } + + #[test] + fn should_build_balances_for_range_query_ascending_with_start_excluded() { + let start = [14u8; 32]; + let pq = Drive::balances_for_range_query(Some((start, false)), true, 5); + assert_eq!(pq.query.limit, Some(5)); + } + + #[test] + fn should_build_balances_for_range_query_descending_no_start() { + let pq = Drive::balances_for_range_query(None, false, 10); + assert_eq!(pq.query.limit, Some(10)); + } + + #[test] + fn should_build_balances_for_range_query_descending_with_start_included() { + let start = [15u8; 32]; + let pq = Drive::balances_for_range_query(Some((start, true)), false, 5); + assert_eq!(pq.query.limit, Some(5)); + } + + #[test] + fn should_build_balances_for_range_query_descending_with_start_excluded() { + let start = [16u8; 32]; + let pq = Drive::balances_for_range_query(Some((start, false)), false, 5); + assert_eq!(pq.query.limit, Some(5)); + } + + #[test] + fn should_build_full_identities_query() { + let ids = [[17u8; 32], [18u8; 32]]; + let grove_version = GroveVersion::latest(); + let pq = Drive::full_identities_query(&ids, grove_version) + .expect("should build full identities query"); + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_full_identity_with_public_key_hash_query() { + let public_key_hash = [19u8; 20]; + let identity_id = [20u8; 32]; + let grove_version = GroveVersion::latest(); + let pq = Drive::full_identity_with_public_key_hash_query( + public_key_hash, + identity_id, + grove_version, + ) + .expect("should build query"); + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_full_identity_with_non_unique_public_key_hash_query_no_after() { + let public_key_hash = [21u8; 20]; + let identity_id = [22u8; 32]; + let grove_version = GroveVersion::latest(); + let pq = Drive::full_identity_with_non_unique_public_key_hash_query( + public_key_hash, + identity_id, + None, + grove_version, + ) + .expect("should build query"); + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_full_identity_with_non_unique_public_key_hash_query_with_after() { + let public_key_hash = [23u8; 20]; + let identity_id = [24u8; 32]; + let after = [25u8; 32]; + let grove_version = GroveVersion::latest(); + let pq = Drive::full_identity_with_non_unique_public_key_hash_query( + public_key_hash, + identity_id, + Some(after), + grove_version, + ) + .expect("should build query"); + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_full_identities_with_keys_hashes_query() { + let ids = [[26u8; 32], [27u8; 32]]; + let hashes = [[28u8; 20], [29u8; 20]]; + let grove_version = GroveVersion::latest(); + let pq = Drive::full_identities_with_keys_hashes_query(&ids, &hashes, grove_version) + .expect("should build query"); + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_identity_balance_query() { + let identity_id = [30u8; 32]; + let pq = Drive::identity_balance_query(&identity_id); + + assert!(!pq.path.is_empty()); + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_identities_contract_keys_query() { + let ids = [[31u8; 32], [32u8; 32]]; + let contract_id = [33u8; 32]; + let purposes = vec![Purpose::ENCRYPTION]; + let pq = Drive::identities_contract_keys_query( + &ids, + &contract_id, + &None, + &purposes, + Some(10), + ); + + assert!(!pq.path.is_empty()); + assert_eq!(pq.query.limit, Some(10)); + } + + #[test] + fn should_build_identities_contract_keys_query_with_document_type() { + let ids = [[34u8; 32]]; + let contract_id = [35u8; 32]; + let doc_type_name = Some("profile".to_string()); + let purposes = vec![Purpose::ENCRYPTION, Purpose::DECRYPTION]; + let pq = Drive::identities_contract_keys_query( + &ids, + &contract_id, + &doc_type_name, + &purposes, + None, + ); + + assert!(!pq.path.is_empty()); + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_identities_contract_document_type_keys_query() { + let ids = [[36u8; 32], [37u8; 32]]; + let contract_id = [38u8; 32]; + let purposes = vec![Purpose::ENCRYPTION]; + let pq = Drive::identities_contract_document_type_keys_query( + &ids, + contract_id, + "profile", + purposes, + ); + + assert!(!pq.path.is_empty()); + assert!(pq.query.limit.is_none()); + } + + #[test] + fn should_build_balance_for_identity_id_query() { + let identity_id = [39u8; 32]; + let pq = Drive::balance_for_identity_id_query(identity_id); + assert!(!pq.path.is_empty()); + } + + #[test] + fn should_build_identity_nonce_query() { + let identity_id = [40u8; 32]; + let pq = Drive::identity_nonce_query(identity_id); + assert!(!pq.path.is_empty()); + } + + #[test] + fn should_build_identity_contract_nonce_query() { + let identity_id = [41u8; 32]; + let contract_id = [42u8; 32]; + let pq = Drive::identity_contract_nonce_query(identity_id, contract_id); + assert!(!pq.path.is_empty()); + } + + #[test] + fn should_build_balance_and_revision_for_identity_id_query() { + let identity_id = [43u8; 32]; + let grove_version = GroveVersion::latest(); + let pq = Drive::balance_and_revision_for_identity_id_query(identity_id, grove_version); + assert!(pq.query.limit.is_none()); + } + } +} From d13c2ae0861ae2cec944f2930910cfc21af07892 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 7 Apr 2026 17:09:31 +0300 Subject: [PATCH 2/2] fix(test): strengthen assertions per CodeRabbit review - contract_keys: assert Ok instead of matching Ok/Err - fetch_by_public_key_hashes: require non-unique key exists instead of conditional assertion - queries: document that doc type param doesn't affect query path Co-Authored-By: Claude Opus 4.6 (1M context) --- .../drive/identity/fetch/contract_keys/mod.rs | 24 ++++++++----------- .../fetch/fetch_by_public_key_hashes/mod.rs | 15 ++++++------ .../src/drive/identity/fetch/queries/mod.rs | 3 +++ 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/packages/rs-drive/src/drive/identity/fetch/contract_keys/mod.rs b/packages/rs-drive/src/drive/identity/fetch/contract_keys/mod.rs index 9ec6a08416c..739dc5b87e0 100644 --- a/packages/rs-drive/src/drive/identity/fetch/contract_keys/mod.rs +++ b/packages/rs-drive/src/drive/identity/fetch/contract_keys/mod.rs @@ -91,14 +91,11 @@ mod tests { platform_version, ); - // This may return an empty map or error depending on whether the identity - // exists. With no identity inserted, the path query should return empty results. - match result { - Ok(map) => assert!(map.is_empty()), - Err(_) => { - // Expected: path does not exist for non-existent identity - } - } + let map = result.expect("expected Ok result for non-existent identity"); + assert!( + map.is_empty(), + "expected empty map for non-existent identity" + ); } #[test] @@ -139,12 +136,11 @@ mod tests { platform_version, ); - match result { - Ok(map) => assert!(map.is_empty()), - Err(_) => { - // Also acceptable - contract info subtree may not exist - } - } + let map = result.expect("expected Ok result for identity without contract keys"); + assert!( + map.is_empty(), + "expected empty map when no contract keys exist" + ); } #[test] diff --git a/packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes/mod.rs b/packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes/mod.rs index 44970ec896e..4a683bd5399 100644 --- a/packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes/mod.rs +++ b/packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes/mod.rs @@ -279,15 +279,14 @@ mod tests { let non_unique_key = identity .public_keys() .values() - .find(|k| !k.key_type().is_unique_key_type()); + .find(|k| !k.key_type().is_unique_key_type()) + .expect("random identity should have at least one non-unique key"); - if let Some(key) = non_unique_key { - let hash = key.public_key_hash().expect("should hash"); - let result = drive - .has_non_unique_public_key_hash(hash, None, &platform_version.drive) - .expect("should not error"); - assert!(result); - } + let hash = non_unique_key.public_key_hash().expect("should hash"); + let result = drive + .has_non_unique_public_key_hash(hash, None, &platform_version.drive) + .expect("should not error"); + assert!(result, "expected non-unique key hash to be found"); } } diff --git a/packages/rs-drive/src/drive/identity/fetch/queries/mod.rs b/packages/rs-drive/src/drive/identity/fetch/queries/mod.rs index 23f5ac96954..ae26edb4f21 100644 --- a/packages/rs-drive/src/drive/identity/fetch/queries/mod.rs +++ b/packages/rs-drive/src/drive/identity/fetch/queries/mod.rs @@ -713,6 +713,9 @@ mod tests { assert!(!pq.path.is_empty()); assert!(pq.query.limit.is_none()); + // Note: currently the document type parameter does not affect the + // query path structure. This may be a bug or an intentional + // simplification in the current implementation. } #[test]