summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rust/src/web.rs94
1 files changed, 67 insertions, 27 deletions
diff --git a/rust/src/web.rs b/rust/src/web.rs
index af74a09..257817d 100644
--- a/rust/src/web.rs
+++ b/rust/src/web.rs
@@ -1,6 +1,7 @@
use std::{
env::args,
io::{stdin, stdout, IsTerminal},
+ sync::Mutex,
};
use actix_web::{
@@ -13,20 +14,14 @@ struct Registration {
url: String,
}
-trait IdGenerator {
- fn next_id(&self) -> String;
+trait AppState {
+ fn register(&mut self, registration: &Registration) -> RegistrationResult;
}
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
enum RegistrationResult {
- Success(RegistrationSuccess),
- Failure(RegistrationFailure),
-}
-
-#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
-struct RegistrationSuccess {
- id: String,
- url: String,
+ RegistrationSuccess { id: String, url: String },
+ UrlAlreadyRegistered { url: String },
}
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
@@ -36,17 +31,14 @@ enum RegistrationFailure {
#[post("/register")]
async fn register(
- id_gen: web::Data<dyn IdGenerator>,
+ app_state: web::Data<Mutex<dyn AppState>>,
registration: web::Json<Registration>,
) -> impl Responder {
- let id = id_gen.next_id();
- let success = RegistrationSuccess {
- id,
- url: registration.url.clone(),
- };
- HttpResponse::Ok()
- .content_type(ContentType::json())
- .body(serde_json::to_string(&RegistrationResult::Success(success)).unwrap())
+ let result = app_state.lock().unwrap().register(&registration);
+ match result {
+ RegistrationResult::RegistrationSuccess { .. } => HttpResponse::Ok().json(result),
+ RegistrationResult::UrlAlreadyRegistered { .. } => HttpResponse::BadRequest().json(result),
+ }
}
#[actix_web::main]
@@ -65,33 +57,43 @@ mod app_tests {
use super::*;
- struct ConstantIdGenerator {
+ struct DummyAppState {
id: String,
}
- impl ConstantIdGenerator {
+ impl DummyAppState {
fn new(id: String) -> Self {
Self { id }
}
}
- impl IdGenerator for ConstantIdGenerator {
- fn next_id(&self) -> String {
- self.id.clone()
+ impl AppState for DummyAppState {
+ fn register(&mut self, registration: &Registration) -> RegistrationResult {
+ if self.id == "" {
+ return RegistrationResult::UrlAlreadyRegistered {
+ url: registration.url.clone(),
+ };
+ } else {
+ RegistrationResult::RegistrationSuccess {
+ id: self.id.clone(),
+ url: registration.url.clone(),
+ }
+ }
}
}
#[actix_web::test]
async fn post_registration_returns_success_with_unique_id() {
let id = "0123456789abcdef0123456789abcdef".to_string();
- let id_generator: Arc<dyn IdGenerator> = Arc::new(ConstantIdGenerator::new(id.clone()));
+ let dummy_state: Arc<Mutex<dyn AppState>> =
+ Arc::new(Mutex::new(DummyAppState::new(id.clone())));
// FIXME should only be called once, move to setup
// env_logger::init();
let app = test::init_service(
App::new()
.wrap(Logger::default())
- .app_data(web::Data::from(id_generator))
+ .app_data(web::Data::from(dummy_state))
.service(register),
)
.await;
@@ -109,7 +111,45 @@ mod app_tests {
let body = resp.into_body();
let bytes = body::to_bytes(body).await;
assert_eq!(
- RegistrationResult::Success(RegistrationSuccess { id, url }),
+ RegistrationResult::RegistrationSuccess { id, url },
+ serde_json::from_slice(&bytes.unwrap()).unwrap()
+ );
+ }
+
+ #[actix_web::test]
+ async fn post_registration_fails_given_url_is_already_registered() {
+ let dummy_state: Arc<Mutex<dyn AppState>> =
+ Arc::new(Mutex::new(DummyAppState::new("".to_string())));
+
+ let app = test::init_service(
+ App::new()
+ .wrap(Logger::default())
+ .app_data(web::Data::from(dummy_state))
+ .service(register),
+ )
+ .await;
+ let url = "http://192.168.1.1".to_string();
+ let _ = test::TestRequest::post()
+ .uri("/register")
+ .set_json(Registration { url: url.clone() })
+ .insert_header(ContentType::json())
+ .to_request();
+
+ // second request with the same URL
+ let req = test::TestRequest::post()
+ .uri("/register")
+ .set_json(Registration { url: url.clone() })
+ .insert_header(ContentType::json())
+ .to_request();
+
+ let resp = test::call_service(&app, req).await;
+
+ assert!(resp.status().is_client_error());
+
+ let body = resp.into_body();
+ let bytes = body::to_bytes(body).await;
+ assert_eq!(
+ RegistrationResult::UrlAlreadyRegistered { url },
serde_json::from_slice(&bytes.unwrap()).unwrap()
);
}