diff --git a/Cargo.toml b/Cargo.toml index 9f2732439..e879fc438 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,8 +5,7 @@ name = "rsidm" version = "0.1.0" authors = ["William Brown "] default-run = "rsidm_core" -# -# edition = "2018" +edition = "2018" # We need three major binaries. The server itself, the unix client, and a cli diff --git a/src/lib/audit.rs b/src/lib/audit.rs index 37d20c596..1511540c2 100644 --- a/src/lib/audit.rs +++ b/src/lib/audit.rs @@ -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)] @@ -143,7 +161,7 @@ impl AuditScope { #[cfg(test)] mod tests { - use super::AuditScope; + use crate::audit::AuditScope; // Create and remove. Perhaps add some core details? #[test] diff --git a/src/lib/be/mod.rs b/src/lib/be/mod.rs index f36f015e7..a18533457 100644 --- a/src/lib/be/mod.rs +++ b/src/lib/be/mod.rs @@ -7,10 +7,10 @@ use rusqlite::NO_PARAMS; use serde_json; // use uuid; -use audit::AuditScope; -use entry::{Entry, EntryCommitted, EntryNew, EntryValid}; -use error::{ConsistencyError, OperationError}; -use filter::{Filter, FilterValid}; +use crate::audit::AuditScope; +use crate::entry::{Entry, EntryCommitted, EntryNew, EntryValid}; +use crate::error::{ConsistencyError, OperationError}; +use crate::filter::{Filter, FilterValid}; mod idl; mod mem_be; diff --git a/src/lib/config.rs b/src/lib/config.rs index 500b8ea2e..ad859c28b 100644 --- a/src/lib/config.rs +++ b/src/lib/config.rs @@ -5,6 +5,7 @@ pub struct Configuration { pub db_path: String, pub maximum_request: usize, // db type later + pub secure_cookies: bool, } impl Configuration { @@ -14,8 +15,9 @@ impl Configuration { threads: 8, db_path: String::from(""), maximum_request: 262144, // 256k - // log type - // log path + // log type + // log path + secure_cookies: true, } } } diff --git a/src/lib/constants.rs b/src/lib/constants.rs index 5e6e48320..5d80b81c8 100644 --- a/src/lib/constants.rs +++ b/src/lib/constants.rs @@ -1,8 +1,8 @@ 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#"{ "valid": 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#"{ "valid": null, "state": null, diff --git a/src/lib/core.rs b/src/lib/core.rs index 950176f13..f3e1ca5b3 100644 --- a/src/lib/core.rs +++ b/src/lib/core.rs @@ -8,13 +8,13 @@ use actix_web::{ use bytes::BytesMut; use futures::{future, Future, Stream}; -use super::config::Configuration; +use crate::config::Configuration; // SearchResult -use super::interval::IntervalActor; -use super::log; -use super::proto_v1::{AuthRequest, CreateRequest, DeleteRequest, ModifyRequest, SearchRequest}; -use super::proto_v1_actors::QueryServerV1; +use crate::interval::IntervalActor; +use crate::log; +use crate::proto_v1::{AuthRequest, CreateRequest, DeleteRequest, ModifyRequest, SearchRequest}; +use crate::proto_v1_actors::QueryServerV1; struct AppState { qe: actix::Addr, @@ -205,10 +205,12 @@ pub fn create_server_core(config: Configuration) { let server_addr = match QueryServerV1::start(log_addr.clone(), config.db_path.as_str(), config.threads) { Ok(addr) => addr, - Err(_e) => { - // Oh shiiiiiiii - // TODO: Handle this properly. - unimplemented!() + Err(e) => { + println!( + "An unknown failure in startup has occured - exiting -> {:?}", + e + ); + return; } }; @@ -217,6 +219,7 @@ pub fn create_server_core(config: Configuration) { // Copy the max size let max_size = config.maximum_request; + let secure_cookies = config.secure_cookies; // start the web server actix_web::server::new(move || { @@ -238,8 +241,7 @@ pub fn create_server_core(config: Configuration) { .http_only(true) .name("rsidm-session") // This forces https only - // TODO: Make this a config value - .secure(false), + .secure(secure_cookies), )) // .resource("/", |r| r.f(index)) // curl --header ...? diff --git a/src/lib/entry.rs b/src/lib/entry.rs index b2c497b48..2ed02a84c 100644 --- a/src/lib/entry.rs +++ b/src/lib/entry.rs @@ -1,11 +1,11 @@ // use serde_json::{Error, Value}; -use super::proto_v1::Entry as ProtoEntry; -use audit::AuditScope; -use error::{OperationError, SchemaError}; -use filter::{Filter, FilterValid}; -use modify::{Modify, ModifyInvalid, ModifyList, ModifyValid}; -use schema::{SchemaAttribute, SchemaClass, SchemaReadTransaction}; -use server::{QueryServerReadTransaction, QueryServerWriteTransaction}; +use crate::audit::AuditScope; +use crate::error::{OperationError, SchemaError}; +use crate::filter::{Filter, FilterValid}; +use crate::modify::{Modify, ModifyInvalid, ModifyList, ModifyValid}; +use crate::proto_v1::Entry as ProtoEntry; +use crate::schema::{SchemaAttribute, SchemaClass, SchemaReadTransaction}; +use crate::server::{QueryServerReadTransaction, QueryServerWriteTransaction}; use std::collections::btree_map::{Iter as BTreeIter, IterMut as BTreeIterMut}; use std::collections::BTreeMap; use std::collections::HashMap; @@ -478,7 +478,7 @@ impl Entry { } }), 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? unimplemented!() } @@ -746,8 +746,8 @@ struct User { #[cfg(test)] mod tests { - use super::{Entry, EntryInvalid, EntryNew}; - use modify::{Modify, ModifyList}; + use crate::entry::{Entry, EntryInvalid, EntryNew}; + use crate::modify::{Modify, ModifyList}; use serde_json; #[test] diff --git a/src/lib/event.rs b/src/lib/event.rs index 9ac75c3f0..6122e2503 100644 --- a/src/lib/event.rs +++ b/src/lib/event.rs @@ -1,15 +1,19 @@ -use super::filter::{Filter, FilterInvalid}; -use super::proto_v1::Entry as ProtoEntry; -use super::proto_v1::{ +use crate::audit::AuditScope; +use crate::entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid}; +use crate::filter::{Filter, FilterInvalid}; +use crate::proto_v1::Entry as ProtoEntry; +use crate::proto_v1::{ 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 modify::{ModifyInvalid, ModifyList}; -use server::{QueryServerTransaction, QueryServerWriteTransaction}; +use crate::error::OperationError; +use crate::modify::{ModifyInvalid, ModifyList}; +use crate::server::{QueryServerTransaction, QueryServerWriteTransaction}; + +// Only used for internal tests +#[cfg(test)] +use crate::proto_v1::SearchRecycledRequest; use actix::prelude::*; @@ -89,6 +93,7 @@ impl SearchEvent { } } + #[cfg(test)] pub fn from_rec_request( audit: &mut AuditScope, request: SearchRecycledRequest, @@ -103,6 +108,7 @@ impl SearchEvent { } } + #[cfg(test)] pub fn new_rec_impersonate(filter: Filter) -> Self { SearchEvent { internal: false, @@ -110,6 +116,7 @@ impl SearchEvent { } } + #[cfg(test)] /* Impersonate an external request */ pub fn new_ext_impersonate(filter: Filter) -> Self { SearchEvent { diff --git a/src/lib/filter.rs b/src/lib/filter.rs index 88ef3f6bf..896ee23e7 100644 --- a/src/lib/filter.rs +++ b/src/lib/filter.rs @@ -2,13 +2,12 @@ // in parallel map/reduce style, or directly on a single // entry to assert it matches. -use audit::AuditScope; -use be::BackendReadTransaction; -use error::{OperationError, SchemaError}; -use proto_v1::Filter as ProtoFilter; -use schema::SchemaReadTransaction; -use server::{ - QueryServer, QueryServerReadTransaction, QueryServerTransaction, QueryServerWriteTransaction, +use crate::audit::AuditScope; +use crate::error::{OperationError, SchemaError}; +use crate::proto_v1::Filter as ProtoFilter; +use crate::schema::SchemaReadTransaction; +use crate::server::{ + QueryServerReadTransaction, QueryServerTransaction, QueryServerWriteTransaction, }; use std::cmp::{Ordering, PartialOrd}; use std::marker::PhantomData; @@ -30,7 +29,7 @@ pub enum Filter { Or(Vec>), And(Vec>), AndNot(Box>), - invalid(PhantomData), + Invalid(PhantomData), } // Change this so you have RawFilter and Filter. RawFilter is the "builder", and then @@ -64,7 +63,7 @@ impl Filter { 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::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? unimplemented!() } @@ -253,7 +252,7 @@ impl Clone for Filter { Filter::Or(l) => Filter::Or(l.clone()), Filter::And(l) => Filter::And(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? unimplemented!() } @@ -271,7 +270,7 @@ impl Clone for Filter { Filter::Or(l) => Filter::Or(l.clone()), Filter::And(l) => Filter::And(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? unimplemented!() } @@ -323,8 +322,8 @@ impl PartialOrd for Filter { #[cfg(test)] mod tests { - use super::{Filter, FilterInvalid}; - use entry::{Entry, EntryNew, EntryValid}; + use crate::entry::{Entry, EntryNew, EntryValid}; + use crate::filter::{Filter, FilterInvalid}; use serde_json; use std::cmp::{Ordering, PartialOrd}; diff --git a/src/lib/interval.rs b/src/lib/interval.rs index 783c81657..edbf9cc8e 100644 --- a/src/lib/interval.rs +++ b/src/lib/interval.rs @@ -1,10 +1,9 @@ use actix::prelude::*; use std::time::Duration; -use constants::PURGE_TIMEOUT; -use event::{PurgeRecycledEvent, PurgeTombstoneEvent}; -use proto_v1_actors::QueryServerV1; -// use server::QueryServer; +use crate::constants::PURGE_TIMEOUT; +use crate::event::{PurgeRecycledEvent, PurgeTombstoneEvent}; +use crate::proto_v1_actors::QueryServerV1; pub struct IntervalActor { // Store any addresses we require diff --git a/src/lib/lib.rs b/src/lib/lib.rs index eff6a1741..248b9dd9f 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -1,5 +1,3 @@ -#![feature(try_from)] - extern crate serde; extern crate serde_json; #[macro_use] diff --git a/src/lib/log.rs b/src/lib/log.rs index 33b6b380a..1fb32a234 100644 --- a/src/lib/log.rs +++ b/src/lib/log.rs @@ -1,13 +1,13 @@ use actix::prelude::*; -use super::audit::AuditScope; +use crate::audit::AuditScope; // Helper for internal logging. // Should only be used at startup/shutdown #[macro_export] macro_rules! log_event { ($log_addr:expr, $($arg:tt)*) => ({ - use log::LogEvent; + use crate::log::LogEvent; use std::fmt; $log_addr.do_send( LogEvent { diff --git a/src/lib/modify.rs b/src/lib/modify.rs index 1658ed231..73c91ec95 100644 --- a/src/lib/modify.rs +++ b/src/lib/modify.rs @@ -1,10 +1,10 @@ -use audit::AuditScope; -use proto_v1::Modify as ProtoModify; -use proto_v1::ModifyList as ProtoModifyList; +use crate::audit::AuditScope; +use crate::proto_v1::Modify as ProtoModify; +use crate::proto_v1::ModifyList as ProtoModifyList; -use error::{OperationError, SchemaError}; -use schema::{SchemaAttribute, SchemaReadTransaction}; -use server::{QueryServerReadTransaction, QueryServerWriteTransaction}; +use crate::error::{OperationError, SchemaError}; +use crate::schema::SchemaReadTransaction; +use crate::server::{QueryServerReadTransaction, QueryServerWriteTransaction}; // Should this be std? use std::slice; diff --git a/src/lib/plugins/base.rs b/src/lib/plugins/base.rs index 8d2871169..c0d631603 100644 --- a/src/lib/plugins/base.rs +++ b/src/lib/plugins/base.rs @@ -1,14 +1,14 @@ -use plugins::Plugin; +use crate::plugins::Plugin; use uuid::Uuid; -use audit::AuditScope; -use be::{BackendReadTransaction, BackendWriteTransaction}; -use entry::{Entry, EntryInvalid, EntryNew}; -use error::{ConsistencyError, OperationError}; -use event::CreateEvent; -use filter::Filter; -use schema::SchemaWriteTransaction; -use server::{QueryServerReadTransaction, QueryServerTransaction, QueryServerWriteTransaction}; +use crate::audit::AuditScope; +use crate::entry::{Entry, EntryInvalid, EntryNew}; +use crate::error::{ConsistencyError, OperationError}; +use crate::event::CreateEvent; +use crate::filter::{Filter, FilterInvalid}; +use crate::server::{ + QueryServerReadTransaction, QueryServerTransaction, QueryServerWriteTransaction, +}; // TO FINISH /* @@ -51,7 +51,7 @@ impl Plugin for Base { // if they don't have uuid, create it. // 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) => { // Actually check we have a value, could be empty array ... // TODO: Should this be left to schema to assert the value? @@ -60,42 +60,31 @@ impl Plugin for Base { return Err(OperationError::Plugin); }; - let v = match u.first() { - 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); - } - }; + // Schema of the value v, is checked in the filter generation. Neat! - // This could actually fail, so we probably need to handle - // this better .... - // TODO: Make this a SCHEMA check, not a manual one. - // - match Uuid::parse_str(v.as_str()) { - Ok(up) => up, - Err(_) => { - audit_log!( - au, - "Entry contains invalid Base content, rejecting out of principle." - ); - return Err(OperationError::Plugin); - } - } + // Should this be forgiving and just generate the UUID? + // NO! If you tried to specify it, but didn't give it, then you made + // a mistake and your intent is unknown. + try_audit!( + au, + u.first().ok_or(OperationError::Plugin).map(|v| v.clone()) + ) } - None => Uuid::new_v4(), + None => Uuid::new_v4().to_hyphenated().to_string(), }; // Make it a string, so we can filter. - let str_uuid = format!("{}", c_uuid); - let mut au_qs = AuditScope::new("qs_exist"); // 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 = 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); // 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", str_uuid); - let ava_uuid: Vec = vec![str_uuid]; + audit_log!(au, "Setting UUID {} to entry", c_uuid); + let ava_uuid: Vec = vec![c_uuid]; entry.set_avas(name_uuid, ava_uuid); audit_log!(au, "Final entry state: {:?}", entry); @@ -135,16 +123,14 @@ impl Plugin for Base { // Search for class = * let entries = match qs.internal_search(au, Filter::Pres("class".to_string())) { - Ok(r) => r, + Ok(v) => v, Err(e) => { - // try_audit? - // TODO: So here, should be returning the oper error? That makes the errors - // recursive, so what is correct? + audit_log!(au, "Internal Search Failure: {:?}", e); return vec![Err(ConsistencyError::QueryServerSearchFailure)]; } }; - let mut r_uniq = entries + let r_uniq = entries .iter() // do an exists checks on the uuid .map(|e| { @@ -202,39 +188,18 @@ impl Plugin for Base { #[cfg(test)] mod tests { #[macro_use] - use plugins::Plugin; - use plugins::base::Base; + use crate::plugins::Plugin; use std::sync::Arc; - use audit::AuditScope; - use be::Backend; - use entry::{Entry, EntryInvalid, EntryNew}; - use event::CreateEvent; - use schema::Schema; - use server::{QueryServer, QueryServerWriteTransaction}; - - // Check empty create - #[test] - fn test_pre_create_empty() { - let preload: Vec> = Vec::new(); - let mut create: Vec> = Vec::new(); - run_pre_create_test!( - preload, - create, - false, - false, - |au: &mut AuditScope, - qs: &QueryServerWriteTransaction, - cand: &mut Vec>, - ce: &CreateEvent| { - let r = Base::pre_create(au, qs, cand, ce); - - assert!(r.is_ok()); - // Nothing should have changed. - assert!(cand.len() == 0); - } - ); - } + use crate::audit::AuditScope; + use crate::be::Backend; + use crate::entry::{Entry, EntryInvalid, EntryNew}; + use crate::error::OperationError; + use crate::event::CreateEvent; + use crate::filter::Filter; + use crate::schema::Schema; + use crate::server::QueryServerReadTransaction; + use crate::server::{QueryServer, QueryServerWriteTransaction}; // check create where no uuid #[test] @@ -255,21 +220,18 @@ mod tests { ) .unwrap(); - let mut create = vec![e]; + let create = vec![e]; - run_pre_create_test!( + run_create_test!( + Ok(()), preload, create, false, - false, - |au: &mut AuditScope, - qs: &QueryServerWriteTransaction, - cand: &mut Vec>, - ce: &CreateEvent| { - 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(); + |au: &mut AuditScope, qs: &QueryServerWriteTransaction| { + let cands = qs + .internal_search(au, Filter::Eq("name".to_string(), "testperson".to_string())) + .unwrap(); + let ue = cands.first().unwrap(); assert!(ue.attribute_pres("uuid")); } ); @@ -295,20 +257,14 @@ mod tests { ) .unwrap(); - let mut create = vec![e.clone()]; + let create = vec![e.clone()]; - run_pre_create_test!( + run_create_test!( + Err(OperationError::Plugin), preload, create, false, - false, - |au: &mut AuditScope, - qs: &QueryServerWriteTransaction, - cand: &mut Vec>, - ce: &CreateEvent| { - let r = Base::pre_create(au, qs, cand, ce); - assert!(r.is_err()); - } + |_, _| {} ); } @@ -332,20 +288,14 @@ mod tests { ) .unwrap(); - let mut create = vec![e.clone()]; + let create = vec![e.clone()]; - run_pre_create_test!( + run_create_test!( + Err(OperationError::Plugin), preload, create, false, - false, - |au: &mut AuditScope, - qs: &QueryServerWriteTransaction, - cand: &mut Vec>, - ce: &CreateEvent| { - let r = Base::pre_create(au, qs, cand, ce); - assert!(r.is_err()); - } + |_, _| {} ); } @@ -369,20 +319,18 @@ mod tests { ) .unwrap(); - let mut create = vec![e.clone()]; + let create = vec![e.clone()]; - run_pre_create_test!( + run_create_test!( + Ok(()), preload, create, false, - false, - |au: &mut AuditScope, - qs: &QueryServerWriteTransaction, - cand: &mut Vec>, - ce: &CreateEvent| { - let r = Base::pre_create(au, qs, cand, ce); - assert!(r.is_ok()); - let ue = cand.first().unwrap(); + |au: &mut AuditScope, qs: &QueryServerWriteTransaction| { + let cands = qs + .internal_search(au, Filter::Eq("name".to_string(), "testperson".to_string())) + .unwrap(); + let ue = cands.first().unwrap(); assert!(ue.attribute_equality("uuid", "79724141-3603-4060-b6bb-35c72772611d")); } ); @@ -407,20 +355,14 @@ mod tests { ) .unwrap(); - let mut create = vec![e.clone()]; + let create = vec![e.clone()]; - run_pre_create_test!( + run_create_test!( + Err(OperationError::Plugin), preload, create, false, - false, - |au: &mut AuditScope, - qs: &QueryServerWriteTransaction, - cand: &mut Vec>, - ce: &CreateEvent| { - let r = Base::pre_create(au, qs, cand, ce); - assert!(r.is_err()); - } + |_, _| {} ); } @@ -442,21 +384,15 @@ mod tests { ) .unwrap(); - let mut create = vec![e.clone()]; + let create = vec![e.clone()]; let preload = vec![e]; - run_pre_create_test!( + run_create_test!( + Err(OperationError::Plugin), preload, create, false, - false, - |au: &mut AuditScope, - qs: &QueryServerWriteTransaction, - cand: &mut Vec>, - ce: &CreateEvent| { - let r = Base::pre_create(au, qs, cand, ce); - assert!(r.is_err()); - } + |_, _| {} ); } diff --git a/src/lib/plugins/macros.rs b/src/lib/plugins/macros.rs index 19fa2e550..2696d75b1 100644 --- a/src/lib/plugins/macros.rs +++ b/src/lib/plugins/macros.rs @@ -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. #[macro_export] -macro_rules! run_pre_create_test { +macro_rules! run_create_test { ( - $preload_entries:ident, - $create_entries:ident, - $ident:ident, - $internal:ident, - $test_fn:expr - ) => {{ - let mut au = AuditScope::new("run_pre_create_test"); + $expect:expr, + $preload_entries:ident, + $create_entries:ident, + $internal:ident, + $check:expr + ) => {{ + let mut au = AuditScope::new("run_create_test"); audit_segment!(au, || { - // Create an in memory BE - let be = Backend::new(&mut au, "").unwrap(); + let qs = setup_test!(&mut au, $preload_entries); - let schema_outer = Schema::new(&mut au).unwrap(); - { - let mut schema = schema_outer.write(); - schema.bootstrap_core(&mut au).unwrap(); - schema.commit().unwrap(); - } - let qs = QueryServer::new(be, Arc::new(schema_outer)); + let ce = if $internal { + CreateEvent::new_internal($create_entries.clone()) + } else { + CreateEvent::from_vec($create_entries.clone()) + }; - if !$preload_entries.is_empty() { - 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 mut au_test = AuditScope::new("create_test"); { let qs_write = qs.write(); - audit_segment!(au_test, || $test_fn( - &mut au_test, - &qs_write, - &mut $create_entries, - &ce, - )); - assert!(qs_write.commit(&mut au).is_ok()); + let r = qs_write.create(&mut au_test, &ce); + assert!(r == $expect); + $check(&mut au_test, &qs_write); + 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); @@ -51,16 +65,81 @@ macro_rules! run_pre_create_test { }}; } -/* #[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_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] -macro_rules! run_post_delete_test { + let de = if $internal { + 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); + }}; } -*/ diff --git a/src/lib/plugins/mod.rs b/src/lib/plugins/mod.rs index f91d2b22e..f774e00b0 100644 --- a/src/lib/plugins/mod.rs +++ b/src/lib/plugins/mod.rs @@ -1,10 +1,8 @@ -use audit::AuditScope; -use be::BackendReadTransaction; -use entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid}; -use error::{ConsistencyError, OperationError}; -use event::{CreateEvent, DeleteEvent, ModifyEvent, SearchEvent}; -use schema::SchemaReadTransaction; -use server::{QueryServerReadTransaction, QueryServerTransaction, QueryServerWriteTransaction}; +use crate::audit::AuditScope; +use crate::entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid}; +use crate::error::{ConsistencyError, OperationError}; +use crate::event::{CreateEvent, DeleteEvent, ModifyEvent}; +use crate::server::{QueryServerTransaction, QueryServerWriteTransaction}; #[macro_use] mod macros; @@ -86,7 +84,7 @@ macro_rules! run_pre_create_plugin { $target_plugin:ty ) => {{ 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, $qs, $cand, @@ -133,46 +131,46 @@ impl Plugins { } pub fn run_post_create( - au: &mut AuditScope, - qs: &QueryServerWriteTransaction, - cand: &Vec>, - ce: &CreateEvent, + _au: &mut AuditScope, + _qs: &QueryServerWriteTransaction, + _cand: &Vec>, + _ce: &CreateEvent, ) -> Result<(), OperationError> { Ok(()) } pub fn run_pre_modify( - au: &mut AuditScope, - qs: &QueryServerWriteTransaction, - cand: &mut Vec>, - me: &ModifyEvent, + _au: &mut AuditScope, + _qs: &QueryServerWriteTransaction, + _cand: &mut Vec>, + _me: &ModifyEvent, ) -> Result<(), OperationError> { Ok(()) } pub fn run_post_modify( - au: &mut AuditScope, - qs: &QueryServerWriteTransaction, - cand: &Vec>, - me: &ModifyEvent, + _au: &mut AuditScope, + _qs: &QueryServerWriteTransaction, + _cand: &Vec>, + _me: &ModifyEvent, ) -> Result<(), OperationError> { Ok(()) } pub fn run_pre_delete( - au: &mut AuditScope, - qs: &QueryServerWriteTransaction, - cand: &mut Vec>, - de: &DeleteEvent, + _au: &mut AuditScope, + _qs: &QueryServerWriteTransaction, + _cand: &mut Vec>, + _de: &DeleteEvent, ) -> Result<(), OperationError> { Ok(()) } pub fn run_post_delete( - au: &mut AuditScope, - qs: &QueryServerWriteTransaction, - cand: &Vec>, - de: &DeleteEvent, + _au: &mut AuditScope, + _qs: &QueryServerWriteTransaction, + _cand: &Vec>, + _de: &DeleteEvent, ) -> Result<(), OperationError> { Ok(()) } diff --git a/src/lib/plugins/refint.rs b/src/lib/plugins/refint.rs index 4ad372b38..4de33c1a5 100644 --- a/src/lib/plugins/refint.rs +++ b/src/lib/plugins/refint.rs @@ -9,12 +9,12 @@ // when that is written, as they *both* manipulate and alter entry reference // data, so we should be careful not to step on each other. -use audit::AuditScope; -use entry::{Entry, EntryCommitted, EntryNew, EntryValid}; -use error::OperationError; -use event::{CreateEvent, DeleteEvent, ModifyEvent, SearchEvent}; -use plugins::Plugin; -use server::QueryServerWriteTransaction; +use crate::audit::AuditScope; +use crate::entry::{Entry, EntryCommitted, EntryNew, EntryValid}; +use crate::error::OperationError; +use crate::event::{CreateEvent, DeleteEvent, ModifyEvent}; +use crate::plugins::Plugin; +use crate::server::QueryServerWriteTransaction; pub struct ReferentialIntegrity; @@ -52,4 +52,26 @@ impl Plugin for ReferentialIntegrity { } #[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 +} diff --git a/src/lib/proto_v1.rs b/src/lib/proto_v1.rs index f5f5b46e6..69267ee58 100644 --- a/src/lib/proto_v1.rs +++ b/src/lib/proto_v1.rs @@ -1,7 +1,7 @@ // use super::entry::Entry; // use super::filter::Filter; +use crate::error::OperationError; use actix::prelude::*; -use error::OperationError; use std::collections::BTreeMap; // These proto implementations are here because they have public definitions diff --git a/src/lib/proto_v1_actors.rs b/src/lib/proto_v1_actors.rs index c574d7a1f..10d2b6100 100644 --- a/src/lib/proto_v1_actors.rs +++ b/src/lib/proto_v1_actors.rs @@ -1,20 +1,20 @@ use actix::prelude::*; use std::sync::Arc; -use audit::AuditScope; -use be::Backend; +use crate::audit::AuditScope; +use crate::be::Backend; -use error::OperationError; -use event::{ +use crate::error::OperationError; +use crate::event::{ CreateEvent, DeleteEvent, ModifyEvent, OpResult, PurgeRecycledEvent, PurgeTombstoneEvent, SearchEvent, SearchResult, }; -use log::EventLog; -use schema::{Schema, SchemaReadTransaction}; +use crate::log::EventLog; +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, SearchResponse, }; diff --git a/src/lib/schema.rs b/src/lib/schema.rs index 8ed0cd56e..0bfb36a21 100644 --- a/src/lib/schema.rs +++ b/src/lib/schema.rs @@ -1,6 +1,6 @@ -use audit::AuditScope; -use constants::*; -use error::{ConsistencyError, OperationError, SchemaError}; +use crate::audit::AuditScope; +use crate::constants::*; +use crate::error::{ConsistencyError, OperationError, SchemaError}; use regex::Regex; use std::collections::HashMap; use std::convert::TryFrom; @@ -1006,13 +1006,13 @@ impl Schema { #[cfg(test)] mod tests { - use audit::AuditScope; - use constants::*; - use entry::{Entry, EntryInvalid, EntryNew, EntryValid}; - use error::{ConsistencyError, SchemaError}; - use filter::{Filter, FilterValid}; - use schema::SchemaReadTransaction; - use schema::{IndexType, Schema, SchemaAttribute, SyntaxType}; + use crate::audit::AuditScope; + use crate::constants::*; + use crate::entry::{Entry, EntryInvalid, EntryNew, EntryValid}; + use crate::error::{ConsistencyError, SchemaError}; + use crate::filter::{Filter, FilterValid}; + use crate::schema::SchemaReadTransaction; + use crate::schema::{IndexType, Schema, SchemaAttribute, SyntaxType}; use serde_json; use std::convert::TryFrom; use uuid::Uuid; diff --git a/src/lib/server.rs b/src/lib/server.rs index b9f204af3..b070fd50f 100644 --- a/src/lib/server.rs +++ b/src/lib/server.rs @@ -3,19 +3,21 @@ // use actix::prelude::*; use std::sync::Arc; -use audit::AuditScope; -use be::{ +use crate::audit::AuditScope; +use crate::be::{ Backend, BackendError, BackendReadTransaction, BackendTransaction, BackendWriteTransaction, }; -use constants::{JSON_ANONYMOUS_V1, JSON_SYSTEM_INFO_V1}; -use entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid}; -use error::{ConsistencyError, OperationError, SchemaError}; -use event::{CreateEvent, DeleteEvent, ExistsEvent, ModifyEvent, ReviveRecycledEvent, SearchEvent}; -use filter::{Filter, FilterInvalid}; -use modify::{Modify, ModifyInvalid, ModifyList}; -use plugins::Plugins; -use schema::{ +use crate::constants::{JSON_ANONYMOUS_V1, JSON_SYSTEM_INFO_V1}; +use crate::entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid}; +use crate::error::{ConsistencyError, OperationError, SchemaError}; +use crate::event::{ + CreateEvent, DeleteEvent, ExistsEvent, ModifyEvent, ReviveRecycledEvent, SearchEvent, +}; +use crate::filter::{Filter, FilterInvalid}; +use crate::modify::{Modify, ModifyInvalid, ModifyList}; +use crate::plugins::Plugins; +use crate::schema::{ Schema, SchemaReadTransaction, SchemaTransaction, SchemaWriteTransaction, SyntaxType, }; @@ -344,7 +346,7 @@ pub trait QueryServerReadTransaction { } // In the opposite direction, we can resolve values for presentation - fn resolve_value(&self, attr: &String, value: &String) -> Result { + fn resolve_value(&self, _attr: &String, value: &String) -> Result { Ok(value.clone()) } } @@ -939,7 +941,7 @@ impl<'a> QueryServerWriteTransaction<'a> { pub fn internal_exists_or_create( &self, - e: Entry, + _e: Entry, ) -> Result<(), OperationError> { // If the thing exists, stop. // if not, create from Entry. @@ -1116,23 +1118,21 @@ mod tests { */ use std::sync::Arc; - use super::super::audit::AuditScope; - use super::super::be::Backend; - use super::super::entry::{Entry, EntryInvalid, EntryNew}; - use super::super::error::{OperationError, SchemaError}; - use super::super::event::{ - CreateEvent, DeleteEvent, ModifyEvent, ReviveRecycledEvent, SearchEvent, - }; - use super::super::filter::Filter; - use super::super::modify::{Modify, ModifyList}; - use super::super::proto_v1::Filter as ProtoFilter; - use super::super::proto_v1::Modify as ProtoModify; - use super::super::proto_v1::ModifyList as ProtoModifyList; - use super::super::proto_v1::{ + use crate::audit::AuditScope; + use crate::be::Backend; + use crate::entry::{Entry, EntryInvalid, EntryNew}; + use crate::error::{OperationError, SchemaError}; + use crate::event::{CreateEvent, DeleteEvent, ModifyEvent, ReviveRecycledEvent, SearchEvent}; + use crate::filter::Filter; + use crate::modify::{Modify, ModifyList}; + use crate::proto_v1::Filter as ProtoFilter; + use crate::proto_v1::Modify as ProtoModify; + use crate::proto_v1::ModifyList as ProtoModifyList; + use crate::proto_v1::{ DeleteRequest, ModifyRequest, ReviveRecycledRequest, SearchRecycledRequest, SearchRequest, }; - use super::super::schema::Schema; - use super::super::server::{QueryServer, QueryServerReadTransaction}; + use crate::schema::Schema; + use crate::server::{QueryServer, QueryServerReadTransaction}; macro_rules! run_test { ($test_fn:expr) => {{