Newer
Older
use std::net::SocketAddr;
use crate::HttpServerBuilder;
use jsonrpsee_test_utils::helpers::*;
use jsonrpsee_test_utils::types::{Id, StatusCode};
use serde_json::Value as JsonValue;
async fn server() -> SocketAddr {
let mut server = HttpServerBuilder::default().build("127.0.0.1:0".parse().unwrap()).unwrap();
let addr = server.local_addr().unwrap();
server.register_method("say_hello", |_| Ok("lo")).unwrap();
server
.register_method("add", |params| {
let params: Vec<u64> = params.parse()?;
let sum: u64 = params.into_iter().sum();
Ok(sum)
})
.unwrap();
server.register_method("notif", |_| Ok("")).unwrap();
tokio::spawn(async move { server.start().await.unwrap() });
addr
}
#[tokio::test]
async fn single_method_call_works() {
let _ = env_logger::try_init();
let addr = server().await;
let uri = to_http_uri(addr);
for i in 0..10 {
let req = format!(r#"{{"jsonrpc":"2.0","method":"say_hello","id":{}}}"#, i);
let response = http_request(req.into(), uri.clone()).await.unwrap();
assert_eq!(response.status, StatusCode::OK);
assert_eq!(response.body, ok_response(JsonValue::String("lo".to_owned()), Id::Num(i)));
#[tokio::test]
async fn invalid_single_method_call() {
let _ = env_logger::try_init();
let addr = server().await;
let uri = to_http_uri(addr);
let req = r#"{"jsonrpc":"2.0","method":1, "params": "bar"}"#;
let response = http_request(req.into(), uri.clone()).await.unwrap();
assert_eq!(response.status, StatusCode::OK);
assert_eq!(response.body, invalid_request(Id::Null));
}
#[tokio::test]
async fn single_method_call_with_params() {
let addr = server().await;
let uri = to_http_uri(addr);
std::thread::sleep(std::time::Duration::from_secs(2));
let req = r#"{"jsonrpc":"2.0","method":"add", "params":[1, 2],"id":1}"#;
let response = http_request(req.into(), uri).await.unwrap();
assert_eq!(response.status, StatusCode::OK);
assert_eq!(response.body, ok_response(JsonValue::Number(3.into()), Id::Num(1)));
}
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#[tokio::test]
async fn valid_batched_method_calls() {
let _ = env_logger::try_init();
let addr = server().await;
let uri = to_http_uri(addr);
let req = r#"[
{"jsonrpc":"2.0","method":"add", "params":[1, 2],"id":1},
{"jsonrpc":"2.0","method":"add", "params":[3, 4],"id":2},
{"jsonrpc":"2.0","method":"say_hello","id":3},
{"jsonrpc":"2.0","method":"add", "params":[5, 6],"id":4}
]"#;
let response = http_request(req.into(), uri).await.unwrap();
assert_eq!(response.status, StatusCode::OK);
assert_eq!(
response.body,
r#"[{"jsonrpc":"2.0","result":3,"id":1},{"jsonrpc":"2.0","result":7,"id":2},{"jsonrpc":"2.0","result":"lo","id":3},{"jsonrpc":"2.0","result":11,"id":4}]"#
);
}
#[tokio::test]
async fn batched_notifications() {
let _ = env_logger::try_init();
let addr = server().await;
let uri = to_http_uri(addr);
let req = r#"[
{"jsonrpc": "2.0", "method": "notif", "params": [1,2,4]},
{"jsonrpc": "2.0", "method": "notif", "params": [7]}
]"#;
let response = http_request(req.into(), uri).await.unwrap();
assert_eq!(response.status, StatusCode::OK);
// Note: this is *not* according to spec. Response should be the empty string, `""`.
assert_eq!(response.body, r#"[{"jsonrpc":"2.0","result":"","id":null},{"jsonrpc":"2.0","result":"","id":null}]"#);
}
#[tokio::test]
async fn invalid_batched_method_calls() {
let _ = env_logger::try_init();
let addr = server().await;
let uri = to_http_uri(addr);
// batch with no requests
let req = r#"[]"#;
let response = http_request(req.into(), uri.clone()).await.unwrap();
assert_eq!(response.status, StatusCode::OK);
assert_eq!(response.body, invalid_request(Id::Null));
// batch with invalid request
let req = r#"[123]"#;
let response = http_request(req.into(), uri.clone()).await.unwrap();
assert_eq!(response.status, StatusCode::OK);
// Note: according to the spec the `id` should be `null` here, not 123.
assert_eq!(response.body, invalid_request(Id::Num(123)));
// batch with invalid request
let req = r#"[1, 2, 3]"#;
let response = http_request(req.into(), uri.clone()).await.unwrap();
assert_eq!(response.status, StatusCode::OK);
// Note: according to the spec this should return an array of three `Invalid Request`s
assert_eq!(response.body, parse_error(Id::Null));
// invalid JSON in batch
let req = r#"[
{"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
{"jsonrpc": "2.0", "method"
]"#;
let response = http_request(req.into(), uri.clone()).await.unwrap();
assert_eq!(response.status, StatusCode::OK);
assert_eq!(response.body, parse_error(Id::Null));
}
#[tokio::test]
async fn should_return_method_not_found() {
let addr = server().await;
let uri = to_http_uri(addr);
let req = r#"{"jsonrpc":"2.0","method":"bar","id":"foo"}"#;
let response = http_request(req.into(), uri).await.unwrap();
assert_eq!(response.status, StatusCode::OK);
assert_eq!(response.body, method_not_found(Id::Str("foo".into())));
}
#[tokio::test]
async fn invalid_json_id_missing_value() {
let addr = server().await;
let uri = to_http_uri(addr);
let req = r#"{"jsonrpc":"2.0","method":"say_hello","id"}"#;
let response = http_request(req.into(), uri).await.unwrap();
// If there was an error in detecting the id in the Request object (e.g. Parse error/Invalid Request), it MUST be Null.
assert_eq!(response.body, parse_error(Id::Null));
}
#[tokio::test]
async fn invalid_request_object() {
let addr = server().await;
let uri = to_http_uri(addr);
let req = r#"{"jsonrpc":"2.0","method":"bar","id":1,"is_not_request_object":1}"#;
let response = http_request(req.into(), uri).await.unwrap();
assert_eq!(response.status, StatusCode::OK);
assert_eq!(response.body, invalid_request(Id::Num(1)));
}