From 3de0765837f49c061fa1dedc888f7e5c3dd1a5c0 Mon Sep 17 00:00:00 2001 From: bsbds <69835502+bsbds@users.noreply.github.com> Date: Fri, 19 Apr 2024 17:24:07 +0800 Subject: [PATCH] test: add tests for xline sp/ucp pools Signed-off-by: bsbds <69835502+bsbds@users.noreply.github.com> --- crates/curp/src/rpc/mod.rs | 2 +- crates/curp/src/server/conflict/mod.rs | 7 + crates/xline/src/conflict/mod.rs | 4 + crates/xline/src/conflict/tests.rs | 221 ++++++++++++++++++ crates/xline/src/conflict/uncommitted_pool.rs | 8 +- 5 files changed, 239 insertions(+), 3 deletions(-) create mode 100644 crates/xline/src/conflict/tests.rs diff --git a/crates/curp/src/rpc/mod.rs b/crates/curp/src/rpc/mod.rs index 16a7c77ea8..601c1367a3 100644 --- a/crates/curp/src/rpc/mod.rs +++ b/crates/curp/src/rpc/mod.rs @@ -909,7 +909,7 @@ impl From> for PoolEntryInner { Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Ord, PartialOrd, Default, )] #[allow(clippy::exhaustive_structs)] // It is exhaustive -pub struct ProposeId(pub(crate) u64, pub(crate) u64); +pub struct ProposeId(pub u64, pub u64); impl std::fmt::Display for ProposeId { #[inline] diff --git a/crates/curp/src/server/conflict/mod.rs b/crates/curp/src/server/conflict/mod.rs index eb51864001..f504fd4375 100644 --- a/crates/curp/src/server/conflict/mod.rs +++ b/crates/curp/src/server/conflict/mod.rs @@ -51,6 +51,13 @@ pub struct CommandEntry { cmd: Arc, } +impl CommandEntry { + /// Creates a new `CommandEntry` + pub fn new(id: ProposeId, cmd: Arc) -> Self { + Self { id, cmd } + } +} + impl Clone for CommandEntry { #[inline] fn clone(&self) -> Self { diff --git a/crates/xline/src/conflict/mod.rs b/crates/xline/src/conflict/mod.rs index d0823dc6b9..d9b56844d3 100644 --- a/crates/xline/src/conflict/mod.rs +++ b/crates/xline/src/conflict/mod.rs @@ -7,6 +7,10 @@ pub(crate) mod spec_pool; /// Uncommitted pool implementations pub(crate) mod uncommitted_pool; +/// Tests +#[cfg(test)] +mod tests; + /// Returns command intervals fn intervals(entry: &C) -> Vec> where diff --git a/crates/xline/src/conflict/tests.rs b/crates/xline/src/conflict/tests.rs new file mode 100644 index 0000000000..5b3dc467a8 --- /dev/null +++ b/crates/xline/src/conflict/tests.rs @@ -0,0 +1,221 @@ +use std::sync::Arc; + +use curp::{rpc::ProposeId, server::conflict::CommandEntry}; +use curp_external_api::conflict::{ConflictPoolOp, SpeculativePoolOp, UncommittedPoolOp}; +use xlineapi::{ + command::{Command, KeyRange}, + AuthEnableRequest, AuthRoleAddRequest, DeleteRangeRequest, LeaseGrantRequest, + LeaseRevokeRequest, PutRequest, RequestWrapper, +}; + +use crate::conflict::{ + spec_pool::ExclusiveSpecPool, + uncommitted_pool::{ExclusiveUncomPool, KvUncomPool, LeaseUncomPool}, +}; + +use super::spec_pool::{KvSpecPool, LeaseSpecPool}; + +#[test] +fn kv_sp_operations_is_ok() { + let mut sp = KvSpecPool::default(); + let mut gen = EntryGenerator::default(); + let entry1 = gen.gen_put("a"); + let entry2 = gen.gen_put("b"); + let entry3 = gen.gen_delete_range("a", "d"); + let entry4 = gen.gen_delete_range("c", "e"); + assert!(sp.insert_if_not_conflict(entry1.clone()).is_none()); + assert!(sp.insert_if_not_conflict(entry1.clone()).is_some()); + assert!(sp.insert_if_not_conflict(entry2.clone()).is_none()); + assert!(sp.insert_if_not_conflict(entry3.clone()).is_some()); + assert!(sp.insert_if_not_conflict(entry4.clone()).is_none()); + assert_eq!(sp.all().len(), 3); + assert_eq!(sp.len(), 3); + sp.remove(entry1.clone()); + assert!(sp.insert_if_not_conflict(entry3.clone()).is_some()); + sp.remove(entry2.clone()); + assert!(sp.insert_if_not_conflict(entry3.clone()).is_some()); + sp.remove(entry4.clone()); + assert!(sp.insert_if_not_conflict(entry3.clone()).is_none()); + sp.clear(); + assert!(sp.is_empty()); + assert_eq!(sp.len(), 0); +} + +#[test] +fn kv_ucp_operations_is_ok() { + let mut ucp = KvUncomPool::default(); + let mut gen = EntryGenerator::default(); + let entry1 = gen.gen_put("a"); + let entry2 = gen.gen_put("a"); + let entry3 = gen.gen_put("b"); + let entry4 = gen.gen_delete_range("a", "d"); + let entry5 = gen.gen_delete_range("c", "e"); + let entry6 = gen.gen_delete_range("c", "f"); + assert!(!ucp.insert(entry1.clone())); + assert!(ucp.insert(entry2.clone())); + assert!(!ucp.insert(entry3.clone())); + assert!(ucp.insert(entry4.clone())); + assert!(ucp.insert(entry5.clone())); + assert_eq!(ucp.all().len(), 5); + assert_eq!(ucp.len(), 5); + assert_eq!(ucp.all_conflict(&entry1).len(), 3); + assert_eq!(ucp.all_conflict(&entry6).len(), 2); + ucp.remove(entry4.clone()); + ucp.remove(entry5.clone()); + assert!(!ucp.insert(entry6.clone())); + ucp.clear(); + assert!(ucp.is_empty()); + assert_eq!(ucp.len(), 0); +} + +#[test] +fn lease_sp_operations_is_ok() { + let mut sp = LeaseSpecPool::default(); + let mut gen = EntryGenerator::default(); + let entry1 = gen.gen_lease_grant(0); + let entry2 = gen.gen_lease_grant(1); + let entry3 = gen.gen_lease_revoke(0); + let entry4 = gen.gen_lease_revoke(1); + assert!(sp.insert_if_not_conflict(entry1.clone()).is_none()); + assert!(sp.insert_if_not_conflict(entry1.clone()).is_some()); + assert!(sp.insert_if_not_conflict(entry2.clone()).is_none()); + assert!(sp.insert_if_not_conflict(entry3.clone()).is_some()); + assert!(sp.insert_if_not_conflict(entry4.clone()).is_some()); + assert_eq!(sp.all().len(), 2); + assert_eq!(sp.len(), 2); + sp.remove(entry1); + sp.remove(entry2); + assert!(sp.insert_if_not_conflict(entry3).is_none()); + assert!(sp.insert_if_not_conflict(entry4).is_none()); + sp.clear(); + assert!(sp.is_empty()); + assert_eq!(sp.len(), 0); +} + +#[test] +fn lease_ucp_operations_is_ok() { + let mut ucp = LeaseUncomPool::default(); + let mut gen = EntryGenerator::default(); + let entry1 = gen.gen_lease_grant(0); + let entry2 = gen.gen_lease_grant(0); + let entry3 = gen.gen_lease_grant(1); + let entry4 = gen.gen_lease_revoke(0); + let entry5 = gen.gen_lease_revoke(1); + assert!(!ucp.insert(entry1.clone())); + assert!(ucp.insert(entry2.clone())); + assert!(!ucp.insert(entry3.clone())); + assert!(ucp.insert(entry4.clone())); + assert!(ucp.insert(entry5.clone())); + assert_eq!(ucp.all().len(), 5); + assert_eq!(ucp.len(), 5); + assert_eq!(ucp.all_conflict(&entry1).len(), 3); + assert_eq!(ucp.all_conflict(&entry3).len(), 2); + ucp.remove(entry3.clone()); + ucp.remove(entry5.clone()); + assert!(!ucp.insert(entry5.clone())); + ucp.clear(); + assert!(ucp.is_empty()); + assert_eq!(ucp.len(), 0); +} + +#[test] +fn exclusive_sp_operations_is_ok() { + let mut sp = ExclusiveSpecPool::default(); + let mut gen = EntryGenerator::default(); + let entry1 = gen.gen_auth_enable(); + let entry2 = gen.gen_role_add(); + assert!(sp.insert_if_not_conflict(entry1.clone()).is_some()); + assert!(sp.insert_if_not_conflict(entry1.clone()).is_some()); + assert!(sp.insert_if_not_conflict(entry2.clone()).is_some()); + assert_eq!(sp.all().len(), 1); + assert_eq!(sp.len(), 1); + sp.remove(entry1); + assert!(sp.insert_if_not_conflict(entry2).is_some()); + sp.clear(); + assert!(sp.is_empty()); + assert_eq!(sp.len(), 0); +} + +#[test] +fn exclusive_ucp_operations_is_ok() { + let mut ucp = ExclusiveUncomPool::default(); + let mut gen = EntryGenerator::default(); + let entry1 = gen.gen_auth_enable(); + let entry2 = gen.gen_role_add(); + assert!(ucp.insert(entry1.clone())); + assert!(ucp.insert(entry2.clone())); + assert_eq!(ucp.all().len(), 2); + assert_eq!(ucp.all_conflict(&entry1).len(), 2); + assert_eq!(ucp.len(), 2); + ucp.remove(entry1.clone()); + ucp.remove(entry2.clone()); + assert!(ucp.insert(entry1.clone())); + ucp.clear(); + assert!(ucp.is_empty()); + assert_eq!(ucp.len(), 0); +} + +#[derive(Default)] +struct EntryGenerator { + id: u64, +} + +impl EntryGenerator { + fn gen_put(&mut self, key: &str) -> CommandEntry { + self.gen_entry( + vec![KeyRange::new_one_key(key)], + RequestWrapper::PutRequest(PutRequest { + key: key.as_bytes().to_vec(), + ..Default::default() + }), + ) + } + + fn gen_delete_range(&mut self, key: &str, range_end: &str) -> CommandEntry { + self.gen_entry( + vec![KeyRange::new(key, range_end)], + RequestWrapper::DeleteRangeRequest(DeleteRangeRequest { + key: key.as_bytes().to_vec(), + range_end: range_end.as_bytes().to_vec(), + ..Default::default() + }), + ) + } + + fn gen_lease_grant(&mut self, id: i64) -> CommandEntry { + self.gen_entry( + vec![], + RequestWrapper::LeaseGrantRequest(LeaseGrantRequest { + id, + ..Default::default() + }), + ) + } + + fn gen_lease_revoke(&mut self, id: i64) -> CommandEntry { + self.gen_entry( + vec![], + RequestWrapper::LeaseRevokeRequest(LeaseRevokeRequest { id }), + ) + } + + fn gen_auth_enable(&mut self) -> CommandEntry { + self.gen_entry( + vec![], + RequestWrapper::AuthEnableRequest(AuthEnableRequest {}), + ) + } + + fn gen_role_add(&mut self) -> CommandEntry { + self.gen_entry( + vec![], + RequestWrapper::AuthRoleAddRequest(AuthRoleAddRequest::default()), + ) + } + + fn gen_entry(&mut self, keys: Vec, req: RequestWrapper) -> CommandEntry { + self.id += 1; + let cmd = Command::new(keys, req); + CommandEntry::new(ProposeId(0, self.id), Arc::new(cmd)) + } +} diff --git a/crates/xline/src/conflict/uncommitted_pool.rs b/crates/xline/src/conflict/uncommitted_pool.rs index 1aa32d0cd3..25f3fefee4 100644 --- a/crates/xline/src/conflict/uncommitted_pool.rs +++ b/crates/xline/src/conflict/uncommitted_pool.rs @@ -54,7 +54,7 @@ impl ConflictPoolOp for KvUncomPool { } fn len(&self) -> usize { - self.map.len() + self.map.iter().flat_map(|(_, v)| v.all()).unique().count() } } @@ -125,7 +125,11 @@ impl ConflictPoolOp for LeaseUncomPool { } fn len(&self) -> usize { - self.leases.len() + self.leases + .iter() + .flat_map(|(_, v)| v.all()) + .unique() + .count() } }