Update to rust 2018 and improve some todo notes

This commit is contained in:
William Brown 2019-04-18 11:28:33 +10:00
parent af9ac8f662
commit 4ab377ec88
21 changed files with 387 additions and 328 deletions

View file

@ -5,8 +5,7 @@ name = "rsidm"
version = "0.1.0" version = "0.1.0"
authors = ["William Brown <william@blackhats.net.au>"] authors = ["William Brown <william@blackhats.net.au>"]
default-run = "rsidm_core" default-run = "rsidm_core"
# edition = "2018"
# edition = "2018"
# We need three major binaries. The server itself, the unix client, and a cli # We need three major binaries. The server itself, the unix client, and a cli

View file

@ -62,6 +62,24 @@ macro_rules! try_audit {
} }
} }
}; };
($audit:ident, $result:expr, $logFormat:expr) => {
match $result {
Ok(v) => v,
Err(e) => {
audit_log!($audit, $logFormat, e);
return Err(e);
}
}
};
($audit:ident, $result:expr) => {
match $result {
Ok(v) => v,
Err(e) => {
audit_log!($audit, "error -> {:?}", e);
return Err(e);
}
}
};
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -143,7 +161,7 @@ impl AuditScope {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::AuditScope; use crate::audit::AuditScope;
// Create and remove. Perhaps add some core details? // Create and remove. Perhaps add some core details?
#[test] #[test]

View file

@ -7,10 +7,10 @@ use rusqlite::NO_PARAMS;
use serde_json; use serde_json;
// use uuid; // use uuid;
use audit::AuditScope; use crate::audit::AuditScope;
use entry::{Entry, EntryCommitted, EntryNew, EntryValid}; use crate::entry::{Entry, EntryCommitted, EntryNew, EntryValid};
use error::{ConsistencyError, OperationError}; use crate::error::{ConsistencyError, OperationError};
use filter::{Filter, FilterValid}; use crate::filter::{Filter, FilterValid};
mod idl; mod idl;
mod mem_be; mod mem_be;

View file

@ -5,6 +5,7 @@ pub struct Configuration {
pub db_path: String, pub db_path: String,
pub maximum_request: usize, pub maximum_request: usize,
// db type later // db type later
pub secure_cookies: bool,
} }
impl Configuration { impl Configuration {
@ -14,8 +15,9 @@ impl Configuration {
threads: 8, threads: 8,
db_path: String::from(""), db_path: String::from(""),
maximum_request: 262144, // 256k maximum_request: 262144, // 256k
// log type // log type
// log path // log path
secure_cookies: true,
} }
} }
} }

View file

@ -1,8 +1,8 @@
pub static PURGE_TIMEOUT: u64 = 3600; pub static PURGE_TIMEOUT: u64 = 3600;
pub static UUID_ADMIN: &'static str = "00000000-0000-0000-0000-000000000000"; pub static _UUID_ADMIN: &'static str = "00000000-0000-0000-0000-000000000000";
pub static UUID_ANONYMOUS: &'static str = "00000000-0000-0000-0000-ffffffffffff"; pub static _UUID_ANONYMOUS: &'static str = "00000000-0000-0000-0000-ffffffffffff";
pub static JSON_ANONYMOUS_V1: &'static str = r#"{ pub static JSON_ANONYMOUS_V1: &'static str = r#"{
"valid": null, "valid": null,
"state": null, "state": null,
@ -16,7 +16,7 @@ pub static JSON_ANONYMOUS_V1: &'static str = r#"{
} }
}"#; }"#;
pub static UUID_SYSTEM_INFO: &'static str = "00000000-0000-0000-0000-ffffff000001"; pub static _UUID_SYSTEM_INFO: &'static str = "00000000-0000-0000-0000-ffffff000001";
pub static JSON_SYSTEM_INFO_V1: &'static str = r#"{ pub static JSON_SYSTEM_INFO_V1: &'static str = r#"{
"valid": null, "valid": null,
"state": null, "state": null,

View file

