Skip to content

Commit

Permalink
feat: add create/update unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hydra-yse committed Nov 19, 2024
1 parent b007c0d commit bd1f7ae
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 6 deletions.
160 changes: 160 additions & 0 deletions lib/core/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,164 @@ impl SyncService {
Ok(())
}
}

#[cfg(test)]
mod tests {
use anyhow::{anyhow, Result};
use std::sync::Arc;
use tokio::sync::mpsc;

use crate::{
prelude::Signer,
test_utils::{
persist::new_persister,
sync::{
new_chain_sync_data, new_receive_sync_data, new_send_sync_data, MockSyncerClient,
},
wallet::MockSigner,
},
};

use super::{
model::{data::SyncData, sync::Record},
SyncService,
};

#[tokio::test]
async fn test_incoming_sync_create_and_update() -> Result<()> {
let (_temp_dir, persister) = new_persister()?;
let persister = Arc::new(persister);

let signer: Arc<Box<dyn Signer>> = Arc::new(Box::new(MockSigner::new()));

let sync_data = vec![
SyncData::Receive(new_receive_sync_data(None, None)),
SyncData::Send(new_send_sync_data(None, None, None)),
SyncData::Chain(new_chain_sync_data(None, None, None)),
];
let incoming_records = vec![
Record::new(
"record-1".to_string(),
sync_data[0].clone(),
1,
signer.clone(),
)?,
Record::new(
"record-2".to_string(),
sync_data[1].clone(),
2,
signer.clone(),
)?,
Record::new(
"record-3".to_string(),
sync_data[2].clone(),
3,
signer.clone(),
)?,
];

let (incoming_tx, incoming_rx) = mpsc::channel::<Record>(10);
let client = Box::new(MockSyncerClient::new(incoming_rx));
let sync_service =
SyncService::new("".to_string(), persister.clone(), signer.clone(), client);

for record in incoming_records {
incoming_tx.send(record).await?;
}
sync_service.pull().await?;

if let Some(receive_swap) = persister.fetch_receive_swap_by_id(&sync_data[0].id())? {
assert!(receive_swap.description.is_none());
assert!(receive_swap.payment_hash.is_none());
} else {
return Err(anyhow!("Receive swap not found"));
}
if let Some(send_swap) = persister.fetch_send_swap_by_id(&sync_data[1].id())? {
assert!(send_swap.preimage.is_none());
assert!(send_swap.description.is_none());
assert!(send_swap.payment_hash.is_none());
} else {
return Err(anyhow!("Send swap not found"));
}
if let Some(chain_swap) = persister.fetch_chain_swap_by_id(&sync_data[2].id())? {
assert!(chain_swap.claim_address.is_none());
assert!(chain_swap.description.is_none());
assert!(chain_swap.accept_zero_conf.eq(&true));
} else {
return Err(anyhow!("Chain swap not found"));
}

let new_payment_hash = Some("payment_hash".to_string());
let new_preimage = Some("preimage".to_string());
let new_description = Some("description".to_string());
let new_claim_address = Some("claim_address".to_string());
let new_accept_zero_conf = false;
let new_server_lockup_tx_id = Some("server_lockup_tx_id".to_string());
let sync_data = vec![
SyncData::Receive(new_receive_sync_data(
new_payment_hash.clone(),
new_description.clone(),
)),
SyncData::Send(new_send_sync_data(
new_preimage.clone(),
new_payment_hash.clone(),
new_description.clone(),
)),
SyncData::Chain(new_chain_sync_data(
new_description.clone(),
new_claim_address.clone(),
Some(new_accept_zero_conf),
new_server_lockup_tx_id.clone(),
)),
];
let incoming_records = vec![
Record::new(
"record-1".to_string(),
sync_data[0].clone(),
4,
signer.clone(),
)?,
Record::new(
"record-2".to_string(),
sync_data[1].clone(),
5,
signer.clone(),
)?,
Record::new(
"record-3".to_string(),
sync_data[2].clone(),
6,
signer.clone(),
)?,
];

for record in incoming_records {
incoming_tx.send(record).await?;
}
sync_service.pull().await?;

if let Some(receive_swap) = persister.fetch_receive_swap_by_id(&sync_data[0].id())? {
assert_eq!(receive_swap.description, new_description);
assert_eq!(receive_swap.payment_hash, new_payment_hash);
} else {
return Err(anyhow!("Receive swap not found"));
}
if let Some(send_swap) = persister.fetch_send_swap_by_id(&sync_data[1].id())? {
assert_eq!(send_swap.preimage, new_preimage);
assert_eq!(send_swap.description, new_description);
assert_eq!(send_swap.payment_hash, new_payment_hash);
} else {
return Err(anyhow!("Send swap not found"));
}
if let Some(chain_swap) = persister.fetch_chain_swap_by_id(&sync_data[2].id())? {
assert_eq!(chain_swap.claim_address, new_claim_address);
assert_eq!(chain_swap.description, new_description);
assert_eq!(chain_swap.accept_zero_conf, new_accept_zero_conf);
assert_eq!(chain_swap.server_lockup_tx_id, new_server_lockup_tx_id);
} else {
return Err(anyhow!("Chain swap not found"));
}

Ok(())
}
}
1 change: 1 addition & 0 deletions lib/core/src/test_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub(crate) mod sdk;
pub(crate) mod send_swap;
pub(crate) mod status_stream;
pub(crate) mod swapper;
pub(crate) mod sync;
pub(crate) mod wallet;

