use serde_json::json;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener};
use std::time::Duration;
use tap_http::{TapHttpConfig, TapHttpServer};
use tap_node::{NodeConfig, TapNode};
use tokio::time::sleep;
fn create_mock_node() -> TapNode {
let node_config = NodeConfig {
storage_path: None, ..Default::default()
};
TapNode::new(node_config)
}
fn find_unused_port() -> Option<u16> {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0);
match TcpListener::bind(addr) {
Ok(listener) => listener.local_addr().map(|addr| addr.port()).ok(),
Err(_) => None,
}
}
#[tokio::test(flavor = "multi_thread")]
async fn test_server_startup() {
let node = create_mock_node();
let port = find_unused_port().expect("Unable to find unused port");
let config = TapHttpConfig {
host: "127.0.0.1".to_string(),
port,
..TapHttpConfig::default()
};
let mut server = TapHttpServer::new(config, node);
server.start().await.expect("Server should start");
sleep(Duration::from_millis(100)).await;
server.stop().await.expect("Server should stop");
}
#[tokio::test(flavor = "multi_thread")]
async fn test_health_endpoint() {
let node = create_mock_node();
let port = find_unused_port().expect("Unable to find unused port");
let config = TapHttpConfig {
host: "127.0.0.1".to_string(),
port,
..TapHttpConfig::default()
};
let mut server = TapHttpServer::new(config, node);
server.start().await.expect("Server should start");
sleep(Duration::from_millis(500)).await;
let client = reqwest::Client::new();
let response = client
.get(format!("http://127.0.0.1:{}/health", port))
.timeout(Duration::from_secs(5))
.send()
.await;
assert!(
response.is_ok(),
"Failed to connect to health endpoint: {:?}",
response.err()
);
let response = response.unwrap();
assert_eq!(response.status(), 200);
let body = response.text().await.unwrap();
let json: serde_json::Value = serde_json::from_str(&body).unwrap();
assert_eq!(json["status"], "ok");
assert!(json["version"].is_string());
server.stop().await.expect("Server should stop");
}
#[tokio::test(flavor = "multi_thread")]
async fn test_didcomm_endpoint() {
let node = create_mock_node();
let port = find_unused_port().expect("Unable to find unused port");
let config = TapHttpConfig {
host: "127.0.0.1".to_string(),
port,
..TapHttpConfig::default()
};
let mut server = TapHttpServer::new(config, node);
server.start().await.expect("Server should start");
sleep(Duration::from_millis(500)).await;
let didcomm_msg = json!({
"id": "1234567890",
"typ": "application/didcomm-plain+json",
"type": "https://didcomm.org/basicmessage/2.0/message",
"body": {
"messageType": "TAP_AUTHORIZATION_REQUEST",
"version": "1.0",
"ledgerId": "eip155:1",
"authorizationRequest": {
"transactionHash": "0x123456789abcdef",
"sender": "eip155:1:0x1234567890123456789012345678901234567890",
"receiver": "eip155:1:0x0987654321098765432109876543210987654321",
"amount": "1000000000000000000"
}
},
"from": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"to": ["did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp"]
});
let client = reqwest::Client::new();
let response = client
.post(format!("http://127.0.0.1:{}/didcomm", port))
.header("Content-Type", "application/didcomm-plain+json")
.json(&didcomm_msg)
.timeout(Duration::from_secs(5))
.send()
.await;
assert!(
response.is_ok(),
"Failed to connect to didcomm endpoint: {:?}",
response.err()
);
let response = response.unwrap();
let status = response.status();
assert_eq!(status, 400);
let body = response.text().await.unwrap();
let json: serde_json::Value = serde_json::from_str(&body).unwrap();
assert_eq!(json["status"], "error");
assert_eq!(json["error"]["type"], "validation_error");
server.stop().await.expect("Server should stop");
}
#[tokio::test(flavor = "multi_thread")]
async fn test_didcomm_endpoint_content_types() {
let node = create_mock_node();
let port = find_unused_port().expect("Unable to find unused port");
let config = TapHttpConfig {
host: "127.0.0.1".to_string(),
port,
..TapHttpConfig::default()
};
let mut server = TapHttpServer::new(config, node);
server.start().await.expect("Server should start");
sleep(Duration::from_millis(500)).await;
let client = reqwest::Client::new();
let encrypted_msg = json!({
"protected": "eyJ0eXAiOiJhcHBsaWNhdGlvbi9kaWRjb21tLWVuY3J5cHRlZCtqc29uIn0=",
"recipients": [{
"header": {"kid": "did:key:test"},
"encrypted_key": "test-key"
}],
"ciphertext": "test-ciphertext",
"tag": "test-tag",
"iv": "test-iv"
});
let response = client
.post(format!("http://127.0.0.1:{}/didcomm", port))
.header("Content-Type", "application/didcomm-encrypted+json")
.json(&encrypted_msg)
.timeout(Duration::from_secs(5))
.send()
.await
.unwrap();
let status = response.status();
let body = response.text().await.unwrap();
assert_eq!(status, 500);
let json: serde_json::Value = serde_json::from_str(&body).unwrap();
assert_eq!(json["status"], "error");
let message = json["message"].as_str().unwrap_or("");
assert!(
message.contains("Internal server error"),
"Expected 'Internal server error' but got: {}",
message
);
let signed_msg = json!({
"payload": "eyJ0ZXN0IjoidGVzdCJ9",
"signatures": [{
"protected": "eyJ0eXAiOiJhcHBsaWNhdGlvbi9kaWRjb21tLXNpZ25lZCtqc29uIn0=",
"signature": "test-signature"
}]
});
let response = client
.post(format!("http://127.0.0.1:{}/didcomm", port))
.header(
"Content-Type",
"application/didcomm-signed+json; charset=utf-8",
)
.json(&signed_msg)
.timeout(Duration::from_secs(5))
.send()
.await
.unwrap();
let status = response.status();
let body = response.text().await.unwrap();
let json: serde_json::Value = serde_json::from_str(&body).unwrap();
assert_eq!(status, 500);
assert_eq!(json["status"], "error");
let message = json["message"].as_str().unwrap_or("");
assert!(
message.contains("Internal server error"),
"Expected 'Internal server error' but got: {}",
message
);
let response = client
.post(format!("http://127.0.0.1:{}/didcomm", port))
.header("Content-Type", "application/json")
.json(&json!({"test": "data"}))
.timeout(Duration::from_secs(5))
.send()
.await
.unwrap();
assert_eq!(response.status(), 400);
let body = response.text().await.unwrap();
let json: serde_json::Value = serde_json::from_str(&body).unwrap();
assert_eq!(json["error"]["type"], "validation_error");
let response = client
.post(format!("http://127.0.0.1:{}/didcomm", port))
.body(json!({"test": "data"}).to_string())
.timeout(Duration::from_secs(5))
.send()
.await
.unwrap();
assert_eq!(response.status(), 400);
let body = response.text().await.unwrap();
let json: serde_json::Value = serde_json::from_str(&body).unwrap();
assert_eq!(json["error"]["type"], "validation_error");
server.stop().await.expect("Server should stop");
}