Skip to content

Commit

Permalink
test: add tests for xline sp/ucp pools
Browse files Browse the repository at this point in the history
Signed-off-by: bsbds <[email protected]>
  • Loading branch information
bsbds committed Apr 19, 2024
1 parent 6e0a111 commit 3de0765
Show file tree
Hide file tree
Showing 5 changed files with 239 additions and 3 deletions.
2 changes: 1 addition & 1 deletion crates/curp/src/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -909,7 +909,7 @@ impl<C> From<Vec<ConfChange>> for PoolEntryInner<C> {
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]
Expand Down
7 changes: 7 additions & 0 deletions crates/curp/src/server/conflict/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ pub struct CommandEntry<C> {
cmd: Arc<C>,
}

impl<C> CommandEntry<C> {
/// Creates a new `CommandEntry`
pub fn new(id: ProposeId, cmd: Arc<C>) -> Self {
Self { id, cmd }
}
}

impl<C> Clone for CommandEntry<C> {
#[inline]
fn clone(&self) -> Self {
Expand Down
4 changes: 4 additions & 0 deletions crates/xline/src/conflict/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<C>(entry: &C) -> Vec<Interval<BytesAffine>>
where
Expand Down
221 changes: 221 additions & 0 deletions crates/xline/src/conflict/tests.rs
Original file line number Diff line number Diff line change
@@ -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<Command> {
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<Command> {
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<Command> {
self.gen_entry(
vec![],
RequestWrapper::LeaseGrantRequest(LeaseGrantRequest {
id,
..Default::default()
}),
)
}

fn gen_lease_revoke(&mut self, id: i64) -> CommandEntry<Command> {
self.gen_entry(
vec![],
RequestWrapper::LeaseRevokeRequest(LeaseRevokeRequest { id }),
)
}

fn gen_auth_enable(&mut self) -> CommandEntry<Command> {
self.gen_entry(
vec![],
RequestWrapper::AuthEnableRequest(AuthEnableRequest {}),
)
}

fn gen_role_add(&mut self) -> CommandEntry<Command> {
self.gen_entry(
vec![],
RequestWrapper::AuthRoleAddRequest(AuthRoleAddRequest::default()),
)
}

fn gen_entry(&mut self, keys: Vec<KeyRange>, req: RequestWrapper) -> CommandEntry<Command> {
self.id += 1;
let cmd = Command::new(keys, req);
CommandEntry::new(ProposeId(0, self.id), Arc::new(cmd))
}
}
8 changes: 6 additions & 2 deletions crates/xline/src/conflict/uncommitted_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}

Expand Down Expand Up @@ -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()
}
}

Expand Down

0 comments on commit 3de0765

Please sign in to comment.