Skip to content

Commit

Permalink
feat(clone): add bdd case for snapshots and clone with io-engine-test…
Browse files Browse the repository at this point in the history
… framework

Signed-off-by: Hrudaya <[email protected]>
  • Loading branch information
hrudaya21 committed Aug 1, 2023
1 parent fa3d8fa commit efb75c7
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 1 deletion.
1 change: 1 addition & 0 deletions io-engine-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub mod nvme;
pub mod nvmf;
pub mod pool;
pub mod replica;
pub mod snapshot;

pub use compose::MayastorTest;

Expand Down
1 change: 1 addition & 0 deletions io-engine-tests/src/replica.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use mayastor_api::v1::replica::{
ReplicaType,
ShareReplicaRequest,
};

use tonic::{Code, Status};

#[derive(Clone)]
Expand Down
199 changes: 199 additions & 0 deletions io-engine-tests/src/snapshot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
use super::{compose::rpc::v1::SharedRpcHandle, generate_uuid};

use mayastor_api::v1::snapshot::{
CreateReplicaSnapshotRequest,
CreateReplicaSnapshotResponse,
CreateSnapshotCloneRequest,
ListSnapshotCloneRequest,
// ListSnapshotCloneResponse,
ListSnapshotsRequest,
// ListSnapshotsResponse,
Replica,
SnapshotInfo,
SnapshotQueryType,
};
use tonic::Status;

pub struct ReplicaSnapshotBuilder {
pub rpc: SharedRpcHandle,
pub replica_uuid: Option<String>,
pub snapshot_uuid: Option<String>,
pub snapshot_name: Option<String>,
pub entity_id: Option<String>,
pub txn_id: Option<String>,
}
impl ReplicaSnapshotBuilder {
pub fn new(rpc: SharedRpcHandle) -> Self {
Self {
rpc,
replica_uuid: None,
snapshot_uuid: None,
snapshot_name: None,
entity_id: None,
txn_id: None,
}
}
pub fn with_replica_uuid(mut self, replica_uuid: &str) -> Self {
self.replica_uuid = Some(replica_uuid.to_owned());
self
}
pub fn with_snapshot_uuid(mut self) -> Self {
self.snapshot_uuid = Some(generate_uuid());
self
}
pub fn with_snapshot_name(mut self, snap_name: &str) -> Self {
self.snapshot_name = Some(snap_name.to_owned());
self
}
pub fn with_entity_id(mut self, entity_id: &str) -> Self {
self.entity_id = Some(entity_id.to_owned());
self
}
pub fn with_txn_id(mut self, txn_id: &str) -> Self {
self.txn_id = Some(txn_id.to_owned());
self
}
pub fn snapshot_uuid(&self) -> String {
self.snapshot_uuid
.as_ref()
.expect("Snapshot UUID must be set")
.clone()
}
pub fn replica_uuid(&self) -> String {
self.replica_uuid
.as_ref()
.expect("Replica UUID must be set")
.clone()
}
pub fn snapshot_name(&self) -> String {
self.snapshot_name
.as_ref()
.expect("Snapshot name must be set")
.clone()
}
pub fn rpc(&self) -> SharedRpcHandle {
self.rpc.clone()
}
pub async fn create_replica_snapshot(
&mut self,
) -> Result<CreateReplicaSnapshotResponse, Status> {
self.rpc()
.lock()
.await
.snapshot
.create_replica_snapshot(CreateReplicaSnapshotRequest {
replica_uuid: self.replica_uuid(),
snapshot_uuid: self.snapshot_uuid(),
snapshot_name: self.snapshot_name(),
entity_id: self.entity_id.as_ref().unwrap().to_string(),
txn_id: self.txn_id.as_ref().unwrap().to_string(),
})
.await
.map(|r| r.into_inner())
}
pub async fn get_snapshots(&self) -> Result<Vec<SnapshotInfo>, Status> {
Ok(list_snapshot(self.rpc())
.await
.expect("List Snapshot Failed")
.into_iter()
.filter(|s| s.source_uuid == self.replica_uuid())
.collect::<Vec<_>>())
}
}
pub async fn list_snapshot(
rpc: SharedRpcHandle,
) -> Result<Vec<SnapshotInfo>, Status> {
rpc.lock()
.await
.snapshot
.list_snapshot(ListSnapshotsRequest {
source_uuid: None,
snapshot_uuid: None,
snapshot_query_type: SnapshotQueryType::AllSnapshots as i32,
})
.await
.map(|r| r.into_inner().snapshots)
}

