Skip to content

Commit 6a2e8dc

Browse files
abaillyArnaud Bailly
authored andcommitted
Add CertificateHandlerHTTPClient implementation #144 #145
Also fixed tests for the Signer
1 parent e522f5d commit 6a2e8dc

File tree

4 files changed

+258
-54
lines changed

4 files changed

+258
-54
lines changed
Lines changed: 231 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,248 @@
11
use async_trait::async_trait;
22
use mithril_aggregator::entities::CertificatePending;
3+
use mithril_aggregator::entities::SingleSignature;
4+
use reqwest::{self, StatusCode};
5+
use slog_scope::debug;
6+
use std::io;
7+
use thiserror::Error;
8+
39
#[cfg(test)]
410
use mockall::automock;
511

12+
#[derive(Error, Debug)]
13+
pub enum CertificateHandlerError {
14+
#[error("remote server technical error: '{0}'")]
15+
RemoteServerTechnical(String),
16+
#[error("remote server logical error: '{0}'")]
17+
RemoteServerLogical(String),
18+
#[error("remote server unreachable: '{0}'")]
19+
RemoteServerUnreachable(String),
20+
#[error("json parsing failed: '{0}'")]
21+
JsonParseFailed(String),
22+
#[error("io error:")]
23+
IOError(#[from] io::Error),
24+
}
25+
626
#[cfg_attr(test, automock)]
727
#[async_trait]
828
pub trait CertificateHandler {
9-
async fn retrieve_pending_certificate(&self) -> Result<Option<CertificatePending>, String>;
29+
/// Retrieves a pending certificate from the aggregator
30+
async fn retrieve_pending_certificate(
31+
&self,
32+
) -> Result<Option<CertificatePending>, CertificateHandlerError>;
1033

11-
async fn register_signatures(&self, signature: &str) -> Result<(), String>;
34+
/// Registers single signatures with the aggregator
35+
async fn register_signatures(
36+
&self,
37+
signatures: &[SingleSignature],
38+
) -> Result<(), CertificateHandlerError>;
1239
}
1340

14-
pub struct CertificateHandlerNoOp {}
41+
/// CertificateHandlerHTTPClient is a http client for an aggregator
42+
pub struct CertificateHandlerHTTPClient {
43+
aggregator_endpoint: String,
44+
}
45+
46+
impl CertificateHandlerHTTPClient {
47+
/// CertificateHandlerHTTPClient factory
48+
pub fn new(aggregator_endpoint: String) -> Self {
49+
debug!("New CertificateHandlerHTTPClient created");
50+
Self {
51+
aggregator_endpoint,
52+
}
53+
}
54+
}
1555

1656
#[async_trait]
17-
impl CertificateHandler for CertificateHandlerNoOp {
18-
async fn retrieve_pending_certificate(&self) -> Result<Option<CertificatePending>, String> {
19-
unimplemented!()
57+
impl CertificateHandler for CertificateHandlerHTTPClient {
58+
async fn retrieve_pending_certificate(
59+
&self,
60+
) -> Result<Option<CertificatePending>, CertificateHandlerError> {
61+
debug!("Retrieve pending certificate");
62+
let url = format!("{}/certificate-pending", self.aggregator_endpoint);
63+
let response = reqwest::get(url.clone()).await;
64+
match response {
65+
Ok(response) => match response.status() {
66+
StatusCode::OK => match response.json::<CertificatePending>().await {
67+
Ok(pending_certificate) => Ok(Some(pending_certificate)),
68+
Err(err) => Err(CertificateHandlerError::JsonParseFailed(err.to_string())),
69+
},
70+
StatusCode::NO_CONTENT => Ok(None),
71+
status_error => Err(CertificateHandlerError::RemoteServerTechnical(
72+
status_error.to_string(),
73+
)),
74+
},
75+
Err(err) => Err(CertificateHandlerError::RemoteServerUnreachable(
76+
err.to_string(),
77+
)),
78+
}
79+
}
80+
81+
async fn register_signatures(
82+
&self,
83+
signatures: &[SingleSignature],
84+
) -> Result<(), CertificateHandlerError> {
85+
debug!("Register signatures");
86+
let url = format!("{}/register-signatures", self.aggregator_endpoint);
87+
let client = reqwest::Client::new();
88+
let response = client.post(url.clone()).json(signatures).send().await;
89+
match response {
90+
Ok(response) => match response.status() {
91+
StatusCode::CREATED => Ok(()),
92+
StatusCode::BAD_REQUEST => Err(CertificateHandlerError::RemoteServerLogical(
93+
"bad request".to_string(),
94+
)),
95+
StatusCode::CONFLICT => Err(CertificateHandlerError::RemoteServerLogical(
96+
"already registered single signatures".to_string(),
97+
)),
98+
status_error => Err(CertificateHandlerError::RemoteServerTechnical(
99+
status_error.to_string(),
100+
)),
101+
},
102+
Err(err) => Err(CertificateHandlerError::RemoteServerUnreachable(
103+
err.to_string(),
104+
)),
105+
}
106+
}
107+
}
108+
109+
#[cfg(test)]
110+
mod tests {
111+
use super::*;
112+
use httpmock::prelude::*;
113+
use serde_json::json;
114+
115+
use mithril_aggregator::fake_data;
116+
117+
use crate::entities::Config;
118+
119+
fn setup_test() -> (MockServer, Config) {
120+
let server = MockServer::start();
121+
let config = Config {
122+
network: "testnet".to_string(),
123+
aggregator_endpoint: server.url(""),
124+
party_id: 0,
125+
run_interval: 100,
126+
};
127+
(server, config)
128+
}
129+
130+
#[tokio::test]
131+
async fn test_certificate_pending_ok_200() {
132+
let (server, config) = setup_test();
133+
let pending_certificate_expected = fake_data::certificate_pending();
134+
let _snapshots_mock = server.mock(|when, then| {
135+
when.path("/certificate-pending");
136+
then.status(200)
137+
.body(json!(pending_certificate_expected).to_string());
138+
});
139+
let certificate_handler = CertificateHandlerHTTPClient::new(config.aggregator_endpoint);
140+
let pending_certificate = certificate_handler.retrieve_pending_certificate().await;
141+
pending_certificate.as_ref().expect("unexpected error");
142+
assert_eq!(
143+
pending_certificate_expected,
144+
pending_certificate.unwrap().unwrap()
145+
);
146+
}
147+
148+
#[tokio::test]
149+
async fn test_certificate_pending_ok_204() {
150+
let (server, config) = setup_test();
151+
let _snapshots_mock = server.mock(|when, then| {
152+
when.path("/certificate-pending");
153+
then.status(204);
154+
});
155+
let certificate_handler = CertificateHandlerHTTPClient::new(config.aggregator_endpoint);
156+
let pending_certificate = certificate_handler.retrieve_pending_certificate().await;
157+
assert!(pending_certificate.expect("unexpected error").is_none());
158+
}
159+
160+
#[tokio::test]
161+
async fn test_certificate_pending_ko_500() {
162+
let (server, config) = setup_test();
163+
let _snapshots_mock = server.mock(|when, then| {
164+
when.path("/certificate-pending");
165+
then.status(500);
166+
});
167+
let certificate_handler = CertificateHandlerHTTPClient::new(config.aggregator_endpoint);
168+
let pending_certificate = certificate_handler.retrieve_pending_certificate().await;
169+
assert_eq!(
170+
CertificateHandlerError::RemoteServerTechnical("500 Internal Server Error".to_string())
171+
.to_string(),
172+
pending_certificate.unwrap_err().to_string()
173+
);
174+
}
175+
176+
#[tokio::test]
177+
async fn test_register_signatures_ok_201() {
178+
let single_signatures = fake_data::single_signatures(5);
179+
let (server, config) = setup_test();
180+
let _snapshots_mock = server.mock(|when, then| {
181+
when.method(POST).path("/register-signatures");
182+
then.status(201);
183+
});
184+
let certificate_handler = CertificateHandlerHTTPClient::new(config.aggregator_endpoint);
185+
let register_signatures = certificate_handler
186+
.register_signatures(&single_signatures)
187+
.await;
188+
register_signatures.expect("unexpected error");
189+
}
190+
191+
#[tokio::test]
192+
async fn test_register_signatures_ko_400() {
193+
let single_signatures = fake_data::single_signatures(5);
194+
let (server, config) = setup_test();
195+
let _snapshots_mock = server.mock(|when, then| {
196+
when.method(POST).path("/register-signatures");
197+
then.status(400);
198+
});
199+
let certificate_handler = CertificateHandlerHTTPClient::new(config.aggregator_endpoint);
200+
let register_signatures = certificate_handler
201+
.register_signatures(&single_signatures)
202+
.await;
203+
assert_eq!(
204+
CertificateHandlerError::RemoteServerLogical("bad request".to_string()).to_string(),
205+
register_signatures.unwrap_err().to_string()
206+
);
207+
}
208+
209+
#[tokio::test]
210+
async fn test_register_signatures_ko_409() {
211+
let single_signatures = fake_data::single_signatures(5);
212+
let (server, config) = setup_test();
213+
let _snapshots_mock = server.mock(|when, then| {
214+
when.method(POST).path("/register-signatures");
215+
then.status(409);
216+
});
217+
let certificate_handler = CertificateHandlerHTTPClient::new(config.aggregator_endpoint);
218+
let register_signatures = certificate_handler
219+
.register_signatures(&single_signatures)
220+
.await;
221+
assert_eq!(
222+
CertificateHandlerError::RemoteServerLogical(
223+
"already registered single signatures".to_string()
224+
)
225+
.to_string(),
226+
register_signatures.unwrap_err().to_string()
227+
);
20228
}
21229

22-
async fn register_signatures(&self, _signature: &str) -> Result<(), String> {
23-
unimplemented!()
230+
#[tokio::test]
231+
async fn test_register_signatures_ko_500() {
232+
let single_signatures = fake_data::single_signatures(5);
233+
let (server, config) = setup_test();
234+
let _snapshots_mock = server.mock(|when, then| {
235+
when.method(POST).path("/register-signatures");
236+
then.status(500);
237+
});
238+
let certificate_handler = CertificateHandlerHTTPClient::new(config.aggregator_endpoint);
239+
let register_signatures = certificate_handler
240+
.register_signatures(&single_signatures)
241+
.await;
242+
assert_eq!(
243+
CertificateHandlerError::RemoteServerTechnical("500 Internal Server Error".to_string())
244+
.to_string(),
245+
register_signatures.unwrap_err().to_string()
246+
);
24247
}
25248
}

mithril-signer/src/main.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::certificate_handler::CertificateHandlerNoOp;
1+
use crate::certificate_handler::CertificateHandlerHTTPClient;
22
use crate::entities::Config;
33
use crate::signer::Signer;
44
use crate::single_signer::{key_decode_hex, MithrilSingleSigner};
@@ -75,7 +75,8 @@ async fn main() {
7575
fake_signer.party_id,
7676
key_decode_hex(&fake_signer.secret_key).unwrap(),
7777
);
78-
let certificate_handler = CertificateHandlerNoOp {};
78+
let certificate_handler =
79+
CertificateHandlerHTTPClient::new(config.aggregator_endpoint.clone());
7980

8081
let mut signer = Signer::new(Box::new(certificate_handler), Box::new(single_signer));
8182
if let Err(e) = signer.run().await {

0 commit comments

Comments
 (0)