use crate::{
dht::{NetworkInfo, Peer},
records::NsRecord,
PeerId,
};
use anyhow::Result;
use async_trait::async_trait;
use libp2p::Multiaddr;
use noosphere_core::data::Did;
#[cfg(doc)]
use crate::server::HttpClient;
#[cfg(doc)]
use crate::NameSystem;
#[async_trait]
pub trait NameSystemClient: Send + Sync {
async fn network_info(&self) -> Result<NetworkInfo>;
fn peer_id(&self) -> &PeerId;
async fn peers(&self) -> Result<Vec<Peer>>;
async fn add_peers(&self, peers: Vec<Multiaddr>) -> Result<()>;
async fn listen(&self, listening_address: Multiaddr) -> Result<Multiaddr>;
async fn stop_listening(&self) -> Result<()>;
async fn address(&self) -> Result<Option<Multiaddr>>;
async fn put_record(&self, record: NsRecord) -> Result<()>;
async fn get_record(&self, identity: &Did) -> Result<Option<NsRecord>>;
async fn bootstrap(&self) -> Result<()>;
}
#[cfg(test)]
#[macro_export]
macro_rules! ns_client_tests {
($type:ty, $before_each:ident, $data:ty) => {
use tokio;
#[tokio::test]
async fn name_system_client_network_info() -> Result<()> {
let (_data, client) = $before_each().await?;
$crate::client::test::test_network_info::<$type>(client).await
}
#[tokio::test]
async fn name_system_client_listeners() -> Result<()> {
let (_data, client) = $before_each().await?;
$crate::client::test::test_listeners::<$type>(client).await
}
#[tokio::test]
async fn name_system_client_records() -> Result<()> {
let (_data, client) = $before_each().await?;
$crate::client::test::test_records::<$type>(client).await
}
};
}
#[cfg(test)]
pub mod test {
use super::*;
use crate::{utils::wait_for_peers, NameSystemBuilder};
use cid::Cid;
use libp2p::multiaddr::Protocol;
use noosphere_core::{authority::generate_ed25519_key, data::Did};
use noosphere_storage::{MemoryStorage, SphereDb};
use std::sync::Arc;
use tokio::sync::Mutex;
use ucan::crypto::KeyMaterial;
pub async fn test_network_info<C: NameSystemClient>(client: Arc<Mutex<C>>) -> Result<()> {
let client = client.lock().await;
let network_info = client.network_info().await?;
assert!(network_info.num_connections >= 1);
Ok(())
}
pub async fn test_listeners<C: NameSystemClient>(client: Arc<Mutex<C>>) -> Result<()> {
let client = client.lock().await;
assert!(client.address().await?.is_none());
let listener_address = client.listen("/ip4/127.0.0.1/tcp/0".parse()?).await?;
assert_eq!(listener_address, client.address().await?.unwrap());
match listener_address.iter().collect::<Vec<_>>()[..] {
[Protocol::Ip4(_ip_addr), Protocol::Tcp(_port), Protocol::P2p(_peer_id)] => {}
_ => panic!("invalid address {}", listener_address),
}
assert_eq!(client.peers().await?.len(), 1);
let (_other_ns, other_peer_id) = {
let key_material = generate_ed25519_key();
let store = SphereDb::new(&MemoryStorage::default()).await.unwrap();
let ns = NameSystemBuilder::default()
.ucan_store(store)
.key_material(&key_material)
.listening_port(0)
.bootstrap_peers(&[listener_address.clone()])
.use_test_config()
.build()
.await
.unwrap();
ns.bootstrap().await.unwrap();
let peer_id = ns.peer_id().to_owned();
(ns, peer_id)
};
wait_for_peers::<C>(&client, 2).await?;
let peers = client.peers().await?;
assert_eq!(peers.len(), 2);
assert!(peers.contains(&Peer {
peer_id: other_peer_id,
}));
assert!(client.address().await?.is_some());
client.stop_listening().await?;
assert!(client.address().await?.is_none());
Ok(())
}
pub async fn test_records<C: NameSystemClient>(client: Arc<Mutex<C>>) -> Result<()> {
let client = client.lock().await;
client.listen("/ip4/127.0.0.1/tcp/0".parse()?).await?;
let sphere_key = generate_ed25519_key();
let sphere_id = Did::from(sphere_key.get_did().await?);
let link: Cid = "bafy2bzacec4p5h37mjk2n6qi6zukwyzkruebvwdzqpdxzutu4sgoiuhqwne72"
.parse()
.unwrap();
let record = NsRecord::from_issuer(&sphere_key, &sphere_id, &link, None).await?;
client.put_record(record).await?;
let retrieved = client
.get_record(&sphere_id)
.await?
.expect("should be some");
assert_eq!(retrieved.identity(), &sphere_id);
assert_eq!(retrieved.link(), Some(&link));
Ok(())
}
}