@ -8,13 +8,13 @@ use actix_web::{
use bytes::BytesMut; use bytes::BytesMut;
use futures::{future, Future, Stream}; use futures::{future, Future, Stream};
use super::config::Configuration; use crate::config::Configuration;
// SearchResult // SearchResult
use super::interval::IntervalActor; use crate::interval::IntervalActor;
use super::log; use crate::log;
use super::proto_v1::{AuthRequest, CreateRequest, DeleteRequest, ModifyRequest, SearchRequest}; use crate::proto_v1::{AuthRequest, CreateRequest, DeleteRequest, ModifyRequest, SearchRequest};
use super::proto_v1_actors::QueryServerV1; use crate::proto_v1_actors::QueryServerV1;
struct AppState { struct AppState {
qe: actix::Addr<QueryServerV1>, qe: actix::Addr<QueryServerV1>,
@ -205,10 +205,12 @@ pub fn create_server_core(config: Configuration) {
let server_addr = let server_addr =
match QueryServerV1::start(log_addr.clone(), config.db_path.as_str(), config.threads) { match QueryServerV1::start(log_addr.clone(), config.db_path.as_str(), config.threads) {
Ok(addr) => addr, Ok(addr) => addr,
Err(_e) => { Err(e) => {
// Oh shiiiiiiii println!(
// TODO: Handle this properly. "An unknown failure in startup has occured - exiting -> {:?}",
unimplemented!() e
);
return;
} }
}; };
@ -217,6 +219,7 @@ pub fn create_server_core(config: Configuration) {
// Copy the max size // Copy the max size
let max_size = config.maximum_request; let max_size = config.maximum_request;
let secure_cookies = config.secure_cookies;
// start the web server // start the web server
actix_web::server::new(move || { actix_web::server::new(move || {
@ -238,8 +241,7 @@ pub fn create_server_core(config: Configuration) {
.http_only(true) .http_only(true)
.name("rsidm-session") .name("rsidm-session")
// This forces https only // This forces https only
// TODO: Make this a config value .secure(secure_cookies),
.secure(false),
)) ))
// .resource("/", |r| r.f(index)) // .resource("/", |r| r.f(index))
// curl --header ...? // curl --header ...?

View file

@ -1,11 +1,11 @@
// use serde_json::{Error, Value}; // use serde_json::{Error, Value};
use super::proto_v1::Entry as ProtoEntry; use crate::audit::AuditScope;
use audit::AuditScope; use crate::error::{OperationError, SchemaError};
use error::{OperationError, SchemaError}; use crate::filter::{Filter, FilterValid};
use filter::{Filter, FilterValid}; use crate::modify::{Modify, ModifyInvalid, ModifyList, ModifyValid};
use modify::{Modify, ModifyInvalid, ModifyList, ModifyValid}; use crate::proto_v1::Entry as ProtoEntry;
use schema::{SchemaAttribute, SchemaClass, SchemaReadTransaction}; use crate::schema::{SchemaAttribute, SchemaClass, SchemaReadTransaction};
use server::{QueryServerReadTransaction, QueryServerWriteTransaction}; use crate::server::{QueryServerReadTransaction, QueryServerWriteTransaction};
use std::collections::btree_map::{Iter as BTreeIter, IterMut as BTreeIterMut}; use std::collections::btree_map::{Iter as BTreeIter, IterMut as BTreeIterMut};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::collections::HashMap; use std::collections::HashMap;
@ -478,7 +478,7 @@ impl<STATE> Entry<EntryValid, STATE> {
} }
}), }),
Filter::AndNot(f) => !self.entry_match_no_index(f), Filter::AndNot(f) => !self.entry_match_no_index(f),
Filter::invalid(_) => { Filter::Invalid(_) => {
// TODO: Is there a better way to not need to match the phantom? // TODO: Is there a better way to not need to match the phantom?
unimplemented!() unimplemented!()
} }
@ -746,8 +746,8 @@ struct User {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{Entry, EntryInvalid, EntryNew}; use crate::entry::{Entry, EntryInvalid, EntryNew};
use modify::{Modify, ModifyList}; use crate::modify::{Modify, ModifyList};
use serde_json; use serde_json;
#[test] #[test]

View file

@ -1,15 +1,19 @@
use super::filter::{Filter, FilterInvalid}; use crate::audit::AuditScope;
use super::proto_v1::Entry as ProtoEntry; use crate::entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
use super::proto_v1::{ use crate::filter::{Filter, FilterInvalid};
use crate::proto_v1::Entry as ProtoEntry;
use crate::proto_v1::{
AuthRequest, AuthResponse, AuthStatus, CreateRequest, DeleteRequest, ModifyRequest, AuthRequest, AuthResponse, AuthStatus, CreateRequest, DeleteRequest, ModifyRequest,
OperationResponse, ReviveRecycledRequest, SearchRecycledRequest, SearchRequest, SearchResponse, OperationResponse, ReviveRecycledRequest, SearchRequest, SearchResponse,
}; };
use audit::AuditScope;
use entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
// use error::OperationError; // use error::OperationError;
use error::OperationError; use crate::error::OperationError;
use modify::{ModifyInvalid, ModifyList}; use crate::modify::{ModifyInvalid, ModifyList};
use server::{QueryServerTransaction, QueryServerWriteTransaction}; use crate::server::{QueryServerTransaction, QueryServerWriteTransaction};
// Only used for internal tests
#[cfg(test)]
use crate::proto_v1::SearchRecycledRequest;
use actix::prelude::*; use actix::prelude::*;
@ -89,6 +93,7 @@ impl SearchEvent {
} }
} }
#[cfg(test)]
pub fn from_rec_request( pub fn from_rec_request(
audit: &mut AuditScope, audit: &mut AuditScope,
request: SearchRecycledRequest, request: SearchRecycledRequest,
@ -103,6 +108,7 @@ impl SearchEvent {
} }
} }
#[cfg(test)]
pub fn new_rec_impersonate(filter: Filter<FilterInvalid>) -> Self { pub fn new_rec_impersonate(filter: Filter<FilterInvalid>) -> Self {
SearchEvent { SearchEvent {
internal: false, internal: false,
@ -110,6 +116,7 @@ impl SearchEvent {
} }
} }
#[cfg(test)]
/* Impersonate an external request */ /* Impersonate an external request */
pub fn new_ext_impersonate(filter: Filter<FilterInvalid>) -> Self { pub fn new_ext_impersonate(filter: Filter<FilterInvalid>) -> Self {
SearchEvent { SearchEvent {

View file

@ -2,13 +2,12 @@
// in parallel map/reduce style, or directly on a single // in parallel map/reduce style, or directly on a single
// entry to assert it matches. // entry to assert it matches.
use audit::AuditScope; use crate::audit::AuditScope;
use be::BackendReadTransaction; use crate::error::{OperationError, SchemaError};
use error::{OperationError, SchemaError}; use crate::proto_v1::Filter as ProtoFilter;
use proto_v1::Filter as ProtoFilter; use crate::schema::SchemaReadTransaction;
use schema::SchemaReadTransaction; use crate::server::{
use server::{ QueryServerReadTransaction, QueryServerTransaction, QueryServerWriteTransaction,
QueryServer, QueryServerReadTransaction, QueryServerTransaction, QueryServerWriteTransaction,
}; };
use std::cmp::{Ordering, PartialOrd}; use std::cmp::{Ordering, PartialOrd};
use std::marker::PhantomData; use std::marker::PhantomData;
@ -30,7 +29,7 @@ pub enum Filter<VALID> {
Or(Vec<Filter<VALID>>), Or(Vec<Filter<VALID>>),
And(Vec<Filter<VALID>>), And(Vec<Filter<VALID>>),
AndNot(Box<Filter<VALID>>), AndNot(Box<Filter<VALID>>),
invalid(PhantomData<VALID>), Invalid(PhantomData<VALID>),
} }
// Change this so you have RawFilter and Filter. RawFilter is the "builder", and then // Change this so you have RawFilter and Filter. RawFilter is the "builder", and then
@ -64,7 +63,7 @@ impl Filter<FilterValid> {
Filter::Or(l) => Filter::Or(l.iter().map(|f| f.invalidate()).collect()), Filter::Or(l) => Filter::Or(l.iter().map(|f| f.invalidate()).collect()),
Filter::And(l) => Filter::And(l.iter().map(|f| f.invalidate()).collect()), Filter::And(l) => Filter::And(l.iter().map(|f| f.invalidate()).collect()),
Filter::AndNot(l) => Filter::AndNot(Box::new(l.invalidate())), Filter::AndNot(l) => Filter::AndNot(Box::new(l.invalidate())),
Filter::invalid(_) => { Filter::Invalid(_) => {
// TODO: Is there a better way to not need to match the phantom? // TODO: Is there a better way to not need to match the phantom?
unimplemented!() unimplemented!()
} }
@ -253,7 +252,7 @@ impl Clone for Filter<FilterValid> {
Filter::Or(l) => Filter::Or(l.clone()), Filter::Or(l) => Filter::Or(l.clone()),
Filter::And(l) => Filter::And(l.clone()), Filter::And(l) => Filter::And(l.clone()),
Filter::AndNot(l) => Filter::AndNot(l.clone()), Filter::AndNot(l) => Filter::AndNot(l.clone()),
Filter::invalid(_) => { Filter::Invalid(_) => {
// TODO: Is there a better way to not need to match the phantom? // TODO: Is there a better way to not need to match the phantom?
unimplemented!() unimplemented!()
} }
@ -271,7 +270,7 @@ impl Clone for Filter<FilterInvalid> {
Filter::Or(l) => Filter::Or(l.clone()), Filter::Or(l) => Filter::Or(l.clone()),
Filter::And(l) => Filter::And(l.clone()), Filter::And(l) => Filter::And(l.clone()),
Filter::AndNot(l) => Filter::AndNot(l.clone()), Filter::AndNot(l) => Filter::AndNot(l.clone()),
Filter::invalid(_) => { Filter::Invalid(_) => {
// TODO: Is there a better way to not need to match the phantom? // TODO: Is there a better way to not need to match the phantom?
unimplemented!() unimplemented!()
} }
@ -323,8 +322,8 @@ impl PartialOrd for Filter<FilterValid> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{Filter, FilterInvalid}; use crate::entry::{Entry, EntryNew, EntryValid};
use entry::{Entry, EntryNew, EntryValid}; use crate::filter::{Filter, FilterInvalid};
use serde_json; use serde_json;
use std::cmp::{Ordering, PartialOrd}; use std::cmp::{Ordering, PartialOrd};

View file

@ -1,10 +1,9 @@
use actix::prelude::*; use actix::prelude::*;
use std::time::Duration; use std::time::Duration;
use constants::PURGE_TIMEOUT; use crate::constants::PURGE_TIMEOUT;
use event::{PurgeRecycledEvent, PurgeTombstoneEvent}; use crate::event::{PurgeRecycledEvent, PurgeTombstoneEvent};
use proto_v1_actors::QueryServerV1; use crate::proto_v1_actors::QueryServerV1;
// use server::QueryServer;
pub struct IntervalActor { pub struct IntervalActor {
// Store any addresses we require // Store any addresses we require

View file

@ -1,5 +1,3 @@
#![feature(try_from)]
extern crate serde; extern crate serde;
extern crate serde_json; extern crate serde_json;
#[macro_use] #[macro_use]

View file

@ -1,13 +1,13 @@
use actix::prelude::*; use actix::prelude::*;
use super::audit::AuditScope; use crate::audit::AuditScope;
// Helper for internal logging. // Helper for internal logging.
// Should only be used at startup/shutdown // Should only be used at startup/shutdown
#[macro_export] #[macro_export]
macro_rules! log_event { macro_rules! log_event {
($log_addr:expr, $($arg:tt)*) => ({ ($log_addr:expr, $($arg:tt)*) => ({
use log::LogEvent; use crate::log::LogEvent;
use std::fmt; use std::fmt;
$log_addr.do_send( $log_addr.do_send(
LogEvent { LogEvent {

View file

@ -1,10 +1,10 @@
use audit::AuditScope; use crate::audit::AuditScope;
use proto_v1::Modify as ProtoModify; use crate::proto_v1::Modify as ProtoModify;
use proto_v1::ModifyList as ProtoModifyList; use crate::proto_v1::ModifyList as ProtoModifyList;
use error::{OperationError, SchemaError}; use crate::error::{OperationError, SchemaError};
use schema::{SchemaAttribute, SchemaReadTransaction}; use crate::schema::SchemaReadTransaction;
use server::{QueryServerReadTransaction, QueryServerWriteTransaction}; use crate::server::{QueryServerReadTransaction, QueryServerWriteTransaction};
// Should this be std? // Should this be std?
use std::slice; use std::slice;

View file

@ -1,14 +1,14 @@
use plugins::Plugin; use crate::plugins::Plugin;
use uuid::Uuid; use uuid::Uuid;
use audit::AuditScope; use crate::audit::AuditScope;
use be::{BackendReadTransaction, BackendWriteTransaction}; use crate::entry::{Entry, EntryInvalid, EntryNew};
use entry::{Entry, EntryInvalid, EntryNew}; use crate::error::{ConsistencyError, OperationError};
use error::{ConsistencyError, OperationError}; use crate::event::CreateEvent;
use event::CreateEvent; use crate::filter::{Filter, FilterInvalid};
use filter::Filter; use crate::server::{
use schema::SchemaWriteTransaction; QueryServerReadTransaction, QueryServerTransaction, QueryServerWriteTransaction,
use server::{QueryServerReadTransaction, QueryServerTransaction, QueryServerWriteTransaction}; };
// TO FINISH // TO FINISH
/* /*
@ -51,7 +51,7 @@ impl Plugin for Base {
// if they don't have uuid, create it. // if they don't have uuid, create it.
// TODO: get_ava should have a str version for effeciency? // TODO: get_ava should have a str version for effeciency?
let mut c_uuid = match entry.get_ava(&name_uuid) { let c_uuid: String = match entry.get_ava(&name_uuid) {
Some(u) => { Some(u) => {
// Actually check we have a value, could be empty array ... // Actually check we have a value, could be empty array ...
// TODO: Should this be left to schema to assert the value? // TODO: Should this be left to schema to assert the value?
@ -60,42 +60,31 @@ impl Plugin for Base {
return Err(OperationError::Plugin); return Err(OperationError::Plugin);
}; };
let v = match u.first() { // Schema of the value v, is checked in the filter generation. Neat!
Some(v) => v,
None => {
// TODO: Should this be forgiving and just generate the UUID?
audit_log!(au, "Entry defines uuid attr, but no value.");
return Err(OperationError::Plugin);
}
};
// This could actually fail, so we probably need to handle // Should this be forgiving and just generate the UUID?
// this better .... // NO! If you tried to specify it, but didn't give it, then you made
// TODO: Make this a SCHEMA check, not a manual one. // a mistake and your intent is unknown.
// try_audit!(
match Uuid::parse_str(v.as_str()) { au,
Ok(up) => up, u.first().ok_or(OperationError::Plugin).map(|v| v.clone())
Err(_) => { )
audit_log!(
au,
"Entry contains invalid Base content, rejecting out of principle."
);
return Err(OperationError::Plugin);
}
}
} }
None => Uuid::new_v4(), None => Uuid::new_v4().to_hyphenated().to_string(),
}; };
// Make it a string, so we can filter. // Make it a string, so we can filter.
let str_uuid = format!("{}", c_uuid);
let mut au_qs = AuditScope::new("qs_exist"); let mut au_qs = AuditScope::new("qs_exist");
// We need to clone to the filter because it owns the content // We need to clone to the filter because it owns the content
let filt = Filter::Eq(name_uuid.clone(), str_uuid.clone()); // Now, str_uuid could we invalid, but the filter validation step here will check
// that for us *and* if we fails, we return because the value was not valid. If it
// works, great, we can check for duplication.
let filt_in: Filter<FilterInvalid> = Filter::Eq(name_uuid.clone(), c_uuid.clone());
// let schema_ro = qs.get_schema();
// let filt = try_audit!(au, filt_in.validate(schema_ro));
let r = qs.internal_exists(&mut au_qs, filt); let r = qs.internal_exists(&mut au_qs, filt_in);
au.append_scope(au_qs); au.append_scope(au_qs);
// end the scope for the be operation. // end the scope for the be operation.
@ -113,9 +102,8 @@ impl Plugin for Base {
} }
} }
let str_uuid = format!("{}", c_uuid); audit_log!(au, "Setting UUID {} to entry", c_uuid);
audit_log!(au, "Setting UUID {} to entry", str_uuid); let ava_uuid: Vec<String> = vec![c_uuid];
let ava_uuid: Vec<String> = vec![str_uuid];
entry.set_avas(name_uuid, ava_uuid); entry.set_avas(name_uuid, ava_uuid);
audit_log!(au, "Final entry state: {:?}", entry); audit_log!(au, "Final entry state: {:?}", entry);
@ -135,16 +123,14 @@ impl Plugin for Base {
// Search for class = * // Search for class = *
let entries = match qs.internal_search(au, Filter::Pres("class".to_string())) { let entries = match qs.internal_search(au, Filter::Pres("class".to_string())) {
Ok(r) => r, Ok(v) => v,
Err(e) => { Err(e) => {
// try_audit? audit_log!(au, "Internal Search Failure: {:?}", e);
// TODO: So here, should be returning the oper error? That makes the errors
// recursive, so what is correct?
return vec![Err(ConsistencyError::QueryServerSearchFailure)]; return vec![Err(ConsistencyError::QueryServerSearchFailure)];
} }
}; };
let mut r_uniq = entries let r_uniq = entries
.iter() .iter()
// do an exists checks on the uuid // do an exists checks on the uuid
.map(|e| { .map(|e| {
@ -202,39 +188,18 @@ impl Plugin for Base {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[macro_use] #[macro_use]
use plugins::Plugin; use crate::plugins::Plugin;
use plugins::base::Base;
use std::sync::Arc; use std::sync::Arc;
use audit::AuditScope; use crate::audit::AuditScope;
use be::Backend; use crate::be::Backend;
use entry::{Entry, EntryInvalid, EntryNew}; use crate::entry::{Entry, EntryInvalid, EntryNew};
use event::CreateEvent; use crate::error::OperationError;
use schema::Schema; use crate::event::CreateEvent;
use server::{QueryServer, QueryServerWriteTransaction}; use crate::filter::Filter;
use crate::schema::Schema;
// Check empty create use crate::server::QueryServerReadTransaction;
#[test] use crate::server::{QueryServer, QueryServerWriteTransaction};
fn test_pre_create_empty() {
let preload: Vec<Entry<EntryInvalid, EntryNew>> = Vec::new();
let mut create: Vec<Entry<EntryInvalid, EntryNew>> = Vec::new();
run_pre_create_test!(
preload,
create,
false,
false,
|au: &mut AuditScope,
qs: &QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
ce: &CreateEvent| {
let r = Base::pre_create(au, qs, cand, ce);
assert!(r.is_ok());
// Nothing should have changed.
assert!(cand.len() == 0);
}
);
}
// check create where no uuid // check create where no uuid
#[test] #[test]
@ -255,21 +220,18 @@ mod tests {
) )
.unwrap(); .unwrap();
let mut create = vec![e]; let create = vec![e];
run_pre_create_test!( run_create_test!(
Ok(()),
preload, preload,
create, create,
false, false,
false, |au: &mut AuditScope, qs: &QueryServerWriteTransaction| {
|au: &mut AuditScope, let cands = qs
qs: &QueryServerWriteTransaction, .internal_search(au, Filter::Eq("name".to_string(), "testperson".to_string()))
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>, .unwrap();
ce: &CreateEvent| { let ue = cands.first().unwrap();
let r = Base::pre_create(au, qs, cand, ce);
assert!(r.is_ok());
// Assert that the entry contains the attr "uuid" now.
let ue = cand.first().unwrap();
assert!(ue.attribute_pres("uuid")); assert!(ue.attribute_pres("uuid"));
} }
); );
@ -295,20 +257,14 @@ mod tests {
) )
.unwrap(); .unwrap();
let mut create = vec![e.clone()]; let create = vec![e.clone()];
run_pre_create_test!( run_create_test!(
Err(OperationError::Plugin),
preload, preload,
create, create,
false, false,
false, |_, _| {}
|au: &mut AuditScope,
qs: &QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
ce: &CreateEvent| {
let r = Base::pre_create(au, qs, cand, ce);
assert!(r.is_err());
}
); );
} }
@ -332,20 +288,14 @@ mod tests {
) )
.unwrap(); .unwrap();
let mut create = vec![e.clone()]; let create = vec![e.clone()];
run_pre_create_test!( run_create_test!(
Err(OperationError::Plugin),
preload, preload,
create, create,
false, false,
false, |_, _| {}
|au: &mut AuditScope,
qs: &QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
ce: &CreateEvent| {
let r = Base::pre_create(au, qs, cand, ce);
assert!(r.is_err());
}
); );
} }
@ -369,20 +319,18 @@ mod tests {
) )
.unwrap(); .unwrap();
let mut create = vec![e.clone()]; let create = vec![e.clone()];
run_pre_create_test!( run_create_test!(
Ok(()),
preload, preload,
create, create,
false, false,
false, |au: &mut AuditScope, qs: &QueryServerWriteTransaction| {
|au: &mut AuditScope, let cands = qs
qs: &QueryServerWriteTransaction, .internal_search(au, Filter::Eq("name".to_string(), "testperson".to_string()))
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>, .unwrap();
ce: &CreateEvent| { let ue = cands.first().unwrap();
let r = Base::pre_create(au, qs, cand, ce);
assert!(r.is_ok());
let ue = cand.first().unwrap();
assert!(ue.attribute_equality("uuid", "79724141-3603-4060-b6bb-35c72772611d")); assert!(ue.attribute_equality("uuid", "79724141-3603-4060-b6bb-35c72772611d"));
} }
); );
@ -407,20 +355,14 @@ mod tests {
) )
.unwrap(); .unwrap();
let mut create = vec![e.clone()]; let create = vec![e.clone()];
run_pre_create_test!( run_create_test!(
Err(OperationError::Plugin),
preload, preload,
create, create,
false, false,
false, |_, _| {}
|au: &mut AuditScope,
qs: &QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
ce: &CreateEvent| {
let r = Base::pre_create(au, qs, cand, ce);
assert!(r.is_err());
}
); );
} }
@ -442,21 +384,15 @@ mod tests {
) )
.unwrap(); .unwrap();
let mut create = vec![e.clone()]; let create = vec![e.clone()];
let preload = vec![e]; let preload = vec![e];
run_pre_create_test!( run_create_test!(
Err(OperationError::Plugin),
preload, preload,
create, create,
false, false,
false, |_, _| {}
|au: &mut AuditScope,
qs: &QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
ce: &CreateEvent| {
let r = Base::pre_create(au, qs, cand, ce);
assert!(r.is_err());
}
); );
} }

View file

@ -1,45 +1,59 @@
#[macro_escape] // #[macro_escape]
macro_rules! setup_test {
(
$au:expr,
$preload_entries:ident
) => {{
// Create an in memory BE
let be = Backend::new($au, "").unwrap();
let schema_outer = Schema::new($au).unwrap();
{
let mut schema = schema_outer.write();
schema.bootstrap_core($au).unwrap();
schema.commit().unwrap();
}
let qs = QueryServer::new(be, Arc::new(schema_outer));
if !$preload_entries.is_empty() {
let qs_write = qs.write();
qs_write.internal_create($au, $preload_entries);
assert!(qs_write.commit($au).is_ok());
}
qs
}};
}
// Test helpers for all plugins. // Test helpers for all plugins.
#[macro_export] #[macro_export]
macro_rules! run_pre_create_test { macro_rules! run_create_test {
( (
$preload_entries:ident, $expect:expr,
$create_entries:ident, $preload_entries:ident,
$ident:ident, $create_entries:ident,
$internal:ident, $internal:ident,
$test_fn:expr $check:expr
) => {{ ) => {{
let mut au = AuditScope::new("run_pre_create_test"); let mut au = AuditScope::new("run_create_test");
audit_segment!(au, || { audit_segment!(au, || {
// Create an in memory BE let qs = setup_test!(&mut au, $preload_entries);
let be = Backend::new(&mut au, "").unwrap();
let schema_outer = Schema::new(&mut au).unwrap(); let ce = if $internal {
{ CreateEvent::new_internal($create_entries.clone())
let mut schema = schema_outer.write(); } else {
schema.bootstrap_core(&mut au).unwrap(); CreateEvent::from_vec($create_entries.clone())
schema.commit().unwrap(); };
}
let qs = QueryServer::new(be, Arc::new(schema_outer));
if !$preload_entries.is_empty() { let mut au_test = AuditScope::new("create_test");
let qs_write = qs.write();
qs_write.internal_create(&mut au, $preload_entries);
assert!(qs_write.commit(&mut au).is_ok());
}
let ce = CreateEvent::from_vec($create_entries.clone());
let mut au_test = AuditScope::new("pre_create_test");
{ {
let qs_write = qs.write(); let qs_write = qs.write();
audit_segment!(au_test, || $test_fn( let r = qs_write.create(&mut au_test, &ce);
&mut au_test, assert!(r == $expect);
&qs_write, $check(&mut au_test, &qs_write);
&mut $create_entries, r.map(|_| {
&ce, assert!(qs_write.commit(&mut au_test).is_ok());
)); });
assert!(qs_write.commit(&mut au).is_ok());
} }
// Make sure there are no errors. // Make sure there are no errors.
assert!(qs.verify(&mut au_test).len() == 0); assert!(qs.verify(&mut au_test).len() == 0);
@ -51,16 +65,81 @@ macro_rules! run_pre_create_test {
}}; }};
} }
/*
#[macro_export] #[macro_export]
macro_rules! run_post_create_test { macro_rules! run_modify_test {
(
$expect:expr,
$preload_entries:ident,
$modify_filter:ident,
$modify_list:ident,
$internal:ident,
$check:expr
) => {{
let mut au = AuditScope::new("run_modify_test");
audit_segment!(au, || {
let qs = setup_test!(&mut au, $preload_entries);
let me = if $internal {
ModifyEvent::new_internal($)
} else {
ModifyEvent::from_filter($modify_entries.clone())
};
let mut au_test = AuditScope::new("modify_test");
{
let qs_write = qs.write();
let r = qs_write.modify(&mut au_test, &me);
$check(&mut au_test, &qs_write);
assert!(r == $expect);
r.map(|_| {
assert!(qs_write.commit(&mut au_test).is_ok());
});
}
// Make sure there are no errors.
assert!(qs.verify(&mut au_test).len() == 0);
au.append_scope(au_test);
});
// Dump the raw audit log.
println!("{}", au);
}};
} }
#[macro_export] #[macro_export]
macro_rules! run_post_modify_test { macro_rules! run_delete_test {
} (
$expect:expr,
$preload_entries:ident,
$delete_filter:ident,
$internal:ident,
$check:expr
) => {{
let mut au = AuditScope::new("run_delete_test");
audit_segment!(au, || {
let qs = setup_test!(&mut au, $preload_entries);
#[macro_export] let de = if $internal {
macro_rules! run_post_delete_test { DeleteEvent::new_internal($delete_filter.clone())
} else {
DeleteEvent::from_filter($delete_filter.clone())
};
let mut au_test = AuditScope::new("delete_test");
{
let qs_write = qs.write();
let r = qs_write.delete(&mut au_test, &de);
$check(&mut au_test, &qs_write);
assert!(r == $expect);
r.map(|_| {
assert!(qs_write.commit(&mut au_test).is_ok());
});
}
// Make sure there are no errors.
assert!(qs.verify(&mut au_test).len() == 0);
au.append_scope(au_test);
});
// Dump the raw audit log.
println!("{}", au);
}};
} }
*/

View file

@ -1,10 +1,8 @@
use audit::AuditScope; use crate::audit::AuditScope;
use be::BackendReadTransaction; use crate::entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
use entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid}; use crate::error::{ConsistencyError, OperationError};
use error::{ConsistencyError, OperationError}; use crate::event::{CreateEvent, DeleteEvent, ModifyEvent};
use event::{CreateEvent, DeleteEvent, ModifyEvent, SearchEvent}; use crate::server::{QueryServerTransaction, QueryServerWriteTransaction};
use schema::SchemaReadTransaction;
use server::{QueryServerReadTransaction, QueryServerTransaction, QueryServerWriteTransaction};
#[macro_use] #[macro_use]
mod macros; mod macros;
@ -86,7 +84,7 @@ macro_rules! run_pre_create_plugin {
$target_plugin:ty $target_plugin:ty
) => {{ ) => {{
let mut audit_scope = AuditScope::new(<($target_plugin)>::id()); let mut audit_scope = AuditScope::new(<($target_plugin)>::id());
let mut r = audit_segment!(audit_scope, || <($target_plugin)>::pre_create( let r = audit_segment!(audit_scope, || <($target_plugin)>::pre_create(
&mut audit_scope, &mut audit_scope,
$qs, $qs,
$cand, $cand,
@ -133,46 +131,46 @@ impl Plugins {
} }
pub fn run_post_create( pub fn run_post_create(
au: &mut AuditScope, _au: &mut AuditScope,
qs: &QueryServerWriteTransaction, _qs: &QueryServerWriteTransaction,
cand: &Vec<Entry<EntryValid, EntryNew>>, _cand: &Vec<Entry<EntryValid, EntryNew>>,
ce: &CreateEvent, _ce: &CreateEvent,
) -> Result<(), OperationError> { ) -> Result<(), OperationError> {
Ok(()) Ok(())
} }
pub fn run_pre_modify( pub fn run_pre_modify(
au: &mut AuditScope, _au: &mut AuditScope,
qs: &QueryServerWriteTransaction, _qs: &QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>, _cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
me: &ModifyEvent, _me: &ModifyEvent,
) -> Result<(), OperationError> { ) -> Result<(), OperationError> {
Ok(()) Ok(())
} }
pub fn run_post_modify( pub fn run_post_modify(
au: &mut AuditScope, _au: &mut AuditScope,
qs: &QueryServerWriteTransaction, _qs: &QueryServerWriteTransaction,
cand: &Vec<Entry<EntryValid, EntryCommitted>>, _cand: &Vec<Entry<EntryValid, EntryCommitted>>,
me: &ModifyEvent, _me: &ModifyEvent,
) -> Result<(), OperationError> { ) -> Result<(), OperationError> {
Ok(()) Ok(())
} }
pub fn run_pre_delete( pub fn run_pre_delete(
au: &mut AuditScope, _au: &mut AuditScope,
qs: &QueryServerWriteTransaction, _qs: &QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>, _cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
de: &DeleteEvent, _de: &DeleteEvent,
) -> Result<(), OperationError> { ) -> Result<(), OperationError> {
Ok(()) Ok(())
} }
pub fn run_post_delete( pub fn run_post_delete(
au: &mut AuditScope, _au: &mut AuditScope,
qs: &QueryServerWriteTransaction, _qs: &QueryServerWriteTransaction,
cand: &Vec<Entry<EntryValid, EntryCommitted>>, _cand: &Vec<Entry<EntryValid, EntryCommitted>>,
de: &DeleteEvent, _de: &DeleteEvent,
) -> Result<(), OperationError> { ) -> Result<(), OperationError> {
Ok(()) Ok(())
} }

View file

@ -9,12 +9,12 @@
// when that is written, as they *both* manipulate and alter entry reference // when that is written, as they *both* manipulate and alter entry reference
// data, so we should be careful not to step on each other. // data, so we should be careful not to step on each other.
use audit::AuditScope; use crate::audit::AuditScope;
use entry::{Entry, EntryCommitted, EntryNew, EntryValid}; use crate::entry::{Entry, EntryCommitted, EntryNew, EntryValid};
use error::OperationError; use crate::error::OperationError;
use event::{CreateEvent, DeleteEvent, ModifyEvent, SearchEvent}; use crate::event::{CreateEvent, DeleteEvent, ModifyEvent};
use plugins::Plugin; use crate::plugins::Plugin;
use server::QueryServerWriteTransaction; use crate::server::QueryServerWriteTransaction;
pub struct ReferentialIntegrity; pub struct ReferentialIntegrity;
@ -52,4 +52,26 @@ impl Plugin for ReferentialIntegrity {
} }
#[cfg(test)] #[cfg(test)]
mod tests {} mod tests {
// The create references a uuid that doesn't exist - reject
// The create references a uuid that does exist - validate
// The create references itself - allow
// The create reference a different object - allow
// Modify references a different object - allow
// Modify reference something that doesn't exist - must be rejected
// Modify removes an entry that something else pointed to. - must remove ref in other
// Modify removes the reference to an entry - doesn't need a test
// Modify adds reference to self - allow
// Delete of something that is referenced - must remove ref in other (unless would make inconsistent)
// Delete of something that holds references - doesn't need a test
}

View file

@ -1,7 +1,7 @@
// use super::entry::Entry; // use super::entry::Entry;
// use super::filter::Filter; // use super::filter::Filter;
use crate::error::OperationError;
use actix::prelude::*; use actix::prelude::*;
use error::OperationError;
use std::collections::BTreeMap; use std::collections::BTreeMap;
// These proto implementations are here because they have public definitions // These proto implementations are here because they have public definitions

View file

@ -1,20 +1,20 @@
use actix::prelude::*; use actix::prelude::*;
use std::sync::Arc; use std::sync::Arc;
use audit::AuditScope; use crate::audit::AuditScope;
use be::Backend; use crate::be::Backend;
use error::OperationError; use crate::error::OperationError;
use event::{ use crate::event::{
CreateEvent, DeleteEvent, ModifyEvent, OpResult, PurgeRecycledEvent, PurgeTombstoneEvent, CreateEvent, DeleteEvent, ModifyEvent, OpResult, PurgeRecycledEvent, PurgeTombstoneEvent,
SearchEvent, SearchResult, SearchEvent, SearchResult,
}; };
use log::EventLog; use crate::log::EventLog;
use schema::{Schema, SchemaReadTransaction}; use crate::schema::{Schema, SchemaReadTransaction};
use server::{QueryServer, QueryServerReadTransaction}; use crate::server::{QueryServer, QueryServerReadTransaction};
use proto_v1::{ use crate::proto_v1::{
AuthRequest, CreateRequest, DeleteRequest, ModifyRequest, OperationResponse, SearchRequest, AuthRequest, CreateRequest, DeleteRequest, ModifyRequest, OperationResponse, SearchRequest,
SearchResponse, SearchResponse,
}; };

View file

@ -1,6 +1,6 @@
use audit::AuditScope; use crate::audit::AuditScope;
use constants::*; use crate::constants::*;
use error::{ConsistencyError, OperationError, SchemaError}; use crate::error::{ConsistencyError, OperationError, SchemaError};
use regex::Regex; use regex::Regex;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryFrom; use std::convert::TryFrom;
@ -1006,13 +1006,13 @@ impl Schema {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use audit::AuditScope; use crate::audit::AuditScope;
use constants::*; use crate::constants::*;
use entry::{Entry, EntryInvalid, EntryNew, EntryValid}; use crate::entry::{Entry, EntryInvalid, EntryNew, EntryValid};
use error::{ConsistencyError, SchemaError}; use crate::error::{ConsistencyError, SchemaError};
use filter::{Filter, FilterValid}; use crate::filter::{Filter, FilterValid};
use schema::SchemaReadTransaction; use crate::schema::SchemaReadTransaction;
use schema::{IndexType, Schema, SchemaAttribute, SyntaxType}; use crate::schema::{IndexType, Schema, SchemaAttribute, SyntaxType};
use serde_json; use serde_json;
use std::convert::TryFrom; use std::convert::TryFrom;
use uuid::Uuid; use uuid::Uuid;

View file

@ -3,19 +3,21 @@
// use actix::prelude::*; // use actix::prelude::*;
use std::sync::Arc; use std::sync::Arc;
use audit::AuditScope; use crate::audit::AuditScope;
use be::{ use crate::be::{
Backend, BackendError, BackendReadTransaction, BackendTransaction, BackendWriteTransaction, Backend, BackendError, BackendReadTransaction, BackendTransaction, BackendWriteTransaction,
}; };
use constants::{JSON_ANONYMOUS_V1, JSON_SYSTEM_INFO_V1}; use crate::constants::{JSON_ANONYMOUS_V1, JSON_SYSTEM_INFO_V1};
use entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid}; use crate::entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
use error::{ConsistencyError, OperationError, SchemaError}; use crate::error::{ConsistencyError, OperationError, SchemaError};
use event::{CreateEvent, DeleteEvent, ExistsEvent, ModifyEvent, ReviveRecycledEvent, SearchEvent}; use crate::event::{
use filter::{Filter, FilterInvalid}; CreateEvent, DeleteEvent, ExistsEvent, ModifyEvent, ReviveRecycledEvent, SearchEvent,
use modify::{Modify, ModifyInvalid, ModifyList}; };
use plugins::Plugins; use crate::filter::{Filter, FilterInvalid};
use schema::{ use crate::modify::{Modify, ModifyInvalid, ModifyList};
use crate::plugins::Plugins;
use crate::schema::{
Schema, SchemaReadTransaction, SchemaTransaction, SchemaWriteTransaction, SyntaxType, Schema, SchemaReadTransaction, SchemaTransaction, SchemaWriteTransaction, SyntaxType,
}; };
@ -344,7 +346,7 @@ pub trait QueryServerReadTransaction {
} }
// In the opposite direction, we can resolve values for presentation // In the opposite direction, we can resolve values for presentation
fn resolve_value(&self, attr: &String, value: &String) -> Result<String, OperationError> { fn resolve_value(&self, _attr: &String, value: &String) -> Result<String, OperationError> {
Ok(value.clone()) Ok(value.clone())
} }
} }
@ -939,7 +941,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
pub fn internal_exists_or_create( pub fn internal_exists_or_create(
&self, &self,
e: Entry<EntryValid, EntryNew>, _e: Entry<EntryValid, EntryNew>,
) -> Result<(), OperationError> { ) -> Result<(), OperationError> {
// If the thing exists, stop. // If the thing exists, stop.
// if not, create from Entry. // if not, create from Entry.
@ -1116,23 +1118,21 @@ mod tests {
*/ */
use std::sync::Arc; use std::sync::Arc;
use super::super::audit::AuditScope; use crate::audit::AuditScope;
use super::super::be::Backend; use crate::be::Backend;
use super::super::entry::{Entry, EntryInvalid, EntryNew}; use crate::entry::{Entry, EntryInvalid, EntryNew};
use super::super::error::{OperationError, SchemaError}; use crate::error::{OperationError, SchemaError};
use super::super::event::{ use crate::event::{CreateEvent, DeleteEvent, ModifyEvent, ReviveRecycledEvent, SearchEvent};
CreateEvent, DeleteEvent, ModifyEvent, ReviveRecycledEvent, SearchEvent, use crate::filter::Filter;
}; use crate::modify::{Modify, ModifyList};
use super::super::filter::Filter; use crate::proto_v1::Filter as ProtoFilter;
use super::super::modify::{Modify, ModifyList}; use crate::proto_v1::Modify as ProtoModify;
use super::super::proto_v1::Filter as ProtoFilter; use crate::proto_v1::ModifyList as ProtoModifyList;
use super::super::proto_v1::Modify as ProtoModify; use crate::proto_v1::{
use super::super::proto_v1::ModifyList as ProtoModifyList;
use super::super::proto_v1::{
DeleteRequest, ModifyRequest, ReviveRecycledRequest, SearchRecycledRequest, SearchRequest, DeleteRequest, ModifyRequest, ReviveRecycledRequest, SearchRecycledRequest, SearchRequest,
}; };
use super::super::schema::Schema; use crate::schema::Schema;
use super::super::server::{QueryServer, QueryServerReadTransaction}; use crate::server::{QueryServer, QueryServerReadTransaction};
macro_rules! run_test { macro_rules! run_test {
($test_fn:expr) => {{ ($test_fn:expr) => {{