Skip to content

Commit e0e9801

Browse files
authored
test: Unit tests solver account and delivery (#124)
* test: Unit test cases * test: Improving mock inside solver-service * test: Adding builder for order * test: Using builders and other fixes * test: Moving builder to test folder * test: Fixes * chore: Sort deps * test: Removing validation for network builder
1 parent a5990d3 commit e0e9801

24 files changed

Lines changed: 602 additions & 92 deletions

File tree

Cargo.lock

Lines changed: 6 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/solver-account/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,7 @@ async-trait = "0.1"
1414
hex = "0.4"
1515
solver-types = { path = "../solver-types" }
1616
thiserror = "1.0"
17-
toml = { workspace = true }
17+
toml = { workspace = true }
18+
19+
[dev-dependencies]
20+
tokio = { workspace = true }

crates/solver-account/src/implementations/local.rs

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use solver_types::{
2020
/// This implementation manages a private key locally and uses it to sign
2121
/// transactions and messages. It's suitable for development and testing
2222
/// environments where key management simplicity is preferred.
23+
#[derive(Debug)]
2324
pub struct LocalWallet {
2425
/// The underlying Alloy signer that handles cryptographic operations.
2526
signer: PrivateKeySigner,
@@ -188,3 +189,185 @@ impl solver_types::ImplementationRegistry for Registry {
188189
}
189190

190191
impl crate::AccountRegistry for Registry {}
192+
193+
#[cfg(test)]
194+
mod tests {
195+
use super::*;
196+
use solver_types::{
197+
utils::tests::builders::TransactionBuilder, Address, ImplementationRegistry, Transaction,
198+
};
199+
use std::collections::HashMap;
200+
201+
// Test private key (FOR TESTING ONLY!)
202+
const TEST_PRIVATE_KEY: &str =
203+
"ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
204+
const TEST_PRIVATE_KEY_WITH_PREFIX: &str =
205+
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
206+
const INVALID_PRIVATE_KEY: &str = "invalid_key";
207+
const SHORT_PRIVATE_KEY: &str = "1234";
208+
209+
fn create_test_config(private_key: &str) -> toml::Value {
210+
let mut config = HashMap::new();
211+
config.insert(
212+
"private_key".to_string(),
213+
toml::Value::String(private_key.to_string()),
214+
);
215+
toml::Value::Table(config.into_iter().collect())
216+
}
217+
218+
fn create_test_transaction() -> Transaction {
219+
TransactionBuilder::new().gas_price_gwei(21).build()
220+
}
221+
222+
#[test]
223+
fn test_local_wallet_new_valid_key() {
224+
let wallet = LocalWallet::new(TEST_PRIVATE_KEY).unwrap();
225+
assert!(wallet.signer.to_bytes().len() == 32);
226+
}
227+
228+
#[test]
229+
fn test_local_wallet_new_valid_key_with_prefix() {
230+
let wallet = LocalWallet::new(TEST_PRIVATE_KEY_WITH_PREFIX).unwrap();
231+
assert!(wallet.signer.to_bytes().len() == 32);
232+
}
233+
234+
#[test]
235+
fn test_local_wallet_new_invalid_key() {
236+
let result = LocalWallet::new(INVALID_PRIVATE_KEY);
237+
assert!(result.is_err());
238+
assert!(matches!(result.unwrap_err(), AccountError::InvalidKey(_)));
239+
}
240+
241+
#[test]
242+
fn test_local_wallet_get_private_key() {
243+
let wallet = LocalWallet::new(TEST_PRIVATE_KEY).unwrap();
244+
let private_key = wallet.get_private_key();
245+
let private_key_str = private_key.with_exposed(|s| s.to_string());
246+
assert!(private_key_str.starts_with("0x"));
247+
assert_eq!(private_key_str.len(), 66); // 0x + 64 hex chars
248+
}
249+
250+
#[test]
251+
fn test_schema_validation_valid_config() {
252+
let config = create_test_config(TEST_PRIVATE_KEY);
253+
let result = LocalWalletSchema::validate_config(&config);
254+
assert!(result.is_ok());
255+
}
256+
257+
#[test]
258+
fn test_schema_validation_valid_config_with_prefix() {
259+
let config = create_test_config(TEST_PRIVATE_KEY_WITH_PREFIX);
260+
let result = LocalWalletSchema::validate_config(&config);
261+
assert!(result.is_ok());
262+
}
263+
264+
#[test]
265+
fn test_schema_validation_invalid_hex() {
266+
let config = create_test_config(INVALID_PRIVATE_KEY);
267+
let result = LocalWalletSchema::validate_config(&config);
268+
assert!(result.is_err());
269+
}
270+
271+
#[test]
272+
fn test_schema_validation_short_key() {
273+
let config = create_test_config(SHORT_PRIVATE_KEY);
274+
let result = LocalWalletSchema::validate_config(&config);
275+
assert!(result.is_err());
276+
}
277+
278+
#[test]
279+
fn test_schema_validation_missing_private_key() {
280+
let config = toml::Value::Table(HashMap::new().into_iter().collect());
281+
let result = LocalWalletSchema::validate_config(&config);
282+
assert!(result.is_err());
283+
}
284+
285+
#[tokio::test]
286+
async fn test_account_interface_address() {
287+
let wallet = LocalWallet::new(TEST_PRIVATE_KEY).unwrap();
288+
let address = wallet.address().await.unwrap();
289+
assert_eq!(address.0.len(), 20);
290+
}
291+
292+
#[tokio::test]
293+
async fn test_account_interface_sign_transaction() {
294+
let wallet = LocalWallet::new(TEST_PRIVATE_KEY).unwrap();
295+
let tx = create_test_transaction();
296+
let signature = wallet.sign_transaction(&tx).await.unwrap();
297+
assert!(!signature.0.is_empty());
298+
}
299+
300+
#[tokio::test]
301+
async fn test_account_interface_sign_transaction_invalid_address() {
302+
let wallet = LocalWallet::new(TEST_PRIVATE_KEY).unwrap();
303+
let mut tx = create_test_transaction();
304+
tx.to = Some(Address(vec![0u8; 19])); // Invalid address length
305+
306+
let result = wallet.sign_transaction(&tx).await;
307+
assert!(result.is_err());
308+
assert!(matches!(
309+
result.unwrap_err(),
310+
AccountError::SigningFailed(_)
311+
));
312+
}
313+
314+
#[tokio::test]
315+
async fn test_account_interface_sign_transaction_contract_creation() {
316+
let wallet = LocalWallet::new(TEST_PRIVATE_KEY).unwrap();
317+
let mut tx = create_test_transaction();
318+
tx.to = None; // Contract creation
319+
320+
let signature = wallet.sign_transaction(&tx).await.unwrap();
321+
assert!(!signature.0.is_empty());
322+
}
323+
324+
#[tokio::test]
325+
async fn test_account_interface_sign_message() {
326+
let wallet = LocalWallet::new(TEST_PRIVATE_KEY).unwrap();
327+
let message = b"Hello, World!";
328+
let signature = wallet.sign_message(message).await.unwrap();
329+
assert!(!signature.0.is_empty());
330+
}
331+
332+
#[test]
333+
fn test_create_account_valid_config() {
334+
let config = create_test_config(TEST_PRIVATE_KEY);
335+
let account = create_account(&config).unwrap();
336+
assert!(!account.get_private_key().with_exposed(|s| s.is_empty()));
337+
}
338+
339+
#[test]
340+
fn test_create_account_invalid_config() {
341+
let config = create_test_config(INVALID_PRIVATE_KEY);
342+
let result = create_account(&config);
343+
assert!(result.is_err());
344+
}
345+
346+
#[test]
347+
fn test_create_account_missing_private_key() {
348+
let config = toml::Value::Table(HashMap::new().into_iter().collect());
349+
let result = create_account(&config);
350+
assert!(result.is_err());
351+
}
352+
353+
#[test]
354+
fn test_registry_name() {
355+
assert_eq!(Registry::NAME, "local");
356+
}
357+
358+
#[test]
359+
fn test_registry_factory() {
360+
let factory = Registry::factory();
361+
let config = create_test_config(TEST_PRIVATE_KEY);
362+
let account = factory(&config).unwrap();
363+
assert!(!account.get_private_key().with_exposed(|s| s.is_empty()));
364+
}
365+
366+
#[test]
367+
fn test_config_schema_interface() {
368+
let wallet = LocalWallet::new(TEST_PRIVATE_KEY).unwrap();
369+
let schema = wallet.config_schema();
370+
let config = create_test_config(TEST_PRIVATE_KEY);
371+
assert!(schema.validate(&config).is_ok());
372+
}
373+
}

crates/solver-delivery/src/implementations/evm/alloy.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,3 +564,117 @@ impl solver_types::ImplementationRegistry for Registry {
564564
}
565565

566566
impl crate::DeliveryRegistry for Registry {}
567+
568+
#[cfg(test)]
569+
mod tests {
570+
use super::*;
571+
use solver_types::{
572+
utils::tests::builders::{NetworkConfigBuilder, NetworksConfigBuilder, RpcEndpointBuilder},
573+
SecretString,
574+
};
575+
use std::collections::HashMap;
576+
577+
fn create_test_networks() -> NetworksConfig {
578+
NetworksConfigBuilder::new()
579+
.add_network(
580+
1,
581+
NetworkConfigBuilder::new()
582+
.add_rpc_endpoint(RpcEndpointBuilder::new().build())
583+
.build(),
584+
)
585+
.build()
586+
}
587+
588+
fn create_test_signer() -> PrivateKeySigner {
589+
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
590+
.parse()
591+
.unwrap()
592+
}
593+
594+
#[tokio::test]
595+
async fn test_alloy_delivery_new_success() {
596+
let networks = create_test_networks();
597+
let signer = create_test_signer();
598+
599+
let result = AlloyDelivery::new(vec![1], &networks, HashMap::new(), signer).await;
600+
601+
assert!(result.is_ok());
602+
let delivery = result.unwrap();
603+
assert!(delivery.providers.contains_key(&1));
604+
}
605+
606+
#[tokio::test]
607+
async fn test_alloy_delivery_new_empty_networks() {
608+
let networks = NetworksConfigBuilder::new().build();
609+
let signer = create_test_signer();
610+
611+
let result = AlloyDelivery::new(vec![], &networks, HashMap::new(), signer).await;
612+
613+
assert!(matches!(result, Err(DeliveryError::Network(_))));
614+
if let Err(DeliveryError::Network(msg)) = result {
615+
assert!(msg.contains("At least one network_id must be specified"));
616+
}
617+
}
618+
619+
#[test]
620+
fn test_config_schema_validation_valid() {
621+
let schema = AlloyDeliverySchema;
622+
let config = toml::Value::Table({
623+
let mut table = toml::map::Map::new();
624+
table.insert(
625+
"network_ids".to_string(),
626+
toml::Value::Array(vec![toml::Value::Integer(1)]),
627+
);
628+
table
629+
});
630+
631+
let result = schema.validate(&config);
632+
assert!(result.is_ok());
633+
}
634+
635+
#[test]
636+
fn test_config_schema_validation_empty_network_ids() {
637+
let schema = AlloyDeliverySchema;
638+
let config = toml::Value::Table({
639+
let mut table = toml::map::Map::new();
640+
table.insert("network_ids".to_string(), toml::Value::Array(vec![]));
641+
table
642+
});
643+
644+
let result = schema.validate(&config);
645+
assert!(result.is_err());
646+
assert!(result
647+
.unwrap_err()
648+
.to_string()
649+
.contains("network_ids cannot be empty"));
650+
}
651+
652+
#[tokio::test(flavor = "multi_thread")]
653+
async fn test_create_http_delivery_success() {
654+
let config = toml::Value::Table({
655+
let mut table = toml::map::Map::new();
656+
table.insert(
657+
"network_ids".to_string(),
658+
toml::Value::Array(vec![toml::Value::Integer(1)]),
659+
);
660+
table
661+
});
662+
663+
let networks = create_test_networks();
664+
let default_key = SecretString::from(
665+
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
666+
);
667+
let network_keys = HashMap::new();
668+
669+
let result = create_http_delivery(&config, &networks, &default_key, &network_keys);
670+
assert!(result.is_ok());
671+
}
672+
673+
#[test]
674+
fn test_registry_name() {
675+
assert_eq!(
676+
<Registry as solver_types::ImplementationRegistry>::NAME,
677+
"evm_alloy"
678+
);
679+
}
680+
}

0 commit comments

Comments
 (0)