Skip to content

Commit

Permalink
Add Unit tests for VssAccessor
Browse files Browse the repository at this point in the history
  • Loading branch information
G8XSU committed Aug 8, 2023
1 parent 0031a6b commit 91fb6aa
Show file tree
Hide file tree
Showing 2 changed files with 296 additions and 3 deletions.
8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ edition = "2021"
build = "build.rs"

[dependencies]
prost = "0.11.9"
prost = "0.11.6"
reqwest = { version = "0.11.13", features = ["rustls-tls"] }

[dev-dependencies]

[build-dependencies]
prost-build = { version = "0.11.3" }
reqwest = { version = "0.11.13", features = ["blocking"] }

[dev-dependencies]
mockito = "0.31.1"
tokio = { version = "1.22.0", features = ["macros"]}

[features]
genproto = []
291 changes: 291 additions & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
#[cfg(test)]
mod tests {
use mockito::{self, Matcher};
use prost::Message;
use vss_client::client::VssClient;
use vss_client::error::VssError;

use vss_client::types::{
ErrorCode, ErrorResponse, GetObjectRequest, GetObjectResponse, KeyValue, ListKeyVersionsRequest,
ListKeyVersionsResponse, PutObjectRequest, PutObjectResponse,
};

const GET_OBJECT_ENDPOINT: &'static str = "/getObject";
const PUT_OBJECT_ENDPOINT: &'static str = "/putObjects";
const LIST_KEY_VERSIONS_ENDPOINT: &'static str = "/listKeyVersions";

#[tokio::test]
async fn test_get() {
// 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 get_request = GetObjectRequest { store_id: "store".to_string(), key: "k1".to_string() };
let mock_response = GetObjectResponse {
value: Some(KeyValue { key: "k1".to_string(), version: 2, value: b"k1v2".to_vec() }),
..Default::default()
};

// Register the mock endpoint with the mockito server.
let mock_server = mockito::mock("POST", GET_OBJECT_ENDPOINT)
.match_body(get_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 client = VssClient::new(&base_url);

let actual_result = client.get_object(&get_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_put() {
// 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 = PutObjectRequest {
store_id: "store".to_string(),
global_version: Some(4),
transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }],
};
let mock_response = PutObjectResponse::default();

// Register the mock endpoint with the mockito server.
let mock_server = mockito::mock("POST", PUT_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.put_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.
let base_url = mockito::server_url().to_string();

// Set up the mock request/response.
let request = ListKeyVersionsRequest {
store_id: "store".to_string(),
page_size: Some(5),
page_token: None,
key_prefix: Some("k".into()),
};

let mock_response = ListKeyVersionsResponse {
key_versions: vec![
KeyValue { key: "k1".to_string(), version: 3, value: vec![] },
KeyValue { key: "k2".to_string(), version: 1, value: vec![] },
],
global_version: Some(4),
next_page_token: Some("k2".into()),
};

// Register the mock endpoint with the mockito server.
let mock_server = mockito::mock("POST", LIST_KEY_VERSIONS_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 client = VssClient::new(&base_url);

let actual_result = client.list_key_versions(&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_invalid_request_err_handling() {
let base_url = mockito::server_url();
let vss_client = VssClient::new(&base_url);

// Invalid Request Error
let error_response = ErrorResponse {
error_code: ErrorCode::InvalidRequestException.into(),
message: "InvalidRequestException".to_string(),
};
let mock_server = mockito::mock("POST", Matcher::Any)
.with_status(400)
.with_body(&error_response.encode_to_vec())
.create();

let get_result = vss_client
.get_object(&GetObjectRequest { store_id: "store".to_string(), key: "k1".to_string() })
.await;
assert!(matches!(get_result.unwrap_err(), VssError::InvalidRequestError { .. }));

let put_result = vss_client
.put_object(&PutObjectRequest {
store_id: "store".to_string(),
global_version: Some(4),
transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }],
})
.await;
assert!(matches!(put_result.unwrap_err(), VssError::InvalidRequestError { .. }));

let list_result = vss_client
.list_key_versions(&ListKeyVersionsRequest {
store_id: "store".to_string(),
page_size: Some(5),
page_token: None,
key_prefix: Some("k".into()),
})
.await;
assert!(matches!(list_result.unwrap_err(), VssError::InvalidRequestError { .. }));

// Verify 3 requests hit the server
mock_server.expect(3).assert();
}

#[tokio::test]
async fn test_conflict_err_handling() {
let base_url = mockito::server_url();
let vss_client = VssClient::new(&base_url);

// Conflict Error
let error_response =
ErrorResponse { error_code: ErrorCode::ConflictException.into(), message: "ConflictException".to_string() };
let mock_server = mockito::mock("POST", Matcher::Any)
.with_status(409)
.with_body(&error_response.encode_to_vec())
.create();

let put_result = vss_client
.put_object(&PutObjectRequest {
store_id: "store".to_string(),
global_version: Some(4),
transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }],
})
.await;
assert!(matches!(put_result.unwrap_err(), VssError::ConflictError { .. }));

// Verify 1 requests hit the server
mock_server.expect(1).assert();
}

#[tokio::test]
async fn test_internal_server_err_handling() {
let base_url = mockito::server_url();
let vss_client = VssClient::new(&base_url);

// Internal Server Error
let error_response = ErrorResponse {
error_code: ErrorCode::InternalServerException.into(),
message: "InternalServerException".to_string(),
};
let mock_server = mockito::mock("POST", Matcher::Any)
.with_status(500)
.with_body(&error_response.encode_to_vec())
.create();

let get_result = vss_client
.get_object(&GetObjectRequest { store_id: "store".to_string(), key: "k1".to_string() })
.await;
assert!(matches!(get_result.unwrap_err(), VssError::InternalServerError { .. }));

let put_result = vss_client
.put_object(&PutObjectRequest {
store_id: "store".to_string(),
global_version: Some(4),
transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }],
})
.await;
assert!(matches!(put_result.unwrap_err(), VssError::InternalServerError { .. }));

