use crate::*;
use std::{collections::HashMap, io::Result};
use model::{Group, GroupQueryBuilder, User, UserQueryBuilder};
pub struct MockResource<T>(Vec<T>);
pub struct MockBadResource;
#[derive(Copy, Clone, Debug)]
pub struct MockError;
impl<T: UniqueID> Resource<T> for MockBadResource {
fn load(&self) -> Result<ArcMap<T>> {
Err(std::io::Error::new(std::io::ErrorKind::Other, MockError))
}
}
impl<T> Resource<T> for MockResource<T>
where
T: Clone + UniqueID,
{
fn load(&self) -> Result<std::sync::Arc<HashMap<u64, T>>> {
Ok(std::sync::Arc::new(
self.0.iter().map(|t| (t.id(), t.clone())).collect(),
))
}
}
impl<T> Resource<T> for &MockResource<T>
where
T: Clone + UniqueID,
{
fn load(&self) -> Result<std::sync::Arc<HashMap<u64, T>>> {
Ok(std::sync::Arc::new(
self.0.iter().map(|t| (t.id(), t.clone())).collect(),
))
}
}
impl<T: UniqueID> Resource<T> for &MockBadResource {
fn load(&self) -> Result<std::sync::Arc<HashMap<u64, T>>> {
Err(std::io::Error::new(std::io::ErrorKind::Other, MockError))
}
}
fn users() -> Vec<User> {
vec![root(), dwoodlin(), same_username_as_dwoodlin()]
}
fn root() -> User {
User {
name: "root".to_string(),
uid: 0,
gid: 0,
comment: "root".to_string(),
home: "/root".to_string(),
shell: "/b
in/bash"
.to_string(),
}
}
fn dwoodlin() -> User {
User {
name: "dwoodlins".to_string(),
uid: 1001,
gid: 1001,
comment: "".to_string(),
home: "/bin/false".to_string(),
shell: "/bin/false".to_string(),
}
}
fn same_username_as_dwoodlin() -> User {
User {
name: "dwoodlins".to_string(),
uid: 10,
gid: 10,
comment: "hi".to_string(),
home: "/bin/true".to_string(),
shell: "/bin/true".to_string(),
}
}
fn sorted_by_id<T: UniqueID>(a: impl IntoIterator<Item = T>) -> Vec<T> {
let mut a: Vec<T> = a.into_iter().collect();
a.sort_by_key(UniqueID::id);
a
}
fn admins() -> Group {
Group {
name: "admin".to_string().to_owned(),
gid: 1,
members: vec![dwoodlin().name.to_string(), root().name.to_string()],
}
}
#[test]
fn get_group() {
let groups = MockResource(vec![admins()]);
assert!(api::get_group(&groups, 1).unwrap() == admins());
}
#[test]
fn get_groups_for_user() {
struct Test {
groups: MockResource<Group>,
uid: u64,
want: Vec<Group>,
msg: &'static str,
}
let tests: Vec<Test> = vec![
Test {
groups: MockResource(vec![admins()]),
want: vec![admins()],
uid: dwoodlin().uid,
msg: "only overlapping groups",
},
Test {
groups: MockResource(vec![]),
want: vec![],
uid: dwoodlin().uid,
msg: "empty groups",
},
];
let users = MockResource(users().to_vec());
for Test { groups, uid, want, msg } in tests {
let got = sorted_by_id(api::get_groups_for_user(&groups, &users, uid).unwrap());
let want = sorted_by_id(want);
assert_eq!(got, want, "{}", msg);
}
assert!(api::get_groups_for_user(&MockBadResource, users, 0).is_none())
}
#[test]
#[ignore]
fn known_bad_test_for_get_groups_for_user() {
assert_eq!(
api::get_groups_for_user(
MockResource(vec![admins()]),
&MockResource(users().to_vec()),
same_username_as_dwoodlin().uid
)
.unwrap(),
vec![],
"should have no overlap, but shared username leads to bad result; not properly unique"
)
}
#[test]
fn get_matching_users() {
struct Test {
query: UserQueryBuilder,
users: Vec<User>,
want: Vec<User>,
msg: &'static str,
}
let tests: Vec<Test> = vec![
Test {
query: UserQueryBuilder::new().with_name(&dwoodlin().name),
users: users(),
want: vec![dwoodlin(), same_username_as_dwoodlin()],
msg: "get multiple matches",
},
Test {
query: UserQueryBuilder::new().with_uid(10000),
users: users(),
want: vec![],
msg: "no matches",
},
];
for Test {
query,
users,
want,
msg,
} in tests
{
let resource = &MockResource(users.to_vec());
let got = api::get_matching_users(query.build().unwrap(), resource).unwrap();
assert_eq!(sorted_by_id(got), sorted_by_id(want.to_vec()), "{}", msg)
}
}
#[test]
fn get_all_groups() {
assert_eq!(
api::get_all_groups(&MockResource(vec![admins()])).unwrap(),
vec![admins()]
);
}
#[test]
fn get_matching_groups() {
struct Test {
groups: Vec<Group>,
query: GroupQueryBuilder,
want: Vec<Group>,
}
let tests: Vec<Test> = vec![Test {
groups: vec![admins()],
query: GroupQueryBuilder::new().with_gid(admins().gid),
want: vec![admins()],
}];
for Test { groups, query, want } in tests {
let groups = MockResource(groups.to_vec());
let query = query.build().unwrap();
assert_eq!(api::get_matching_groups(query, groups).unwrap(), want);
}
}
#[test]
fn test_is_match() {
for query in vec![
UserQueryBuilder::new().with_name(&root().name),
UserQueryBuilder::new().with_comment(&root().comment),
UserQueryBuilder::new().with_uid(root().uid),
UserQueryBuilder::new().with_gid(root().gid),
UserQueryBuilder::new().with_home(&root().home),
UserQueryBuilder::new().with_shell(&root().shell),
] {
assert!(query.build().unwrap().is_match(&root()))
}
for query in vec![
UserQueryBuilder::new().with_name(&dwoodlin().name),
UserQueryBuilder::new().with_comment(&dwoodlin().comment),
UserQueryBuilder::new().with_uid(dwoodlin().uid),
UserQueryBuilder::new().with_gid(dwoodlin().gid),
UserQueryBuilder::new().with_home(&dwoodlin().home),
UserQueryBuilder::new().with_shell(&dwoodlin().shell),
] {
assert!(!query.build().unwrap().is_match(&root()))
}
let exact_match = UserQueryBuilder {
name: Some(root().name.to_string()),
comment: Some(root().comment.to_string()),
uid: Some(root().uid),
gid: Some(root().gid),
home: Some(root().home.to_string()),
shell: Some(root().shell.to_string()),
};
assert!(exact_match.clone().build().unwrap().is_match(&root()));
let one_criteria_fails = exact_match.with_comment(&dwoodlin().comment);
assert!(!one_criteria_fails.build().unwrap().is_match(&root()))
}
impl std::fmt::Display for MockError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "mock error")
}
}
impl std::error::Error for MockError {}