From 5502013b76b18da27dbdedd7a419f83ed423a209 Mon Sep 17 00:00:00 2001 From: Jeff Baskin Date: Sun, 4 May 2025 09:55:05 -0400 Subject: [PATCH] Patch errors if page is missing. --- src/document.rs | 68 ++++++++++++++++++++++++++++++++++++++---------- src/main.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 14 deletions(-) diff --git a/src/document.rs b/src/document.rs index 7b7af60..de39ad8 100644 --- a/src/document.rs +++ b/src/document.rs @@ -41,25 +41,41 @@ impl Document { loop { let msg = self.rx.recv().unwrap(); match msg.get_data("action") { - Some(action) => match action.to_action().unwrap() { - ActionType::Add => self.add(msg), - _ => self.get(msg), - }, + Some(action_field) => { + let action = action_field.to_action().unwrap(); + match action { + ActionType::Add | ActionType::Update => self.add(action, msg), + _ => self.get(msg), + } + } None => self.get(msg), } } } - fn add(&mut self, msg: Message) { + fn add(&mut self, action: ActionType, msg: Message) { let name = msg.get_data("name").unwrap().to_string(); match self.data.get(&name) { - Some(_) => { - self.queue - .send(msg.reply_with_error(ErrorType::DocumentAlreadyExists)) - .unwrap(); - return; - } - None => {} + Some(_) => match action { + ActionType::Add => { + self.queue + .send(msg.reply_with_error(ErrorType::DocumentAlreadyExists)) + .unwrap(); + return; + } + ActionType::Update => {} + _ => unreachable!("listen should prevent anything else"), + }, + None => match action { + ActionType::Add => {} + ActionType::Update => { + self.queue + .send(msg.reply_with_error(ErrorType::DocumentNotFound)) + .unwrap(); + return; + } + _ => unreachable!("listen should prevent anything else"), + }, } let doc: Value = match serde_json::from_str(&msg.get_data("doc").unwrap().to_string()) { Ok(value) => value, @@ -251,8 +267,8 @@ pub mod documents { #[test] fn invalid_json() { let inputs = ["Invalid json request.", "{}"]; + let (queue, rx) = setup_document(); for input in inputs.into_iter() { - let (queue, rx) = setup_document(); let mut msg = Message::new(MsgType::DocumentRequest); msg.add_data("action", ActionType::Add); msg.add_data("name", "doc"); @@ -282,4 +298,30 @@ pub mod documents { } } } + + #[test] + fn patch_nonexistant_page() { + let (queue, rx) = setup_document(); + let input = json!({ + "template": "Sothing here" + }); + let mut msg = Message::new(MsgType::DocumentRequest); + msg.add_data("action", ActionType::Update); + msg.add_data("name", "something"); + msg.add_data("doc", input.to_string()); + queue.send(msg.clone()).unwrap(); + let reply = rx.recv_timeout(TIMEOUT).unwrap(); + assert_eq!(reply.get_id(), msg.get_id()); + match reply.get_msg_type() { + MsgType::Error => {} + _ => unreachable!("got {:?}: shoud have been error", reply.get_msg_type()), + } + match reply.get_data("error_type") { + Some(err) => match err.to_error_type().unwrap() { + ErrorType::DocumentNotFound => {} + _ => unreachable!("got {:?}: should have been document not found'", err), + }, + None => unreachable!("should contain error type"), + } + } } diff --git a/src/main.rs b/src/main.rs index bc15e4b..0353e88 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,7 +45,7 @@ async fn create_app(state: MoreThanText) -> Router { Router::new() .route("/", get(mtt_conn)) .route("/{document}", get(mtt_conn)) - .route("/api/{document}", post(mtt_conn)) + .route("/api/{document}", post(mtt_conn).patch(mtt_conn)) .layer(CookieManagerLayer::new()) .layer(Extension(state.clone())) .with_state(state) @@ -91,6 +91,7 @@ async fn mtt_conn( let action = match method { Method::GET => ActionType::Get, Method::POST => ActionType::Add, + Method::PATCH => ActionType::Update, _ => unreachable!("reouter should prevent this"), }; let doc = match path.get("document") { @@ -305,4 +306,70 @@ mod servers { "do not allow post to existing documents" ); } + + #[tokio::test] + async fn patch_root() { + let content = format!("content-{}", Uuid::new_v4()); + let document = json!({ + "template": content.clone() + }); + let app = create_app(MoreThanText::new()).await; + let response = app + .clone() + .oneshot( + Request::builder() + .method(Method::PATCH) + .uri("/api/root".to_string()) + .body(document.to_string()) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!( + response.status(), + StatusCode::OK, + "failed to patch /api/root", + ); + let response = app + .oneshot( + Request::builder() + .uri("/".to_string()) + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!( + response.status(), + StatusCode::OK, + "failed to get to home page", + ); + let body = response.into_body().collect().await.unwrap().to_bytes(); + assert_eq!(body, content); + } + + #[tokio::test] + async fn patch_missing_page() { + let content = format!("content-{}", Uuid::new_v4()); + let document = json!({ + "template": content.clone() + }); + let app = create_app(MoreThanText::new()).await; + let response = app + .clone() + .oneshot( + Request::builder() + .method(Method::PATCH) + .uri("/api/something".to_string()) + .body(document.to_string()) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!( + response.status(), + StatusCode::NOT_FOUND, + "failed to patch /api/somethingt", + ); + } }