pub struct SnapshotCloneBuilder {
pub rpc: SharedRpcHandle,
pub snapshot_uuid: Option<String>,
pub clone_name: Option<String>,
pub clone_uuid: Option<String>,
}
impl SnapshotCloneBuilder {
pub fn new(rpc: SharedRpcHandle) -> Self {
Self {
rpc,
snapshot_uuid: None,
clone_name: None,
clone_uuid: None,
}
}
pub fn with_snapshot_uuid(mut self, snapshot_uuid: &str) -> Self {
self.snapshot_uuid = Some(snapshot_uuid.to_owned());
self
}
pub fn with_clone_name(mut self, clone_name: &str) -> Self {
self.clone_name = Some(clone_name.to_owned());
self
}
pub fn with_clone_uuid(mut self, clone_uuid: &str) -> Self {
self.clone_uuid = Some(clone_uuid.to_owned());
self
}
pub fn rpc(&self) -> SharedRpcHandle {
self.rpc.clone()
}
pub fn snapshot_uuid(&self) -> String {
self.snapshot_uuid
.as_ref()
.expect("snapshot_uuid must be set")
.clone()
}
pub fn clone_name(&self) -> String {
self.clone_name
.as_ref()
.expect("clone_name must be set")
.clone()
}
pub fn clone_uuid(&self) -> String {
self.clone_uuid
.as_ref()
.expect("clone_uuid must be set")
.clone()
}
pub async fn create_snapshot_clone(&mut self) -> Result<Replica, Status> {
self.rpc()
.lock()
.await
.snapshot
.create_snapshot_clone(CreateSnapshotCloneRequest {
snapshot_uuid: self.snapshot_uuid(),
clone_name: self.clone_name(),
clone_uuid: self.clone_uuid(),
})
.await
.map(|r| r.into_inner())
}
pub async fn get_clones(&self) -> Result<Vec<Replica>, Status> {
Ok(list_snapshot_clone(self.rpc())
.await
.expect("List Clone Failed")
.into_iter()
.filter(|s| s.snapshot_uuid == Some(self.snapshot_uuid()))
.collect::<Vec<_>>())
}
}
pub async fn list_snapshot_clone(
rpc: SharedRpcHandle,
) -> Result<Vec<Replica>, Status> {
rpc.lock()
.await
.snapshot
.list_snapshot_clone(ListSnapshotCloneRequest {
snapshot_uuid: None,
})
.await
.map(|r| r.into_inner().replicas)
}
1 change: 0 additions & 1 deletion io-engine/src/grpc/v1/replica.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use crate::{
Protocol,
Share,
ShareProps,
SnapshotOps,
UntypedBdev,
UpdateProps,
},
Expand Down
89 changes: 89 additions & 0 deletions io-engine/tests/snapshot_lvol.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
pub mod common;

use common::{
compose::{rpc::v1::GrpcConnect, Binary, Builder},
pool::PoolBuilder,
replica::ReplicaBuilder,
snapshot::ReplicaSnapshotBuilder,
};
use io_engine_tests::{
file_io::DataSize,
nvmf::test_write_to_nvmf,
replica::validate_replicas,
snapshot::SnapshotCloneBuilder,
};

use once_cell::sync::OnceCell;

use common::{bdev_io, compose::MayastorTest};
Expand Down Expand Up @@ -1384,3 +1397,79 @@ async fn test_delete_snapshot_with_valid_clone_fail_1() {
})
.await;
}

#[tokio::test]
async fn test_snapshot_verify_restore_data() {
common::composer_init();

let test = Builder::new()
.name("cargo-test")
.network("10.1.0.0/16")
.unwrap()
.add_container_bin(
"ms",
Binary::from_dbg("io-engine").with_args(vec!["-l", "1,2,3,4"]),
)
.with_clean(true)
.build()
.await
.unwrap();

let conn = GrpcConnect::new(&test);

let ms = conn.grpc_handle_shared("ms").await.unwrap();

const POOL_SIZE: u64 = 200;
const REPL_SIZE: u64 = 40;

let mut pool = PoolBuilder::new(ms.clone())
.with_name("pool0")
.with_new_uuid()
.with_malloc("mem0", POOL_SIZE);
let mut repl_1 = ReplicaBuilder::new(ms.clone())
.with_pool(&pool)
.with_name("repl1")
.with_new_uuid()
.with_size_mb(REPL_SIZE)
.with_thin(false);
// Create pool.
pool.create().await.unwrap();
// Create replica.
repl_1.create().await.unwrap();
// Share replica.
repl_1.share().await.unwrap();
// Write some data to replica.
test_write_to_nvmf(
&repl_1.nvmf_location(),
DataSize::from_bytes(0),
30,
DataSize::from_mb(1),
)
.await
.unwrap();
// Create snapshot for the replica.
let mut snap_1 = ReplicaSnapshotBuilder::new(ms.clone())
.with_replica_uuid(repl_1.uuid().as_str())
.with_snapshot_uuid()
.with_snapshot_name("snap1")
.with_entity_id("snap1_e1")
.with_txn_id("snap1-t1");
snap_1.create_replica_snapshot().await.unwrap();

// Create a clone from the replica.
let mut clone_1 = SnapshotCloneBuilder::new(ms.clone())
.with_snapshot_uuid(snap_1.snapshot_uuid().as_str())
.with_clone_name("clone1")
.with_clone_uuid(Uuid::new_v4().to_string().as_str());
clone_1.create_snapshot_clone().await.unwrap();

// Create restore object.
let mut restore_1 = ReplicaBuilder::new(ms.clone())
.with_uuid(clone_1.clone_uuid().as_str())
.with_name(clone_1.clone_name().as_str());

restore_1.share().await.unwrap();

// Check the original replica and restore clone is identical.
validate_replicas(&vec![repl_1.clone(), restore_1.clone()]).await;
}

0 comments on commit efb75c7

Please sign in to comment.