Skip to content

Commit 77db6ca

Browse files
committed
Add testing framework and unit tests
This commit creates the testing framework used to verify the client library. It also adds unit tests for the operations implemented thus far. Signed-off-by: Ionut Mihalcea <[email protected]>
1 parent 3db5dcb commit 77db6ca

File tree

10 files changed

+522
-12
lines changed

10 files changed

+522
-12
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,7 @@ num = "0.2.1"
1717
rand = "0.7.3"
1818
log = "0.4.8"
1919
derivative = "2.0.2"
20+
21+
[dev-dependencies]
22+
mockstream = "0.0.3"
23+
uuid = "0.7.4"

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ This project uses the following third party crates:
1616
* rand (Apache-2.0)
1717
* log (Apache-2.0)
1818
* derivative (MIT and Apache-2.0)
19+
* mockstream (MIT)
20+
* uuid (MIT and Apache-2.0)
1921

2022
## Contributing
2123

src/core/mod.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,20 @@ impl CoreClient {
8282
}
8383

8484
/// ping
85-
pub fn ping(&self) -> Result<()> {
86-
let _ = self.op_handler.process_operation(
85+
pub fn ping(&self) -> Result<(u8, u8)> {
86+
let res = self.op_handler.process_operation(
8787
NativeOperation::Ping(Ping {}),
8888
ProviderID::Core,
8989
&AuthenticationData::None,
9090
)?;
9191

92-
Ok(())
92+
if let NativeResult::Ping(res) = res {
93+
Ok((res.wire_protocol_version_maj, res.wire_protocol_version_min))
94+
} else {
95+
// Should really not be reached given the checks we do, but it's not impossible if some
96+
// changes happen in the interface
97+
Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
98+
}
9399
}
94100

95101
/// generate key

src/core/operation_handler.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub struct OperationHandler {
2222
pub wire_protocol_version_min: u8,
2323
pub content_type: BodyType,
2424
pub accept_type: BodyType,
25+
#[cfg_attr(test, derivative(Debug = "ignore"))]
2526
pub request_handler: RequestHandler,
2627
}
2728

src/core/request_handler.rs

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,51 @@
22
// SPDX-License-Identifier: Apache-2.0
33
#![allow(dead_code)]
44

5-
use crate::error::{ClientErrorKind, Error, Result};
5+
use crate::error::{ClientErrorKind, Result};
6+
#[cfg(test)]
7+
use mockstream::SyncMockStream;
68
use parsec_interface::requests::{Request, Response};
9+
use std::io::{Read, Write};
10+
#[cfg(not(test))]
711
use std::os::unix::net::UnixStream;
812
use std::path::PathBuf;
913
use std::time::Duration;
1014

11-
const DEFAULT_MAX_BODY_SIZE: usize = 1 << 31;
15+
const DEFAULT_MAX_BODY_SIZE: usize = usize::max_value();
1216
const DEFAULT_SOCKET_PATH: &str = "/tmp/security-daemon-socket";
1317

1418
/// Low level client structure to send a `Request` and get a `Response`.
15-
#[derive(Clone, Debug)]
19+
#[derive(Clone)]
20+
#[cfg_attr(not(test), derive(Debug))]
1621
pub struct RequestHandler {
1722
pub max_body_size: usize,
1823
pub timeout: Option<Duration>,
1924
pub socket_path: PathBuf,
25+
#[cfg(test)]
26+
pub mock_stream: SyncMockStream,
2027
}
2128

2229
impl RequestHandler {
2330
/// Send a request and get a response.
2431
pub fn process_request(&self, request: Request) -> Result<Response> {
2532
// Try to connect once, wait for a timeout until trying again.
26-
let mut stream = UnixStream::connect(&self.socket_path).map_err(ClientErrorKind::Ipc)?;
33+
let mut stream = self.connect_to_socket()?;
34+
35+
request
36+
.write_to_stream(&mut stream)
37+
.map_err(ClientErrorKind::Interface)?;
38+
Ok(Response::read_from_stream(&mut stream, self.max_body_size)
39+
.map_err(ClientErrorKind::Interface)?)
40+
}
41+
42+
#[cfg(test)]
43+
fn connect_to_socket(&self) -> Result<impl Read + Write> {
44+
Ok(self.mock_stream.clone())
45+
}
46+
47+
#[cfg(not(test))]
48+
fn connect_to_socket(&self) -> Result<impl Read + Write> {
49+
let stream = UnixStream::connect(&self.socket_path).map_err(ClientErrorKind::Ipc)?;
2750

2851
stream
2952
.set_read_timeout(self.timeout)
@@ -32,10 +55,7 @@ impl RequestHandler {
3255
.set_write_timeout(self.timeout)
3356
.map_err(ClientErrorKind::Ipc)?;
3457

35-
request
36-
.write_to_stream(&mut stream)
37-
.map_err(ClientErrorKind::Interface)?;
38-
Ok(Response::read_from_stream(&mut stream, self.max_body_size).map_err(Error::Service)?)
58+
Ok(stream)
3959
}
4060
}
4161

@@ -45,6 +65,8 @@ impl Default for RequestHandler {
4565
max_body_size: DEFAULT_MAX_BODY_SIZE,
4666
timeout: None,
4767
socket_path: DEFAULT_SOCKET_PATH.into(),
68+
#[cfg(test)]
69+
mock_stream: SyncMockStream::new(),
4870
}
4971
}
5072
}
@@ -66,4 +88,22 @@ impl crate::CoreClient {
6688
pub fn set_socket_path(&mut self, socket_path: PathBuf) {
6789
self.op_handler.request_handler.socket_path = socket_path;
6890
}
91+
92+
/// Test helper used to set the data to be returned from the mock stream
93+
#[cfg(test)]
94+
pub fn set_mock_read(&mut self, data: &[u8]) {
95+
self.op_handler
96+
.request_handler
97+
.mock_stream
98+
.push_bytes_to_read(data);
99+
}
100+
101+
/// Test helper used to verify the data written to the mock stream
102+
#[cfg(test)]
103+
pub fn get_mock_write(&mut self) -> Vec<u8> {
104+
self.op_handler
105+
.request_handler
106+
.mock_stream
107+
.pop_bytes_written()
108+
}
69109
}

src/error.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use parsec_interface::requests::ResponseStatus;
55

66
/// Enum used to denote errors returned to the library user
7-
#[derive(Debug)]
7+
#[derive(Debug, PartialEq)]
88
pub enum Error {
99
/// Errors originating in the service
1010
Service(ResponseStatus),
@@ -29,5 +29,33 @@ impl From<ClientErrorKind> for Error {
2929
}
3030
}
3131

32+
impl PartialEq for ClientErrorKind {
33+
fn eq(&self, other: &Self) -> bool {
34+
match self {
35+
ClientErrorKind::Interface(status) => {
36+
if let ClientErrorKind::Interface(other_status) = other {
37+
other_status == status
38+
} else {
39+
false
40+
}
41+
}
42+
ClientErrorKind::Ipc(error) => {
43+
if let ClientErrorKind::Ipc(other_error) = other {
44+
other_error.kind() == error.kind()
45+
} else {
46+
false
47+
}
48+
}
49+
ClientErrorKind::InvalidServiceResponseType => {
50+
if let ClientErrorKind::InvalidServiceResponseType = other {
51+
true
52+
} else {
53+
false
54+
}
55+
}
56+
}
57+
}
58+
}
59+
3260
/// Result type used for the internals and interface of the Parsec client
3361
pub type Result<T> = ::std::result::Result<T, Error>;

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@
3434
pub mod auth;
3535
mod core;
3636
pub mod error;
37+
mod tests;
3738

3839
pub use crate::core::CoreClient;

0 commit comments

Comments
 (0)