Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unit tests for VDR #20

Merged
merged 19 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
295 changes: 258 additions & 37 deletions vdr/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,28 @@ impl Debug for LedgerClient {
#[cfg(test)]
pub mod test {
use super::*;
use crate::types::EventLog;
use crate::{
client::MockClient, signer::basic_signer::test::basic_signer, types::EventLog, Role,
};
use async_trait::async_trait;
use once_cell::sync::Lazy;
use std::{env, fs};
use std::{env, fs, sync::RwLock};

pub const CONTRACT_NAME_EXAMPLE: &str = "ValidatorControl";
pub const CONTRACT_METHOD_EXAMPLE: &str = "addValidator";
pub const VALIDATOR_LIST_BYTES: Lazy<Vec<u8>> = Lazy::new(|| {
Artemkaaas marked this conversation as resolved.
Show resolved Hide resolved
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,
]
});

pub const CHAIN_ID: u64 = 1337;
pub const CONTRACTS_SPEC_BASE_PATH: &str = "../smart_contracts/artifacts/contracts/";
Expand All @@ -235,6 +253,8 @@ pub mod test {
"http://127.0.0.1:21004",
];
pub const DEFAULT_NONCE: u64 = 0;
pub static ACCOUNT_ROLES: [Role; 4] =
Artemkaaas marked this conversation as resolved.
Show resolved Hide resolved
[Role::Empty, Role::Trustee, Role::Steward, Role::Endorser];

pub static SCHEMA_REGISTRY_ADDRESS: Lazy<Address> =
Lazy::new(|| Address::from("0x0000000000000000000000000000000000005555"));
Expand Down Expand Up @@ -302,64 +322,265 @@ 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<u64> {
Ok(0)
}

async fn submit_transaction(&self, _transaction: &[u8]) -> VdrResult<Vec<u8>> {
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<Vec<u8>> {
todo!()
}
let mut client = MockClient::new();
client.expect_get_transaction_count().returning(|_| Ok(0));

async fn query_events(&self, _query: &EventQuery) -> VdrResult<Vec<EventLog>> {
todo!()
}
ledger_client.client = Box::new(client);
ledger_client
}

async fn get_receipt(&self, _hash: &[u8]) -> VdrResult<String> {
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<u64>) -> VdrResult<BlockDetails> {
todo!()
}
transaction
}

async fn get_transaction(&self, _hash: &[u8]) -> VdrResult<Option<Transaction>> {
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<dyn Client>) -> 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 mockall::predicate::eq;
use serde_json::Value;

use super::*;

#[test]
fn create_client_test() {
client();
}

#[test]
fn create_client_invalid_contract_data() {
let contract_config = vec![ContractConfig {
address: VALIDATOR_CONTROL_ADDRESS.to_string(),
spec_path: None,
spec: Some(ContractSpec {
name: CONTRACT_NAME_EXAMPLE.to_string(),
abi: Value::String("".to_string()),
}),
}];

let client_err = LedgerClient::new(CHAIN_ID, RPC_NODE_ADDRESS, &contract_config, None)
.err()
.unwrap();

assert!(matches!(
client_err, | VdrError::ContractInvalidInputData { .. }
));
}

#[test]
fn create_client_invalid_node_address() {
let client_err = LedgerClient::new(CHAIN_ID, "..", &contracts(), None)
.err()
.unwrap();

assert!(matches!(
client_err, | VdrError::ClientNodeUnreachable { .. }
));
}

#[test]
fn create_client_contract_path_and_spec_provided() {
Artemkaaas marked this conversation as resolved.
Show resolved Hide resolved
let contract_config = vec![ContractConfig {
address: VALIDATOR_CONTROL_ADDRESS.to_string(),
spec_path: Some(build_contract_path(VALIDATOR_CONTROL_PATH)),
spec: Some(ContractSpec {
name: CONTRACT_NAME_EXAMPLE.to_string(),
abi: Value::Array(vec![]),
Artemkaaas marked this conversation as resolved.
Show resolved Hide resolved
}),
}];

let client_err = LedgerClient::new(CHAIN_ID, RPC_NODE_ADDRESS, &contract_config, None)
.err()
.unwrap();

assert!(matches!(
client_err, | VdrError::ContractInvalidSpec { .. }
));
}
Artemkaaas marked this conversation as resolved.
Show resolved Hide resolved

#[test]
fn create_client_empty_contract_spec() {
let contract_config = vec![ContractConfig {
address: VALIDATOR_CONTROL_ADDRESS.to_string(),
spec_path: None,
spec: None,
}];

let client_err = LedgerClient::new(CHAIN_ID, RPC_NODE_ADDRESS, &contract_config, None)
.err()
.unwrap();

assert!(matches!(
client_err, | VdrError::ContractInvalidSpec { .. }
));
}

#[async_std::test]
async fn create_client_invalid_contract_address() {
let contract_config = vec![ContractConfig {
address: "123".to_string(),
spec_path: Some(build_contract_path(VALIDATOR_CONTROL_PATH)),
spec: None,
}];

let client_err = LedgerClient::new(CHAIN_ID, RPC_NODE_ADDRESS, &contract_config, None)
.err()
.unwrap();

assert!(matches!(
client_err, | VdrError::CommonInvalidData { .. }
));
}

#[async_std::test]
async fn call_transaction_empty_recipient_address() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combine these tests into single with cases

let transaction = Transaction {
to: Address::from(""),
..read_transaction()
};
let client = client();

let submit_err = client.submit_transaction(&transaction).await.unwrap_err();

assert!(matches!(
submit_err, | VdrError::ClientInvalidTransaction { .. }
));
}

#[async_std::test]
async fn call_transaction_invalid_recipient_address() {
let transaction = Transaction {
to: Address::from("123"),
..read_transaction()
};
let client = client();

let call_err = client.submit_transaction(&transaction).await.unwrap_err();

assert!(matches!(
call_err, | VdrError::ClientInvalidTransaction { .. }
));
}

#[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_transcation_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("123"))
Artemkaaas marked this conversation as resolved.
Show resolved Hide resolved
.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("123").err().unwrap();

assert!(matches!(
contract_err, | VdrError::ContractInvalidName { .. }
));
}
}

#[cfg(feature = "ledger_test")]
Expand Down
9 changes: 9 additions & 0 deletions vdr/src/client/implementation/web3/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,15 @@ impl Client for Web3Client {
async fn get_receipt(&self, hash: &[u8]) -> VdrResult<String> {
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()
Expand Down
18 changes: 18 additions & 0 deletions vdr/src/client/implementation/web3/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,21 @@ impl Debug for Web3Contract {
write!(f, r#"Web3Contract {{ address: {:?} }}"#, self.address)
}
}

#[cfg(test)]
pub mod test {
use crate::client::client::test::{mock_client, CONTRACT_NAME_EXAMPLE};

use super::*;
#[async_std::test]
async fn function_method_does_not_exist() {
let client = mock_client();
let contract = client.contract(&CONTRACT_NAME_EXAMPLE.to_string()).unwrap();

let err = contract.function("123").unwrap_err();

assert!(matches!(
err, | VdrError::ContractInvalidName { .. }
));
}
}
Loading
Loading