Skip to main content

jsonrpsee_test_utils/
mocks.rs

1// Copyright 2019-2021 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any
4// person obtaining a copy of this software and associated
5// documentation files (the "Software"), to deal in the
6// Software without restriction, including without
7// limitation the rights to use, copy, modify, merge,
8// publish, distribute, sublicense, and/or sell copies of
9// the Software, and to permit persons to whom the Software
10// is furnished to do so, subject to the following
11// conditions:
12//
13// The above copyright notice and this permission notice
14// shall be included in all copies or substantial portions
15// of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25// DEALINGS IN THE SOFTWARE.
26
27use std::{io, net::SocketAddr};
28
29use futures_util::io::{BufReader, BufWriter};
30use serde::{Deserialize, Serialize};
31use soketto::handshake::{self, Error as SokettoError};
32use tokio::net::TcpStream;
33use tokio_util::compat::{Compat, TokioAsyncReadCompatExt};
34
35pub use hyper::{HeaderMap, StatusCode, Uri};
36
37type Error = Box<dyn std::error::Error + Send + Sync + 'static>;
38
39/// Request Id
40#[derive(Debug, PartialEq, Clone, Hash, Eq, Deserialize, Serialize)]
41#[serde(deny_unknown_fields)]
42#[serde(untagged)]
43pub enum Id {
44    /// No id (notification)
45    Null,
46    /// Numeric id
47    Num(u64),
48    /// String id
49    Str(String),
50}
51
52#[derive(Debug)]
53pub struct HttpResponse {
54    pub status: StatusCode,
55    pub header: HeaderMap,
56    pub body: String,
57}
58
59/// WebSocket client to construct with arbitrary payload to construct bad payloads.
60pub struct WebSocketTestClient {
61    tx: soketto::Sender<BufReader<BufWriter<Compat<TcpStream>>>>,
62    rx: soketto::Receiver<BufReader<BufWriter<Compat<TcpStream>>>>,
63}
64
65impl std::fmt::Debug for WebSocketTestClient {
66    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67        write!(f, "WebSocketTestClient")
68    }
69}
70
71#[derive(Debug)]
72pub enum WebSocketTestError {
73    Redirect,
74    RejectedWithStatusCode(u16),
75    Soketto(SokettoError),
76}
77
78impl From<io::Error> for WebSocketTestError {
79    fn from(err: io::Error) -> Self {
80        WebSocketTestError::Soketto(SokettoError::Io(err))
81    }
82}
83
84impl WebSocketTestClient {
85    pub async fn new(url: SocketAddr) -> Result<Self, WebSocketTestError> {
86        let socket = TcpStream::connect(url).await?;
87        let mut client = handshake::Client::new(
88            BufReader::new(BufWriter::new(socket.compat())),
89            "test-client",
90            "/",
91        );
92        match client.handshake().await {
93            Ok(handshake::ServerResponse::Accepted { .. }) => {
94                let (tx, rx) = client.into_builder().finish();
95                Ok(Self { tx, rx })
96            }
97            Ok(handshake::ServerResponse::Redirect { .. }) => Err(WebSocketTestError::Redirect),
98            Ok(handshake::ServerResponse::Rejected { status_code }) => {
99                Err(WebSocketTestError::RejectedWithStatusCode(status_code))
100            }
101            Err(err) => Err(WebSocketTestError::Soketto(err)),
102        }
103    }
104
105    pub async fn send_request_text(&mut self, msg: impl AsRef<str>) -> Result<String, Error> {
106        self.send(msg).await?;
107        let mut data = Vec::new();
108        self.rx.receive_data(&mut data).await?;
109        String::from_utf8(data).map_err(Into::into)
110    }
111
112    pub async fn send(&mut self, msg: impl AsRef<str>) -> Result<(), Error> {
113        self.tx.send_text(msg).await?;
114        self.tx.flush().await.map_err(Into::into)
115    }
116
117    pub async fn send_request_binary(&mut self, msg: &[u8]) -> Result<String, Error> {
118        self.tx.send_binary(msg).await?;
119        self.tx.flush().await?;
120        self.receive().await
121    }
122
123    pub async fn receive(&mut self) -> Result<String, Error> {
124        let mut data = Vec::new();
125        self.rx.receive_data(&mut data).await?;
126        String::from_utf8(data).map_err(Into::into)
127    }
128
129    pub async fn close(&mut self) -> Result<(), Error> {
130        self.tx.close().await.map_err(Into::into)
131    }
132}