pub(crate) fn generate_random_string(size: usize) -> String {
Expand Down
115 changes: 115 additions & 0 deletions lib/core/src/test_utils/sync.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#![cfg(test)]

use crate::{
prelude::Direction,
sync::{
client::SyncerClient,
model::{
data::{ChainSyncData, ReceiveSyncData, SendSyncData},
sync::{
ListChangesReply, ListChangesRequest, Record, SetRecordReply, SetRecordRequest,
},
},
},
};
use anyhow::Result;
use async_trait::async_trait;
use tokio::sync::{mpsc::Receiver, Mutex};

pub(crate) struct MockSyncerClient {
pub(crate) incoming_rx: Mutex<Receiver<Record>>,
}

impl MockSyncerClient {
pub(crate) fn new(incoming_rx: Receiver<Record>) -> Self {
Self {
incoming_rx: Mutex::new(incoming_rx),
}
}
}

#[async_trait]
impl SyncerClient for MockSyncerClient {
async fn connect(&self, _connect_url: String) -> Result<()> {
todo!()
}

async fn push(&self, _req: SetRecordRequest) -> Result<SetRecordReply> {
todo!()
}

async fn pull(&self, _req: ListChangesRequest) -> Result<ListChangesReply> {
let mut rx = self.incoming_rx.lock().await;
let mut changes = Vec::with_capacity(3);
rx.recv_many(&mut changes, 3).await;
Ok(ListChangesReply { changes })
}

async fn disconnect(&self) -> Result<()> {
todo!()
}
}

pub(crate) fn new_receive_sync_data(
payment_hash: Option<String>,
description: Option<String>,
) -> ReceiveSyncData {
ReceiveSyncData {
swap_id: "receive-swap".to_string(),
invoice: "".to_string(),
create_response_json: "".to_string(),
payer_amount_sat: 0,
receiver_amount_sat: 0,
created_at: 0,
claim_fees_sat: 0,
claim_private_key: "".to_string(),
mrh_address: "".to_string(),
mrh_script_pubkey: "".to_string(),
preimage: "".to_string(),
payment_hash,
description,
}
}

pub(crate) fn new_send_sync_data(
preimage: Option<String>,
payment_hash: Option<String>,
description: Option<String>,
) -> SendSyncData {
SendSyncData {
swap_id: "send-swap".to_string(),
invoice: "".to_string(),
create_response_json: "".to_string(),
refund_private_key: "".to_string(),
payer_amount_sat: 0,
receiver_amount_sat: 0,
created_at: 0,
preimage,
payment_hash,
description,
}
}

pub(crate) fn new_chain_sync_data(
description: Option<String>,
claim_address: Option<String>,
accept_zero_conf: Option<bool>,
) -> ChainSyncData {
ChainSyncData {
swap_id: "chain-swap".to_string(),
preimage: "".to_string(),
create_response_json: "".to_string(),
direction: Direction::Incoming,
lockup_address: "".to_string(),
claim_fees_sat: 0,
claim_private_key: "".to_string(),
refund_private_key: "".to_string(),
timeout_block_height: 0,
payer_amount_sat: 0,
receiver_amount_sat: 0,
accept_zero_conf: accept_zero_conf.unwrap_or(true),
created_at: 0,
description,
claim_address,
}
}
31 changes: 25 additions & 6 deletions lib/core/src/test_utils/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ use crate::{
};
use anyhow::Result;
use async_trait::async_trait;
use boltz_client::{Keypair, Secp256k1};
use lazy_static::lazy_static;
use lwk_wollet::{
elements::{Address, Transaction},
elements_miniscript::ToPublicKey as _,
secp256k1::Message,
Tip, WalletTx,
};

Expand Down Expand Up @@ -82,11 +85,15 @@ impl OnchainWallet for MockWallet {
}
}

pub(crate) struct MockSigner {}
pub(crate) struct MockSigner {
keypair: Keypair,
}

impl MockSigner {
pub(crate) fn new() -> Self {
Self {}
let secp = Secp256k1::new();
let keypair = Keypair::new(&secp, &mut bip39::rand::thread_rng());
Self { keypair }
}
}

Expand All @@ -103,8 +110,16 @@ impl Signer for MockSigner {
todo!()
}

fn sign_ecdsa_recoverable(&self, _msg: Vec<u8>) -> Result<Vec<u8>, SignerError> {
todo!()
fn sign_ecdsa_recoverable(&self, msg: Vec<u8>) -> Result<Vec<u8>, SignerError> {
let secp = Secp256k1::new();
let msg: Message = Message::from_digest_slice(msg.as_slice())
.map_err(|e| SignerError::Generic { err: e.to_string() })?;
// Get message signature and encode to zbase32
let recoverable_sig = secp.sign_ecdsa_recoverable(&msg, &self.keypair.secret_key());
let (recovery_id, sig) = recoverable_sig.serialize_compact();
let mut complete_signature = vec![31 + recovery_id.to_i32() as u8];
complete_signature.extend_from_slice(&sig);
Ok(complete_signature)
}

fn slip77_master_blinding_key(&self) -> Result<Vec<u8>, SignerError> {
Expand All @@ -116,10 +131,14 @@ impl Signer for MockSigner {
}

fn ecies_encrypt(&self, msg: &[u8]) -> Result<Vec<u8>, SignerError> {
todo!()
let rc_pub = self.keypair.public_key().to_public_key().to_bytes();
Ok(ecies::encrypt(&rc_pub, msg)
.map_err(|err| anyhow::anyhow!("Could not encrypt data: {err}"))?)
}

fn ecies_decrypt(&self, msg: &[u8]) -> Result<Vec<u8>, SignerError> {
todo!()
let rc_prv = self.keypair.secret_bytes();
Ok(ecies::decrypt(&rc_prv, msg)
.map_err(|err| anyhow::anyhow!("Could not decrypt data: {err}"))?)
}
}

0 comments on commit bd1f7ae

Please sign in to comment.