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

Project Skeleton #5

Merged
merged 7 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
1,923 changes: 1,923 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,25 @@
name = "didethresolver"
version = "0.1.0"
edition = "2021"
resolver = "2"

[profile.release]
panic = 'abort'
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
log = "0.4"
tokio = { version = "1.34", features = ["macros", "rt"] }
async-trait = "0.1"
tracing = "0.1"
serde = { version = "1", features = ["derive"] }
jsonrpsee = { version = "0.20", features = ["macros", "server", "client-core"] }
anyhow = "1"

[dev-dependencies]
mockall = "0.11"
jsonrpsee = { version = "0.20", features = ["macros", "server", "client"] }
futures = "0.3"
tokio = { version = "1.34", features = ["macros", "rt", "time"] }
tracing-forest = { version = "0.1", features = ["ansi", "chrono", "env-filter"] }
tracing-subscriber = "0.3.18"
4 changes: 4 additions & 0 deletions rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[toolchain]
channel = "stable"
components = [ "rustc", "cargo", "clippy", "rustfmt", "rust-analyzer" ]
profile = "default"
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod rpc;
pub mod types;
mod util;
3 changes: 0 additions & 3 deletions src/main.rs

This file was deleted.

58 changes: 58 additions & 0 deletions src/rpc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
mod api;
mod methods;

// re-export the defined API
pub use api::*;

#[cfg(test)]
mod tests {
use std::{future::Future, time::Duration};

use futures::future::FutureExt;
use jsonrpsee::{
server::Server,
ws_client::{WsClient, WsClientBuilder},
};
use tokio::time::timeout as timeout_tokio;

use super::*;

/// Test harness for using a WebSockets Server
/// Optionally provide a timeout [`std::time::Duration`] deadline by which the test must
/// finish.
///
/// # Panics
///
/// If `fun` panics, the test will end upon reaching `timeout`. Default timeout is 50
/// milliseconds.
pub async fn with_client<F, R, T>(timeout: Option<Duration>, fun: F) -> T
where
F: FnOnce(WsClient) -> R + 'static,
R: Future<Output = T> + FutureExt + Send + 'static,
{
crate::util::init_logging();

let server = Server::builder().build("127.0.0.1:0").await.unwrap();
let addr = server.local_addr().unwrap();
let handle = server.start(methods::DidRegistryMethods.into_rpc());

let client = WsClientBuilder::default()
.build(&format!("ws://{addr}"))
.await
.unwrap();

// cant catch_unwind b/c jsonrpsee uses tokio mpsc which is !UnwindSafe, so we wrap with a
// timeout.
// If we panic in the closure without the timeout or catch_unwind, we never return and the server will never stop, hanging our
// tests.
let result = timeout_tokio(timeout.unwrap_or(Duration::from_millis(50)), fun(client)).await;

handle.stop().unwrap();
handle.stopped().await;

if let Err(_) = result {
log::debug!("Test timed out due to panic, or running too long.");
}
result.unwrap()
}
}
50 changes: 50 additions & 0 deletions src/rpc/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//! Trait Interface Definitions for DID Registry JSON-RPC

use crate::types::DidDocument;

use jsonrpsee::{proc_macros::rpc, types::ErrorObjectOwned};

/// Decentralized Identifier JSON-RPC Interface Methods
#[rpc(server, client, namespace = "did")]
pub trait DidRegistry {
#[method(name = "resolveDid")]
async fn resolve_did(&self, public_key: String) -> Result<DidDocument, ErrorObjectOwned>;
}

#[cfg(test)]
mod tests {
use super::*;

use async_trait::async_trait;
use mockall::{mock, predicate::*};

use crate::rpc::tests::with_client;

mock! {
pub DidRegistryMethods {}

#[async_trait]
impl DidRegistryServer for DidRegistryMethods {
async fn resolve_did(&self, _public_key: String) -> Result<DidDocument, ErrorObjectOwned>;
}
}

#[tokio::test]
pub async fn test_resolve_did() {
crate::util::init_logging();

let mut mock = MockDidRegistryMethods::new();
mock.expect_resolve_did().returning(|_| Ok(DidDocument));
// test stub
}

#[tokio::test]
#[should_panic]
pub async fn test_resolve_did_server() {
let _ = super::tests::with_client(None, |client| async move {
client.resolve_did("Hello".to_string()).await?;
Ok::<_, anyhow::Error>(())
})
.await;
}
}
21 changes: 21 additions & 0 deletions src/rpc/methods.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! Interface Implementations for DID Registry JSON-RPC

use super::api::*;
use crate::types::DidDocument;

use jsonrpsee::types::ErrorObjectOwned;

use async_trait::async_trait;

const LOG_TARGET: &str = "rpc";

pub struct DidRegistryMethods;

#[async_trait]
impl DidRegistryServer for DidRegistryMethods {
async fn resolve_did(&self, _public_key: String) -> Result<DidDocument, ErrorObjectOwned> {
//TODO: Stub for resolveDid, ref: [#4](https://github.com/xmtp/didethresolver/issues/4)
log::debug!(target: LOG_TARGET, "resolve_did called");
todo!();
}
}
8 changes: 8 additions & 0 deletions src/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//! Type Definitions for the DID Registry compatible with JSON

use serde::{Deserialize, Serialize};

// TODO: Stub
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
/// DID Document
pub struct DidDocument;
21 changes: 21 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! Internal Utility functions for use in crate

#[cfg(test)]
use std::sync::Once;
#[cfg(test)]
use tracing_forest::ForestLayer;
#[cfg(test)]
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry};

#[cfg(test)]
static INIT: Once = Once::new();

#[cfg(test)]
pub(crate) fn init_logging() {
INIT.call_once(|| {
Registry::default()
.with(ForestLayer::default())
.with(EnvFilter::from_default_env())
.init()
})
}
1 change: 1 addition & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Integration Tests
13 changes: 13 additions & 0 deletions tests/integration_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
mod integration_util;

// use didethresolver::rpc::DidRegistryServer;

pub const SEPOLIA_URL: &str = "...";
pub const CONTRACT_URL: &str = "...";

#[test]
#[should_panic]
pub fn test_resolve_did() {
todo!()
// stub
}
15 changes: 15 additions & 0 deletions tests/integration_util/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! Shared setup code for integration tests
use std::sync::Once;
use tracing_forest::ForestLayer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry};

static INIT: Once = Once::new();

pub(crate) fn init_logging() {
INIT.call_once(|| {
Registry::default()
.with(ForestLayer::default())
.with(EnvFilter::from_default_env())
.init()
})
}