Skip to content

Commit d64c50f

Browse files
committed
Add Unit tests for VssAccessor
1 parent 0031a6b commit d64c50f

File tree

2 files changed

+295
-3
lines changed

2 files changed

+295
-3
lines changed

Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ edition = "2021"
55
build = "build.rs"
66

77
[dependencies]
8-
prost = "0.11.9"
8+
prost = "0.11.6"
99
reqwest = { version = "0.11.13", features = ["rustls-tls"] }
1010

11-
[dev-dependencies]
12-
1311
[build-dependencies]
1412
prost-build = { version = "0.11.3" }
1513
reqwest = { version = "0.11.13", features = ["blocking"] }
1614

15+
[dev-dependencies]
16+
mockito = "0.31.1"
17+
tokio = { version = "1.22.0", features = ["full"]}
18+
1719
[features]
1820
genproto = []

tests/tests.rs

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
#[cfg(test)]
2+
mod tests {
3+
use mockito::{self, Matcher};
4+
use prost::Message;
5+
use std::future::Future;
6+
use vss_client::client::VssClient;
7+
use vss_client::error::VssError;
8+
9+
use vss_client::types::{
10+
ErrorCode, ErrorResponse, GetObjectRequest, GetObjectResponse, KeyValue, ListKeyVersionsRequest,
11+
ListKeyVersionsResponse, PutObjectRequest, PutObjectResponse,
12+
};
13+
14+
const GET_OBJECT_ENDPOINT: &'static str = "/getObject";
15+
const PUT_OBJECT_ENDPOINT: &'static str = "/putObjects";
16+
const LIST_KEY_VERSIONS_ENDPOINT: &'static str = "/listKeyVersions";
17+
18+
#[tokio::test]
19+
async fn test_get() {
20+
// Spin-up mock server with mock response for given request.
21+
let base_url = mockito::server_url().to_string();
22+
23+
// Set up the mock request/response.
24+
let get_request = GetObjectRequest { store_id: "store".to_string(), key: "k1".to_string() };
25+
let mock_response = GetObjectResponse {
26+
value: Some(KeyValue { key: "k1".to_string(), version: 2, value: b"k1v2".to_vec() }),
27+
..Default::default()
28+
};
29+
30+
// Register the mock endpoint with the mockito server.
31+
let mock_server = mockito::mock("POST", GET_OBJECT_ENDPOINT)
32+
.match_body(get_request.encode_to_vec())
33+
.with_status(200)
34+
.with_body(mock_response.encode_to_vec())
35+
.create();
36+
37+
// Create a new VssClient with the mock server URL.
38+
let client = VssClient::new(&base_url);
39+
40+
let actual_result = client.get_object(&get_request).await.unwrap();
41+
42+
let expected_result = &mock_response;
43+
assert_eq!(actual_result, *expected_result);
44+
45+
// Verify server endpoint was called exactly once.
46+
mock_server.expect(1).assert();
47+
}
48+
49+
#[tokio::test]
50+
async fn test_put() {
51+
// Spin-up mock server with mock response for given request.
52+
let base_url = mockito::server_url().to_string();
53+
54+
// Set up the mock request/response.
55+
let request = PutObjectRequest {
56+
store_id: "store".to_string(),
57+
global_version: Some(4),
58+
transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }],
59+
};
60+
let mock_response = PutObjectResponse::default();
61+
62+
// Register the mock endpoint with the mockito server.
63+
let mock_server = mockito::mock("POST", PUT_OBJECT_ENDPOINT)
64+
.match_body(request.encode_to_vec())
65+
.with_status(200)
66+
.with_body(mock_response.encode_to_vec())
67+
.create();
68+
69+
// Create a new VssClient with the mock server URL.
70+
let vss_client = VssClient::new(&base_url);
71+
let actual_result = vss_client.put_object(&request).await.unwrap();
72+
73+
let expected_result = &mock_response;
74+
assert_eq!(actual_result, *expected_result);
75+
76+
// Verify server endpoint was called exactly once.
77+
mock_server.expect(1).assert();
78+
}
79+
80+
#[tokio::test]
81+
async fn test_list_key_versions() {
82+
// Spin-up mock server with mock response for given request.
83+
let base_url = mockito::server_url().to_string();
84+
85+
// Set up the mock request/response.
86+
let request = ListKeyVersionsRequest {
87+
store_id: "store".to_string(),
88+
page_size: Some(5),
89+
page_token: None,
90+
key_prefix: Some("k".into()),
91+
};
92+
let key_versions = vec![
93+
KeyValue { key: "k1".to_string(), version: 3, value: b"".to_vec() },
94+
KeyValue { key: "k2".to_string(), version: 1, value: b"".to_vec() },
95+
];
96+
97+
let mock_response =
98+
ListKeyVersionsResponse { key_versions, global_version: Some(4), next_page_token: Some("k2".into()) };
99+
100+
// Register the mock endpoint with the mockito server.
101+
let mock_server = mockito::mock("POST", LIST_KEY_VERSIONS_ENDPOINT)
102+
.match_body(request.encode_to_vec())
103+
.with_status(200)
104+
.with_body(mock_response.encode_to_vec())
105+
.create();
106+
107+
// Create a new VssClient with the mock server URL.
108+
let client = VssClient::new(&base_url);
109+
110+
let actual_result = client.list_key_versions(&request).await.unwrap();
111+
112+
let expected_result = &mock_response;
113+
assert_eq!(actual_result, *expected_result);
114+
115+
// Verify server endpoint was called exactly once.
116+
mock_server.expect(1).assert();
117+
}
118+
119+
#[tokio::test]
120+
async fn test_invalid_request_err_handling() {
121+
let base_url = mockito::server_url();
122+
let vss_client = VssClient::new(&base_url);
123+
124+
// Invalid Request Error
125+
let error_response = ErrorResponse {
126+
error_code: ErrorCode::InvalidRequestException.into(),
127+
message: "InvalidRequestException".to_string(),
128+
};
129+
let mock_server = mockito::mock("POST", Matcher::Any)
130+
.with_status(400)
131+
.with_body(&error_response.encode_to_vec())
132+
.create();
133+
134+
let get_result = vss_client
135+
.get_object(&GetObjectRequest { store_id: "store".to_string(), key: "k1".to_string() })
136+
.await;
137+
assert!(matches!(get_result.unwrap_err(), VssError::InvalidRequestError { .. }));
138+
139+
let put_result = vss_client
140+
.put_object(&PutObjectRequest {
141+
store_id: "store".to_string(),
142+
global_version: Some(4),
143+
transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }],
144+
})
145+
.await;
146+
assert!(matches!(put_result.unwrap_err(), VssError::InvalidRequestError { .. }));
147+
148+
let list_result = vss_client
149+
.list_key_versions(&ListKeyVersionsRequest {
150+
store_id: "store".to_string(),
151+
page_size: Some(5),
152+
page_token: None,
153+
key_prefix: Some("k".into()),
154+
})
155+
.await;
156+
assert!(matches!(list_result.unwrap_err(), VssError::InvalidRequestError { .. }));
157+
158+
// Verify 3 requests hit the server
159+
mock_server.expect(3).assert();
160+
}
161+
162+
#[tokio::test]
163+
async fn test_conflict_err_handling() {
164+
let base_url = mockito::server_url();
165+
let vss_client = VssClient::new(&base_url);
166+
167+
// Conflict Error
168+
let error_response =
169+
ErrorResponse { error_code: ErrorCode::ConflictException.into(), message: "ConflictException".to_string() };
170+
let mock_server = mockito::mock("POST", Matcher::Any)
171+
.with_status(409)
172+
.with_body(&error_response.encode_to_vec())
173+
.create();
174+
175+
let put_result = vss_client
176+
.put_object(&PutObjectRequest {
177+
store_id: "store".to_string(),
178+
global_version: Some(4),
179+
transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }],
180+
})
181+
.await;
182+
assert!(matches!(put_result.unwrap_err(), VssError::ConflictError { .. }));
183+
184+
// Verify 1 requests hit the server
185+
mock_server.expect(1).assert();
186+
}
187+
188+
#[tokio::test]
189+
async fn test_internal_server_err_handling() {
190+
let base_url = mockito::server_url();
191+
let vss_client = VssClient::new(&base_url);
192+
193+
// Internal Server Error
194+
let error_response = ErrorResponse {
195+
error_code: ErrorCode::InternalServerException.into(),
196+
message: "InternalServerException".to_string(),
197+
};
198+
let mock_server = mockito::mock("POST", Matcher::Any)
199+
.with_status(500)
200+
.with_body(&error_response.encode_to_vec())
201+
.create();
202+
203+
let get_result = vss_client
204+
.get_object(&GetObjectRequest { store_id: "store".to_string(), key: "k1".to_string() })
205+
.await;
206+
assert!(matches!(get_result.unwrap_err(), VssError::InternalServerError { .. }));
207+
208+
let put_result = vss_client
209+
.put_object(&PutObjectRequest {
210+
store_id: "store".to_string(),
211+
global_version: Some(4),
212+
transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }],
213+
})
214+
.await;
215+
assert!(matches!(put_result.unwrap_err(), VssError::InternalServerError { .. }));
216+
217+
let list_result = vss_client
218+
.list_key_versions(&ListKeyVersionsRequest {
219+
store_id: "store".to_string(),
220+
page_size: Some(5),
221+
page_token: None,
222+
key_prefix: Some("k".into()),
223+
})
224+
.await;
225+
assert!(matches!(list_result.unwrap_err(), VssError::InternalServerError { .. }));
226+
227+
// Verify 3 requests hit the server
228+
mock_server.expect(3).assert();
229+
}
230+
231+
#[tokio::test]
232+
async fn test_internal_err_handling() {
233+
let base_url = mockito::server_url();
234+
let vss_client = VssClient::new(&base_url);
235+
236+
let error_response = ErrorResponse { error_code: 999, message: "UnknownException".to_string() };
237+
let mut _mock_server = mockito::mock("POST", Matcher::Any)
238+
.with_status(999)
239+
.with_body(&error_response.encode_to_vec())
240+
.create();
241+
242+
let get_request = GetObjectRequest { store_id: "store".to_string(), key: "k1".to_string() };
243+
let get_result = vss_client.get_object(&get_request).await;
244+
assert!(matches!(get_result.unwrap_err(), VssError::InternalError { .. }));
245+
246+
let put_request = PutObjectRequest {
247+
store_id: "store".to_string(),
248+
global_version: Some(4),
249+
transaction_items: vec![KeyValue { key: "k1".to_string(), version: 2, value: b"k1v3".to_vec() }],
250+
};
251+
let put_result = vss_client.put_object(&put_request).await;
252+
assert!(matches!(put_result.unwrap_err(), VssError::InternalError { .. }));
253+
254+
let list_request = ListKeyVersionsRequest {
255+
store_id: "store".to_string(),
256+
page_size: Some(5),
257+
page_token: None,
258+
key_prefix: Some("k".into()),
259+
};
260+
let list_result = vss_client.list_key_versions(&list_request).await;
261+
assert!(matches!(list_result.unwrap_err(), VssError::InternalError { .. }));
262+
263+
let malformed_error_response = b"malformed";
264+
_mock_server = mockito::mock("POST", Matcher::Any)
265+
.with_status(409)
266+
.with_body(&malformed_error_response)
267+
.create();
268+
269+
let get_malformed_err_response = vss_client.get_object(&get_request).await;
270+
assert!(matches!(get_malformed_err_response.unwrap_err(), VssError::InternalError { .. }));
271+
272+
let put_malformed_err_response = vss_client.put_object(&put_request).await;
273+
assert!(matches!(put_malformed_err_response.unwrap_err(), VssError::InternalError { .. }));
274+
275+
let list_malformed_err_response = vss_client.list_key_versions(&list_request).await;
276+
assert!(matches!(list_malformed_err_response.unwrap_err(), VssError::InternalError { .. }));
277+
278+
// Requests to endpoints are no longer mocked and will result in network error.
279+
drop(_mock_server);
280+
281+
let get_network_err = vss_client.get_object(&get_request).await;
282+
assert!(matches!(get_network_err.unwrap_err(), VssError::InternalError { .. }));
283+
284+
let put_network_err = vss_client.put_object(&put_request).await;
285+
assert!(matches!(put_network_err.unwrap_err(), VssError::InternalError { .. }));
286+
287+
let list_network_err = vss_client.list_key_versions(&list_request).await;
288+
assert!(matches!(list_network_err.unwrap_err(), VssError::InternalError { .. }));
289+
}
290+
}

0 commit comments

Comments
 (0)