diff --git a/vdr/Cargo.lock b/vdr/Cargo.lock index 825467bf..de53b143 100644 --- a/vdr/Cargo.lock +++ b/vdr/Cargo.lock @@ -1047,6 +1047,12 @@ dependencies = [ "rand_core", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "gloo-timers" version = "0.2.6" @@ -1357,6 +1363,7 @@ dependencies = [ "mockall", "once_cell", "rand", + "rstest", "secp256k1 0.28.0", "serde", "serde_derive", @@ -2133,6 +2140,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "relative-path" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc" + [[package]] name = "reqwest" version = "0.11.23" @@ -2203,6 +2216,35 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "rstest" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97eeab2f3c0a199bc4be135c36c924b6590b88c377d416494288c14f2db30199" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" +dependencies = [ + "cfg-if", + "glob", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn 2.0.37", + "unicode-ident", +] + [[package]] name = "rustc-demangle" version = "0.1.23" diff --git a/vdr/Cargo.toml b/vdr/Cargo.toml index edadacd1..d239ddf9 100644 --- a/vdr/Cargo.toml +++ b/vdr/Cargo.toml @@ -47,6 +47,7 @@ web-sys = { version = "0.3.64", optional = true, features = ["Window"] } web3-wasm = { package = "web3", version = "0.19.0", default-features = false, features = ["wasm", "http", "http-tls"], optional = true } [dev-dependencies] +rstest = "0.18.2" mockall = "0.12.0" env_logger = "0.10.0" rand = "0.8.5" \ No newline at end of file diff --git a/vdr/src/client/client.rs b/vdr/src/client/client.rs index 091ed6b7..8fc12850 100644 --- a/vdr/src/client/client.rs +++ b/vdr/src/client/client.rs @@ -213,10 +213,9 @@ impl Debug for LedgerClient { #[cfg(test)] pub mod test { use super::*; - use crate::types::EventLog; - use async_trait::async_trait; + use crate::{client::MockClient, signer::basic_signer::test::basic_signer}; use once_cell::sync::Lazy; - use std::{env, fs}; + use std::{env, fs, sync::RwLock}; pub const CHAIN_ID: u64 = 1337; pub const CONTRACTS_SPEC_BASE_PATH: &str = "../smart_contracts/artifacts/contracts/"; @@ -235,6 +234,7 @@ pub mod test { "http://127.0.0.1:21004", ]; pub const DEFAULT_NONCE: u64 = 0; + pub const INVALID_ADDRESS: &str = "123"; pub static SCHEMA_REGISTRY_ADDRESS: Lazy
= Lazy::new(|| Address::from("0x0000000000000000000000000000000000005555")); @@ -302,64 +302,219 @@ pub mod test { LedgerClient::new(CHAIN_ID, RPC_NODE_ADDRESS, &contracts(), None).unwrap() } - pub struct MockClient {} - - impl Debug for MockClient { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, r#"MockClient {{ }}"#) - } - } - - #[async_trait] - impl Client for MockClient { - async fn get_transaction_count(&self, _address: &Address) -> VdrResult { - Ok(0) - } - - async fn submit_transaction(&self, _transaction: &[u8]) -> VdrResult> { - todo!() - } + pub fn mock_client() -> LedgerClient { + let mut ledger_client = LedgerClient::new( + CHAIN_ID, + RPC_NODE_ADDRESS, + &contracts(), + Some(&QuorumConfig::default()), + ) + .unwrap(); - async fn call_transaction(&self, _to: &str, _transaction: &[u8]) -> VdrResult> { - todo!() - } + let mut client = MockClient::new(); + client.expect_get_transaction_count().returning(|_| Ok(0)); - async fn query_events(&self, _query: &EventQuery) -> VdrResult> { - todo!() - } + ledger_client.client = Box::new(client); + ledger_client + } - async fn get_receipt(&self, _hash: &[u8]) -> VdrResult { - todo!() - } + pub fn write_transaction() -> Transaction { + let transaction = Transaction { + type_: TransactionType::Write, + from: Some(TRUSTEE_ACC.clone()), + to: VALIDATOR_CONTROL_ADDRESS.clone(), + nonce: Some(DEFAULT_NONCE.clone()), + chain_id: CHAIN_ID, + data: vec![], + signature: RwLock::new(None), + hash: None, + }; + let signer = basic_signer(); + let sign_bytes = transaction.get_signing_bytes().unwrap(); + let signature = signer.sign(&sign_bytes, TRUSTEE_ACC.as_ref()).unwrap(); + transaction.set_signature(signature); - async fn get_block(&self, _block: Option) -> VdrResult { - todo!() - } + transaction + } - async fn get_transaction(&self, _hash: &[u8]) -> VdrResult> { - todo!() + pub fn read_transaction() -> Transaction { + Transaction { + type_: TransactionType::Read, + from: None, + to: VALIDATOR_CONTROL_ADDRESS.clone(), + nonce: None, + chain_id: CHAIN_ID, + data: vec![], + signature: RwLock::new(None), + hash: None, } } - pub fn mock_client() -> LedgerClient { - let mut client = LedgerClient::new( + pub fn mock_custom_client(client: Box) -> LedgerClient { + let mut ledger_client = LedgerClient::new( CHAIN_ID, RPC_NODE_ADDRESS, &contracts(), Some(&QuorumConfig::default()), ) .unwrap(); - client.client = Box::new(MockClient {}); - client + + ledger_client.client = client; + ledger_client } mod create { + use crate::validator_control::test::VALIDATOR_CONTROL_NAME; + use mockall::predicate::eq; + use rstest::rstest; + use serde_json::Value; + use super::*; #[test] fn create_client_test() { client(); } + + #[test] + fn create_client_invalid_node_address() { + let client_err = LedgerClient::new(CHAIN_ID, "..", &contracts(), None) + .err() + .unwrap(); + + assert!(matches!( + client_err, | VdrError::ClientNodeUnreachable { .. } + )); + } + + #[rstest] + #[case::invalid_contract_data(vec![ContractConfig { + address: VALIDATOR_CONTROL_ADDRESS.to_string(), + spec_path: None, + spec: Some(ContractSpec { + name: VALIDATOR_CONTROL_NAME.to_string(), + abi: Value::String("".to_string()), + }), + }], VdrError::ContractInvalidInputData)] + #[case::both_contract_path_and_spec_provided(vec![ContractConfig { + address: VALIDATOR_CONTROL_ADDRESS.to_string(), + spec_path: Some(build_contract_path(VALIDATOR_CONTROL_PATH)), + spec: Some(ContractSpec { + name: VALIDATOR_CONTROL_NAME.to_string(), + abi: Value::Array(vec ! []), + }), + }], VdrError::ContractInvalidSpec("".to_string()))] + #[case::non_existent_spec_path(vec![ContractConfig { + address: VALIDATOR_CONTROL_ADDRESS.to_string(), + spec_path: Some(build_contract_path("")), + spec: None, + }], VdrError::ContractInvalidSpec("".to_string()))] + #[case::empty_contract_spec(vec![ContractConfig { + address: VALIDATOR_CONTROL_ADDRESS.to_string(), + spec_path: None, + spec: None, + }], VdrError::ContractInvalidSpec("".to_string()))] + fn test_create_client_errors( + #[case] contract_config: Vec, + #[case] expected_error: VdrError, + ) { + let client_err = LedgerClient::new(CHAIN_ID, RPC_NODE_ADDRESS, &contract_config, None) + .err() + .unwrap(); + + assert!(matches!(client_err, expected_error)); + } + + #[rstest] + #[case::empty_recipient_address("", VdrError::ClientInvalidTransaction("".to_string()))] + #[case::invalid_recipient_address(INVALID_ADDRESS, VdrError::ClientInvalidTransaction("".to_string()))] + async fn call_transaction_various_recipient_addresses( + #[case] recipient_address: &str, + #[case] expected_error: VdrError, + ) { + let transaction = Transaction { + to: Address::from(recipient_address), + ..read_transaction() + }; + let client = client(); + + let error = client.submit_transaction(&transaction).await.unwrap_err(); + + assert!(matches!(error, expected_error)); + } + + #[async_std::test] + async fn get_receipt_invalid_transaction_hash() { + let client = client(); + let txn_hash = vec![1; 4]; + + let receipt_err = client.get_receipt(&txn_hash).await.unwrap_err(); + + assert!(matches!( + receipt_err, | VdrError::CommonInvalidData { .. } + )); + } + + #[async_std::test] + async fn get_receipt_transaction_does_not_exist() { + let mut client_mock = MockClient::new(); + let txn_hash = vec![1; 32]; + client_mock + .expect_get_receipt() + .with(eq(txn_hash.clone())) + .returning(|_| { + Err(VdrError::ClientInvalidResponse( + "Missing transaction receipt".to_string(), + )) + }); + + let client = mock_custom_client(Box::new(client_mock)); + + let receipt_err = client.get_receipt(&txn_hash).await.unwrap_err(); + + assert!(matches!( + receipt_err, | VdrError::ClientInvalidResponse { .. } + )); + } + + #[async_std::test] + async fn get_receipt_positive() { + let mut client_mock = MockClient::new(); + let txn_hash = vec![1; 32]; + client_mock + .expect_get_receipt() + .with(eq(txn_hash.clone())) + .returning(|_| Ok("".to_string())); + + let client = mock_custom_client(Box::new(client_mock)); + + client.get_receipt(&txn_hash).await.unwrap(); + } + + #[async_std::test] + async fn get_transaction_count_invalid_address() { + let client = client(); + + let get_nonce_err = client + .get_transaction_count(&Address::from(INVALID_ADDRESS)) + .await + .unwrap_err(); + + assert!(matches!( + get_nonce_err, | VdrError::ClientInvalidTransaction { .. } + )); + } + + #[async_std::test] + async fn get_contract_does_not_exist() { + let client = client(); + + let contract_err = client.contract(INVALID_ADDRESS).err().unwrap(); + + assert!(matches!( + contract_err, | VdrError::ContractInvalidName { .. } + )); + } } #[cfg(feature = "ledger_test")] diff --git a/vdr/src/client/implementation/web3/client.rs b/vdr/src/client/implementation/web3/client.rs index eb46b2de..88694ba4 100644 --- a/vdr/src/client/implementation/web3/client.rs +++ b/vdr/src/client/implementation/web3/client.rs @@ -216,6 +216,15 @@ impl Client for Web3Client { async fn get_receipt(&self, hash: &[u8]) -> VdrResult { trace!("Web3Client::get_receipt(hash: {:?})", hash); + if hash.len() != 32 { + let vdr_error = + VdrError::CommonInvalidData("Transaction hash length != 32 bytes".to_string()); + + warn!("Error: {} getting receipt", vdr_error,); + + return Err(vdr_error); + } + let receipt = self .client .eth() diff --git a/vdr/src/client/implementation/web3/contract.rs b/vdr/src/client/implementation/web3/contract.rs index b86794dc..125af635 100644 --- a/vdr/src/client/implementation/web3/contract.rs +++ b/vdr/src/client/implementation/web3/contract.rs @@ -115,3 +115,26 @@ impl Debug for Web3Contract { write!(f, r#"Web3Contract {{ address: {:?} }}"#, self.address) } } + +#[cfg(test)] +pub mod test { + use crate::{ + client::client::test::{mock_client, INVALID_ADDRESS}, + validator_control::test::VALIDATOR_CONTROL_NAME, + }; + + use super::*; + #[async_std::test] + async fn function_method_does_not_exist() { + let client = mock_client(); + let contract = client + .contract(&VALIDATOR_CONTROL_NAME.to_string()) + .unwrap(); + + let err = contract.function(INVALID_ADDRESS).unwrap_err(); + + assert!(matches!( + err, | VdrError::ContractInvalidName { .. } + )); + } +} diff --git a/vdr/src/contracts/auth/role_control.rs b/vdr/src/contracts/auth/role_control.rs index 4987e877..97c662f7 100644 --- a/vdr/src/contracts/auth/role_control.rs +++ b/vdr/src/contracts/auth/role_control.rs @@ -164,6 +164,9 @@ pub mod test { }; use std::sync::RwLock; + pub static ACCOUNT_ROLES: [Role; 4] = + [Role::Empty, Role::Trustee, Role::Steward, Role::Endorser]; + pub const NEW_ACCOUNT: &str = "0x0886328869e4e1f401e1052a5f4aae8b45f42610"; fn account() -> Address { diff --git a/vdr/src/contracts/cl/credential_definition_registry.rs b/vdr/src/contracts/cl/credential_definition_registry.rs index f624c169..c2227b17 100644 --- a/vdr/src/contracts/cl/credential_definition_registry.rs +++ b/vdr/src/contracts/cl/credential_definition_registry.rs @@ -359,43 +359,43 @@ pub mod test { } } - // mod parse_resolve_credential_definition_result { - // use super::*; - // - // #[test] - // fn parse_resolve_credential_definition_result_test() { - // init_env_logger(); - // let client = mock_client(); - // let data = vec![ - // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - // 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - // 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 166, 63, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 123, 34, 99, 114, - // 101, 100, 68, 101, 102, 84, 121, 112, 101, 34, 58, 34, 67, 76, 34, 44, 34, 105, - // 115, 115, 117, 101, 114, 73, 100, 34, 58, 34, 100, 105, 100, 58, 105, 110, 100, - // 121, 50, 58, 116, 101, 115, 116, 110, 101, 116, 58, 51, 76, 112, 106, 115, 122, - // 107, 103, 84, 109, 69, 51, 113, 84, 104, 103, 101, 50, 53, 70, 90, 119, 34, 44, 34, - // 115, 99, 104, 101, 109, 97, 73, 100, 34, 58, 34, 100, 105, 100, 58, 105, 110, 100, - // 121, 50, 58, 116, 101, 115, 116, 110, 101, 116, 58, 51, 76, 112, 106, 115, 122, - // 107, 103, 84, 109, 69, 51, 113, 84, 104, 103, 101, 50, 53, 70, 90, 119, 47, 97, - // 110, 111, 110, 99, 114, 101, 100, 115, 47, 118, 48, 47, 83, 67, 72, 69, 77, 65, 47, - // 70, 49, 68, 67, 108, 97, 70, 69, 122, 105, 51, 116, 47, 49, 46, 48, 46, 48, 34, 44, - // 34, 116, 97, 103, 34, 58, 34, 100, 101, 102, 97, 117, 108, 116, 34, 44, 34, 118, - // 97, 108, 117, 101, 34, 58, 123, 34, 110, 34, 58, 34, 55, 55, 57, 46, 46, 46, 51, - // 57, 55, 34, 44, 34, 114, 99, 116, 120, 116, 34, 58, 34, 55, 55, 52, 46, 46, 46, 57, - // 55, 55, 34, 44, 34, 115, 34, 58, 34, 55, 53, 48, 46, 46, 56, 57, 51, 34, 44, 34, - // 122, 34, 58, 34, 54, 51, 50, 46, 46, 46, 48, 48, 53, 34, 125, 125, 0, 0, 0, 0, 0, - // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - // ]; - // let parsed_cred_def = - // parse_resolve_credential_definition_result(&client, &data).unwrap(); - // let (_, expected_cred_def) = credential_definition( - // &DID::from(ISSUER_ID), - // &SchemaId::from(SCHEMA_ID), - // Some(CREDENTIAL_DEFINITION_TAG), - // ); - // assert_eq!(expected_cred_def, parsed_cred_def); - // } - // } + mod parse_resolve_credential_definition_result { + use super::*; + + // #[test] + // fn parse_resolve_credential_definition_result_test() { + // init_env_logger(); + // let client = mock_client(); + // let data = vec![ + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 166, 63, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 123, 34, 99, 114, + // 101, 100, 68, 101, 102, 84, 121, 112, 101, 34, 58, 34, 67, 76, 34, 44, 34, 105, + // 115, 115, 117, 101, 114, 73, 100, 34, 58, 34, 100, 105, 100, 58, 105, 110, 100, + // 121, 50, 58, 116, 101, 115, 116, 110, 101, 116, 58, 51, 76, 112, 106, 115, 122, + // 107, 103, 84, 109, 69, 51, 113, 84, 104, 103, 101, 50, 53, 70, 90, 119, 34, 44, 34, + // 115, 99, 104, 101, 109, 97, 73, 100, 34, 58, 34, 100, 105, 100, 58, 105, 110, 100, + // 121, 50, 58, 116, 101, 115, 116, 110, 101, 116, 58, 51, 76, 112, 106, 115, 122, + // 107, 103, 84, 109, 69, 51, 113, 84, 104, 103, 101, 50, 53, 70, 90, 119, 47, 97, + // 110, 111, 110, 99, 114, 101, 100, 115, 47, 118, 48, 47, 83, 67, 72, 69, 77, 65, 47, + // 70, 49, 68, 67, 108, 97, 70, 69, 122, 105, 51, 116, 47, 49, 46, 48, 46, 48, 34, 44, + // 34, 116, 97, 103, 34, 58, 34, 100, 101, 102, 97, 117, 108, 116, 34, 44, 34, 118, + // 97, 108, 117, 101, 34, 58, 123, 34, 110, 34, 58, 34, 55, 55, 57, 46, 46, 46, 51, + // 57, 55, 34, 44, 34, 114, 99, 116, 120, 116, 34, 58, 34, 55, 55, 52, 46, 46, 46, 57, + // 55, 55, 34, 44, 34, 115, 34, 58, 34, 55, 53, 48, 46, 46, 56, 57, 51, 34, 44, 34, + // 122, 34, 58, 34, 54, 51, 50, 46, 46, 46, 48, 48, 53, 34, 125, 125, 0, 0, 0, 0, 0, + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // ]; + // let parsed_cred_def = + // parse_resolve_credential_definition_result(&client, &data).unwrap(); + // let (_, expected_cred_def) = credential_definition( + // &DID::from(ISSUER_ID), + // &SchemaId::from(SCHEMA_ID), + // Some(CREDENTIAL_DEFINITION_TAG), + // ); + // assert_eq!(expected_cred_def, parsed_cred_def); + // } + } } diff --git a/vdr/src/contracts/cl/schema_registry.rs b/vdr/src/contracts/cl/schema_registry.rs index cd4abedb..58ab75ca 100644 --- a/vdr/src/contracts/cl/schema_registry.rs +++ b/vdr/src/contracts/cl/schema_registry.rs @@ -282,16 +282,15 @@ pub mod test { 145, 232, 190, 123, 84, 240, 64, 217, 94, 167, 52, 119, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 153, 123, 34, 105, 115, 115, 117, 101, 114, 73, 100, 34, 58, 34, + 0, 0, 0, 0, 0, 141, 123, 34, 105, 115, 115, 117, 101, 114, 73, 100, 34, 58, 34, 100, 105, 100, 58, 101, 116, 104, 114, 58, 116, 101, 115, 116, 110, 101, 116, 58, 48, 120, 102, 48, 101, 50, 100, 98, 54, 99, 56, 100, 99, 54, 99, 54, 56, 49, 98, 98, 53, 100, 54, 97, 100, 49, 50, 49, 97, 49, 48, 55, 102, 51, 48, 48, 101, 57, 98, 50, 98, 53, 34, 44, 34, 110, 97, 109, 101, 34, 58, 34, 70, 49, 68, 67, 108, 97, 70, 69, 122, 105, 51, 116, 34, 44, 34, 118, 101, 114, 115, 105, 111, 110, 34, 58, 34, 49, 46, 48, 46, 48, 34, 44, 34, 97, 116, 116, 114, 78, - 97, 109, 101, 115, 34, 58, 91, 34, 76, 97, 115, 116, 32, 78, 97, 109, 101, 34, - 44, 34, 70, 105, 114, 115, 116, 32, 78, 97, 109, 101, 34, 93, 125, 0, 0, 0, 0, - 0, 0, 0, + 97, 109, 101, 115, 34, 58, 91, 34, 70, 105, 114, 115, 116, 32, 78, 97, 109, + 101, 34, 93, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], signature: RwLock::new(None), hash: None, diff --git a/vdr/src/contracts/cl/types/schema.rs b/vdr/src/contracts/cl/types/schema.rs index b0595893..2b41196a 100644 --- a/vdr/src/contracts/cl/types/schema.rs +++ b/vdr/src/contracts/cl/types/schema.rs @@ -83,7 +83,6 @@ pub mod test { pub const SCHEMA_NAME: &str = "F1DClaFEzi3t"; pub const SCHEMA_VERSION: &str = "1.0.0"; pub const SCHEMA_ATTRIBUTE_FIRST_NAME: &str = "First Name"; - pub const SCHEMA_ATTRIBUTE_LAST_NAME: &str = "Last Name"; pub fn schema_id(issuer_id: &DID, name: &str) -> SchemaId { SchemaId::build(issuer_id, name, SCHEMA_VERSION) @@ -94,7 +93,6 @@ pub mod test { let id = schema_id(issuer_id, name.as_str()); let mut attr_names: HashSet = HashSet::new(); attr_names.insert(SCHEMA_ATTRIBUTE_FIRST_NAME.to_string()); - attr_names.insert(SCHEMA_ATTRIBUTE_LAST_NAME.to_string()); let schema = Schema { issuer_id: issuer_id.clone(), diff --git a/vdr/src/contracts/mod.rs b/vdr/src/contracts/mod.rs index 6adc8488..abb5123d 100644 --- a/vdr/src/contracts/mod.rs +++ b/vdr/src/contracts/mod.rs @@ -3,7 +3,4 @@ pub mod cl; pub mod did; pub mod network; -pub use auth::{role_control, Role}; -pub use cl::{credential_definition_registry, schema_registry, CredentialDefinition, Schema}; pub use did::*; -pub use network::validator_control; diff --git a/vdr/src/contracts/network/validator_control.rs b/vdr/src/contracts/network/validator_control.rs index 8a95956a..115c8467 100644 --- a/vdr/src/contracts/network/validator_control.rs +++ b/vdr/src/contracts/network/validator_control.rs @@ -118,6 +118,22 @@ pub mod test { pub static VALIDATOR_ADDRESS: Lazy
= Lazy::new(|| Address::from("0x93917cadbace5dfce132b991732c6cda9bcc5b8a")); + pub const VALIDATOR_CONTROL_NAME: &str = "ValidatorControl"; + pub const ADD_VALIDATOR_METHOD: &str = "addValidator"; + pub const VALIDATOR_LIST_BYTES: Lazy> = Lazy::new(|| { + vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 145, 124, 173, 186, 206, 93, + 252, 225, 50, 185, 145, 115, 44, 108, 218, 155, 204, 91, 138, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 39, 169, 124, 154, 175, 4, 241, 143, 48, 20, 195, 46, 3, 109, 208, 172, + 118, 218, 95, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 65, 47, 152, 131, 119, 227, + 31, 77, 15, 241, 45, 116, 223, 115, 181, 28, 66, 208, 202, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 152, 193, 51, 68, 150, 97, 74, 237, 73, 210, 232, 21, 38, 208, 137, 247, 38, + 79, 237, 156, + ] + }); + mod build_add_validator_transaction { use super::*; diff --git a/vdr/src/types/transaction.rs b/vdr/src/types/transaction.rs index 0d81add3..49818881 100644 --- a/vdr/src/types/transaction.rs +++ b/vdr/src/types/transaction.rs @@ -495,3 +495,228 @@ pub struct BlockDetails { pub number: u64, pub timestamp: u64, } + +#[cfg(test)] +pub mod test { + use super::*; + use crate::{ + client::client::test::{mock_client, write_transaction, INVALID_ADDRESS}, + contracts::network::test::{ + ADD_VALIDATOR_METHOD, VALIDATOR_ADDRESS, VALIDATOR_CONTROL_NAME, VALIDATOR_LIST_BYTES, + }, + }; + + const INVALID_METHOD: Option<&str> = Some(INVALID_ADDRESS); + const INVALID_CONTRACT: Option<&str> = Some(INVALID_ADDRESS); + const INVALID_ACC_ADDRESS: Option<&str> = Some(INVALID_ADDRESS); + const CONTRACT_METHOD_EXAMPLE: Option<&str> = Some(ADD_VALIDATOR_METHOD); + const CONTRACT_NAME_EXAMPLE: Option<&str> = Some(VALIDATOR_CONTROL_NAME); + + #[cfg(test)] + pub mod txn_test { + use super::*; + + #[async_std::test] + async fn get_to_invalid() { + let transaction = Transaction { + to: Address::from(INVALID_ADDRESS), + ..write_transaction() + }; + + let get_to_err = transaction.get_to().unwrap_err(); + + assert!(matches!( + get_to_err, | VdrError::ClientInvalidTransaction { .. } + )); + } + + #[async_std::test] + async fn get_nonce_not_set() { + let transaction = Transaction { + nonce: None, + ..write_transaction() + }; + + let get_nonce_err = transaction.get_nonce().unwrap_err(); + + assert!(matches!( + get_nonce_err, | VdrError::ClientInvalidTransaction { .. } + )); + } + + #[async_std::test] + async fn get_transaction_signature_not_set() { + let transaction = Transaction { + signature: RwLock::new(None), + ..write_transaction() + }; + + let get_sig_err = transaction.get_transaction_signature().unwrap_err(); + + assert!(matches!( + get_sig_err, | VdrError::ClientInvalidTransaction { .. } + )); + } + + #[async_std::test] + async fn get_transaction_signature_invalid() { + let transaction = Transaction { + signature: RwLock::new(Some(TransactionSignature { + v: 1, + r: vec![1; 32], + s: vec![1; 32], + })), + ..write_transaction() + }; + + let get_sig_err = transaction.get_transaction_signature().unwrap_err(); + + assert!(matches!( + get_sig_err, | VdrError::ClientInvalidTransaction { .. } + )); + } + } + + #[cfg(test)] + pub mod txn_builder_test { + use super::*; + use rstest::rstest; + use std::ops::Deref; + + #[rstest] + #[case::contract_name_does_not_set( + None, + CONTRACT_METHOD_EXAMPLE, + Some(TransactionType::Read), + None, + VdrError::ContractInvalidName("".to_string()) + )] + #[case::contract_method_does_not_set( + CONTRACT_NAME_EXAMPLE, + None, + Some(TransactionType::Read), + None, + VdrError::ContractInvalidName("".to_string()) + )] + #[case::contract_method_does_not_exist( + CONTRACT_NAME_EXAMPLE, + INVALID_METHOD, + Some(TransactionType::Read), + None, + VdrError::ContractInvalidName("".to_string()) + )] + #[case::write_sender_does_not_set( + CONTRACT_NAME_EXAMPLE, + CONTRACT_METHOD_EXAMPLE, + Some(TransactionType::Write), + None, + VdrError::ClientInvalidTransaction("".to_string()) + )] + #[case::invalid_from_address( + CONTRACT_NAME_EXAMPLE, + CONTRACT_METHOD_EXAMPLE, + Some(TransactionType::Write), + INVALID_ACC_ADDRESS, + VdrError::ClientInvalidTransaction("".to_string()) + )] + async fn transaction_builder_tests( + #[case] contract: Option<&str>, + #[case] method: Option<&str>, + #[case] txn_type: Option, + #[case] from: Option<&str>, + #[case] expected_error: VdrError, + ) { + let client = mock_client(); + + let mut builder = TransactionBuilder::new() + .add_param(VALIDATOR_ADDRESS.deref()) + .unwrap(); + + if let Some(contract) = contract { + builder = builder.set_contract(contract); + } + + if let Some(method) = method { + builder = builder.set_method(method); + } + + if let Some(txn_type) = txn_type.clone() { + builder = builder.set_type(txn_type); + } + + if let Some(from) = from { + builder = builder.set_from(&Address::from(from)); + } + + let result = builder.build(&client).await; + + match result { + Ok(ref txn) => assert_eq!(txn.type_, txn_type.unwrap()), + Err(ref err) => assert!(matches!(err.clone(), expected_error)), + } + } + } + + #[cfg(test)] + pub mod txn_parser_test { + use super::*; + use crate::contracts::network::ValidatorAddresses; + use once_cell::sync::Lazy; + use rstest::rstest; + + const EMPTY_RESPONSE: Lazy> = Lazy::new(|| Vec::new()); + + #[rstest] + #[case::empty_response_bytes( + CONTRACT_NAME_EXAMPLE, + CONTRACT_METHOD_EXAMPLE, + EMPTY_RESPONSE, + VdrError::ContractInvalidResponseData("".to_string()) + )] + #[case::contract_not_set( + None, + CONTRACT_METHOD_EXAMPLE, + VALIDATOR_LIST_BYTES, + VdrError::ContractInvalidName("".to_string()) + )] + #[case::contract_does_not_exist( + INVALID_CONTRACT, + CONTRACT_METHOD_EXAMPLE, + VALIDATOR_LIST_BYTES, + VdrError::ContractInvalidName("".to_string()) + )] + #[case::contract_method_not_set( + CONTRACT_NAME_EXAMPLE, + None, + VALIDATOR_LIST_BYTES, + VdrError::ContractInvalidName("".to_string()) + )] + #[case::contract_method_does_not_exist( + CONTRACT_NAME_EXAMPLE, + INVALID_METHOD, + VALIDATOR_LIST_BYTES, + VdrError::ContractInvalidName("".to_string()) + )] + async fn transaction_parser_tests( + #[case] contract: Option<&str>, + #[case] method: Option<&str>, + #[case] response: Lazy, fn() -> Vec>, + #[case] expected_error: VdrError, + ) { + let client = mock_client(); + let mut parser = TransactionParser::new(); + + if let Some(contract) = contract { + parser = parser.set_contract(contract); + } + + if let Some(method) = method { + parser = parser.set_method(method); + } + + let result = parser.parse::(&client, response.as_slice()); + + assert!(matches!(result.unwrap_err(), expected_error)); + } + } +}