let list_result = vss_client
.list_key_versions(&ListKeyVersionsRequest {
store_id: "store".to_string(),
page_size: Some(5),
page_token: None,
key_prefix: Some("k".into()),
})
.await;
assert!(matches!(list_result.unwrap_err(), VssError::InternalServerError { .. }));

// Verify 3 requests hit the server
mock_server.expect(3).assert();
}

#[tokio::test]
async fn test_internal_err_handling() {
let base_url = mockito::server_url();
let vss_client = VssClient::new(&base_url);

let error_response = ErrorResponse { error_code: 999, message: "UnknownException".to_string() };
let mut _mock_server = mockito::mock("POST", Matcher::Any)
.with_status(999)
.with_body(&error_response.encode_to_vec())
.create();

let get_request = GetObjectRequest { store_id: "store".to_string(), key: "k1".to_string() };
let get_result = vss_client.get_object(&get_request).await;
assert!(matches!(get_result.unwrap_err(), VssError::InternalError { .. }));

let put_request = PutObjectRequest {
store_id: "store".to_string(),
global_version: Some(4),
transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }],
};
let put_result = vss_client.put_object(&put_request).await;
assert!(matches!(put_result.unwrap_err(), VssError::InternalError { .. }));

let list_request = ListKeyVersionsRequest {
store_id: "store".to_string(),
page_size: Some(5),
page_token: None,
key_prefix: Some("k".into()),
};
let list_result = vss_client.list_key_versions(&list_request).await;
assert!(matches!(list_result.unwrap_err(), VssError::InternalError { .. }));

let malformed_error_response = b"malformed";
_mock_server = mockito::mock("POST", Matcher::Any)
.with_status(409)
.with_body(&malformed_error_response)
.create();

let get_malformed_err_response = vss_client.get_object(&get_request).await;
assert!(matches!(get_malformed_err_response.unwrap_err(), VssError::InternalError { .. }));

let put_malformed_err_response = vss_client.put_object(&put_request).await;
assert!(matches!(put_malformed_err_response.unwrap_err(), VssError::InternalError { .. }));

let list_malformed_err_response = vss_client.list_key_versions(&list_request).await;
assert!(matches!(list_malformed_err_response.unwrap_err(), VssError::InternalError { .. }));

// Requests to endpoints are no longer mocked and will result in network error.
drop(_mock_server);

let get_network_err = vss_client.get_object(&get_request).await;
assert!(matches!(get_network_err.unwrap_err(), VssError::InternalError { .. }));

let put_network_err = vss_client.put_object(&put_request).await;
assert!(matches!(put_network_err.unwrap_err(), VssError::InternalError { .. }));

let list_network_err = vss_client.list_key_versions(&list_request).await;
assert!(matches!(list_network_err.unwrap_err(), VssError::InternalError { .. }));
}
}

0 comments on commit 91fb6aa

Please sign in to comment.