1use std::collections::{BTreeMap, BTreeSet};
14use std::sync::Arc;
15
16use crate::entry::{Entry, EntryCommitted, EntrySealed};
17use crate::event::{CreateEvent, DeleteEvent, ModifyEvent};
18use crate::plugins::Plugin;
19use crate::prelude::*;
20use crate::value::PartialValue;
21
22pub struct MemberOf;
23
24fn do_group_memberof(
25 qs: &mut QueryServerWriteTransaction,
26 uuid: Uuid,
27 tgte: &mut EntryInvalidCommitted,
28) -> Result<(), OperationError> {
29 let groups = qs
31 .internal_search(filter!(f_and!([
32 f_eq(Attribute::Class, EntryClass::Group.into()),
33 f_or!([
34 f_eq(Attribute::Member, PartialValue::Refer(uuid)),
35 f_eq(Attribute::DynMember, PartialValue::Refer(uuid))
36 ])
37 ])))
38 .map_err(|e| {
39 admin_error!("internal search failure -> {:?}", e);
40 e
41 })?;
42
43 tgte.add_ava_if_not_exist(Attribute::Class, EntryClass::MemberOf.into());
45 tgte.purge_ava(Attribute::MemberOf);
48 tgte.purge_ava(Attribute::DirectMemberOf);
49
50 let dmo = ValueSetRefer::from_iter(groups.iter().map(|g| g.get_uuid()));
52
53 let mut mo = ValueSetRefer::from_iter(
54 groups
55 .iter()
56 .filter_map(|g| {
57 g.get_ava_set(Attribute::MemberOf)
58 .and_then(|s| s.as_refer_set())
59 .map(|s| s.iter())
60 })
61 .flatten()
62 .copied(),
63 );
64
65 if let Some(dmo) = dmo {
67 tgte.set_ava_set(&Attribute::DirectMemberOf, dmo.clone());
69
70 if let Some(mo) = &mut mo {
71 let dmo = dmo as ValueSet;
72 mo.merge(&dmo)?;
73 } else {
74 mo = Some(dmo);
77 };
78 };
79
80 if let Some(mo) = mo {
81 tgte.set_ava_set(&Attribute::MemberOf, mo);
82 }
83
84 trace!(
85 "Updating {:?} to be dir mo {:?}",
86 uuid,
87 tgte.get_ava_set(Attribute::DirectMemberOf)
88 );
89 trace!(
90 "Updating {:?} to be mo {:?}",
91 uuid,
92 tgte.get_ava_set(Attribute::MemberOf)
93 );
94 Ok(())
95}
96
97fn do_leaf_memberof(
98 qs: &mut QueryServerWriteTransaction,
99 all_affected_uuids: BTreeSet<Uuid>,
100) -> Result<(), OperationError> {
101 trace!("---");
102
103 let all_affected_filter: Vec<_> = all_affected_uuids
106 .into_iter()
107 .map(|u| f_eq(Attribute::Uuid, PartialValue::Uuid(u)))
108 .collect();
109
110 if all_affected_filter.is_empty() {
111 trace!("all affected filter is empty, return");
112 return Ok(());
113 }
114
115 let leaf_entries = qs.internal_search_writeable(&filter!(f_and!([
117 f_andnot(f_eq(Attribute::Class, EntryClass::Group.into())),
118 FC::Or(all_affected_filter)
119 ])))?;
120
121 if leaf_entries.is_empty() {
122 trace!("leaf entries empty, return");
123 return Ok(());
124 }
125
126 let mut leaf_entries: BTreeMap<_, _> = leaf_entries
127 .into_iter()
128 .map(|entry_tuple| (entry_tuple.0.get_uuid(), entry_tuple))
129 .collect();
130
131 let mut changes = Vec::with_capacity(leaf_entries.len());
132
133 let mut groups_or = Vec::with_capacity(leaf_entries.len() * 2);
138
139 for uuid in leaf_entries.keys().copied() {
140 groups_or.push(f_eq(Attribute::Member, PartialValue::Refer(uuid)));
141 groups_or.push(f_eq(Attribute::DynMember, PartialValue::Refer(uuid)));
142 }
143
144 let all_groups = qs
145 .internal_search(filter!(f_and!([
146 f_eq(Attribute::Class, EntryClass::Group.into()),
147 FC::Or(groups_or)
148 ])))
149 .map_err(|err| {
150 error!(?err, "internal search failure");
151 err
152 })?;
153
154 for (_pre, tgte) in leaf_entries.values_mut() {
172 tgte.add_ava_if_not_exist(Attribute::Class, EntryClass::MemberOf.into());
174 tgte.purge_ava(Attribute::MemberOf);
177 tgte.purge_ava(Attribute::DirectMemberOf);
178 }
179
180 for group in all_groups {
183 trace!(group_id = %group.get_display_id());
184 let group_uuid = group.get_uuid();
186
187 let memberof_ref = group.get_ava_refer(Attribute::MemberOf);
188
189 let member_ref = group.get_ava_refer(Attribute::Member);
190 let dynmember_ref = group.get_ava_refer(Attribute::DynMember);
191
192 let dir_members = member_ref
193 .iter()
194 .flat_map(|set| set.iter())
195 .chain(dynmember_ref.iter().flat_map(|set| set.iter()))
196 .copied();
197
198 for dir_member in dir_members {
201 if let Some((_pre, tgte)) = leaf_entries.get_mut(&dir_member) {
202 trace!(?dir_member, entry_id = ?tgte.get_display_id());
203 if let Some(dmo_set) = tgte.get_ava_refer_mut(Attribute::DirectMemberOf) {
205 dmo_set.insert(group_uuid);
206 } else {
207 let dmo = ValueSetRefer::new(group_uuid);
208 tgte.set_ava_set(&Attribute::DirectMemberOf, dmo);
209 }
210
211 if let Some(mo_set) = tgte.get_ava_refer_mut(Attribute::MemberOf) {
213 mo_set.insert(group_uuid);
214 } else {
215 let mo = ValueSetRefer::new(group_uuid);
216 tgte.set_ava_set(&Attribute::MemberOf, mo);
217 }
218
219 if let Some(group_mo) = memberof_ref {
222 if let Some(mo_set) = tgte.get_ava_refer_mut(Attribute::MemberOf) {
225 mo_set.extend(group_mo.iter())
226 }
227 }
228
229 if cfg!(debug_assertions) {
230 if let Some(dmo) = group.get_ava_refer(Attribute::DirectMemberOf) {
231 if let Some(mo) = group.get_ava_refer(Attribute::MemberOf) {
232 debug_assert!(mo.is_superset(dmo))
233 }
234 }
235 }
236 }
237 }
241 }
243
244 leaf_entries
247 .into_iter()
248 .try_for_each(|(auuid, (pre, tgte))| {
249 if pre.get_ava_set(Attribute::MemberOf) != tgte.get_ava_set(Attribute::MemberOf)
251 || pre.get_ava_set(Attribute::DirectMemberOf)
252 != tgte.get_ava_set(Attribute::DirectMemberOf)
253 {
254 trace!("=> processing affected uuid {:?}", auuid);
255
256 if cfg!(debug_assertions) {
257 if let Some(dmo_set) = tgte.get_ava_refer(Attribute::DirectMemberOf) {
258 trace!(?dmo_set);
259
260 if let Some(mo_set) = tgte.get_ava_refer(Attribute::MemberOf) {
261 trace!(?mo_set);
262 debug_assert!(mo_set.is_superset(dmo_set));
263 } else {
264 unreachable!();
265 }
266 } else {
267 trace!("NONE");
268 };
269
270 if let Some(pre_dmo_set) = pre.get_ava_refer(Attribute::DirectMemberOf) {
271 trace!(?pre_dmo_set);
272
273 if let Some(pre_mo_set) = pre.get_ava_refer(Attribute::MemberOf) {
274 trace!(?pre_mo_set);
275 debug_assert!(pre_mo_set.is_superset(pre_dmo_set));
276 } else {
277 unreachable!();
278 }
279 } else {
280 trace!("NONE");
281 };
282 };
283
284 changes.push((pre, tgte));
285 } else {
286 trace!("=> ignoring unmodified uuid {:?}", auuid);
287 }
288 Ok(())
289 })?;
290
291 qs.internal_apply_writable(changes)
293 }
295
296#[allow(clippy::cognitive_complexity)]
298fn apply_memberof(
299 qs: &mut QueryServerWriteTransaction,
300 mut affected_uuids: BTreeSet<Uuid>,
303) -> Result<(), OperationError> {
304 trace!(" => entering apply_memberof");
305
306 let mut all_affected_uuids: BTreeSet<_> = affected_uuids.iter().copied().collect();
313
314 while !affected_uuids.is_empty() {
316 trace!(?affected_uuids);
317
318 let filt = filter!(f_and!([
320 f_eq(Attribute::Class, EntryClass::Group.into()),
321 FC::Or(
322 affected_uuids
323 .iter()
324 .copied()
325 .map(|u| f_eq(Attribute::Uuid, PartialValue::Uuid(u)))
326 .collect()
327 )
328 ]));
329
330 affected_uuids.clear();
332
333 let work_set = qs.internal_search_writeable(&filt)?;
334 let mut changes = Vec::with_capacity(work_set.len());
335
336 for (pre, mut tgte) in work_set.into_iter() {
337 let guuid = pre.get_uuid();
338
339 trace!(
340 "=> processing group update -> {:?} {}",
341 guuid,
342 tgte.get_display_id()
343 );
344
345 do_group_memberof(qs, guuid, &mut tgte)?;
346
347 if pre.get_ava_set(Attribute::MemberOf) != tgte.get_ava_set(Attribute::MemberOf)
349 || pre.get_ava_set(Attribute::DirectMemberOf)
350 != tgte.get_ava_set(Attribute::DirectMemberOf)
351 {
352 trace!(
356 "{:?} {} changed, flagging members as groups to change. ",
357 guuid,
358 tgte.get_display_id()
359 );
360
361 let pre_member = pre.get_ava_refer(Attribute::Member);
365 let post_member = tgte.get_ava_refer(Attribute::Member);
366
367 match (pre_member, post_member) {
368 (Some(pre_m), Some(post_m)) => {
369 affected_uuids.extend(pre_m);
370 affected_uuids.extend(post_m);
371 }
372 (Some(members), None) | (None, Some(members)) => {
373 affected_uuids.extend(members);
375 }
376 (None, None) => {}
377 };
378
379 let pre_dynmember = pre.get_ava_refer(Attribute::DynMember);
380 let post_dynmember = tgte.get_ava_refer(Attribute::DynMember);
381
382 match (pre_dynmember, post_dynmember) {
383 (Some(pre_m), Some(post_m)) => {
384 affected_uuids.extend(pre_m);
385 affected_uuids.extend(post_m);
386 }
387 (Some(members), None) | (None, Some(members)) => {
388 affected_uuids.extend(members);
390 }
391 (None, None) => {}
392 };
393
394 changes.push((pre, tgte));
396 } else {
397 trace!("{:?} {} stable", guuid, tgte.get_display_id());
409 }
410 }
411
412 if !changes.is_empty() {
414 trace!("wrote stripe {}", changes.len());
415 qs.internal_apply_writable(changes).map_err(|err| {
416 error!(?err, "Failed to commit memberof group set");
417 err
418 })?;
419 }
420
421 all_affected_uuids.extend(affected_uuids.iter());
423
424 trace!("-------------------------------------");
426 }
427
428 do_leaf_memberof(qs, all_affected_uuids)
430}
431
432impl Plugin for MemberOf {
433 fn id() -> &'static str {
434 Attribute::MemberOf.as_ref()
435 }
436
437 #[instrument(level = "debug", name = "memberof_post_create", skip_all)]
438 fn post_create(
439 qs: &mut QueryServerWriteTransaction,
440 cand: &[Entry<EntrySealed, EntryCommitted>],
441 ce: &CreateEvent,
442 ) -> Result<(), OperationError> {
443 Self::post_create_inner(qs, cand, &ce.ident)
444 }
445
446 #[instrument(level = "debug", name = "memberof_post_repl_refresh", skip_all)]
447 fn post_repl_refresh(
448 qs: &mut QueryServerWriteTransaction,
449 cand: &[Entry<EntrySealed, EntryCommitted>],
450 ) -> Result<(), OperationError> {
451 let ident = Identity::from_internal();
452 Self::post_create_inner(qs, cand, &ident)
453 }
454
455 #[instrument(level = "debug", name = "memberof_post_repl_incremental", skip_all)]
456 fn post_repl_incremental(
457 qs: &mut QueryServerWriteTransaction,
458 pre_cand: &[Arc<EntrySealedCommitted>],
459 cand: &[EntrySealedCommitted],
460 conflict_uuids: &BTreeSet<Uuid>,
461 ) -> Result<(), OperationError> {
462 let force_dyngroup_cand_update = !conflict_uuids.is_empty();
469
470 let ident_internal = Identity::from_internal();
473 Self::post_modify_inner(
474 qs,
475 pre_cand,
476 cand,
477 &ident_internal,
478 force_dyngroup_cand_update,
479 )
480 }
481
482 #[instrument(level = "debug", name = "memberof_post_modify", skip_all)]
483 fn post_modify(
484 qs: &mut QueryServerWriteTransaction,
485 pre_cand: &[Arc<Entry<EntrySealed, EntryCommitted>>],
486 cand: &[Entry<EntrySealed, EntryCommitted>],
487 me: &ModifyEvent,
488 ) -> Result<(), OperationError> {
489 Self::post_modify_inner(qs, pre_cand, cand, &me.ident, false)
490 }
491
492 #[instrument(level = "debug", name = "memberof_post_batch_modify", skip_all)]
493 fn post_batch_modify(
494 qs: &mut QueryServerWriteTransaction,
495 pre_cand: &[Arc<Entry<EntrySealed, EntryCommitted>>],
496 cand: &[Entry<EntrySealed, EntryCommitted>],
497 me: &BatchModifyEvent,
498 ) -> Result<(), OperationError> {
499 Self::post_modify_inner(qs, pre_cand, cand, &me.ident, false)
500 }
501
502 #[instrument(level = "debug", name = "memberof_pre_delete", skip_all)]
503 fn pre_delete(
504 _qs: &mut QueryServerWriteTransaction,
505 cand: &mut Vec<EntryInvalidCommitted>,
506 _de: &DeleteEvent,
507 ) -> Result<(), OperationError> {
508 for entry in cand.iter_mut() {
512 if let Some(direct_mo_vs) = entry.pop_ava(Attribute::DirectMemberOf) {
513 entry.set_ava_set(&Attribute::RecycledDirectMemberOf, direct_mo_vs);
514 } else {
515 entry.purge_ava(Attribute::RecycledDirectMemberOf);
517 }
518 entry.purge_ava(Attribute::MemberOf);
519 }
520
521 Ok(())
522 }
523
524 #[instrument(level = "debug", name = "memberof_post_delete", skip_all)]
525 fn post_delete(
526 qs: &mut QueryServerWriteTransaction,
527 cand: &[Entry<EntrySealed, EntryCommitted>],
528 _de: &DeleteEvent,
529 ) -> Result<(), OperationError> {
530 let affected_uuids = cand
533 .iter()
534 .filter_map(|e| {
535 if e.attribute_equality(Attribute::Class, &EntryClass::Group.into()) {
537 e.get_ava_as_refuuid(Attribute::Member)
538 } else {
539 None
540 }
541 })
542 .flatten()
543 .chain(
544 cand.iter()
546 .filter_map(|post| {
547 if post.attribute_equality(Attribute::Class, &EntryClass::DynGroup.into()) {
548 post.get_ava_as_refuuid(Attribute::DynMember)
549 } else {
550 None
551 }
552 })
553 .flatten(),
554 )
555 .collect();
556
557 apply_memberof(qs, affected_uuids)
558 }
559
560 #[instrument(level = "debug", name = "memberof::verify", skip_all)]
561 fn verify(qs: &mut QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
562 let mut r = Vec::with_capacity(0);
563
564 let filt_in = filter!(f_pres(Attribute::Class));
565
566 let all_cand = match qs
567 .internal_search(filt_in)
568 .map_err(|_| Err(ConsistencyError::QueryServerSearchFailure))
569 {
570 Ok(all_cand) => all_cand,
571 Err(e) => return vec![e],
572 };
573
574 let mut direct_membership_map: BTreeMap<Uuid, BTreeSet<Uuid>> = Default::default();
578
579 let pv_class: PartialValue = EntryClass::Group.into();
580
581 for entry in all_cand.iter() {
582 if !entry.attribute_equality(Attribute::Class, &pv_class) {
583 continue;
585 }
586
587 let group_uuid = entry.get_uuid();
588
589 let member_iter = entry
590 .get_ava_refer(Attribute::Member)
591 .into_iter()
592 .flat_map(|set| set.iter())
593 .chain(
594 entry
595 .get_ava_refer(Attribute::DynMember)
596 .into_iter()
597 .flat_map(|set| set.iter()),
598 );
599
600 for member_uuid in member_iter {
601 let member_groups = direct_membership_map.entry(*member_uuid).or_default();
602 member_groups.insert(group_uuid);
603 }
604 }
605
606 for e in all_cand {
608 let uuid = e.get_uuid();
609
610 let d_groups_set: Option<&BTreeSet<Uuid>> = direct_membership_map.get(&uuid);
611
612 trace!(
613 "DMO search groups {:?} -> {:?}",
614 e.get_display_id(),
615 d_groups_set
616 );
617
618 match (e.get_ava_set(Attribute::DirectMemberOf), d_groups_set) {
623 (Some(edmos), Some(b)) => {
624 match edmos.as_refer_set() {
626 Some(a) => {
627 let diff: Vec<_> = a.symmetric_difference(b).collect();
628 if !diff.is_empty() {
629 error!(
630 "MemberOfInvalid: Entry {}, DMO has inconsistencies",
631 e.get_display_id(),
632 );
633 trace!(entry_direct_member_of = ?a);
634 trace!(expected_direct_groups = ?b);
635 trace!(?diff);
636
637 r.push(Err(ConsistencyError::MemberOfInvalid(e.get_id())));
638 }
639 }
640 _ => {
641 error!("MemberOfInvalid: Entry {}, DMO has incorrect syntax - should be reference uuid set", e.get_display_id());
642 r.push(Err(ConsistencyError::MemberOfInvalid(e.get_id())));
643 }
644 }
645 }
646 (None, None) => {
647 }
649 (entry_direct_member_of, expected_direct_groups) => {
650 error!(
651 "MemberOfInvalid directmemberof set and DMO search set differ in presence: {}",
652 e.get_display_id()
653 );
654 trace!(?entry_direct_member_of);
656 trace!(?expected_direct_groups);
657 r.push(Err(ConsistencyError::MemberOfInvalid(e.get_id())));
658 }
659 }
660 }
661
662 r
663 }
664}
665
666impl MemberOf {
667 fn post_create_inner(
668 qs: &mut QueryServerWriteTransaction,
669 cand: &[Entry<EntrySealed, EntryCommitted>],
670 ident: &Identity,
671 ) -> Result<(), OperationError> {
672 let dyngroup_change = super::dyngroup::DynGroup::post_create(qs, cand, ident)?;
673
674 let affected_uuids = cand
675 .iter()
676 .map(|e| e.get_uuid())
677 .chain(dyngroup_change)
678 .chain(
680 cand.iter()
681 .filter_map(|e| {
682 if e.attribute_equality(Attribute::Class, &EntryClass::Group.into()) {
684 e.get_ava_as_refuuid(Attribute::Member)
685 } else {
686 None
687 }
688 })
689 .flatten(),
690 )
691 .collect();
692
693 apply_memberof(qs, affected_uuids)
694 }
695
696 fn post_modify_inner(
697 qs: &mut QueryServerWriteTransaction,
698 pre_cand: &[Arc<EntrySealedCommitted>],
699 cand: &[EntrySealedCommitted],
700 ident: &Identity,
701 force_dyngroup_cand_update: bool,
702 ) -> Result<(), OperationError> {
703 let dyngroup_change = super::dyngroup::DynGroup::post_modify(
704 qs,
705 pre_cand,
706 cand,
707 ident,
708 force_dyngroup_cand_update,
709 )?;
710
711 let mut affected_uuids: BTreeSet<_> = cand
712 .iter()
713 .map(|post| post.get_uuid())
714 .chain(dyngroup_change)
715 .collect();
716
717 for (pre, post) in pre_cand.iter().zip(cand.iter()).filter(|(pre, post)| {
718 post.attribute_equality(Attribute::Class, &EntryClass::Group.into())
719 || pre.attribute_equality(Attribute::Class, &EntryClass::Group.into())
720 }) {
721 let pre_member = pre.get_ava_refer(Attribute::Member);
722 let post_member = post.get_ava_refer(Attribute::Member);
723
724 match (pre_member, post_member) {
725 (Some(pre_m), Some(post_m)) => {
726 affected_uuids.extend(pre_m.symmetric_difference(post_m));
728 }
729 (Some(members), None) | (None, Some(members)) => {
730 affected_uuids.extend(members);
732 }
733 (None, None) => {}
734 };
735
736 let pre_dynmember = pre.get_ava_refer(Attribute::DynMember);
737 let post_dynmember = post.get_ava_refer(Attribute::DynMember);
738
739 match (pre_dynmember, post_dynmember) {
740 (Some(pre_m), Some(post_m)) => {
741 affected_uuids.extend(pre_m.symmetric_difference(post_m));
743 }
744 (Some(members), None) | (None, Some(members)) => {
745 affected_uuids.extend(members);
747 }
748 (None, None) => {}
749 };
750 }
751
752 apply_memberof(qs, affected_uuids)
753 }
754}
755
756#[cfg(test)]
757mod tests {
758 use crate::prelude::*;
759
760 const UUID_A: &str = "aaaaaaaa-f82e-4484-a407-181aa03bda5c";
761 const UUID_B: &str = "bbbbbbbb-2438-4384-9891-48f4c8172e9b";
762 const UUID_C: &str = "cccccccc-9b01-423f-9ba6-51aa4bbd5dd2";
763 const UUID_D: &str = "dddddddd-2ab3-48e3-938d-1b4754cd2984";
764
765 lazy_static! {
766 static ref EA: EntryInitNew = entry_init!(
767 (Attribute::Class, EntryClass::Group.to_value()),
768 (Attribute::Class, EntryClass::MemberOf.to_value()),
769 (Attribute::Name, Value::new_iname("testgroup_a")),
770 (Attribute::Uuid, Value::Uuid(uuid::uuid!(UUID_A)))
771 );
772 static ref EB: EntryInitNew = entry_init!(
773 (Attribute::Class, EntryClass::Group.to_value()),
774 (Attribute::Class, EntryClass::MemberOf.to_value()),
775 (Attribute::Name, Value::new_iname("testgroup_b")),
776 (Attribute::Uuid, Value::Uuid(uuid::uuid!(UUID_B)))
777 );
778 static ref EC: EntryInitNew = entry_init!(
779 (Attribute::Class, EntryClass::Group.to_value()),
780 (Attribute::Class, EntryClass::MemberOf.to_value()),
781 (Attribute::Name, Value::new_iname("testgroup_c")),
782 (Attribute::Uuid, Value::Uuid(uuid::uuid!(UUID_C)))
783 );
784 static ref ED: EntryInitNew = entry_init!(
785 (Attribute::Class, EntryClass::Group.to_value()),
786 (Attribute::Class, EntryClass::MemberOf.to_value()),
787 (Attribute::Name, Value::new_iname("testgroup_d")),
788 (Attribute::Uuid, Value::Uuid(uuid::uuid!(UUID_D)))
789 );
790 }
791
792 macro_rules! assert_memberof_int {
793 (
794 $qs:expr,
795 $ea:expr,
796 $eb:expr,
797 $mo:expr,
798 $cand:expr
799 ) => {{
800 let filt = filter!(f_and!([
801 f_eq(Attribute::Uuid, PartialValue::new_uuid_s($ea).unwrap()),
802 f_eq($mo, PartialValue::new_refer_s($eb).unwrap())
803 ]));
804 let cands = $qs.internal_search(filt).expect("Internal search failure");
805 debug!("assert_mo_cands {:?}", cands);
806 assert_eq!(cands.len(), $cand);
807 }};
808 }
809
810 macro_rules! assert_memberof {
811 (
812 $qs:expr,
813 $ea:expr,
814 $eb:expr
815 ) => {{
816 assert_memberof_int!($qs, $ea, $eb, Attribute::MemberOf, 1);
817 }};
818 }
819
820 macro_rules! assert_dirmemberof {
821 (
822 $qs:expr,
823 $ea:expr,
824 $eb:expr
825 ) => {{
826 assert_memberof_int!($qs, $ea, $eb, Attribute::DirectMemberOf, 1);
827 }};
828 }
829
830 macro_rules! assert_not_memberof {
831 (
832 $qs:expr,
833 $ea:expr,
834 $eb:expr
835 ) => {{
836 assert_memberof_int!($qs, $ea, $eb, Attribute::MemberOf, 0);
837 }};
838 }
839
840 macro_rules! assert_not_dirmemberof {
841 (
842 $qs:expr,
843 $ea:expr,
844 $eb:expr
845 ) => {{
846 assert_memberof_int!($qs, $ea, $eb, Attribute::DirectMemberOf, 0);
847 }};
848 }
849
850 #[test]
851 fn test_create_mo_single() {
852 let mut ea = EA.clone();
854 let eb = EB.clone();
855
856 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
857
858 let preload = Vec::with_capacity(0);
859 let create = vec![ea, eb];
860 run_create_test!(
861 Ok(()),
862 preload,
863 create,
864 None,
865 |qs: &mut QueryServerWriteTransaction| {
866 assert_memberof!(qs, UUID_B, UUID_A);
869 assert_not_memberof!(qs, UUID_A, UUID_B);
870
871 assert_dirmemberof!(qs, UUID_B, UUID_A);
872 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
873 }
874 );
875 }
876
877 #[test]
878 fn test_create_mo_nested() {
879 let mut ea = EA.clone();
881
882 let mut eb = EB.clone();
883
884 let ec = EC.clone();
885
886 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
887 eb.add_ava(Attribute::Member, Value::new_refer_s(UUID_C).unwrap());
888
889 let preload = Vec::with_capacity(0);
890 let create = vec![ea, eb, ec];
891 run_create_test!(
892 Ok(()),
893 preload,
894 create,
895 None,
896 |qs: &mut QueryServerWriteTransaction| {
897 assert_not_memberof!(qs, UUID_A, UUID_A);
900 assert_not_memberof!(qs, UUID_A, UUID_B);
901 assert_not_memberof!(qs, UUID_A, UUID_C);
902
903 assert_memberof!(qs, UUID_B, UUID_A);
904 assert_not_memberof!(qs, UUID_B, UUID_B);
905 assert_not_memberof!(qs, UUID_B, UUID_C);
906
907 assert_memberof!(qs, UUID_C, UUID_A);
909 assert_memberof!(qs, UUID_C, UUID_B);
910 assert_not_memberof!(qs, UUID_C, UUID_C);
911
912 assert_not_dirmemberof!(qs, UUID_A, UUID_A);
913 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
914 assert_not_dirmemberof!(qs, UUID_A, UUID_C);
915
916 assert_dirmemberof!(qs, UUID_B, UUID_A);
917 assert_not_dirmemberof!(qs, UUID_B, UUID_B);
918 assert_not_dirmemberof!(qs, UUID_B, UUID_C);
919
920 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
921 assert_dirmemberof!(qs, UUID_C, UUID_B);
922 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
923 }
924 );
925 }
926
927 #[test]
928 fn test_create_mo_cycle() {
929 let mut ea = EA.clone();
932
933 let mut eb = EB.clone();
934
935 let mut ec = EC.clone();
936
937 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
938 eb.add_ava(Attribute::Member, Value::new_refer_s(UUID_C).unwrap());
939 ec.add_ava(Attribute::Member, Value::new_refer_s(UUID_A).unwrap());
940
941 let preload = Vec::with_capacity(0);
942 let create = vec![ea, eb, ec];
943 run_create_test!(
944 Ok(()),
945 preload,
946 create,
947 None,
948 |qs: &mut QueryServerWriteTransaction| {
949 assert_memberof!(qs, UUID_A, UUID_A);
952 assert_memberof!(qs, UUID_A, UUID_B);
953 assert_memberof!(qs, UUID_A, UUID_C);
954
955 assert_memberof!(qs, UUID_B, UUID_A);
956 assert_memberof!(qs, UUID_B, UUID_B);
957 assert_memberof!(qs, UUID_B, UUID_C);
958
959 assert_memberof!(qs, UUID_C, UUID_A);
960 assert_memberof!(qs, UUID_C, UUID_B);
961 assert_memberof!(qs, UUID_C, UUID_C);
962
963 assert_not_dirmemberof!(qs, UUID_A, UUID_A);
964 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
965 assert_dirmemberof!(qs, UUID_A, UUID_C);
966
967 assert_dirmemberof!(qs, UUID_B, UUID_A);
968 assert_not_dirmemberof!(qs, UUID_B, UUID_B);
969 assert_not_dirmemberof!(qs, UUID_B, UUID_C);
970
971 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
972 assert_dirmemberof!(qs, UUID_C, UUID_B);
973 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
974 }
975 );
976 }
977
978 #[test]
979 fn test_create_mo_multi_cycle() {
980 let mut ea = EA.clone();
984
985 let mut eb = EB.clone();
986
987 let mut ec = EC.clone();
988
989 let mut ed = ED.clone();
990
991 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
992 eb.add_ava(Attribute::Member, Value::new_refer_s(UUID_C).unwrap());
993
994 ec.add_ava(Attribute::Member, Value::new_refer_s(UUID_A).unwrap());
995 ec.add_ava(Attribute::Member, Value::new_refer_s(UUID_D).unwrap());
996
997 ed.add_ava(Attribute::Member, Value::new_refer_s(UUID_A).unwrap());
998
999 let preload = Vec::with_capacity(0);
1000 let create = vec![ea, eb, ec, ed];
1001 run_create_test!(
1002 Ok(()),
1003 preload,
1004 create,
1005 None,
1006 |qs: &mut QueryServerWriteTransaction| {
1007 assert_memberof!(qs, UUID_A, UUID_A);
1010 assert_memberof!(qs, UUID_A, UUID_B);
1011 assert_memberof!(qs, UUID_A, UUID_C);
1012 assert_memberof!(qs, UUID_A, UUID_D);
1013
1014 assert_memberof!(qs, UUID_B, UUID_A);
1015 assert_memberof!(qs, UUID_B, UUID_B);
1016 assert_memberof!(qs, UUID_B, UUID_C);
1017 assert_memberof!(qs, UUID_B, UUID_D);
1018
1019 assert_memberof!(qs, UUID_C, UUID_A);
1020 assert_memberof!(qs, UUID_C, UUID_B);
1021 assert_memberof!(qs, UUID_C, UUID_C);
1022 assert_memberof!(qs, UUID_C, UUID_D);
1023
1024 assert_memberof!(qs, UUID_D, UUID_A);
1025 assert_memberof!(qs, UUID_D, UUID_B);
1026 assert_memberof!(qs, UUID_D, UUID_C);
1027 assert_memberof!(qs, UUID_D, UUID_D);
1028
1029 assert_not_dirmemberof!(qs, UUID_A, UUID_A);
1030 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
1031 assert_dirmemberof!(qs, UUID_A, UUID_C);
1032 assert_dirmemberof!(qs, UUID_A, UUID_D);
1033
1034 assert_dirmemberof!(qs, UUID_B, UUID_A);
1035 assert_not_dirmemberof!(qs, UUID_B, UUID_B);
1036 assert_not_dirmemberof!(qs, UUID_B, UUID_C);
1037 assert_not_dirmemberof!(qs, UUID_B, UUID_D);
1038
1039 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
1040 assert_dirmemberof!(qs, UUID_C, UUID_B);
1041 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
1042 assert_not_dirmemberof!(qs, UUID_C, UUID_D);
1043
1044 assert_not_dirmemberof!(qs, UUID_D, UUID_A);
1045 assert_not_dirmemberof!(qs, UUID_D, UUID_B);
1046 assert_dirmemberof!(qs, UUID_D, UUID_C);
1047 assert_not_dirmemberof!(qs, UUID_D, UUID_D);
1048 }
1049 );
1050 }
1051
1052 #[test]
1053 fn test_modify_mo_add_simple() {
1054 let ea = EA.clone();
1058 let eb = EB.clone();
1059
1060 let preload = vec![ea, eb];
1061 run_modify_test!(
1062 Ok(()),
1063 preload,
1064 filter!(f_eq(
1065 Attribute::Uuid,
1066 PartialValue::new_uuid_s(UUID_A).unwrap()
1067 )),
1068 ModifyList::new_list(vec![Modify::Present(
1069 Attribute::Member,
1070 Value::new_refer_s(UUID_B).unwrap()
1071 )]),
1072 None,
1073 |_| {},
1074 |qs: &mut QueryServerWriteTransaction| {
1075 assert_memberof!(qs, UUID_B, UUID_A);
1078 assert_not_memberof!(qs, UUID_A, UUID_B);
1079
1080 assert_dirmemberof!(qs, UUID_B, UUID_A);
1081 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
1082 }
1083 );
1084 }
1085
1086 #[test]
1087 fn test_modify_mo_add_nested_1() {
1088 let ea = EA.clone();
1092 let mut eb = EB.clone();
1093 let ec = EC.clone();
1094
1095 eb.add_ava(Attribute::Member, Value::new_refer_s(UUID_C).unwrap());
1096
1097 let preload = vec![ea, eb, ec];
1098 run_modify_test!(
1099 Ok(()),
1100 preload,
1101 filter!(f_eq(
1102 Attribute::Uuid,
1103 PartialValue::new_uuid_s(UUID_A).unwrap()
1104 )),
1105 ModifyList::new_list(vec![Modify::Present(
1106 Attribute::Member,
1107 Value::new_refer_s(UUID_B).unwrap()
1108 )]),
1109 None,
1110 |_| {},
1111 |qs: &mut QueryServerWriteTransaction| {
1112 assert_not_memberof!(qs, UUID_A, UUID_A);
1115 assert_not_memberof!(qs, UUID_A, UUID_B);
1116 assert_not_memberof!(qs, UUID_A, UUID_C);
1117
1118 assert_memberof!(qs, UUID_B, UUID_A);
1119 assert_not_memberof!(qs, UUID_B, UUID_B);
1120 assert_not_memberof!(qs, UUID_B, UUID_C);
1121
1122 assert_memberof!(qs, UUID_C, UUID_A);
1123 assert_memberof!(qs, UUID_C, UUID_B);
1124 assert_not_memberof!(qs, UUID_C, UUID_C);
1125
1126 assert_not_dirmemberof!(qs, UUID_A, UUID_A);
1127 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
1128 assert_not_dirmemberof!(qs, UUID_A, UUID_C);
1129
1130 assert_dirmemberof!(qs, UUID_B, UUID_A);
1131 assert_not_dirmemberof!(qs, UUID_B, UUID_B);
1132 assert_not_dirmemberof!(qs, UUID_B, UUID_C);
1133
1134 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
1135 assert_dirmemberof!(qs, UUID_C, UUID_B);
1136 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
1137 }
1138 );
1139 }
1140
1141 #[test]
1142 fn test_modify_mo_add_nested_2() {
1143 let mut ea = EA.clone();
1147 let eb = EB.clone();
1148 let ec = EC.clone();
1149
1150 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
1151
1152 let preload = vec![ea, eb, ec];
1153 run_modify_test!(
1154 Ok(()),
1155 preload,
1156 filter!(f_eq(
1157 Attribute::Uuid,
1158 PartialValue::new_uuid_s(UUID_B).unwrap()
1159 )),
1160 ModifyList::new_list(vec![Modify::Present(
1161 Attribute::Member,
1162 Value::new_refer_s(UUID_C).unwrap()
1163 )]),
1164 None,
1165 |_| {},
1166 |qs: &mut QueryServerWriteTransaction| {
1167 assert_not_memberof!(qs, UUID_A, UUID_A);
1170 assert_not_memberof!(qs, UUID_A, UUID_B);
1171 assert_not_memberof!(qs, UUID_A, UUID_C);
1172
1173 assert_memberof!(qs, UUID_B, UUID_A);
1174 assert_not_memberof!(qs, UUID_B, UUID_B);
1175 assert_not_memberof!(qs, UUID_B, UUID_C);
1176
1177 assert_memberof!(qs, UUID_C, UUID_A);
1178 assert_memberof!(qs, UUID_C, UUID_B);
1179 assert_not_memberof!(qs, UUID_C, UUID_C);
1180
1181 assert_not_dirmemberof!(qs, UUID_A, UUID_A);
1182 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
1183 assert_not_dirmemberof!(qs, UUID_A, UUID_C);
1184
1185 assert_dirmemberof!(qs, UUID_B, UUID_A);
1186 assert_not_dirmemberof!(qs, UUID_B, UUID_B);
1187 assert_not_dirmemberof!(qs, UUID_B, UUID_C);
1188
1189 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
1190 assert_dirmemberof!(qs, UUID_C, UUID_B);
1191 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
1192 }
1193 );
1194 }
1195
1196 #[test]
1197 fn test_modify_mo_add_cycle() {
1198 let mut ea = EA.clone();
1204 let mut eb = EB.clone();
1205 let ec = EC.clone();
1206
1207 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
1208 eb.add_ava(Attribute::Member, Value::new_refer_s(UUID_C).unwrap());
1209
1210 let preload = vec![ea, eb, ec];
1211 run_modify_test!(
1212 Ok(()),
1213 preload,
1214 filter!(f_eq(
1215 Attribute::Uuid,
1216 PartialValue::new_uuid_s(UUID_C).unwrap()
1217 )),
1218 ModifyList::new_list(vec![Modify::Present(
1219 Attribute::Member,
1220 Value::new_refer_s(UUID_A).unwrap()
1221 )]),
1222 None,
1223 |_| {},
1224 |qs: &mut QueryServerWriteTransaction| {
1225 assert_memberof!(qs, UUID_A, UUID_A);
1228 assert_memberof!(qs, UUID_A, UUID_B);
1229 assert_memberof!(qs, UUID_A, UUID_C);
1230
1231 assert_memberof!(qs, UUID_B, UUID_A);
1232 assert_memberof!(qs, UUID_B, UUID_B);
1233 assert_memberof!(qs, UUID_B, UUID_C);
1234
1235 assert_memberof!(qs, UUID_C, UUID_A);
1236 assert_memberof!(qs, UUID_C, UUID_B);
1237 assert_memberof!(qs, UUID_C, UUID_C);
1238
1239 assert_not_dirmemberof!(qs, UUID_A, UUID_A);
1240 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
1241 assert_dirmemberof!(qs, UUID_A, UUID_C);
1242
1243 assert_dirmemberof!(qs, UUID_B, UUID_A);
1244 assert_not_dirmemberof!(qs, UUID_B, UUID_B);
1245 assert_not_dirmemberof!(qs, UUID_B, UUID_C);
1246
1247 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
1248 assert_dirmemberof!(qs, UUID_C, UUID_B);
1249 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
1250 }
1251 );
1252 }
1253
1254 #[test]
1255 fn test_modify_mo_add_multi_cycle() {
1256 let mut ea = EA.clone();
1266 let mut eb = EB.clone();
1267 let mut ec = EC.clone();
1268 let ed = ED.clone();
1269
1270 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
1271 eb.add_ava(Attribute::Member, Value::new_refer_s(UUID_C).unwrap());
1272 ec.add_ava(Attribute::Member, Value::new_refer_s(UUID_D).unwrap());
1273
1274 let preload = vec![ea, eb, ec, ed];
1275 run_modify_test!(
1276 Ok(()),
1277 preload,
1278 filter!(f_or!([
1279 f_eq(Attribute::Uuid, PartialValue::new_uuid_s(UUID_C).unwrap()),
1280 f_eq(Attribute::Uuid, PartialValue::new_uuid_s(UUID_D).unwrap()),
1281 ])),
1282 ModifyList::new_list(vec![Modify::Present(
1283 Attribute::Member,
1284 Value::new_refer_s(UUID_A).unwrap()
1285 )]),
1286 None,
1287 |_| {},
1288 |qs: &mut QueryServerWriteTransaction| {
1289 assert_memberof!(qs, UUID_A, UUID_A);
1292 assert_memberof!(qs, UUID_A, UUID_B);
1293 assert_memberof!(qs, UUID_A, UUID_C);
1294 assert_memberof!(qs, UUID_A, UUID_D);
1295
1296 assert_memberof!(qs, UUID_B, UUID_A);
1297 assert_memberof!(qs, UUID_B, UUID_B);
1298 assert_memberof!(qs, UUID_B, UUID_C);
1299 assert_memberof!(qs, UUID_B, UUID_D);
1300
1301 assert_memberof!(qs, UUID_C, UUID_A);
1302 assert_memberof!(qs, UUID_C, UUID_B);
1303 assert_memberof!(qs, UUID_C, UUID_C);
1304 assert_memberof!(qs, UUID_C, UUID_D);
1305
1306 assert_memberof!(qs, UUID_D, UUID_A);
1307 assert_memberof!(qs, UUID_D, UUID_B);
1308 assert_memberof!(qs, UUID_D, UUID_C);
1309 assert_memberof!(qs, UUID_D, UUID_D);
1310
1311 assert_not_dirmemberof!(qs, UUID_A, UUID_A);
1312 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
1313 assert_dirmemberof!(qs, UUID_A, UUID_C);
1314 assert_dirmemberof!(qs, UUID_A, UUID_D);
1315
1316 assert_dirmemberof!(qs, UUID_B, UUID_A);
1317 assert_not_dirmemberof!(qs, UUID_B, UUID_B);
1318 assert_not_dirmemberof!(qs, UUID_B, UUID_C);
1319 assert_not_dirmemberof!(qs, UUID_B, UUID_D);
1320
1321 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
1322 assert_dirmemberof!(qs, UUID_C, UUID_B);
1323 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
1324 assert_not_dirmemberof!(qs, UUID_C, UUID_D);
1325
1326 assert_not_dirmemberof!(qs, UUID_D, UUID_A);
1327 assert_not_dirmemberof!(qs, UUID_D, UUID_B);
1328 assert_dirmemberof!(qs, UUID_D, UUID_C);
1329 assert_not_dirmemberof!(qs, UUID_D, UUID_D);
1330 }
1331 );
1332 }
1333
1334 #[test]
1335 fn test_modify_mo_del_simple() {
1336 let mut ea = EA.clone();
1340 let mut eb = EB.clone();
1341
1342 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
1343 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1344
1345 let preload = vec![ea, eb];
1346 run_modify_test!(
1347 Ok(()),
1348 preload,
1349 filter!(f_eq(
1350 Attribute::Uuid,
1351 PartialValue::new_uuid_s(UUID_A).unwrap()
1352 )),
1353 ModifyList::new_list(vec![Modify::Removed(
1354 Attribute::Member,
1355 PartialValue::new_refer_s(UUID_B).unwrap()
1356 )]),
1357 None,
1358 |_| {},
1359 |qs: &mut QueryServerWriteTransaction| {
1360 assert_not_memberof!(qs, UUID_B, UUID_A);
1363 assert_not_memberof!(qs, UUID_A, UUID_B);
1364
1365 assert_not_dirmemberof!(qs, UUID_B, UUID_A);
1366 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
1367 }
1368 );
1369 }
1370
1371 #[test]
1372 fn test_modify_mo_del_nested_1() {
1373 let mut ea = EA.clone();
1377 let mut eb = EB.clone();
1378 let mut ec = EC.clone();
1379
1380 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
1381 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1382 eb.add_ava(Attribute::Member, Value::new_refer_s(UUID_C).unwrap());
1383 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1384
1385 let preload = vec![ea, eb, ec];
1386 run_modify_test!(
1387 Ok(()),
1388 preload,
1389 filter!(f_eq(
1390 Attribute::Uuid,
1391 PartialValue::new_uuid_s(UUID_A).unwrap()
1392 )),
1393 ModifyList::new_list(vec![Modify::Removed(
1394 Attribute::Member,
1395 PartialValue::new_refer_s(UUID_B).unwrap()
1396 )]),
1397 None,
1398 |_| {},
1399 |qs: &mut QueryServerWriteTransaction| {
1400 assert_not_memberof!(qs, UUID_A, UUID_A);
1403 assert_not_memberof!(qs, UUID_A, UUID_B);
1404 assert_not_memberof!(qs, UUID_A, UUID_C);
1405
1406 assert_not_memberof!(qs, UUID_B, UUID_A);
1407 assert_not_memberof!(qs, UUID_B, UUID_B);
1408 assert_not_memberof!(qs, UUID_B, UUID_C);
1409
1410 assert_not_memberof!(qs, UUID_C, UUID_A);
1411 assert_memberof!(qs, UUID_C, UUID_B);
1412 assert_not_memberof!(qs, UUID_C, UUID_C);
1413
1414 assert_not_dirmemberof!(qs, UUID_A, UUID_A);
1415 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
1416 assert_not_dirmemberof!(qs, UUID_A, UUID_C);
1417
1418 assert_not_dirmemberof!(qs, UUID_B, UUID_A);
1419 assert_not_dirmemberof!(qs, UUID_B, UUID_B);
1420 assert_not_dirmemberof!(qs, UUID_B, UUID_C);
1421
1422 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
1423 assert_dirmemberof!(qs, UUID_C, UUID_B);
1424 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
1425 }
1426 );
1427 }
1428
1429 #[test]
1430 fn test_modify_mo_del_nested_2() {
1431 let mut ea = EA.clone();
1435 let mut eb = EB.clone();
1436 let mut ec = EC.clone();
1437
1438 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
1439 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1440 eb.add_ava(Attribute::Member, Value::new_refer_s(UUID_C).unwrap());
1441 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1442 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1443
1444 let preload = vec![ea, eb, ec];
1445 run_modify_test!(
1446 Ok(()),
1447 preload,
1448 filter!(f_eq(
1449 Attribute::Uuid,
1450 PartialValue::new_uuid_s(UUID_B).unwrap()
1451 )),
1452 ModifyList::new_list(vec![Modify::Removed(
1453 Attribute::Member,
1454 PartialValue::new_refer_s(UUID_C).unwrap()
1455 )]),
1456 None,
1457 |_| {},
1458 |qs: &mut QueryServerWriteTransaction| {
1459 assert_not_memberof!(qs, UUID_A, UUID_A);
1462 assert_not_memberof!(qs, UUID_A, UUID_B);
1463 assert_not_memberof!(qs, UUID_A, UUID_C);
1464
1465 assert_memberof!(qs, UUID_B, UUID_A);
1466 assert_not_memberof!(qs, UUID_B, UUID_B);
1467 assert_not_memberof!(qs, UUID_B, UUID_C);
1468
1469 assert_not_memberof!(qs, UUID_C, UUID_A);
1470 assert_not_memberof!(qs, UUID_C, UUID_B);
1471 assert_not_memberof!(qs, UUID_C, UUID_C);
1472
1473 assert_not_dirmemberof!(qs, UUID_A, UUID_A);
1474 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
1475 assert_not_dirmemberof!(qs, UUID_A, UUID_C);
1476
1477 assert_dirmemberof!(qs, UUID_B, UUID_A);
1478 assert_not_dirmemberof!(qs, UUID_B, UUID_B);
1479 assert_not_dirmemberof!(qs, UUID_B, UUID_C);
1480
1481 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
1482 assert_not_dirmemberof!(qs, UUID_C, UUID_B);
1483 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
1484 }
1485 );
1486 }
1487
1488 #[test]
1489 fn test_modify_mo_del_cycle() {
1490 let mut ea = EA.clone();
1495 let mut eb = EB.clone();
1496 let mut ec = EC.clone();
1497
1498 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
1499 ea.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_C).unwrap());
1500 ea.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1501 ea.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1502
1503 eb.add_ava(Attribute::Member, Value::new_refer_s(UUID_C).unwrap());
1504 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_C).unwrap());
1505 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1506 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1507
1508 ec.add_ava(Attribute::Member, Value::new_refer_s(UUID_A).unwrap());
1509 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_C).unwrap());
1510 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1511 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1512
1513 let preload = vec![ea, eb, ec];
1514 run_modify_test!(
1515 Ok(()),
1516 preload,
1517 filter!(f_eq(
1518 Attribute::Uuid,
1519 PartialValue::new_uuid_s(UUID_C).unwrap()
1520 )),
1521 ModifyList::new_list(vec![Modify::Removed(
1522 Attribute::Member,
1523 PartialValue::new_refer_s(UUID_A).unwrap()
1524 )]),
1525 None,
1526 |_| {},
1527 |qs: &mut QueryServerWriteTransaction| {
1528 assert_not_memberof!(qs, UUID_A, UUID_A);
1531 assert_not_memberof!(qs, UUID_A, UUID_B);
1532 assert_not_memberof!(qs, UUID_A, UUID_C);
1533
1534 assert_memberof!(qs, UUID_B, UUID_A);
1535 assert_not_memberof!(qs, UUID_B, UUID_B);
1536 assert_not_memberof!(qs, UUID_B, UUID_C);
1537
1538 assert_memberof!(qs, UUID_C, UUID_A);
1539 assert_memberof!(qs, UUID_C, UUID_B);
1540 assert_not_memberof!(qs, UUID_C, UUID_C);
1541
1542 assert_not_dirmemberof!(qs, UUID_A, UUID_A);
1543 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
1544 assert_not_dirmemberof!(qs, UUID_A, UUID_C);
1545
1546 assert_dirmemberof!(qs, UUID_B, UUID_A);
1547 assert_not_dirmemberof!(qs, UUID_B, UUID_B);
1548 assert_not_dirmemberof!(qs, UUID_B, UUID_C);
1549
1550 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
1551 assert_dirmemberof!(qs, UUID_C, UUID_B);
1552 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
1553 }
1554 );
1555 }
1556
1557 #[test]
1558 fn test_modify_mo_del_multi_cycle() {
1559 let mut ea = EA.clone();
1570 let mut eb = EB.clone();
1571 let mut ec = EC.clone();
1572 let mut ed = ED.clone();
1573
1574 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
1575 ea.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_D).unwrap());
1576 ea.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_C).unwrap());
1577 ea.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1578 ea.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1579
1580 eb.add_ava(Attribute::Member, Value::new_refer_s(UUID_C).unwrap());
1581 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_D).unwrap());
1582 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_C).unwrap());
1583 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1584 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1585
1586 ec.add_ava(Attribute::Member, Value::new_refer_s(UUID_A).unwrap());
1587 ec.add_ava(Attribute::Member, Value::new_refer_s(UUID_D).unwrap());
1588 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_D).unwrap());
1589 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_C).unwrap());
1590 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1591 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1592
1593 ed.add_ava(Attribute::Member, Value::new_refer_s(UUID_A).unwrap());
1594 ed.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_D).unwrap());
1595 ed.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_C).unwrap());
1596 ed.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1597 ed.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1598
1599 let preload = vec![ea, eb, ec, ed];
1600 run_modify_test!(
1601 Ok(()),
1602 preload,
1603 filter!(f_eq(
1604 Attribute::Uuid,
1605 PartialValue::new_uuid_s(UUID_C).unwrap()
1606 )),
1607 ModifyList::new_list(vec![
1608 Modify::Removed(
1609 Attribute::Member,
1610 PartialValue::new_refer_s(UUID_A).unwrap()
1611 ),
1612 Modify::Removed(
1613 Attribute::Member,
1614 PartialValue::new_refer_s(UUID_D).unwrap()
1615 ),
1616 ]),
1617 None,
1618 |_| {},
1619 |qs: &mut QueryServerWriteTransaction| {
1620 assert_not_memberof!(qs, UUID_A, UUID_A);
1623 assert_not_memberof!(qs, UUID_A, UUID_B);
1624 assert_not_memberof!(qs, UUID_A, UUID_C);
1625 assert_memberof!(qs, UUID_A, UUID_D);
1626
1627 assert_memberof!(qs, UUID_B, UUID_A);
1628 assert_not_memberof!(qs, UUID_B, UUID_B);
1629 assert_not_memberof!(qs, UUID_B, UUID_C);
1630 assert_memberof!(qs, UUID_B, UUID_D);
1631
1632 assert_memberof!(qs, UUID_C, UUID_A);
1633 assert_memberof!(qs, UUID_C, UUID_B);
1634 assert_not_memberof!(qs, UUID_C, UUID_C);
1635 assert_memberof!(qs, UUID_C, UUID_D);
1636
1637 assert_not_memberof!(qs, UUID_D, UUID_A);
1638 assert_not_memberof!(qs, UUID_D, UUID_B);
1639 assert_not_memberof!(qs, UUID_D, UUID_C);
1640 assert_not_memberof!(qs, UUID_D, UUID_D);
1641
1642 assert_not_dirmemberof!(qs, UUID_A, UUID_A);
1643 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
1644 assert_not_dirmemberof!(qs, UUID_A, UUID_C);
1645 assert_dirmemberof!(qs, UUID_A, UUID_D);
1646
1647 assert_dirmemberof!(qs, UUID_B, UUID_A);
1648 assert_not_dirmemberof!(qs, UUID_B, UUID_B);
1649 assert_not_dirmemberof!(qs, UUID_B, UUID_C);
1650 assert_not_dirmemberof!(qs, UUID_B, UUID_D);
1651
1652 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
1653 assert_dirmemberof!(qs, UUID_C, UUID_B);
1654 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
1655 assert_not_dirmemberof!(qs, UUID_C, UUID_D);
1656
1657 assert_not_dirmemberof!(qs, UUID_D, UUID_A);
1658 assert_not_dirmemberof!(qs, UUID_D, UUID_B);
1659 assert_not_dirmemberof!(qs, UUID_D, UUID_C);
1660 assert_not_dirmemberof!(qs, UUID_D, UUID_D);
1661 }
1662 );
1663 }
1664
1665 #[test]
1666 fn test_delete_mo_simple() {
1667 let mut ea = EA.clone();
1669 let mut eb = EB.clone();
1670
1671 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
1672 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1673
1674 let preload = vec![ea, eb];
1675 run_delete_test!(
1676 Ok(()),
1677 preload,
1678 filter!(f_eq(
1679 Attribute::Uuid,
1680 PartialValue::new_uuid_s(UUID_A).unwrap()
1681 )),
1682 None,
1683 |qs: &mut QueryServerWriteTransaction| {
1684 assert_not_memberof!(qs, UUID_B, UUID_A);
1687 assert_not_memberof!(qs, UUID_A, UUID_B);
1688
1689 assert_not_dirmemberof!(qs, UUID_B, UUID_A);
1690 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
1691 }
1692 );
1693 }
1694
1695 #[test]
1696 fn test_delete_mo_nested_head() {
1697 let mut ea = EA.clone();
1699 let mut eb = EB.clone();
1700 let mut ec = EC.clone();
1701
1702 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
1703 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1704
1705 eb.add_ava(Attribute::Member, Value::new_refer_s(UUID_C).unwrap());
1706 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1707 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1708
1709 let preload = vec![ea, eb, ec];
1710 run_delete_test!(
1711 Ok(()),
1712 preload,
1713 filter!(f_eq(
1714 Attribute::Uuid,
1715 PartialValue::new_uuid_s(UUID_A).unwrap()
1716 )),
1717 None,
1718 |qs: &mut QueryServerWriteTransaction| {
1719 assert_not_memberof!(qs, UUID_B, UUID_A);
1722 assert_not_memberof!(qs, UUID_B, UUID_B);
1723 assert_not_memberof!(qs, UUID_B, UUID_C);
1724
1725 assert_not_memberof!(qs, UUID_C, UUID_A);
1726 assert_memberof!(qs, UUID_C, UUID_B);
1727 assert_not_memberof!(qs, UUID_C, UUID_C);
1728
1729 assert_not_dirmemberof!(qs, UUID_B, UUID_A);
1730 assert_not_dirmemberof!(qs, UUID_B, UUID_B);
1731 assert_not_dirmemberof!(qs, UUID_B, UUID_C);
1732
1733 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
1734 assert_dirmemberof!(qs, UUID_C, UUID_B);
1735 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
1736 }
1737 );
1738 }
1739
1740 #[test]
1741 fn test_delete_mo_nested_branch() {
1742 let mut ea = EA.clone();
1744 let mut eb = EB.clone();
1745 let mut ec = EC.clone();
1746
1747 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
1748 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1749
1750 eb.add_ava(Attribute::Member, Value::new_refer_s(UUID_C).unwrap());
1751 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1752 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1753
1754 let preload = vec![ea, eb, ec];
1755 run_delete_test!(
1756 Ok(()),
1757 preload,
1758 filter!(f_eq(
1759 Attribute::Uuid,
1760 PartialValue::new_uuid_s(UUID_B).unwrap()
1761 )),
1762 None,
1763 |qs: &mut QueryServerWriteTransaction| {
1764 assert_not_memberof!(qs, UUID_A, UUID_A);
1767 assert_not_memberof!(qs, UUID_A, UUID_B);
1768 assert_not_memberof!(qs, UUID_A, UUID_C);
1769
1770 assert_not_memberof!(qs, UUID_C, UUID_A);
1771 assert_not_memberof!(qs, UUID_C, UUID_B);
1772 assert_not_memberof!(qs, UUID_C, UUID_C);
1773
1774 assert_not_dirmemberof!(qs, UUID_A, UUID_A);
1775 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
1776 assert_not_dirmemberof!(qs, UUID_A, UUID_C);
1777
1778 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
1779 assert_not_dirmemberof!(qs, UUID_C, UUID_B);
1780 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
1781 }
1782 );
1783 }
1784
1785 #[test]
1786 fn test_delete_mo_cycle() {
1787 let mut ea = EA.clone();
1790 let mut eb = EB.clone();
1791 let mut ec = EC.clone();
1792
1793 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
1794 ea.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1795 ea.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1796 ea.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_C).unwrap());
1797
1798 eb.add_ava(Attribute::Member, Value::new_refer_s(UUID_C).unwrap());
1799 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1800 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1801 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_C).unwrap());
1802
1803 ec.add_ava(Attribute::Member, Value::new_refer_s(UUID_A).unwrap());
1804 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1805 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1806 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_C).unwrap());
1807
1808 let preload = vec![ea, eb, ec];
1809 run_delete_test!(
1810 Ok(()),
1811 preload,
1812 filter!(f_eq(
1813 Attribute::Uuid,
1814 PartialValue::new_uuid_s(UUID_A).unwrap()
1815 )),
1816 None,
1817 |qs: &mut QueryServerWriteTransaction| {
1818 assert_not_memberof!(qs, UUID_B, UUID_A);
1821 assert_not_memberof!(qs, UUID_B, UUID_B);
1822 assert_not_memberof!(qs, UUID_B, UUID_C);
1823
1824 assert_not_memberof!(qs, UUID_C, UUID_A);
1825 assert_memberof!(qs, UUID_C, UUID_B);
1826 assert_not_memberof!(qs, UUID_C, UUID_C);
1827
1828 assert_not_dirmemberof!(qs, UUID_B, UUID_A);
1829 assert_not_dirmemberof!(qs, UUID_B, UUID_B);
1830 assert_not_dirmemberof!(qs, UUID_B, UUID_C);
1831
1832 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
1833 assert_dirmemberof!(qs, UUID_C, UUID_B);
1834 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
1835 }
1836 );
1837 }
1838
1839 #[test]
1840 fn test_delete_mo_multi_cycle() {
1841 let mut ea = EA.clone();
1845 let mut eb = EB.clone();
1846 let mut ec = EC.clone();
1847 let mut ed = ED.clone();
1848
1849 ea.add_ava(Attribute::Member, Value::new_refer_s(UUID_B).unwrap());
1850 ea.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1851 ea.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1852 ea.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_C).unwrap());
1853 ea.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_D).unwrap());
1854
1855 eb.add_ava(Attribute::Member, Value::new_refer_s(UUID_C).unwrap());
1856 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1857 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1858 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_C).unwrap());
1859 eb.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_D).unwrap());
1860
1861 ec.add_ava(Attribute::Member, Value::new_refer_s(UUID_A).unwrap());
1862 ec.add_ava(Attribute::Member, Value::new_refer_s(UUID_D).unwrap());
1863 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1864 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1865 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_C).unwrap());
1866 ec.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_D).unwrap());
1867
1868 ed.add_ava(Attribute::Member, Value::new_refer_s(UUID_A).unwrap());
1869 ed.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_A).unwrap());
1870 ed.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_B).unwrap());
1871 ed.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_C).unwrap());
1872 ed.add_ava(Attribute::MemberOf, Value::new_refer_s(UUID_D).unwrap());
1873
1874 let preload = vec![ea, eb, ec, ed];
1875 run_delete_test!(
1876 Ok(()),
1877 preload,
1878 filter!(f_eq(
1879 Attribute::Uuid,
1880 PartialValue::new_uuid_s(UUID_B).unwrap()
1881 )),
1882 None,
1883 |qs: &mut QueryServerWriteTransaction| {
1884 assert_not_memberof!(qs, UUID_A, UUID_B);
1887 assert_not_memberof!(qs, UUID_A, UUID_A);
1888 assert_memberof!(qs, UUID_A, UUID_C);
1889 assert_memberof!(qs, UUID_A, UUID_D);
1890
1891 assert_not_memberof!(qs, UUID_C, UUID_A);
1892 assert_not_memberof!(qs, UUID_C, UUID_B);
1893 assert_not_memberof!(qs, UUID_C, UUID_C);
1894 assert_not_memberof!(qs, UUID_C, UUID_D);
1895
1896 assert_not_memberof!(qs, UUID_D, UUID_A);
1897 assert_not_memberof!(qs, UUID_D, UUID_B);
1898 assert_memberof!(qs, UUID_D, UUID_C);
1899 assert_not_memberof!(qs, UUID_D, UUID_D);
1900
1901 assert_not_dirmemberof!(qs, UUID_A, UUID_A);
1902 assert_not_dirmemberof!(qs, UUID_A, UUID_B);
1903 assert_dirmemberof!(qs, UUID_A, UUID_C);
1904 assert_dirmemberof!(qs, UUID_A, UUID_D);
1905
1906 assert_not_dirmemberof!(qs, UUID_C, UUID_A);
1907 assert_not_dirmemberof!(qs, UUID_C, UUID_B);
1908 assert_not_dirmemberof!(qs, UUID_C, UUID_C);
1909 assert_not_dirmemberof!(qs, UUID_C, UUID_D);
1910
1911 assert_not_dirmemberof!(qs, UUID_D, UUID_A);
1912 assert_not_dirmemberof!(qs, UUID_C, UUID_B);
1913 assert_dirmemberof!(qs, UUID_D, UUID_C);
1914 assert_not_dirmemberof!(qs, UUID_D, UUID_D);
1915 }
1916 );
1917 }
1918}