diff --git a/pallets/ddc-nodes/src/benchmarking.rs b/pallets/ddc-nodes/src/benchmarking.rs index 90559d4c3..b1ae3e629 100644 --- a/pallets/ddc-nodes/src/benchmarking.rs +++ b/pallets/ddc-nodes/src/benchmarking.rs @@ -51,4 +51,10 @@ benchmarks! { p2p_port: 65000u16, }); } + + impl_benchmark_test_suite!( + DdcNodes, + crate::mock::ExtBuilder.build(), + crate::mock::Test, + ); } diff --git a/pallets/ddc-nodes/src/lib.rs b/pallets/ddc-nodes/src/lib.rs index 42beeca36..a6ce51fb7 100644 --- a/pallets/ddc-nodes/src/lib.rs +++ b/pallets/ddc-nodes/src/lib.rs @@ -144,6 +144,7 @@ pub mod pallet { fn delete(node_pub_key: NodePubKey) -> Result<(), NodeRepositoryError>; } + #[derive(Debug, PartialEq)] pub enum NodeRepositoryError { StorageNodeAlreadyExists, CDNNodeAlreadyExists, diff --git a/pallets/ddc-nodes/src/mock.rs b/pallets/ddc-nodes/src/mock.rs index 0b67ca60d..8a4be3286 100644 --- a/pallets/ddc-nodes/src/mock.rs +++ b/pallets/ddc-nodes/src/mock.rs @@ -117,7 +117,7 @@ pub(crate) type TestRuntimeCall = ::RuntimeCall; pub struct ExtBuilder; impl ExtBuilder { - fn build(self) -> TestExternalities { + pub fn build(self) -> TestExternalities { sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); diff --git a/pallets/ddc-nodes/src/node.rs b/pallets/ddc-nodes/src/node.rs index 93cdba545..99fbdea81 100644 --- a/pallets/ddc-nodes/src/node.rs +++ b/pallets/ddc-nodes/src/node.rs @@ -102,6 +102,7 @@ impl NodeTrait for Node { } } +#[derive(Debug, PartialEq)] pub enum NodeError { InvalidStorageNodePubKey, InvalidCDNNodePubKey, diff --git a/pallets/ddc-nodes/src/tests.rs b/pallets/ddc-nodes/src/tests.rs index e0fc0f599..c678de436 100644 --- a/pallets/ddc-nodes/src/tests.rs +++ b/pallets/ddc-nodes/src/tests.rs @@ -7,7 +7,7 @@ use sp_runtime::AccountId32; use super::{mock::*, *}; #[test] -fn create_node_works() { +fn create_cdn_node_works() { ExtBuilder.build_and_execute(|| { System::set_block_number(1); let bytes = [0u8; 32]; @@ -34,6 +34,31 @@ fn create_node_works() { Error::::InvalidNodeParams ); + // Pub key invalid + assert_noop!( + CDNNode::::new( + NodePubKey::StoragePubKey(node_pub_key.clone()), + 1u64, + NodeParams::CDNParams(cdn_node_params.clone()) + ), + NodeError::InvalidCDNNodePubKey + ); + + // Host length exceeds limit + assert_noop!( + DdcNodes::create_node( + RuntimeOrigin::signed(1), + NodePubKey::CDNPubKey(node_pub_key.clone()), + NodeParams::CDNParams(CDNNodeParams { + host: vec![1u8; 256], + http_port: 35000u16, + grpc_port: 25000u16, + p2p_port: 15000u16, + }) + ), + Error::::HostLenExceedsLimit + ); + // Node created assert_ok!(DdcNodes::create_node( RuntimeOrigin::signed(1), @@ -41,6 +66,17 @@ fn create_node_works() { NodeParams::CDNParams(cdn_node_params.clone()) )); + // Check storage + assert!(CDNNodes::::contains_key(node_pub_key.clone())); + assert!(DdcNodes::exists(&NodePubKey::CDNPubKey(node_pub_key.clone()))); + if let Ok(cluster_id) = + DdcNodes::get_cluster_id(&NodePubKey::CDNPubKey(node_pub_key.clone())) + { + assert_eq!(cluster_id, None); + } + let cdn_node = DdcNodes::cdn_nodes(&node_pub_key).unwrap(); + assert_eq!(cdn_node.pub_key, node_pub_key); + // Node already exists assert_noop!( DdcNodes::create_node( @@ -60,7 +96,162 @@ fn create_node_works() { } #[test] -fn set_node_params_works() { +fn create_cdn_node_with_node_creator() { + ExtBuilder.build_and_execute(|| { + System::set_block_number(1); + let bytes = [0u8; 32]; + let node_pub_key = AccountId32::from(bytes); + let cdn_node_params = CDNNodeParams { + host: vec![1u8, 255], + http_port: 35000u16, + grpc_port: 25000u16, + p2p_port: 15000u16, + }; + + // Node created + assert_ok!(>::create_node( + NodePubKey::CDNPubKey(node_pub_key.clone()), + 1u64, + NodeParams::CDNParams(cdn_node_params) + )); + + // Check storage + assert!(CDNNodes::::contains_key(node_pub_key.clone())); + assert!(DdcNodes::exists(&NodePubKey::CDNPubKey(node_pub_key.clone()))); + if let Ok(cluster_id) = + DdcNodes::get_cluster_id(&NodePubKey::CDNPubKey(node_pub_key.clone())) + { + assert_eq!(cluster_id, None); + } + let cdn_node = DdcNodes::cdn_nodes(&node_pub_key).unwrap(); + assert_eq!(cdn_node.pub_key, node_pub_key); + }) +} + +#[test] +fn create_storage_node_works() { + ExtBuilder.build_and_execute(|| { + System::set_block_number(1); + let bytes = [0u8; 32]; + let node_pub_key = AccountId32::from(bytes); + let storage_node_params = StorageNodeParams { + host: vec![1u8, 255], + http_port: 35000u16, + grpc_port: 25000u16, + p2p_port: 15000u16, + }; + + // Node params are not valid + assert_noop!( + DdcNodes::create_node( + RuntimeOrigin::signed(1), + NodePubKey::StoragePubKey(node_pub_key.clone()), + NodeParams::CDNParams(CDNNodeParams { + host: vec![1u8, 255], + http_port: 35000u16, + grpc_port: 25000u16, + p2p_port: 15000u16, + }) + ), + Error::::InvalidNodeParams + ); + + // Pub key invalid + assert_noop!( + StorageNode::::new( + NodePubKey::CDNPubKey(node_pub_key.clone()), + 1u64, + NodeParams::StorageParams(storage_node_params.clone()) + ), + NodeError::InvalidStorageNodePubKey + ); + + // Host length exceeds limit + assert_noop!( + DdcNodes::create_node( + RuntimeOrigin::signed(1), + NodePubKey::StoragePubKey(node_pub_key.clone()), + NodeParams::StorageParams(StorageNodeParams { + host: vec![1u8; 256], + http_port: 35000u16, + grpc_port: 25000u16, + p2p_port: 15000u16, + }) + ), + Error::::HostLenExceedsLimit + ); + + // Node created + assert_ok!(DdcNodes::create_node( + RuntimeOrigin::signed(1), + NodePubKey::StoragePubKey(node_pub_key.clone()), + NodeParams::StorageParams(storage_node_params.clone()) + )); + + // Check storage + assert!(StorageNodes::::contains_key(node_pub_key.clone())); + assert!(DdcNodes::exists(&NodePubKey::StoragePubKey(node_pub_key.clone()))); + if let Ok(cluster_id) = + DdcNodes::get_cluster_id(&NodePubKey::StoragePubKey(node_pub_key.clone())) + { + assert_eq!(cluster_id, None); + } + let storage_node = DdcNodes::storage_nodes(&node_pub_key).unwrap(); + assert_eq!(storage_node.pub_key, node_pub_key); + + // Node already exists + assert_noop!( + DdcNodes::create_node( + RuntimeOrigin::signed(1), + NodePubKey::StoragePubKey(node_pub_key.clone()), + NodeParams::StorageParams(storage_node_params) + ), + Error::::NodeAlreadyExists + ); + + // Checking that event was emitted + assert_eq!(System::events().len(), 1); + System::assert_last_event( + Event::NodeCreated { node_pub_key: NodePubKey::StoragePubKey(node_pub_key) }.into(), + ) + }) +} + +#[test] +fn create_storage_node_with_node_creator() { + ExtBuilder.build_and_execute(|| { + System::set_block_number(1); + let bytes = [0u8; 32]; + let node_pub_key = AccountId32::from(bytes); + let storage_node_params = StorageNodeParams { + host: vec![1u8, 255], + http_port: 35000u16, + grpc_port: 25000u16, + p2p_port: 15000u16, + }; + + // Node created + assert_ok!(>::create_node( + NodePubKey::StoragePubKey(node_pub_key.clone()), + 1u64, + NodeParams::StorageParams(storage_node_params) + )); + + // Check storage + assert!(StorageNodes::::contains_key(node_pub_key.clone())); + assert!(DdcNodes::exists(&NodePubKey::StoragePubKey(node_pub_key.clone()))); + if let Ok(cluster_id) = + DdcNodes::get_cluster_id(&NodePubKey::StoragePubKey(node_pub_key.clone())) + { + assert_eq!(cluster_id, None); + } + let cdn_node = DdcNodes::storage_nodes(&node_pub_key).unwrap(); + assert_eq!(cdn_node.pub_key, node_pub_key); + }) +} + +#[test] +fn set_cdn_node_params_works() { ExtBuilder.build_and_execute(|| { System::set_block_number(1); let bytes = [0u8; 32]; @@ -117,11 +308,55 @@ fn set_node_params_works() { DdcNodes::set_node_params( RuntimeOrigin::signed(2), NodePubKey::CDNPubKey(node_pub_key.clone()), - NodeParams::CDNParams(cdn_node_params) + NodeParams::CDNParams(cdn_node_params.clone()) ), Error::::OnlyNodeProvider ); + // CDN host length exceeds limit + assert_noop!( + DdcNodes::set_node_params( + RuntimeOrigin::signed(1), + NodePubKey::CDNPubKey(node_pub_key.clone()), + NodeParams::CDNParams(CDNNodeParams { + host: vec![1u8; 256], + http_port: 35000u16, + grpc_port: 25000u16, + p2p_port: 15000u16, + }) + ), + Error::::HostLenExceedsLimit + ); + + let bytes_2 = [1u8; 32]; + let node_pub_key_2 = AccountId32::from(bytes_2); + let node = Node::::new( + NodePubKey::CDNPubKey(node_pub_key_2), + 2u64, + NodeParams::CDNParams(cdn_node_params), + ) + .unwrap(); + + // Update should fail if node doesn't exist + assert_noop!( + >::update(node), + NodeRepositoryError::CDNNodeDoesNotExist + ); + + assert_noop!( + DdcNodes::set_node_params( + RuntimeOrigin::signed(1), + NodePubKey::CDNPubKey(node_pub_key.clone()), + NodeParams::CDNParams(CDNNodeParams { + host: vec![1u8; 256], + http_port: 35000u16, + grpc_port: 25000u16, + p2p_port: 15000u16, + }) + ), + Error::::HostLenExceedsLimit + ); + // Checking that event was emitted assert_eq!(System::events().len(), 2); System::assert_last_event( @@ -131,7 +366,109 @@ fn set_node_params_works() { } #[test] -fn set_delete_node_works() { +fn set_storage_node_params_works() { + ExtBuilder.build_and_execute(|| { + System::set_block_number(1); + let bytes = [0u8; 32]; + let node_pub_key = AccountId32::from(bytes); + let storage_node_params = StorageNodeParams { + host: vec![1u8, 255], + http_port: 35000u16, + grpc_port: 25000u16, + p2p_port: 15000u16, + }; + let cdn_node_params = CDNNodeParams { + host: vec![1u8, 255], + http_port: 35000u16, + grpc_port: 25000u16, + p2p_port: 15000u16, + }; + + // Node doesn't exist + assert_noop!( + DdcNodes::set_node_params( + RuntimeOrigin::signed(1), + NodePubKey::StoragePubKey(node_pub_key.clone()), + NodeParams::StorageParams(storage_node_params.clone()) + ), + Error::::NodeDoesNotExist + ); + + // Node created + assert_ok!(DdcNodes::create_node( + RuntimeOrigin::signed(1), + NodePubKey::StoragePubKey(node_pub_key.clone()), + NodeParams::StorageParams(storage_node_params.clone()) + )); + + // Set node params + assert_ok!(DdcNodes::set_node_params( + RuntimeOrigin::signed(1), + NodePubKey::StoragePubKey(node_pub_key.clone()), + NodeParams::StorageParams(storage_node_params.clone()) + )); + + // Node params are not valid + assert_noop!( + DdcNodes::set_node_params( + RuntimeOrigin::signed(1), + NodePubKey::StoragePubKey(node_pub_key.clone()), + NodeParams::CDNParams(cdn_node_params) + ), + Error::::InvalidNodeParams + ); + + // Only node provider can set params + assert_noop!( + DdcNodes::set_node_params( + RuntimeOrigin::signed(2), + NodePubKey::StoragePubKey(node_pub_key.clone()), + NodeParams::StorageParams(storage_node_params.clone()) + ), + Error::::OnlyNodeProvider + ); + + let bytes_2 = [1u8; 32]; + let node_pub_key_2 = AccountId32::from(bytes_2); + let node = Node::::new( + NodePubKey::StoragePubKey(node_pub_key_2), + 2u64, + NodeParams::StorageParams(storage_node_params), + ) + .unwrap(); + + // Update should fail if node doesn't exist + assert_noop!( + >::update(node), + NodeRepositoryError::StorageNodeDoesNotExist + ); + + // Storage host length exceeds limit + assert_noop!( + DdcNodes::set_node_params( + RuntimeOrigin::signed(1), + NodePubKey::StoragePubKey(node_pub_key.clone()), + NodeParams::StorageParams(StorageNodeParams { + host: vec![1u8; 256], + http_port: 35000u16, + grpc_port: 25000u16, + p2p_port: 15000u16, + }) + ), + Error::::HostLenExceedsLimit + ); + + // Checking that event was emitted + assert_eq!(System::events().len(), 2); + System::assert_last_event( + Event::NodeParamsChanged { node_pub_key: NodePubKey::StoragePubKey(node_pub_key) } + .into(), + ) + }) +} + +#[test] +fn delete_cdn_node_works() { ExtBuilder.build_and_execute(|| { System::set_block_number(1); let bytes = [0u8; 32]; @@ -181,3 +518,55 @@ fn set_delete_node_works() { ) }) } + +#[test] +fn delete_storage_node_works() { + ExtBuilder.build_and_execute(|| { + System::set_block_number(1); + let bytes = [0u8; 32]; + let node_pub_key = AccountId32::from(bytes); + let storage_node_params = StorageNodeParams { + host: vec![1u8, 255], + http_port: 35000u16, + grpc_port: 25000u16, + p2p_port: 15000u16, + }; + + // Node doesn't exist + assert_noop!( + DdcNodes::delete_node( + RuntimeOrigin::signed(1), + NodePubKey::StoragePubKey(node_pub_key.clone()) + ), + Error::::NodeDoesNotExist + ); + + // Create node + assert_ok!(DdcNodes::create_node( + RuntimeOrigin::signed(1), + NodePubKey::StoragePubKey(node_pub_key.clone()), + NodeParams::StorageParams(storage_node_params) + )); + + // Only node provider can delete + assert_noop!( + DdcNodes::delete_node( + RuntimeOrigin::signed(2), + NodePubKey::StoragePubKey(node_pub_key.clone()) + ), + Error::::OnlyNodeProvider + ); + + // Delete node + assert_ok!(DdcNodes::delete_node( + RuntimeOrigin::signed(1), + NodePubKey::StoragePubKey(node_pub_key.clone()), + )); + + // Checking that event was emitted + assert_eq!(System::events().len(), 2); + System::assert_last_event( + Event::NodeDeleted { node_pub_key: NodePubKey::StoragePubKey(node_pub_key) }.into(), + ) + }) +}