From 143b5a5c3eebbe49d952a14097fc8315c7278569 Mon Sep 17 00:00:00 2001 From: Gursharan Singh <3442979+G8XSU@users.noreply.github.com> Date: Wed, 16 Aug 2023 18:34:11 -0700 Subject: [PATCH] Add delete_object fn to client --- src/client.rs | 22 +++++++++++++++-- src/lib.rs | 7 ++---- tests/tests.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 80 insertions(+), 13 deletions(-) diff --git a/src/client.rs b/src/client.rs index f5ef392..b3ab04f 100644 --- a/src/client.rs +++ b/src/client.rs @@ -4,8 +4,8 @@ use reqwest::Client; use crate::error::VssError; use crate::types::{ - GetObjectRequest, GetObjectResponse, ListKeyVersionsRequest, ListKeyVersionsResponse, PutObjectRequest, - PutObjectResponse, + DeleteObjectRequest, DeleteObjectResponse, GetObjectRequest, GetObjectResponse, ListKeyVersionsRequest, + ListKeyVersionsResponse, PutObjectRequest, PutObjectResponse, }; /// Thin-client to access a hosted instance of Versioned Storage Service (VSS). @@ -60,6 +60,24 @@ impl VssClient { } } + /// Deletes the given `key` and `value` in `request`. + /// Makes a service call to the `DeleteObject` endpoint of the VSS server. + /// For API contract/usage, refer to docs for [`DeleteObjectRequest`] and [`DeleteObjectResponse`]. + pub async fn delete_object(&self, request: &DeleteObjectRequest) -> Result { + let url = format!("{}/deleteObject", self.base_url); + + let response_raw = self.client.post(url).body(request.encode_to_vec()).send().await?; + let status = response_raw.status(); + let payload = response_raw.bytes().await?; + + if status.is_success() { + let response = DeleteObjectResponse::decode(&payload[..])?; + Ok(response) + } else { + Err(VssError::new(status, payload)) + } + } + /// Lists keys and their corresponding version for a given [`ListKeyVersionsRequest::store_id`]. /// Makes a service call to the `ListKeyVersions` endpoint of the VSS server. /// For API contract/usage, refer to docs for [`ListKeyVersionsRequest`] and [`ListKeyVersionsResponse`]. diff --git a/src/lib.rs b/src/lib.rs index 4569ad4..d2b6b94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,13 +10,10 @@ #![deny(rustdoc::broken_intra_doc_links)] #![deny(rustdoc::private_intra_doc_links)] -use crate::client::VssClient; -use crate::error::VssError; - -/// Implements a thin-client ([`VssClient`]) to access a hosted instance of Versioned Storage Service (VSS). +/// Implements a thin-client ([`client::VssClient`]) to access a hosted instance of Versioned Storage Service (VSS). pub mod client; -/// Implements the error type ([`VssError`]) returned on interacting with [`VssClient`] +/// Implements the error type ([`error::VssError`]) returned on interacting with [`client::VssClient`] pub mod error; /// Contains request/response types generated from the API definition of VSS. diff --git a/tests/tests.rs b/tests/tests.rs index af26256..610d988 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -6,12 +6,13 @@ mod tests { use vss_client::error::VssError; use vss_client::types::{ - ErrorCode, ErrorResponse, GetObjectRequest, GetObjectResponse, KeyValue, ListKeyVersionsRequest, - ListKeyVersionsResponse, PutObjectRequest, PutObjectResponse, + DeleteObjectRequest, DeleteObjectResponse, ErrorCode, ErrorResponse, GetObjectRequest, GetObjectResponse, + KeyValue, ListKeyVersionsRequest, ListKeyVersionsResponse, PutObjectRequest, PutObjectResponse, }; const GET_OBJECT_ENDPOINT: &'static str = "/getObject"; const PUT_OBJECT_ENDPOINT: &'static str = "/putObjects"; + const DELETE_OBJECT_ENDPOINT: &'static str = "/deleteObject"; const LIST_KEY_VERSIONS_ENDPOINT: &'static str = "/listKeyVersions"; #[tokio::test] @@ -55,6 +56,7 @@ mod tests { store_id: "store".to_string(), global_version: Some(4), transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }], + delete_items: vec![], }; let mock_response = PutObjectResponse::default(); @@ -76,6 +78,36 @@ mod tests { mock_server.expect(1).assert(); } + #[tokio::test] + async fn test_delete() { + // Spin-up mock server with mock response for given request. + let base_url = mockito::server_url().to_string(); + + // Set up the mock request/response. + let request = DeleteObjectRequest { + store_id: "store".to_string(), + key_value: Some(KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }), + }; + let mock_response = DeleteObjectResponse::default(); + + // Register the mock endpoint with the mockito server. + let mock_server = mockito::mock("POST", DELETE_OBJECT_ENDPOINT) + .match_body(request.encode_to_vec()) + .with_status(200) + .with_body(mock_response.encode_to_vec()) + .create(); + + // Create a new VssClient with the mock server URL. + let vss_client = VssClient::new(&base_url); + let actual_result = vss_client.delete_object(&request).await.unwrap(); + + let expected_result = &mock_response; + assert_eq!(actual_result, *expected_result); + + // Verify server endpoint was called exactly once. + mock_server.expect(1).assert(); + } + #[tokio::test] async fn test_list_key_versions() { // Spin-up mock server with mock response for given request. @@ -142,10 +174,19 @@ mod tests { store_id: "store".to_string(), global_version: Some(4), transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }], + delete_items: vec![], }) .await; assert!(matches!(put_result.unwrap_err(), VssError::InvalidRequestError { .. })); + let delete_result = vss_client + .delete_object(&DeleteObjectRequest { + store_id: "store".to_string(), + key_value: Some(KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }), + }) + .await; + assert!(matches!(delete_result.unwrap_err(), VssError::InvalidRequestError { .. })); + let list_result = vss_client .list_key_versions(&ListKeyVersionsRequest { store_id: "store".to_string(), @@ -156,8 +197,8 @@ mod tests { .await; assert!(matches!(list_result.unwrap_err(), VssError::InvalidRequestError { .. })); - // Verify 3 requests hit the server - mock_server.expect(3).assert(); + // Verify 4 requests hit the server + mock_server.expect(4).assert(); } #[tokio::test] @@ -178,6 +219,7 @@ mod tests { store_id: "store".to_string(), global_version: Some(4), transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }], + delete_items: vec![], }) .await; assert!(matches!(put_result.unwrap_err(), VssError::ConflictError { .. })); @@ -211,10 +253,19 @@ mod tests { store_id: "store".to_string(), global_version: Some(4), transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }], + delete_items: vec![], }) .await; assert!(matches!(put_result.unwrap_err(), VssError::InternalServerError { .. })); + let delete_result = vss_client + .delete_object(&DeleteObjectRequest { + store_id: "store".to_string(), + key_value: Some(KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }), + }) + .await; + assert!(matches!(delete_result.unwrap_err(), VssError::InternalServerError { .. })); + let list_result = vss_client .list_key_versions(&ListKeyVersionsRequest { store_id: "store".to_string(), @@ -225,8 +276,8 @@ mod tests { .await; assert!(matches!(list_result.unwrap_err(), VssError::InternalServerError { .. })); - // Verify 3 requests hit the server - mock_server.expect(3).assert(); + // Verify 4 requests hit the server + mock_server.expect(4).assert(); } #[tokio::test] @@ -248,6 +299,7 @@ mod tests { store_id: "store".to_string(), global_version: Some(4), transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }], + delete_items: vec![], }; let put_result = vss_client.put_object(&put_request).await; assert!(matches!(put_result.unwrap_err(), VssError::InternalError { .. }));