Skip to content

Commit 0d4dd8d

Browse files
committed
Add Unit tests for VssAccessor
1 parent 5d70ce6 commit 0d4dd8d

File tree

4 files changed

+297
-1
lines changed

4 files changed

+297
-1
lines changed

vss-accessor/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ prost = "0.11.3"
99
reqwest = { version = "0.11.13", features = ["rustls-tls"] }
1010

1111
[dev-dependencies]
12+
mockito = "0.31.1"
13+
tokio = { version = "1.22.0", features = ["full"]}
1214

1315
[build-dependencies]
1416
prost-build = { version = "0.11.3" }

vss-accessor/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::vss::{
99
};
1010
use crate::vss_error::VssError;
1111

12-
mod vss_error;
12+
pub mod vss_error;
1313

1414
pub mod vss {
1515
include!(concat!(env!("OUT_DIR"), "/org.vss.rs"));

vss-accessor/src/vss_error.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,15 @@ impl From<reqwest::Error> for VssError {
7373
VssError::InternalError(err.to_string())
7474
}
7575
}
76+
77+
impl PartialEq for VssError {
78+
fn eq(&self, other: &Self) -> bool {
79+
match (self, other) {
80+
(VssError::InvalidRequestError(_e1), VssError::InvalidRequestError(_e2)) => true,
81+
(VssError::ConflictError(_e1), VssError::ConflictError(_e2)) => true,
82+
(VssError::InternalServerError(_e1), VssError::InternalServerError(_e2)) => true,
83+
(VssError::InternalError(_m1), VssError::InternalError(_m2)) => true,
84+
_ => false,
85+
}
86+
}
87+
}

vss-accessor/tests/tests.rs

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

0 commit comments

Comments
 (0)