|
@@ -2,25 +2,24 @@
|
|
|
|
|
|
use crate::*;
|
|
|
|
|
|
+use frame_support::dispatch::{DispatchError, DispatchResult};
|
|
|
use frame_support::traits::{OnFinalize, OnInitialize};
|
|
|
use frame_support::{impl_outer_event, impl_outer_origin, parameter_types};
|
|
|
use sp_core::H256;
|
|
|
use sp_runtime::{
|
|
|
testing::Header,
|
|
|
traits::{BlakeTwo256, IdentityLookup},
|
|
|
- Perbill,
|
|
|
+ ModuleId, Perbill,
|
|
|
};
|
|
|
|
|
|
use crate::ContentActorAuthenticator;
|
|
|
use crate::Trait;
|
|
|
use common::currency::GovernanceCurrency;
|
|
|
-use common::storage::StorageSystem;
|
|
|
|
|
|
pub type CuratorId = <Test as ContentActorAuthenticator>::CuratorId;
|
|
|
pub type CuratorGroupId = <Test as ContentActorAuthenticator>::CuratorGroupId;
|
|
|
pub type MemberId = <Test as MembershipTypes>::MemberId;
|
|
|
pub type ChannelId = <Test as StorageOwnership>::ChannelId;
|
|
|
-// pub type DAOId = <Test as StorageOwnership>::DAOId;
|
|
|
|
|
|
/// Origins
|
|
|
|
|
@@ -55,11 +54,21 @@ mod content {
|
|
|
pub use crate::Event;
|
|
|
}
|
|
|
|
|
|
+mod storage_mod {
|
|
|
+ pub use storage::Event;
|
|
|
+}
|
|
|
+
|
|
|
+mod membership_mod {
|
|
|
+ pub use membership::Event;
|
|
|
+}
|
|
|
+
|
|
|
impl_outer_event! {
|
|
|
pub enum MetaEvent for Test {
|
|
|
content<T>,
|
|
|
frame_system<T>,
|
|
|
balances<T>,
|
|
|
+ membership_mod<T>,
|
|
|
+ storage_mod<T>,
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -116,7 +125,6 @@ impl common::MembershipTypes for Test {
|
|
|
|
|
|
impl common::StorageOwnership for Test {
|
|
|
type ChannelId = u64;
|
|
|
- type DAOId = u64;
|
|
|
type ContentId = u64;
|
|
|
type DataObjectTypeId = u64;
|
|
|
}
|
|
@@ -139,6 +147,19 @@ impl GovernanceCurrency for Test {
|
|
|
type Currency = balances::Module<Self>;
|
|
|
}
|
|
|
|
|
|
+parameter_types! {
|
|
|
+ pub const ScreenedMemberMaxInitialBalance: u64 = 5000;
|
|
|
+}
|
|
|
+
|
|
|
+impl membership::Trait for Test {
|
|
|
+ type Event = MetaEvent;
|
|
|
+ type MemberId = u64;
|
|
|
+ type PaidTermId = u64;
|
|
|
+ type SubscriptionId = u64;
|
|
|
+ type ActorId = u64;
|
|
|
+ type ScreenedMemberMaxInitialBalance = ();
|
|
|
+}
|
|
|
+
|
|
|
impl ContentActorAuthenticator for Test {
|
|
|
type CuratorId = u64;
|
|
|
type CuratorGroupId = u64;
|
|
@@ -166,39 +187,144 @@ impl ContentActorAuthenticator for Test {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-pub struct MockStorageSystem {}
|
|
|
+parameter_types! {
|
|
|
+ pub const MaxNumberOfDataObjectsPerBag: u64 = 4;
|
|
|
+ pub const MaxDistributionBucketFamilyNumber: u64 = 4;
|
|
|
+ pub const MaxDistributionBucketNumberPerFamily: u64 = 10;
|
|
|
+ pub const DataObjectDeletionPrize: u64 = 10;
|
|
|
+ pub const StorageModuleId: ModuleId = ModuleId(*b"mstorage"); // module storage
|
|
|
+ pub const BlacklistSizeLimit: u64 = 1;
|
|
|
+ pub const MaxNumberOfPendingInvitationsPerDistributionBucket: u64 = 1;
|
|
|
+ pub const StorageBucketsPerBagValueConstraint: storage::StorageBucketsPerBagValueConstraint =
|
|
|
+ storage::StorageBucketsPerBagValueConstraint {min: 3, max_min_diff: 7};
|
|
|
+ pub const InitialStorageBucketsNumberForDynamicBag: u64 = 3;
|
|
|
+ pub const MaxRandomIterationNumber: u64 = 3;
|
|
|
+ pub const DefaultMemberDynamicBagNumberOfStorageBuckets: u64 = 3;
|
|
|
+ pub const DefaultChannelDynamicBagNumberOfStorageBuckets: u64 = 4;
|
|
|
+ pub const DistributionBucketsPerBagValueConstraint: storage::DistributionBucketsPerBagValueConstraint =
|
|
|
+ storage::StorageBucketsPerBagValueConstraint {min: 3, max_min_diff: 7};
|
|
|
+ pub const MaxDataObjectSize: u64 = 400;
|
|
|
+}
|
|
|
|
|
|
-// Anyone can upload and delete without restriction
|
|
|
-impl StorageSystem<Test> for MockStorageSystem {
|
|
|
- fn atomically_add_content(
|
|
|
- _owner: StorageObjectOwner<Test>,
|
|
|
- _content_parameters: Vec<ContentParameters<Test>>,
|
|
|
- ) -> DispatchResult {
|
|
|
- Ok(())
|
|
|
+pub const STORAGE_WG_LEADER_ACCOUNT_ID: u64 = 100001;
|
|
|
+pub const DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID: u64 = 100002;
|
|
|
+pub const DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID: u64 = 100003;
|
|
|
+pub const DISTRIBUTION_WG_LEADER_ACCOUNT_ID: u64 = 100004;
|
|
|
+pub const DEFAULT_STORAGE_PROVIDER_ID: u64 = 10;
|
|
|
+pub const ANOTHER_STORAGE_PROVIDER_ID: u64 = 11;
|
|
|
+pub const DEFAULT_DISTRIBUTION_PROVIDER_ID: u64 = 12;
|
|
|
+pub const ANOTHER_DISTRIBUTION_PROVIDER_ID: u64 = 13;
|
|
|
+
|
|
|
+impl storage::Trait for Test {
|
|
|
+ type Event = MetaEvent;
|
|
|
+ type DataObjectId = u64;
|
|
|
+ type StorageBucketId = u64;
|
|
|
+ type DistributionBucketId = u64;
|
|
|
+ type DistributionBucketFamilyId = u64;
|
|
|
+ type DistributionBucketOperatorId = u64;
|
|
|
+ type ChannelId = u64;
|
|
|
+ type MaxNumberOfDataObjectsPerBag = MaxNumberOfDataObjectsPerBag;
|
|
|
+ type DataObjectDeletionPrize = DataObjectDeletionPrize;
|
|
|
+ type BlacklistSizeLimit = BlacklistSizeLimit;
|
|
|
+ type ModuleId = StorageModuleId;
|
|
|
+ type MemberOriginValidator = ();
|
|
|
+ type StorageBucketsPerBagValueConstraint = StorageBucketsPerBagValueConstraint;
|
|
|
+ type DefaultMemberDynamicBagNumberOfStorageBuckets =
|
|
|
+ DefaultMemberDynamicBagNumberOfStorageBuckets;
|
|
|
+ type DefaultChannelDynamicBagNumberOfStorageBuckets =
|
|
|
+ DefaultChannelDynamicBagNumberOfStorageBuckets;
|
|
|
+ type Randomness = CollectiveFlip;
|
|
|
+ type MaxRandomIterationNumber = MaxRandomIterationNumber;
|
|
|
+ type MaxDistributionBucketFamilyNumber = MaxDistributionBucketFamilyNumber;
|
|
|
+ type MaxDistributionBucketNumberPerFamily = MaxDistributionBucketNumberPerFamily;
|
|
|
+ type DistributionBucketsPerBagValueConstraint = DistributionBucketsPerBagValueConstraint;
|
|
|
+ type MaxNumberOfPendingInvitationsPerDistributionBucket =
|
|
|
+ MaxNumberOfPendingInvitationsPerDistributionBucket;
|
|
|
+ type ContentId = u64;
|
|
|
+ type MaxDataObjectSize = MaxDataObjectSize;
|
|
|
+
|
|
|
+ fn ensure_storage_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
|
|
|
+ let account_id = ensure_signed(origin)?;
|
|
|
+
|
|
|
+ if account_id != STORAGE_WG_LEADER_ACCOUNT_ID {
|
|
|
+ Err(DispatchError::BadOrigin)
|
|
|
+ } else {
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ fn ensure_storage_worker_origin(origin: Self::Origin, _: u64) -> DispatchResult {
|
|
|
+ let account_id = ensure_signed(origin)?;
|
|
|
+
|
|
|
+ if account_id != DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID {
|
|
|
+ Err(DispatchError::BadOrigin)
|
|
|
+ } else {
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ fn ensure_storage_worker_exists(worker_id: &u64) -> DispatchResult {
|
|
|
+ let allowed_storage_providers =
|
|
|
+ vec![DEFAULT_STORAGE_PROVIDER_ID, ANOTHER_STORAGE_PROVIDER_ID];
|
|
|
+
|
|
|
+ if !allowed_storage_providers.contains(worker_id) {
|
|
|
+ Err(DispatchError::Other("Invalid worker"))
|
|
|
+ } else {
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ fn ensure_distribution_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
|
|
|
+ let account_id = ensure_signed(origin)?;
|
|
|
+
|
|
|
+ if account_id != DISTRIBUTION_WG_LEADER_ACCOUNT_ID {
|
|
|
+ Err(DispatchError::BadOrigin)
|
|
|
+ } else {
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- fn can_add_content(
|
|
|
- _owner: StorageObjectOwner<Test>,
|
|
|
- _content_parameters: Vec<ContentParameters<Test>>,
|
|
|
- ) -> DispatchResult {
|
|
|
- Ok(())
|
|
|
+ fn ensure_distribution_worker_origin(origin: Self::Origin, _: u64) -> DispatchResult {
|
|
|
+ let account_id = ensure_signed(origin)?;
|
|
|
+
|
|
|
+ if account_id != DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID {
|
|
|
+ Err(DispatchError::BadOrigin)
|
|
|
+ } else {
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- fn atomically_remove_content(
|
|
|
- _owner: &StorageObjectOwner<Test>,
|
|
|
- _content_ids: &[u64],
|
|
|
- ) -> DispatchResult {
|
|
|
- Ok(())
|
|
|
+ fn ensure_distribution_worker_exists(worker_id: &u64) -> DispatchResult {
|
|
|
+ let allowed_providers = vec![
|
|
|
+ DEFAULT_DISTRIBUTION_PROVIDER_ID,
|
|
|
+ ANOTHER_DISTRIBUTION_PROVIDER_ID,
|
|
|
+ ];
|
|
|
+
|
|
|
+ if !allowed_providers.contains(worker_id) {
|
|
|
+ Err(DispatchError::Other("Invalid worker"))
|
|
|
+ } else {
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- fn can_remove_content(
|
|
|
- _owner: &StorageObjectOwner<Test>,
|
|
|
- _content_ids: &[u64],
|
|
|
- ) -> DispatchResult {
|
|
|
- Ok(())
|
|
|
+pub const DEFAULT_MEMBER_ID: u64 = 100;
|
|
|
+pub const DEFAULT_MEMBER_ACCOUNT_ID: u64 = 101;
|
|
|
+
|
|
|
+impl common::origin::ActorOriginValidator<Origin, u64, u64> for () {
|
|
|
+ fn ensure_actor_origin(origin: Origin, member_id: u64) -> Result<u64, &'static str> {
|
|
|
+ let signed_account_id = frame_system::ensure_signed(origin)?;
|
|
|
+
|
|
|
+ if signed_account_id == DEFAULT_MEMBER_ACCOUNT_ID && member_id == DEFAULT_MEMBER_ID {
|
|
|
+ Ok(signed_account_id)
|
|
|
+ } else {
|
|
|
+ Err(DispatchError::BadOrigin.into())
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// Anyone can upload and delete without restriction
|
|
|
+
|
|
|
parameter_types! {
|
|
|
pub const MaxNumberOfCuratorsPerGroup: u32 = 10;
|
|
|
pub const ChannelOwnershipPaymentEscrowId: [u8; 8] = *b"12345678";
|
|
@@ -234,9 +360,6 @@ impl Trait for Test {
|
|
|
|
|
|
/// The maximum number of curators per group constraint
|
|
|
type MaxNumberOfCuratorsPerGroup = MaxNumberOfCuratorsPerGroup;
|
|
|
-
|
|
|
- // Type that handles asset uploads to storage frame_system
|
|
|
- type StorageSystem = MockStorageSystem;
|
|
|
}
|
|
|
|
|
|
pub type System = frame_system::Module<Test>;
|
|
@@ -307,3 +430,214 @@ pub fn run_to_block(n: u64) {
|
|
|
<System as OnInitialize<u64>>::on_initialize(System::block_number());
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+pub type CollectiveFlip = randomness_collective_flip::Module<Test>;
|
|
|
+
|
|
|
+pub fn create_channel_mock(
|
|
|
+ sender: u64,
|
|
|
+ actor: ContentActor<CuratorGroupId, CuratorId, MemberId>,
|
|
|
+ params: ChannelCreationParameters<Test>,
|
|
|
+ result: DispatchResult,
|
|
|
+) {
|
|
|
+ let channel_id = Content::next_channel_id();
|
|
|
+
|
|
|
+ assert_eq!(
|
|
|
+ Content::create_channel(Origin::signed(sender), actor.clone(), params.clone()),
|
|
|
+ result.clone(),
|
|
|
+ );
|
|
|
+
|
|
|
+ if result.is_ok() {
|
|
|
+ let num_assets = match params.assets.clone() {
|
|
|
+ NewAssets::<Test>::Urls(v) => v.len() as u64,
|
|
|
+ NewAssets::<Test>::Upload(c) => c.object_creation_list.len() as u64,
|
|
|
+ };
|
|
|
+ let owner = Content::actor_to_channel_owner(&actor).unwrap();
|
|
|
+
|
|
|
+ assert_eq!(
|
|
|
+ System::events().last().unwrap().event,
|
|
|
+ MetaEvent::content(RawEvent::ChannelCreated(
|
|
|
+ actor.clone(),
|
|
|
+ channel_id,
|
|
|
+ ChannelRecord {
|
|
|
+ owner: owner,
|
|
|
+ is_censored: false,
|
|
|
+ reward_account: params.reward_account,
|
|
|
+ deletion_prize_source_account_id: sender,
|
|
|
+ num_assets: num_assets,
|
|
|
+ num_videos: 0,
|
|
|
+ },
|
|
|
+ params.clone(),
|
|
|
+ ))
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub fn update_channel_mock(
|
|
|
+ sender: u64,
|
|
|
+ actor: ContentActor<CuratorGroupId, CuratorId, MemberId>,
|
|
|
+ channel_id: ChannelId,
|
|
|
+ params: ChannelUpdateParameters<Test>,
|
|
|
+ result: DispatchResult,
|
|
|
+) {
|
|
|
+ let channel_pre = ChannelById::<Test>::get(channel_id.clone());
|
|
|
+
|
|
|
+ assert_eq!(
|
|
|
+ Content::update_channel(
|
|
|
+ Origin::signed(sender),
|
|
|
+ actor.clone(),
|
|
|
+ channel_id.clone(),
|
|
|
+ params.clone()
|
|
|
+ ),
|
|
|
+ result.clone(),
|
|
|
+ );
|
|
|
+
|
|
|
+ if result.is_ok() {
|
|
|
+ let maybe_num_assets = params.assets.clone().map_or(None, |assets| match assets {
|
|
|
+ NewAssets::<Test>::Urls(v) => Some(v.len() as u64),
|
|
|
+ NewAssets::<Test>::Upload(c) => Some(c.object_creation_list.len() as u64),
|
|
|
+ });
|
|
|
+ assert_eq!(
|
|
|
+ System::events().last().unwrap().event,
|
|
|
+ MetaEvent::content(RawEvent::ChannelUpdated(
|
|
|
+ actor.clone(),
|
|
|
+ channel_id,
|
|
|
+ ChannelRecord {
|
|
|
+ owner: channel_pre.owner.clone(),
|
|
|
+ is_censored: channel_pre.is_censored,
|
|
|
+ reward_account: channel_pre.reward_account.clone(),
|
|
|
+ deletion_prize_source_account_id: sender,
|
|
|
+ num_assets: channel_pre.num_assets + maybe_num_assets.unwrap_or(0),
|
|
|
+ num_videos: channel_pre.num_videos,
|
|
|
+ },
|
|
|
+ params.clone(),
|
|
|
+ ))
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub fn delete_channel_assets_mock(
|
|
|
+ sender: u64,
|
|
|
+ actor: ContentActor<CuratorGroupId, CuratorId, MemberId>,
|
|
|
+ channel_id: ChannelId,
|
|
|
+ assets: BTreeSet<<Test as storage::Trait>::DataObjectId>,
|
|
|
+ result: DispatchResult,
|
|
|
+) {
|
|
|
+ let channel_pre = ChannelById::<Test>::get(channel_id.clone());
|
|
|
+
|
|
|
+ assert_eq!(
|
|
|
+ Content::remove_channel_assets(
|
|
|
+ Origin::signed(sender),
|
|
|
+ actor.clone(),
|
|
|
+ channel_id.clone(),
|
|
|
+ assets.clone(),
|
|
|
+ ),
|
|
|
+ result.clone(),
|
|
|
+ );
|
|
|
+
|
|
|
+ if result.is_ok() {
|
|
|
+ let num_assets_removed = assets.len();
|
|
|
+ assert_eq!(
|
|
|
+ System::events().last().unwrap().event,
|
|
|
+ MetaEvent::content(RawEvent::ChannelAssetsRemoved(
|
|
|
+ actor.clone(),
|
|
|
+ channel_id,
|
|
|
+ assets.clone(),
|
|
|
+ ChannelRecord {
|
|
|
+ owner: channel_pre.owner.clone(),
|
|
|
+ is_censored: channel_pre.is_censored,
|
|
|
+ reward_account: channel_pre.reward_account.clone(),
|
|
|
+ deletion_prize_source_account_id: sender,
|
|
|
+ num_assets: channel_pre.num_assets - (num_assets_removed as u64),
|
|
|
+ num_videos: channel_pre.num_videos,
|
|
|
+ },
|
|
|
+ ))
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub fn delete_channel_mock(
|
|
|
+ sender: u64,
|
|
|
+ actor: ContentActor<CuratorGroupId, CuratorId, MemberId>,
|
|
|
+ channel_id: ChannelId,
|
|
|
+ result: DispatchResult,
|
|
|
+) {
|
|
|
+ assert_eq!(
|
|
|
+ Content::delete_channel(Origin::signed(sender), actor.clone(), channel_id.clone()),
|
|
|
+ result.clone(),
|
|
|
+ );
|
|
|
+
|
|
|
+ if result.is_ok() {
|
|
|
+ assert_eq!(
|
|
|
+ System::events().last().unwrap().event,
|
|
|
+ MetaEvent::content(RawEvent::ChannelDeleted(actor.clone(), channel_id))
|
|
|
+ )
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub fn create_video_mock(
|
|
|
+ sender: u64,
|
|
|
+ actor: ContentActor<CuratorGroupId, CuratorId, MemberId>,
|
|
|
+ channel_id: ChannelId,
|
|
|
+ params: VideoCreationParameters<Test>,
|
|
|
+ result: DispatchResult,
|
|
|
+) {
|
|
|
+ let video_id = Content::next_video_id();
|
|
|
+ let num_videos_pre = Content::channel_by_id(channel_id).num_videos;
|
|
|
+
|
|
|
+ assert_eq!(
|
|
|
+ Content::create_video(
|
|
|
+ Origin::signed(sender),
|
|
|
+ actor.clone(),
|
|
|
+ channel_id.clone(),
|
|
|
+ params.clone()
|
|
|
+ ),
|
|
|
+ result.clone(),
|
|
|
+ );
|
|
|
+
|
|
|
+ if result.is_ok() {
|
|
|
+ assert_eq!(
|
|
|
+ System::events().last().unwrap().event,
|
|
|
+ MetaEvent::content(RawEvent::VideoCreated(
|
|
|
+ actor.clone(),
|
|
|
+ channel_id,
|
|
|
+ video_id,
|
|
|
+ params.clone(),
|
|
|
+ ))
|
|
|
+ );
|
|
|
+ assert_eq!(
|
|
|
+ num_videos_pre + 1,
|
|
|
+ Content::channel_by_id(channel_id).num_videos,
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+pub fn update_video_mock(
|
|
|
+ sender: u64,
|
|
|
+ actor: ContentActor<CuratorGroupId, CuratorId, MemberId>,
|
|
|
+ video_id: <Test as Trait>::VideoId,
|
|
|
+ params: VideoUpdateParameters<Test>,
|
|
|
+ result: DispatchResult,
|
|
|
+) {
|
|
|
+ // let channel_id = Content::video_by_id(video_id.clone()).in_channel;
|
|
|
+ // let num_videos_pre = Content::channel_by_id(channel_id).num_videos;
|
|
|
+
|
|
|
+ assert_eq!(
|
|
|
+ Content::update_video(
|
|
|
+ Origin::signed(sender),
|
|
|
+ actor.clone(),
|
|
|
+ video_id.clone(),
|
|
|
+ params.clone()
|
|
|
+ ),
|
|
|
+ result.clone(),
|
|
|
+ );
|
|
|
+
|
|
|
+ if result.is_ok() {
|
|
|
+ assert_eq!(
|
|
|
+ System::events().last().unwrap().event,
|
|
|
+ MetaEvent::content(RawEvent::VideoUpdated(
|
|
|
+ actor.clone(),
|
|
|
+ video_id,
|
|
|
+ params.clone(),
|
|
|
+ ))
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|