Skip to content

Commit 91fb6aa

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

File tree

2 files changed

+296
-3
lines changed

2 files changed

+296
-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 = ["macros"]}
18+
1719
[features]
1820
genproto = []

tests/tests.rs

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

0 commit comments

Comments
 (0)