Parcourir la source

Merge branch 'development' into integrate-content-wg

Mokhtar Naamani il y a 5 ans
Parent
commit
53f1cd1ba0

+ 9 - 9
Cargo.lock

@@ -1002,15 +1002,15 @@ dependencies = [
  "substrate-client 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)",
  "substrate-consensus-babe-primitives 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)",
  "substrate-forum-module 1.1.0 (git+https://github.com/joystream/substrate-forum-module?rev=4bdeadaadfcca1fd6e822c520f429d4beacc4c8a)",
- "substrate-hiring-module 1.0.0 (git+https://github.com/joystream/substrate-hiring-module?rev=cd31dbb71d29ec0d7f14979aaec9c213c2dacfbc)",
+ "substrate-hiring-module 1.0.0 (git+https://github.com/Joystream/substrate-hiring-module?rev=30ac830aecb2e61fb943a8c4327bcf52c289e383)",
  "substrate-offchain-primitives 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)",
  "substrate-primitives 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)",
- "substrate-recurring-reward-module 1.0.0 (git+https://github.com/joystream/substrate-recurring-reward-module?rev=417f7bb5b82ae50f02716ac4eefa2fc7952e0f61)",
+ "substrate-recurring-reward-module 1.0.0 (git+https://github.com/Joystream/substrate-recurring-reward-module?rev=417f7bb5b82ae50f02716ac4eefa2fc7952e0f61)",
  "substrate-session 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)",
  "substrate-stake-module 1.0.0 (git+https://github.com/joystream/substrate-stake-module?rev=0516efe9230da112bc095e28f34a3715c2e03ca8)",
  "substrate-token-mint-module 1.0.0 (git+https://github.com/joystream/substrate-token-minting-module/?rev=5570e3b56e9caffa7df1dbede6308b2e6ce18217)",
  "substrate-versioned-store 1.1.0 (git+https://github.com/joystream/substrate-versioned-store-module?rev=d0c68722405355404840512edf3064d5ced3e1fe)",
- "substrate-versioned-store-permissions-module 1.0.0 (git+https://github.com/mnaamani/substrate-versioned-store-permissions-module?rev=02cfd53c132f95c99cb936bace4432a064b62b86)",
+ "substrate-versioned-store-permissions-module 1.0.0 (git+https://github.com/joystream/substrate-versioned-store-permissions-module?rev=816b796b1b72bba05eebe128cdaa5e18611ac3ae)",
  "substrate-wasm-builder-runner 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -3209,7 +3209,7 @@ dependencies = [
 [[package]]
 name = "substrate-hiring-module"
 version = "1.0.0"
-source = "git+https://github.com/joystream/substrate-hiring-module?rev=cd31dbb71d29ec0d7f14979aaec9c213c2dacfbc#cd31dbb71d29ec0d7f14979aaec9c213c2dacfbc"
+source = "git+https://github.com/Joystream/substrate-hiring-module?rev=30ac830aecb2e61fb943a8c4327bcf52c289e383#30ac830aecb2e61fb943a8c4327bcf52c289e383"
 dependencies = [
  "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3328,7 +3328,7 @@ dependencies = [
 [[package]]
 name = "substrate-recurring-reward-module"
 version = "1.0.0"
-source = "git+https://github.com/joystream/substrate-recurring-reward-module?rev=417f7bb5b82ae50f02716ac4eefa2fc7952e0f61#417f7bb5b82ae50f02716ac4eefa2fc7952e0f61"
+source = "git+https://github.com/Joystream/substrate-recurring-reward-module?rev=417f7bb5b82ae50f02716ac4eefa2fc7952e0f61#417f7bb5b82ae50f02716ac4eefa2fc7952e0f61"
 dependencies = [
  "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3480,7 +3480,7 @@ dependencies = [
 [[package]]
 name = "substrate-versioned-store-permissions-module"
 version = "1.0.0"
-source = "git+https://github.com/mnaamani/substrate-versioned-store-permissions-module?rev=02cfd53c132f95c99cb936bace4432a064b62b86#02cfd53c132f95c99cb936bace4432a064b62b86"
+source = "git+https://github.com/joystream/substrate-versioned-store-permissions-module?rev=816b796b1b72bba05eebe128cdaa5e18611ac3ae#816b796b1b72bba05eebe128cdaa5e18611ac3ae"
 dependencies = [
  "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -4511,7 +4511,7 @@ dependencies = [
 "checksum substrate-finality-grandpa-primitives 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)" = "<none>"
 "checksum substrate-forum-module 1.1.0 (git+https://github.com/joystream/substrate-forum-module?rev=4bdeadaadfcca1fd6e822c520f429d4beacc4c8a)" = "<none>"
 "checksum substrate-header-metadata 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)" = "<none>"
-"checksum substrate-hiring-module 1.0.0 (git+https://github.com/joystream/substrate-hiring-module?rev=cd31dbb71d29ec0d7f14979aaec9c213c2dacfbc)" = "<none>"
+"checksum substrate-hiring-module 1.0.0 (git+https://github.com/Joystream/substrate-hiring-module?rev=30ac830aecb2e61fb943a8c4327bcf52c289e383)" = "<none>"
 "checksum substrate-inherents 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)" = "<none>"
 "checksum substrate-keyring 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)" = "<none>"
 "checksum substrate-offchain-primitives 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)" = "<none>"
@@ -4519,7 +4519,7 @@ dependencies = [
 "checksum substrate-phragmen 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)" = "<none>"
 "checksum substrate-primitives 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)" = "<none>"
 "checksum substrate-primitives-storage 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)" = "<none>"
-"checksum substrate-recurring-reward-module 1.0.0 (git+https://github.com/joystream/substrate-recurring-reward-module?rev=417f7bb5b82ae50f02716ac4eefa2fc7952e0f61)" = "<none>"
+"checksum substrate-recurring-reward-module 1.0.0 (git+https://github.com/Joystream/substrate-recurring-reward-module?rev=417f7bb5b82ae50f02716ac4eefa2fc7952e0f61)" = "<none>"
 "checksum substrate-serializer 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)" = "<none>"
 "checksum substrate-session 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)" = "<none>"
 "checksum substrate-stake-module 1.0.0 (git+https://github.com/joystream/substrate-stake-module?rev=0516efe9230da112bc095e28f34a3715c2e03ca8)" = "<none>"
@@ -4528,7 +4528,7 @@ dependencies = [
 "checksum substrate-token-mint-module 1.0.0 (git+https://github.com/joystream/substrate-token-minting-module/?rev=5570e3b56e9caffa7df1dbede6308b2e6ce18217)" = "<none>"
 "checksum substrate-trie 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)" = "<none>"
 "checksum substrate-versioned-store 1.1.0 (git+https://github.com/joystream/substrate-versioned-store-module?rev=d0c68722405355404840512edf3064d5ced3e1fe)" = "<none>"
-"checksum substrate-versioned-store-permissions-module 1.0.0 (git+https://github.com/mnaamani/substrate-versioned-store-permissions-module?rev=02cfd53c132f95c99cb936bace4432a064b62b86)" = "<none>"
+"checksum substrate-versioned-store-permissions-module 1.0.0 (git+https://github.com/joystream/substrate-versioned-store-permissions-module?rev=816b796b1b72bba05eebe128cdaa5e18611ac3ae)" = "<none>"
 "checksum substrate-wasm-builder-runner 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bd48273fe9d7f92c1f7d6c1c537bb01c8068f925b47ad2cd8367e11dc32f8550"
 "checksum substrate-wasm-interface 2.0.0 (git+https://github.com/paritytech/substrate.git?rev=0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3)" = "<none>"
 "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"

+ 6 - 7
Cargo.toml

@@ -270,22 +270,21 @@ rev = '5570e3b56e9caffa7df1dbede6308b2e6ce18217'
 
 [dependencies.recurringrewards]
 default_features = false
-git = 'https://github.com/joystream/substrate-recurring-reward-module'
+git = 'https://github.com/Joystream/substrate-recurring-reward-module'
 package = 'substrate-recurring-reward-module'
 rev = '417f7bb5b82ae50f02716ac4eefa2fc7952e0f61'
 
 [dependencies.stake]
 default_features = false
-git = 'https://github.com/joystream/substrate-stake-module'
+git = 'https://github.com/Joystream/substrate-stake-module/'
 package = 'substrate-stake-module'
 rev = '0516efe9230da112bc095e28f34a3715c2e03ca8'
 
 [dependencies.hiring]
 default_features = false
+git = 'https://github.com/Joystream/substrate-hiring-module'
 package = 'substrate-hiring-module'
-git = 'https://github.com/joystream/substrate-hiring-module'
-rev = 'cd31dbb71d29ec0d7f14979aaec9c213c2dacfbc'
-
+rev = '30ac830aecb2e61fb943a8c4327bcf52c289e383'
 
 [dependencies.versioned_store]
 default_features = false
@@ -296,5 +295,5 @@ rev = 'd0c68722405355404840512edf3064d5ced3e1fe'
 [dependencies.versioned_store_permissions]
 default_features = false
 package = 'substrate-versioned-store-permissions-module'
-git = 'https://github.com/mnaamani/substrate-versioned-store-permissions-module'
-rev = '02cfd53c132f95c99cb936bace4432a064b62b86'
+git = 'https://github.com/joystream/substrate-versioned-store-permissions-module'
+rev = '816b796b1b72bba05eebe128cdaa5e18611ac3ae'

+ 1 - 1
README.md

@@ -1,4 +1,4 @@
-![Joystream Runtime](./banner.svg)
+![Joystream Runtime](./banner_new.svg)
 
 # Joystream Runtime
 

Fichier diff supprimé car celui-ci est trop grand
+ 72 - 0
banner_new.svg


+ 138 - 0
src/content_working_group/genesis.rs

@@ -0,0 +1,138 @@
+#![cfg(test)]
+
+use super::lib::{Trait, *};
+pub use primitives::{map, Blake2Hasher, H256};
+use rstd::prelude::*;
+
+/// DIRTY IMPORT BECAUSE
+/// InputValidationLengthConstraint has not been factored out yet!!!
+use forum::InputValidationLengthConstraint;
+
+/// The way a map (linked_map) is represented in the GenesisConfig produced by decl_storage
+//pub type GenesisConfigMap<K, V> = std::vec::Vec<(K, V)>;
+
+/// Builder of genesis configuration of content working group.
+pub struct GenesisConfigBuilder<T: Trait> {
+    mint_capacity: minting::BalanceOf<T>,
+
+    /*
+    lead_by_id: GenesisConfigMap<LeadId<T>, Lead<T::AccountId, T::RewardRelationshipId, T::BlockNumber>>,
+    next_lead_id: LeadId<T>,
+    curator_opening_by_id: GenesisConfigMap<CuratorOpeningId<T>, CuratorOpening<T::OpeningId, T::BlockNumber, BalanceOf<T>, CuratorApplicationId<T>>>,
+    next_curator_opening_id: CuratorOpeningId<T>,
+    curator_application_by_id: GenesisConfigMap<CuratorApplicationId<T>, CuratorApplication<T::AccountId, CuratorOpeningId<T>, T::MemberId, T::ApplicationId>>,
+    next_curator_application_id: CuratorApplicationId<T>,
+    channel_by_id: GenesisConfigMap<ChannelId<T>, Channel<T::MemberId, T::AccountId, T::BlockNumber, PrincipalId<T>>>,
+    next_channel_id: ChannelId<T>,
+    channel_id_by_handle: GenesisConfigMap<Vec<u8>, ChannelId<T>>,
+    curator_by_id: GenesisConfigMap<CuratorId<T>, Curator<T::AccountId, T::RewardRelationshipId, T::StakeId, T::BlockNumber, LeadId<T>, CuratorApplicationId<T>, PrincipalId<T>>>,
+    next_curator_id: CuratorId<T>,
+    principal_by_id: GenesisConfigMap<PrincipalId<T>, Principal<CuratorId<T>, ChannelId<T>>>,
+    next_principal_id: PrincipalId<T>,
+
+    unstaker_by_stake_id: GenesisConfigMap<TestStakeId, WorkingGroupUnstaker<LeadId<T>, CuratorId<T>>>,
+    */
+    channel_creation_enabled: bool,
+    channel_handle_constraint: InputValidationLengthConstraint,
+    channel_description_constraint: InputValidationLengthConstraint,
+    opening_human_readble_text: InputValidationLengthConstraint,
+    curator_application_human_readable_text: InputValidationLengthConstraint,
+    curator_exit_rationale_text: InputValidationLengthConstraint,
+    channel_title_constraint: InputValidationLengthConstraint,
+    channel_avatar_constraint: InputValidationLengthConstraint,
+    channel_banner_constraint: InputValidationLengthConstraint,
+    opening_human_readable_text: InputValidationLengthConstraint,
+}
+
+impl<T: Trait> GenesisConfigBuilder<T> {
+    /*
+    pub fn set_mint(mut self, mint: <T as minting::Trait>::MintId) -> Self {
+        self.mint = mint;
+        self
+    }
+    pub fn set_channel_handle_constraint(mut self, constraint: InputValidationLengthConstraint) -> Self {
+        self.channel_description_constraint = constraint;
+        self
+    }
+    pub fn set_channel_description_constraint(mut self, constraint: InputValidationLengthConstraint) -> Self {
+        self.channel_description_constraint = constraint;
+        self
+    }
+    pub fn set_channel_creation_enabled(mut self, channel_creation_enabled: bool) -> Self {
+        self.channel_creation_enabled = channel_creation_enabled;
+        self
+    }
+    */
+    pub fn build(self) -> GenesisConfig<T> {
+        GenesisConfig {
+            mint_capacity: self.mint_capacity,
+            initial_lead: None,
+            curator_opening_by_id: map![], //GenesisConfigMap<CuratorOpeningId, Opening>,
+            next_curator_opening_id: CuratorOpeningId::<T>::default(),
+            curator_application_by_id: map![], //GenesisConfigMap<CuratorApplicationId,CuratorApplication>,
+            next_curator_application_id: CuratorApplicationId::<T>::default(),
+
+            channel_by_id: map![], //GenesisConfigMap<ChannelId, Channel>,
+            next_channel_id: ChannelId::<T>::default(),
+            channel_id_by_handle: map![], //GenesisConfigMap<Vec<u8>, ChannelId>,
+            curator_by_id: map![],        //GenesisConfigMap<CuratorId, Curator>,
+            next_curator_id: CuratorId::<T>::default(),
+            principal_by_id: map![], //GenesisConfigMap<PrinicipalId, Prinicipal>,
+            next_principal_id: PrincipalId::<T>::default(),
+            channel_creation_enabled: self.channel_creation_enabled,
+            unstaker_by_stake_id: map![], //GenesisConfigMap<LeadId, CuratorId>,
+
+            channel_handle_constraint: self.channel_handle_constraint,
+            channel_description_constraint: self.channel_description_constraint,
+            curator_application_human_readable_text: self.curator_application_human_readable_text,
+            curator_exit_rationale_text: self.curator_exit_rationale_text,
+
+            channel_title_constraint: self.channel_title_constraint,
+            channel_avatar_constraint: self.channel_avatar_constraint,
+            channel_banner_constraint: self.channel_banner_constraint,
+            opening_human_readable_text: self.opening_human_readable_text,
+        }
+    }
+}
+
+impl<T: Trait> Default for GenesisConfigBuilder<T> {
+    fn default() -> Self {
+        let default_constraint = InputValidationLengthConstraint {
+            min: 8,
+            max_min_diff: 44,
+        };
+
+        Self {
+            mint_capacity: minting::BalanceOf::<T>::from(10000),
+
+            /*
+            current_lead_id: LeadId::<T>::default(), //Option<LeadId>,
+            lead_by_id: map![], //GenesisConfigMap<LeadId, Lead>,
+            next_lead_id: 0,
+            curator_opening_by_id: map![], //GenesisConfigMap<CuratorOpeningId, Opening>,
+            next_curator_opening_id: 0,
+            curator_application_by_id: map![], //GenesisConfigMap<CuratorApplicationId,CuratorApplication>,
+            next_curator_application_id: 0,
+            channel_by_id: map![], //GenesisConfigMap<ChannelId, Channel>,
+            next_channel_id: 0,
+            channel_id_by_handle: map![], //GenesisConfigMap<Vec<u8>, ChannelId>,
+            curator_by_id: map![], //GenesisConfigMap<CuratorId, Curator>,
+            next_curator_id: 0,
+            principal_by_id: map![], //GenesisConfigMap<PrinicipalId, Prinicipal>,
+            next_principal_id: 0,
+
+            unstaker_by_stake_id: map![], //GenesisConfigMap<LeadId, CuratorId>,
+            */
+            channel_creation_enabled: true,
+            channel_handle_constraint: default_constraint.clone(),
+            channel_description_constraint: default_constraint.clone(),
+            opening_human_readble_text: default_constraint.clone(),
+            curator_application_human_readable_text: default_constraint.clone(),
+            curator_exit_rationale_text: default_constraint.clone(),
+            channel_title_constraint: default_constraint.clone(),
+            channel_avatar_constraint: default_constraint.clone(),
+            channel_banner_constraint: default_constraint.clone(),
+            opening_human_readable_text: default_constraint.clone(),
+        }
+    }
+}

Fichier diff supprimé car celui-ci est trop grand
+ 413 - 173
src/content_working_group/lib.rs


+ 0 - 0
src/content_working_group/macroes.rs


+ 131 - 32
src/content_working_group/mock.rs

@@ -1,10 +1,10 @@
 #![cfg(test)]
 
-pub use super::lib::{self, Module, Trait};
+pub use super::lib::{self, *}; // {self, Module, Trait, GenesisConfig};
 pub use srml_support::traits::Currency;
 pub use system;
 
-pub use primitives::{Blake2Hasher, H256};
+pub use primitives::{map, Blake2Hasher, H256};
 pub use runtime_primitives::{
     testing::{Digest, DigestItem, Header, UintAuthorityId},
     traits::{BlakeTwo256, Convert, IdentityLookup, OnFinalize},
@@ -12,19 +12,18 @@ pub use runtime_primitives::{
     BuildStorage, Perbill,
 };
 
-use srml_support::{impl_outer_origin, parameter_types};
-
-use hiring;
-use minting;
-use recurringrewards;
-use stake;
-use versioned_store;
-use versioned_store_permissions;
-
-//use crate::membership;
-use super::super::membership::members as membership;
+use srml_support::{impl_outer_event, impl_outer_origin, parameter_types};
 
 pub use crate::currency::GovernanceCurrency;
+pub use crate::membership::members;
+pub use hiring;
+pub use minting;
+pub use recurringrewards;
+pub use stake;
+pub use versioned_store;
+pub use versioned_store_permissions;
+
+use super::genesis;
 
 parameter_types! {
     pub const BlockHashCount: u64 = 250;
@@ -49,17 +48,45 @@ impl_outer_origin! {
     pub enum Origin for Test {}
 }
 
+impl_outer_event! {
+    pub enum TestEvent for Test {
+        versioned_store<T>,
+        members<T>,
+        balances<T>,
+        lib<T>,
+    }
+}
+
+pub type RawLibTestEvent = lib::RawEvent<
+    ChannelId<Test>,
+    LeadId<Test>,
+    CuratorOpeningId<Test>,
+    CuratorApplicationId<Test>,
+    CuratorId<Test>,
+    <Test as system::Trait>::AccountId,
+>;
+
+pub fn get_last_event_or_panic() -> RawLibTestEvent {
+    if let TestEvent::lib(ref x) = System::events().last().unwrap().event {
+        x.clone()
+    } else {
+        panic!("No event deposited.");
+    }
+}
+
+type TestAccountId = u64;
+type TestBlockNumber = u64;
 impl system::Trait for Test {
     type Origin = Origin;
     type Index = u64;
-    type BlockNumber = u64;
+    type BlockNumber = TestBlockNumber;
     type Call = ();
     type Hash = H256;
     type Hashing = BlakeTwo256;
-    type AccountId = u64;
+    type AccountId = TestAccountId;
     type Lookup = IdentityLookup<Self::AccountId>;
     type Header = Header;
-    type Event = ();
+    type Event = TestEvent;
     type BlockHashCount = BlockHashCount;
     type MaximumBlockWeight = MaximumBlockWeight;
     type MaximumBlockLength = MaximumBlockLength;
@@ -81,7 +108,7 @@ impl balances::Trait for Test {
     /// What to do if a new account is created.
     type OnNewAccount = ();
     /// The ubiquitous event type.
-    type Event = ();
+    type Event = TestEvent;
 
     type DustRemoval = ();
     type TransferPayment = ();
@@ -104,44 +131,53 @@ impl GovernanceCurrency for Test {
     type Currency = Balances;
 }
 
+type TestMintId = u64;
 impl minting::Trait for Test {
     type Currency = Balances;
-    type MintId = u64;
+    type MintId = TestMintId;
 }
 
+type TestRecipientId = u64;
+type TestRewardRelationshipId = u64;
 impl recurringrewards::Trait for Test {
     type PayoutStatusHandler = ();
-    type RecipientId = u64;
-    type RewardRelationshipId = u64;
+    type RecipientId = TestRecipientId;
+    type RewardRelationshipId = TestRewardRelationshipId;
 }
 
+type TestStakeId = u64;
+type TestSlashId = u64;
 impl stake::Trait for Test {
     type Currency = Balances;
     type StakePoolId = StakePoolId;
     type StakingEventsHandler = ();
-    type StakeId = u64;
-    type SlashId = u64;
+    type StakeId = TestStakeId;
+    type SlashId = TestSlashId;
 }
 
+type TestOpeningId = u64;
+type TestApplicationId = u64;
 impl hiring::Trait for Test {
-    type OpeningId = u64;
-    type ApplicationId = u64;
+    type OpeningId = TestOpeningId;
+    type ApplicationId = TestApplicationId;
     type ApplicationDeactivatedHandler = ();
 }
 
 impl versioned_store::Trait for Test {
-    type Event = ();
+    type Event = TestEvent;
 }
 
+type TestPrincipalId = u64;
 impl versioned_store_permissions::Trait for Test {
-    type Credential = u64;
+    type Credential = TestPrincipalId;
     type CredentialChecker = ();
     type CreateClassPermissionsChecker = ();
 }
 
-impl membership::Trait for Test {
-    type Event = ();
-    type MemberId = u64;
+type TestMemberId = u64;
+impl members::Trait for Test {
+    type Event = TestEvent;
+    type MemberId = TestMemberId;
     type PaidTermId = u64;
     type SubscriptionId = u64;
     type ActorId = u64;
@@ -149,9 +185,72 @@ impl membership::Trait for Test {
 }
 
 impl Trait for Test {
-    type Event = ();
+    type Event = TestEvent;
+}
+
+pub struct TestExternalitiesBuilder<T: Trait> {
+    system_config: Option<system::GenesisConfig>,
+    membership_config: Option<members::GenesisConfig<T>>,
+    content_wg_config: Option<GenesisConfig<T>>,
+}
+
+impl<T: Trait> Default for TestExternalitiesBuilder<T> {
+    fn default() -> Self {
+        Self {
+            system_config: None,
+            membership_config: None,
+            content_wg_config: None,
+        }
+    }
+}
+
+impl<T: Trait> TestExternalitiesBuilder<T> {
+    /*
+    pub fn set_system_config(mut self, system_config: system::GenesisConfig) -> Self {
+        self.system_config = Some(system_config);
+        self
+    }
+    pub fn set_membership_config(mut self, membership_config: members::GenesisConfig<T>) -> Self {
+        self.membership_config = Some(membership_config);
+        self
+    }
+    pub fn set_content_wg_config(mut self, conteng_wg_config: GenesisConfig<T>) -> Self {
+        self.content_wg_config = Some(conteng_wg_config);
+        self
+    }
+    */
+    pub fn build(self) -> runtime_io::TestExternalities {
+        // Add system
+        let mut t = self
+            .system_config
+            .unwrap_or(system::GenesisConfig::default())
+            .build_storage::<T>()
+            .unwrap();
+
+        // Add membership
+        self.membership_config
+            .unwrap_or(members::GenesisConfig::default())
+            .assimilate_storage(&mut t)
+            .unwrap();
+
+        // Add content wg
+
+        if self.content_wg_config.is_none() {
+            genesis::GenesisConfigBuilder::<Test>::default()
+                .build()
+                .assimilate_storage(&mut t)
+                .unwrap();
+        } else {
+            self.content_wg_config
+                .unwrap()
+                .assimilate_storage(&mut t)
+                .unwrap();
+        }
+
+        t.into()
+    }
 }
 
-//pub type System = system::Module<Test>;
+pub type System = system::Module<Test>;
 pub type Balances = balances::Module<Test>;
-//pub type ContentWorkingGroup = Module<Test>;
+pub type ContentWorkingGroup = Module<Test>;

+ 1 - 0
src/content_working_group/mod.rs

@@ -1,3 +1,4 @@
+pub mod genesis;
 pub mod lib;
 //pub mod types;
 

+ 2070 - 25
src/content_working_group/tests.rs

@@ -1,43 +1,2088 @@
 #![cfg(test)]
 
+//use super::genesis;
+use super::lib;
+use super::mock::{self, *};
+//use crate::membership;
+use hiring;
+use rstd::collections::btree_map::BTreeMap;
+use rstd::collections::btree_set::BTreeSet;
+use runtime_primitives::traits::One;
+use srml_support::{StorageLinkedMap, StorageValue};
+
+/// DIRTY IMPORT BECAUSE
+/// InputValidationLengthConstraint has not been factored out yet!!!
+use forum::InputValidationLengthConstraint;
+
+#[test]
+fn create_channel_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            // Add channel creator as member
+            let channel_creator_member_root_and_controller_account = 12312;
+
+            let channel_creator_member_id = add_member(
+                channel_creator_member_root_and_controller_account,
+                to_vec(CHANNEL_CREATOR_HANDLE),
+            );
+
+            let fixture = CreateChannelFixture::make_valid_unpulished_video_channel_for(
+                channel_creator_member_id,
+                None,
+            );
+
+            fixture.call_and_assert_success();
+        });
+}
+
+#[test]
+fn create_channel_is_not_a_member() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            let channel_creator_member_id = add_channel_creator_member();
+
+            let mut fixture = CreateChannelFixture::make_valid_unpulished_video_channel_for(
+                channel_creator_member_id,
+                None,
+            );
+
+            // Change to invalid member id, i.e. != channel_creator_member_id
+            fixture.channel_creator_member_id = fixture.channel_creator_member_id
+                + <<Test as members::Trait>::MemberId as One>::one();
+
+            fixture.call_and_assert_error(MSG_CREATE_CHANNEL_IS_NOT_MEMBER);
+        });
+}
+
+#[test]
+fn create_channel_not_enabled() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            add_member_and_set_as_lead();
+
+            set_channel_creation_enabled(false);
+
+            let channel_creator_member_id = add_channel_creator_member();
+
+            let fixture = CreateChannelFixture::make_valid_unpulished_video_channel_for(
+                channel_creator_member_id,
+                None,
+            );
+
+            fixture.call_and_assert_error(MSG_CHANNEL_CREATION_DISABLED);
+        });
+}
+
+#[test]
+fn create_channel_with_bad_member_role_account() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            let channel_creator_member_id = add_channel_creator_member();
+
+            let fixture = CreateChannelFixture::make_valid_unpulished_video_channel_for(
+                channel_creator_member_id,
+                Some(0),
+            );
+
+            fixture.call_and_assert_error(MSG_CREATE_CHANNEL_NOT_CONTROLLER_ACCOUNT);
+        });
+}
+
+#[test]
+fn create_channel_handle_too_long() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            let channel_creator_member_id = add_channel_creator_member();
+
+            let mut fixture = CreateChannelFixture::make_valid_unpulished_video_channel_for(
+                channel_creator_member_id,
+                None,
+            );
+
+            fixture.channel_handle =
+                generate_too_long_length_buffer(&ChannelHandleConstraint::get());
+
+            fixture.call_and_assert_error(MSG_CHANNEL_HANDLE_TOO_LONG);
+        });
+}
+
+#[test]
+fn create_channel_handle_too_short() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            let channel_creator_member_id = add_channel_creator_member();
+
+            let mut fixture = CreateChannelFixture::make_valid_unpulished_video_channel_for(
+                channel_creator_member_id,
+                None,
+            );
+
+            fixture.channel_handle =
+                generate_too_short_length_buffer(&ChannelHandleConstraint::get());
+
+            fixture.call_and_assert_error(MSG_CHANNEL_HANDLE_TOO_SHORT);
+        });
+}
+
+#[test]
+fn create_channel_description_too_long() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            let channel_creator_member_id = add_channel_creator_member();
+
+            let mut fixture = CreateChannelFixture::make_valid_unpulished_video_channel_for(
+                channel_creator_member_id,
+                None,
+            );
+
+            fixture.description =
+                generate_too_long_length_buffer(&ChannelDescriptionConstraint::get());
+
+            fixture.call_and_assert_error(MSG_CHANNEL_DESCRIPTION_TOO_LONG);
+        });
+}
+
+#[test]
+fn create_channel_description_too_short() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            let channel_creator_member_id = add_channel_creator_member();
+
+            let mut fixture = CreateChannelFixture::make_valid_unpulished_video_channel_for(
+                channel_creator_member_id,
+                None,
+            );
+
+            fixture.description =
+                generate_too_short_length_buffer(&ChannelDescriptionConstraint::get());
+
+            fixture.call_and_assert_error(MSG_CHANNEL_DESCRIPTION_TOO_SHORT);
+        });
+}
+
+#[test]
+fn transfer_channel_ownership_success() {}
+
+#[test]
+fn update_channel_as_owner_success() {}
+
+struct UpdateChannelAsCurationActorFixture {
+    pub origin: Origin,
+    pub curation_actor: CurationActor<CuratorId<Test>>,
+    pub new_verified: Option<bool>,
+    pub new_description: Option<Vec<u8>>,
+    pub new_curation_status: Option<ChannelCurationStatus>,
+}
+
+impl UpdateChannelAsCurationActorFixture {
+    fn update_channel_as_curation_actor(
+        &self,
+        channel_id: ChannelId<Test>,
+    ) -> Result<(), &'static str> {
+        ContentWorkingGroup::update_channel_as_curation_actor(
+            self.origin.clone(),
+            self.curation_actor.clone(),
+            channel_id,
+            self.new_verified,
+            self.new_description.clone(),
+            self.new_curation_status,
+        )
+    }
+
+    pub fn call_and_assert_success(&self, channel_id: ChannelId<Test>) {
+        let old_channel = ChannelById::<Test>::get(channel_id);
+
+        let expected_updated_channel = lib::Channel::new(
+            old_channel.title,
+            self.new_verified.unwrap_or(old_channel.verified),
+            self.new_description
+                .clone()
+                .unwrap_or(old_channel.description),
+            old_channel.content,
+            old_channel.owner,
+            old_channel.role_account,
+            old_channel.publishing_status,
+            self.new_curation_status
+                .unwrap_or(old_channel.curation_status),
+            old_channel.created,
+            old_channel.principal_id,
+            old_channel.avatar,
+            old_channel.banner,
+            old_channel.handle,
+        );
+
+        // Call and check result
+
+        let call_result = self.update_channel_as_curation_actor(channel_id);
+
+        assert_eq!(call_result, Ok(()));
+
+        // Event triggered
+        let event_channel_id = Self::get_event_deposited();
+
+        assert_eq!(event_channel_id, channel_id);
+
+        // Channel has been updated correctly
+        assert!(ChannelById::<Test>::exists(channel_id));
+
+        let updated_channel = ChannelById::<Test>::get(channel_id);
+
+        assert_eq!(updated_channel, expected_updated_channel);
+    }
+
+    fn get_event_deposited() -> lib::ChannelId<Test> {
+        if let mock::TestEvent::lib(ref x) = System::events().last().unwrap().event {
+            if let lib::RawEvent::ChannelUpdatedByCurationActor(ref channel_id) = x {
+                return channel_id.clone();
+            } else {
+                panic!("Event was not ChannelUpdatedByCurationActor.")
+            }
+        } else {
+            panic!("No event deposited.")
+        }
+    }
+}
+
+#[test]
+fn update_channel_as_curation_actor_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            // Add lead and hire curator
+            let curator_params = AddMemberAndApplyOnOpeningParams::new(
+                2222,
+                to_vec("yoyoyo0"), // generate_valid_length_buffer(&ChannelHandleConstraint::get()),
+                2222 * 2,
+                2222 * 3,
+                generate_valid_length_buffer(&CuratorApplicationHumanReadableText::get()),
+            );
+
+            // Hire curator
+            let setup_and_fill_opening_result =
+                setup_and_fill_opening(&vec![FillOpeningApplicantParams::new(
+                    curator_params.clone(),
+                    true,
+                )]);
+
+            let curator_id = match setup_and_fill_opening_result.application_outomes[0] {
+                FillOpeningApplicantOutcome::Hired { curator_id } => curator_id,
+                _ => panic!(),
+            };
+
+            // Make channel
+            let channel_creator_member_id = add_channel_creator_member();
+            let channel_id = channel_creator_member_id;
+
+            CreateChannelFixture::make_valid_unpulished_video_channel_for(
+                channel_creator_member_id,
+                None,
+            )
+            .call_and_assert_success();
+
+            // Update channel as curator
+            UpdateChannelAsCurationActorFixture {
+                origin: Origin::signed(curator_params.curator_applicant_role_account),
+                curation_actor: CurationActor::Curator(curator_id),
+                new_verified: Some(true),
+                new_description: None, //  don't touch!
+                new_curation_status: Some(ChannelCurationStatus::Censored),
+            }
+            .call_and_assert_success(channel_id);
+        });
+}
+
+#[test]
+fn add_curator_opening_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            /*
+             * Setup
+             */
+
+            add_member_and_set_as_lead();
+
+            let expected_opening_id = hiring::NextOpeningId::<Test>::get();
+
+            let expected_curator_opening_id = NextCuratorOpeningId::<Test>::get();
+
+            /*
+             * Test
+             */
+
+            // Add opening
+            let activate_at = hiring::ActivateOpeningAt::ExactBlock(34);
+
+            let human_readable_text =
+                generate_valid_length_buffer(&OpeningHumanReadableText::get());
+
+            assert_eq!(
+                ContentWorkingGroup::add_curator_opening(
+                    Origin::signed(LEAD_ROLE_ACCOUNT),
+                    activate_at.clone(),
+                    get_baseline_opening_policy(),
+                    human_readable_text.clone()
+                )
+                .unwrap(),
+                ()
+            );
+
+            assert_eq!(
+                get_last_event_or_panic(),
+                lib::RawEvent::CuratorOpeningAdded(expected_curator_opening_id)
+            );
+
+            // Assert that given opening id has been added,
+            // and has the right properties.
+            assert!(lib::CuratorOpeningById::<Test>::exists(
+                expected_curator_opening_id
+            ));
+
+            let created_curator_opening =
+                lib::CuratorOpeningById::<Test>::get(expected_curator_opening_id);
+
+            let expected_curator_opening = CuratorOpening {
+                opening_id: expected_opening_id,
+                curator_applications: BTreeSet::new(),
+                policy_commitment: get_baseline_opening_policy(),
+            };
+
+            assert_eq!(created_curator_opening, expected_curator_opening);
+
+            // Assert that next id incremented.
+            assert_eq!(
+                lib::NextCuratorOpeningId::<Test>::get(),
+                expected_opening_id + 1
+            );
+
+            /*
+             * TODO: add assertion abouot side-effect in hiring module,
+             * this is where state of application has fundamentally changed.
+             */
+        });
+}
+
+#[test]
+fn accept_curator_applications_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            /*
+             * Setup
+             */
+
+            add_member_and_set_as_lead();
+
+            let curator_opening_id = add_curator_opening();
+
+            /*
+             * Test
+             */
+
+            assert_eq!(
+                ContentWorkingGroup::accept_curator_applications(
+                    Origin::signed(LEAD_ROLE_ACCOUNT),
+                    curator_opening_id
+                )
+                .unwrap(),
+                ()
+            );
+
+            assert_eq!(
+                get_last_event_or_panic(),
+                lib::RawEvent::AcceptedCuratorApplications(curator_opening_id)
+            )
+
+            /*
+             * TODO: add assertion abouot side-effect in hiring module,
+             * this is where state of application has fundamentally changed.
+             */
+        });
+}
+
+#[test]
+fn begin_curator_applicant_review_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            /*
+             * Setup
+             */
+
+            let normal_opening_constructed = setup_normal_accepting_opening();
+
+            let _ = add_member_and_apply_on_opening(
+                normal_opening_constructed.curator_opening_id,
+                333,
+                to_vec("CuratorWannabe"),
+                11111,
+                91000,
+                generate_valid_length_buffer(&CuratorApplicationHumanReadableText::get()),
+            );
+
+            /*
+             * Test
+             */
+
+            assert_eq!(
+                ContentWorkingGroup::begin_curator_applicant_review(
+                    Origin::signed(LEAD_ROLE_ACCOUNT),
+                    normal_opening_constructed.curator_opening_id
+                )
+                .unwrap(),
+                ()
+            );
+
+            assert_eq!(
+                get_last_event_or_panic(),
+                lib::RawEvent::BeganCuratorApplicationReview(
+                    normal_opening_constructed.curator_opening_id
+                )
+            );
+
+            /*
+             * TODO: add assertion abouot side-effect in hiring module,
+             * this is where state of application has fundamentally changed.
+             */
+        });
+}
+
+#[test]
+fn fill_curator_opening_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            /*
+             * Setup
+             */
+
+            let applicants = vec![
+                FillOpeningApplicantParams::new(
+                    AddMemberAndApplyOnOpeningParams::new(
+                        2222,
+                        to_vec("yoyoyo0"), // generate_valid_length_buffer(&ChannelHandleConstraint::get()),
+                        2222 * 2,
+                        2222 * 3,
+                        generate_valid_length_buffer(&CuratorApplicationHumanReadableText::get()),
+                    ),
+                    true,
+                ),
+                FillOpeningApplicantParams::new(
+                    AddMemberAndApplyOnOpeningParams::new(
+                        3333,
+                        to_vec("yoyoyo1"), // generate_valid_length_buffer(&ChannelHandleConstraint::get()),
+                        3333 * 2,
+                        3333 * 3,
+                        generate_valid_length_buffer(&CuratorApplicationHumanReadableText::get()),
+                    ),
+                    true,
+                ),
+                FillOpeningApplicantParams::new(
+                    AddMemberAndApplyOnOpeningParams::new(
+                        5555,
+                        to_vec("yoyoyo2"), // generate_valid_length_buffer(&ChannelHandleConstraint::get()),
+                        5555 * 2,
+                        5555 * 3,
+                        generate_valid_length_buffer(&CuratorApplicationHumanReadableText::get()),
+                    ),
+                    false,
+                ),
+                FillOpeningApplicantParams::new(
+                    AddMemberAndApplyOnOpeningParams::new(
+                        6666,
+                        to_vec("yoyoyo3"), // generate_valid_length_buffer(&ChannelHandleConstraint::get()),
+                        6666 * 2,
+                        6666 * 3,
+                        generate_valid_length_buffer(&CuratorApplicationHumanReadableText::get()),
+                    ),
+                    true,
+                ),
+            ];
+
+            /*
+             * Exercise and assert
+             */
+
+            setup_and_fill_opening(&applicants);
+        });
+}
+
+#[test]
+fn withdraw_curator_application_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            /*
+             * Setup
+             */
+
+            let normal_opening_constructed = setup_normal_accepting_opening();
+
+            let curator_applicant_root_and_controller_account = 333;
+            let curator_applicant_role_account = 11111;
+            let human_readable_text =
+                generate_valid_length_buffer(&CuratorApplicationHumanReadableText::get());
+
+            let result = add_member_and_apply_on_opening(
+                normal_opening_constructed.curator_opening_id,
+                curator_applicant_root_and_controller_account,
+                to_vec("CuratorWannabe"),
+                curator_applicant_role_account,
+                91000,
+                human_readable_text,
+            );
+
+            /*
+             * Test
+             */
+
+            assert_eq!(
+                ContentWorkingGroup::withdraw_curator_application(
+                    Origin::signed(curator_applicant_role_account),
+                    result.curator_application_id
+                )
+                .unwrap(),
+                ()
+            );
+
+            // Event was triggered
+            assert_eq!(
+                get_last_event_or_panic(),
+                lib::RawEvent::CuratorApplicationWithdrawn(result.curator_application_id)
+            );
+
+            /*
+             * TODO: add assertion abouot side-effect in hiring module,
+             * this is where state of application has fundamentally changed.
+             */
+        });
+}
+
+#[test]
+fn terminate_curator_application_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            /*
+             * Setup
+             */
+
+            let normal_opening_constructed = setup_normal_accepting_opening();
+
+            let result = add_member_and_apply_on_opening(
+                normal_opening_constructed.curator_opening_id,
+                333,
+                to_vec("CuratorWannabe"),
+                11111,
+                91000,
+                generate_valid_length_buffer(&CuratorApplicationHumanReadableText::get()),
+            );
+
+            /*
+             * Test
+             */
+
+            assert_eq!(
+                ContentWorkingGroup::terminate_curator_application(
+                    Origin::signed(LEAD_ROLE_ACCOUNT),
+                    normal_opening_constructed.curator_opening_id
+                )
+                .unwrap(),
+                ()
+            );
+
+            assert_eq!(
+                get_last_event_or_panic(),
+                lib::RawEvent::CuratorApplicationTerminated(result.curator_application_id)
+            );
+
+            /*
+             * TODO: add assertion abouot side-effect in hiring module,
+             * this is where state of application has fundamentally changed.
+             */
+        });
+}
+
+#[test]
+fn apply_on_curator_opening_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            /*
+             * Setup
+             */
+
+            let normal_opening_constructed = setup_normal_accepting_opening();
+
+            // Add curator membership
+
+            let curator_applicant_root_and_controller_account = 72618;
+
+            let curator_applicant_member_id = add_member(
+                curator_applicant_root_and_controller_account,
+                to_vec("IwillTrytoapplyhere"),
+            );
+
+            let curator_applicant_role_account = 8881111;
+
+            let role_stake_balance = get_baseline_opening_policy()
+                .role_staking_policy
+                .unwrap()
+                .amount;
+            let application_stake_balance = get_baseline_opening_policy()
+                .application_staking_policy
+                .unwrap()
+                .amount;
+            let total_balance = role_stake_balance + application_stake_balance;
+
+            let source_account = 918111;
+
+            // Credit staking source account
+            let _ = balances::Module::<Test>::deposit_creating(&source_account, total_balance);
+
+            let human_readable_text = generate_valid_length_buffer(&ChannelHandleConstraint::get());
+
+            let expected_curator_application_id = NextCuratorApplicationId::<Test>::get();
+
+            let old_curator_opening =
+                CuratorOpeningById::<Test>::get(normal_opening_constructed.curator_opening_id);
+
+            let new_curator_application_id = NextCuratorApplicationId::<Test>::get();
+
+            /*
+             * Test
+             */
+
+            assert_eq!(
+                ContentWorkingGroup::apply_on_curator_opening(
+                    Origin::signed(curator_applicant_root_and_controller_account),
+                    curator_applicant_member_id,
+                    normal_opening_constructed.curator_opening_id,
+                    curator_applicant_role_account,
+                    source_account,
+                    Some(role_stake_balance),
+                    Some(application_stake_balance),
+                    human_readable_text
+                )
+                .unwrap(),
+                ()
+            );
+
+            assert_eq!(
+                get_last_event_or_panic(),
+                lib::RawEvent::AppliedOnCuratorOpening(
+                    normal_opening_constructed.curator_opening_id,
+                    new_curator_application_id
+                )
+            );
+
+            assert!(CuratorApplicationById::<Test>::exists(
+                new_curator_application_id
+            ));
+
+            // Assert that appropriate application has been added
+            let new_curator_application =
+                CuratorApplicationById::<Test>::get(new_curator_application_id);
+
+            let expected_curator_application = CuratorApplication {
+                role_account: curator_applicant_role_account,
+                curator_opening_id: normal_opening_constructed.curator_opening_id,
+                member_id: curator_applicant_member_id,
+                application_id: expected_curator_application_id,
+            };
+
+            assert_eq!(expected_curator_application, new_curator_application);
+
+            // Assert that the opening has had the application added to application list
+            let mut singleton = BTreeSet::new(); // Unavoidable mutable, BTreeSet can only be populated this way.
+            singleton.insert(new_curator_application_id);
+
+            let new_curator_applications = old_curator_opening
+                .curator_applications
+                .union(&singleton)
+                .cloned()
+                .collect();
+
+            let expected_curator_opening = CuratorOpening {
+                curator_applications: new_curator_applications,
+                ..old_curator_opening
+            };
+
+            let new_curator_opening =
+                CuratorOpeningById::<Test>::get(normal_opening_constructed.curator_opening_id);
+
+            assert_eq!(expected_curator_opening, new_curator_opening);
+        });
+}
+
+struct UpdateCuratorRoleAccountFixture {
+    pub origin: Origin,
+    pub member_id: <Test as members::Trait>::MemberId,
+    pub curator_id: CuratorId<Test>,
+    pub new_role_account: <Test as system::Trait>::AccountId,
+}
+
+impl UpdateCuratorRoleAccountFixture {
+    fn call(&self) -> Result<(), &'static str> {
+        ContentWorkingGroup::update_curator_role_account(
+            self.origin.clone(),
+            self.member_id,
+            self.curator_id,
+            self.new_role_account,
+        )
+    }
+
+    pub fn call_and_assert_success(&self) {
+        let original_curator = CuratorById::<Test>::get(self.curator_id);
+
+        let call_result = self.call();
+
+        assert_eq!(call_result, Ok(()));
+
+        let updated_curator = CuratorById::<Test>::get(self.curator_id);
+
+        assert_eq!(
+            lib::Curator {
+                role_account: self.new_role_account,
+                ..original_curator
+            },
+            updated_curator
+        );
+
+        let (event_curator_id, event_new_role_account) = if let mock::TestEvent::lib(ref x) =
+            System::events().last().unwrap().event
+        {
+            if let lib::RawEvent::CuratorRoleAccountUpdated(ref curator_id, ref new_role_account) =
+                x
+            {
+                (curator_id.clone(), new_role_account.clone())
+            } else {
+                panic!("Event was not CuratorRoleAccountUpdated.")
+            }
+        } else {
+            panic!("No event deposited.")
+        };
+
+        assert_eq!(self.curator_id, event_curator_id);
+
+        assert_eq!(self.new_role_account, event_new_role_account);
+    }
+
+    pub fn call_and_assert_failed_result(&self, error_message: &'static str) {
+        let call_result = self.call();
+
+        assert_eq!(call_result, Err(error_message));
+    }
+}
+
+#[test]
+fn update_curator_role_account_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            let result = setup_lead_and_hire_curator();
+
+            let fixture = UpdateCuratorRoleAccountFixture {
+                origin: Origin::signed(
+                    result
+                        .curator_params()
+                        .curator_applicant_root_and_controller_account,
+                ),
+                member_id: result.curator_member_id(),
+                curator_id: result.curator_id(),
+                new_role_account: 777777,
+            };
+
+            fixture.call_and_assert_success();
+        });
+}
+
+struct UpdateCuratorRewardAccountFixture {
+    pub origin: Origin,
+    pub curator_id: CuratorId<Test>,
+    pub new_reward_account: <Test as system::Trait>::AccountId,
+}
+
+impl UpdateCuratorRewardAccountFixture {
+    fn call(&self) -> Result<(), &'static str> {
+        ContentWorkingGroup::update_curator_reward_account(
+            self.origin.clone(),
+            self.curator_id,
+            self.new_reward_account,
+        )
+    }
+
+    pub fn call_and_assert_success(&self) {
+        let _original_curator = CuratorById::<Test>::get(self.curator_id);
+
+        let call_result = self.call();
+
+        assert_eq!(call_result, Ok(()));
+
+        /*
+            Actually checking new reward account requires checking call to token mint module, but we cannot do that properly yet.
+        */
+
+        let (event_curator_id, event_reward_account) = if let mock::TestEvent::lib(ref x) =
+            System::events().last().unwrap().event
+        {
+            if let lib::RawEvent::CuratorRewardAccountUpdated(ref curator_id, ref reward_account) =
+                x
+            {
+                (curator_id.clone(), reward_account.clone())
+            } else {
+                panic!("Event was not CuratorRewardAccountUpdated.")
+            }
+        } else {
+            panic!("No event deposited.")
+        };
+
+        assert_eq!(self.curator_id, event_curator_id);
+
+        assert_eq!(self.new_reward_account, event_reward_account);
+    }
+
+    pub fn call_and_assert_failed_result(&self, error_message: &'static str) {
+        let call_result = self.call();
+
+        assert_eq!(call_result, Err(error_message));
+    }
+}
+
+#[test]
+fn update_curator_reward_account_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            let result = setup_lead_and_hire_curator();
+
+            let _fixture = UpdateCuratorRewardAccountFixture {
+                origin: Origin::signed(result.curator_params().curator_applicant_role_account),
+                curator_id: result.curator_id(),
+                new_reward_account: 123321,
+            };
+
+            // TEMPORARILY DISABLED
+            //fixture.call_and_assert_success();
+        });
+}
+
+struct LeaveCuratorRoleFixture {
+    pub origin: Origin,
+    pub curator_id: CuratorId<Test>,
+    pub rationale_text: Vec<u8>,
+}
+
+impl LeaveCuratorRoleFixture {
+    fn call(&self) -> Result<(), &'static str> {
+        ContentWorkingGroup::leave_curator_role(
+            self.origin.clone(),
+            self.curator_id,
+            self.rationale_text.clone(),
+        )
+    }
+
+    pub fn call_and_assert_success(&self) {
+        let original_curator = CuratorById::<Test>::get(self.curator_id);
+
+        let call_result = self.call();
+
+        assert_eq!(call_result, Ok(()));
+
+        let expected_curator = Curator {
+            stage: CuratorRoleStage::Unstaking(CuratorExitSummary::new(
+                &CuratorExitInitiationOrigin::Curator,
+                &1,
+                &self.rationale_text,
+            )),
+            ..(original_curator.clone())
+        };
+
+        let updated_curator = CuratorById::<Test>::get(self.curator_id);
+
+        assert_eq!(updated_curator, expected_curator);
+
+        assert_eq!(
+            get_last_event_or_panic(),
+            lib::RawEvent::CuratorUnstaking(self.curator_id)
+        );
+
+        // Tracking unstaking
+        let curator_role_stake_id = original_curator.role_stake_profile.unwrap().stake_id;
+
+        assert!(UnstakerByStakeId::<Test>::exists(curator_role_stake_id));
+
+        let unstaker = UnstakerByStakeId::<Test>::get(curator_role_stake_id);
+
+        assert_eq!(unstaker, WorkingGroupUnstaker::Curator(self.curator_id));
+
+        /*
+         * TODO: Missing checks to calls to
+         * recurringrewards, stake
+         */
+    }
+
+    pub fn call_and_assert_failed_result(&self, error_message: &'static str) {
+        let call_result = self.call();
+
+        assert_eq!(call_result, Err(error_message));
+    }
+}
+
+#[test]
+fn leave_curator_role_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            let result = setup_lead_and_hire_curator();
+
+            let fixture = LeaveCuratorRoleFixture {
+                origin: Origin::signed(result.curator_params().curator_applicant_role_account),
+                curator_id: result.curator_id(),
+                rationale_text: "I am sick of this horrible thing".as_bytes().to_vec(),
+            };
+
+            fixture.call_and_assert_success();
+        });
+}
+
+struct TerminateCuratorRoleFixture {
+    pub origin: Origin,
+    pub curator_id: CuratorId<Test>,
+    pub rationale_text: Vec<u8>,
+}
+
+impl TerminateCuratorRoleFixture {
+    fn call(&self) -> Result<(), &'static str> {
+        ContentWorkingGroup::terminate_curator_role(
+            self.origin.clone(),
+            self.curator_id,
+            self.rationale_text.clone(),
+        )
+    }
+
+    pub fn call_and_assert_success(&self) {
+        let original_curator = CuratorById::<Test>::get(self.curator_id);
+
+        let call_result = self.call();
+
+        assert_eq!(call_result, Ok(()));
+
+        let expected_curator = Curator {
+            stage: CuratorRoleStage::Unstaking(CuratorExitSummary::new(
+                &CuratorExitInitiationOrigin::Lead,
+                &1,
+                &self.rationale_text,
+            )),
+            ..(original_curator.clone())
+        };
+
+        let updated_curator = CuratorById::<Test>::get(self.curator_id);
+
+        assert_eq!(updated_curator, expected_curator);
+
+        assert_eq!(
+            get_last_event_or_panic(),
+            lib::RawEvent::CuratorUnstaking(self.curator_id)
+        );
+
+        // Tracking unstaking
+        let curator_role_stake_id = original_curator.role_stake_profile.unwrap().stake_id;
+
+        assert!(UnstakerByStakeId::<Test>::exists(curator_role_stake_id));
+
+        let unstaker = UnstakerByStakeId::<Test>::get(curator_role_stake_id);
+
+        assert_eq!(unstaker, WorkingGroupUnstaker::Curator(self.curator_id));
+
+        /*
+         * TODO: Missing checks to calls to
+         * recurringrewards, stake
+         */
+    }
+
+    pub fn call_and_assert_failed_result(&self, error_message: &'static str) {
+        let call_result = self.call();
+
+        assert_eq!(call_result, Err(error_message));
+    }
+}
+
+#[test]
+fn terminate_curator_role_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            let result = setup_lead_and_hire_curator();
+
+            let fixture = TerminateCuratorRoleFixture {
+                origin: Origin::signed(LEAD_ROLE_ACCOUNT),
+                curator_id: result.curator_id(),
+                rationale_text: "This curator is a joke!".as_bytes().to_vec(),
+            };
+
+            fixture.call_and_assert_success();
+        });
+}
+
+struct SetLeadFixture {
+    pub origin: Origin,
+    pub member_id: <Test as members::Trait>::MemberId,
+    pub new_role_account: <Test as system::Trait>::AccountId,
+}
+
+impl SetLeadFixture {
+    fn call(&self) -> Result<(), &'static str> {
+        ContentWorkingGroup::set_lead(self.origin.clone(), self.member_id, self.new_role_account)
+    }
+
+    pub fn call_and_assert_success(&self) {
+        let original_next_lead_id = NextLeadId::<Test>::get();
+
+        let call_result = self.call();
+
+        assert_eq!(call_result, Ok(()));
+
+        let updated_next_lead_id = NextLeadId::<Test>::get();
+
+        assert_eq!(original_next_lead_id + 1, updated_next_lead_id);
+
+        let new_lead_id = if let Some(id) = CurrentLeadId::<Test>::get() {
+            id
+        } else {
+            panic!("Lead not set when it must be.")
+        };
+
+        let new_lead = LeadById::<Test>::get(new_lead_id);
+
+        let expected_new_lead = Lead {
+            role_account: self.new_role_account,
+            reward_relationship: None,
+            inducted: 1, // make dynamic later
+            stage: LeadRoleState::Active,
+        };
+
+        assert_eq!(new_lead, expected_new_lead);
+
+        assert_eq!(
+            get_last_event_or_panic(),
+            lib::RawEvent::LeadSet(new_lead_id)
+        );
+    }
+
+    pub fn call_and_assert_failed_result(&self, error_message: &'static str) {
+        let number_of_events_before_call = System::events().len();
+
+        let call_result = self.call();
+
+        assert_eq!(call_result, Err(error_message));
+
+        assert_eq!(System::events().len(), number_of_events_before_call);
+    }
+}
+
+#[test]
+fn set_lead_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            let member_id =
+                add_member(LEAD_ROOT_AND_CONTROLLER_ACCOUNT, to_vec(LEAD_MEMBER_HANDLE));
+
+            SetLeadFixture {
+                origin: Origin::system(system::RawOrigin::Root),
+                member_id,
+                new_role_account: 44444,
+            }
+            .call_and_assert_success();
+        });
+}
+
+struct UnsetLeadFixture {
+    pub origin: Origin,
+}
+
+impl UnsetLeadFixture {
+    fn call(&self) -> Result<(), &'static str> {
+        ContentWorkingGroup::unset_lead(self.origin.clone())
+    }
+
+    pub fn call_and_assert_success(&self) {
+        let original_lead_id = CurrentLeadId::<Test>::get().unwrap();
+        let original_lead = LeadById::<Test>::get(original_lead_id);
+
+        let call_result = self.call();
+
+        assert_eq!(call_result, Ok(()));
+
+        assert!(CurrentLeadId::<Test>::get().is_none());
+
+        let updated_lead = LeadById::<Test>::get(original_lead_id);
+
+        let expected_updated_lead = Lead {
+            stage: LeadRoleState::Exited(ExitedLeadRole {
+                initiated_at_block_number: 1,
+            }),
+            ..original_lead
+        };
+
+        assert_eq!(updated_lead, expected_updated_lead);
+
+        assert_eq!(
+            get_last_event_or_panic(),
+            lib::RawEvent::LeadUnset(original_lead_id)
+        );
+    }
+
+    pub fn call_and_assert_failed_result(&self, error_message: &'static str) {
+        let number_of_events_before_call = System::events().len();
+
+        let call_result = self.call();
+
+        assert_eq!(call_result, Err(error_message));
+
+        assert_eq!(System::events().len(), number_of_events_before_call);
+    }
+}
+
 #[test]
-fn add_opening_error_wrapper_succeeded() {
-    let mut message: &str;
+fn unset_lead_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            let _ = add_member_and_set_as_lead();
+
+            UnsetLeadFixture {
+                origin: Origin::system(system::RawOrigin::Root),
+            }
+            .call_and_assert_success();
+        });
+}
+
+struct UnstakedFixture {
+    pub stake_id: StakeId<Test>,
+}
 
-    message = super::lib::WrappedError {
-        error: hiring::AddOpeningError::OpeningMustActivateInTheFuture,
+impl UnstakedFixture {
+    fn call(&self) {
+        ContentWorkingGroup::unstaked(self.stake_id);
     }
-    .into();
-    assert_eq!(message, "Opening must activate in the future");
 
-    message = super::lib::WrappedError {
-        error: hiring::AddOpeningError::StakeAmountLessThanMinimumCurrencyBalance(
-            hiring::StakePurpose::Role,
-        ),
+    pub fn call_and_assert_success(&self) {
+        let unstaker = UnstakerByStakeId::<Test>::get(self.stake_id);
+
+        let curator_id = if let WorkingGroupUnstaker::Curator(curator_id) = unstaker {
+            curator_id
+        } else {
+            panic!("Unstaker not curator")
+        };
+
+        let original_curator = CuratorById::<Test>::get(curator_id);
+
+        let original_exit_summary =
+            if let CuratorRoleStage::Unstaking(exit_summary) = (original_curator.clone()).stage {
+                exit_summary
+            } else {
+                panic!("Curator not unstaking")
+            };
+
+        self.call();
+
+        let expected_curator = Curator {
+            stage: CuratorRoleStage::Exited(original_exit_summary),
+            ..(original_curator.clone())
+        };
+
+        let updated_curator = CuratorById::<Test>::get(curator_id);
+
+        assert_eq!(updated_curator, expected_curator);
+
+        assert_eq!(
+            get_last_event_or_panic(),
+            lib::RawEvent::TerminatedCurator(curator_id)
+        );
+
+        // Unstaker gone
+        assert!(!UnstakerByStakeId::<Test>::exists(self.stake_id));
+    }
+
+    // pub fn call_and_assert_failed_result(&self, error_message: &'static str) {
+    //     let call_result = self.call();
+
+    //     assert_eq!(call_result, Err(error_message));
+    // }
+}
+
+#[test]
+fn unstaked_curator_success() {
+    TestExternalitiesBuilder::<Test>::default()
+        .build()
+        .execute_with(|| {
+            let result = setup_lead_and_hire_curator();
+
+            TerminateCuratorRoleFixture {
+                origin: Origin::signed(LEAD_ROLE_ACCOUNT),
+                curator_id: result.curator_id(),
+                rationale_text: "This curator is a joke!".as_bytes().to_vec(),
+            }
+            .call_and_assert_success();
+
+            let curator_role_stake_id = CuratorById::<Test>::get(result.curator_id())
+                .role_stake_profile
+                .unwrap()
+                .stake_id;
+
+            UnstakedFixture {
+                stake_id: curator_role_stake_id,
+            }
+            .call_and_assert_success();
+        });
+}
+
+#[test]
+fn account_can_act_as_principal_success() {}
+
+/*
+ * Fixtures
+ */
+
+static LEAD_ROOT_AND_CONTROLLER_ACCOUNT: <Test as system::Trait>::AccountId = 1289;
+static LEAD_ROLE_ACCOUNT: <Test as system::Trait>::AccountId = 1289;
+static LEAD_MEMBER_HANDLE: &str = "IamTheLead";
+static CHANNEL_CREATOR_ROOT_AND_CONTROLLER_ACCOUNT: <Test as system::Trait>::AccountId = 11;
+static CHANNEL_CREATOR_HANDLE: &str = "Coolcreator";
+
+fn make_generic_add_member_params() -> AddMemberAndApplyOnOpeningParams {
+    AddMemberAndApplyOnOpeningParams::new(
+        2222,
+        to_vec("yoyoyo0"), // generate_valid_length_buffer(&ChannelHandleConstraint::get()),
+        2222 * 2,
+        2222 * 3,
+        generate_valid_length_buffer(&CuratorApplicationHumanReadableText::get()),
+    )
+}
+
+/// Made into function to avoid having to clone every time we read fields
+pub fn get_baseline_opening_policy(
+) -> OpeningPolicyCommitment<<Test as system::Trait>::BlockNumber, BalanceOf<Test>> {
+    OpeningPolicyCommitment {
+        application_rationing_policy: Some(hiring::ApplicationRationingPolicy {
+            max_active_applicants: 5,
+        }),
+        max_review_period_length: 100,
+        application_staking_policy: Some(hiring::StakingPolicy {
+            amount: 40000,
+            amount_mode: hiring::StakingAmountLimitMode::Exact,
+            crowded_out_unstaking_period_length: Some(3),
+            review_period_expired_unstaking_period_length: Some(22),
+        }),
+        role_staking_policy: Some(hiring::StakingPolicy {
+            amount: 900000,
+            amount_mode: hiring::StakingAmountLimitMode::AtLeast,
+            crowded_out_unstaking_period_length: Some(30),
+            review_period_expired_unstaking_period_length: Some(2),
+        }),
+        role_slashing_terms: SlashingTerms::Unslashable,
+
+        fill_opening_successful_applicant_application_stake_unstaking_period: None,
+        fill_opening_failed_applicant_application_stake_unstaking_period: None,
+        fill_opening_failed_applicant_role_stake_unstaking_period: None,
+        terminate_curator_application_stake_unstaking_period: None,
+        terminate_curator_role_stake_unstaking_period: None,
+        exit_curator_role_application_stake_unstaking_period: None,
+        exit_curator_role_stake_unstaking_period: None,
+    }
+}
+
+pub fn to_vec(s: &str) -> Vec<u8> {
+    s.as_bytes().to_vec()
+}
+
+/*
+ * Setups
+ */
+
+//type TestSeed = u128;
+
+/*
+fn account_from_seed(TestSeed: seed) -> <Test as system::Trait>::AccountId {
+
+}
+
+fn vector_from_seed(TestSeed: seed) {
+
+}
+*/
+
+/*
+static INITIAL_SEED_VALUE: u128 = 0;
+static CURRENT_SEED: u128 = INITIAL_SEED_VALUE;
+
+fn get_current_seed() {
+
+}
+
+fn update_seed() {
+
+}
+
+fn reset_seed() {
+    CURRENT_SEED: u128 = INITIAL_SEED_VALUE;
+}
+*/
+
+// MOVE THIS LATER WHEN fill_opening is factored out
+#[derive(Clone)]
+pub struct FillOpeningApplicantParams {
+    pub add_and_apply_params: AddMemberAndApplyOnOpeningParams,
+    pub hire: bool,
+}
+
+impl FillOpeningApplicantParams {
+    pub fn new(add_and_apply_params: AddMemberAndApplyOnOpeningParams, hire: bool) -> Self {
+        Self {
+            add_and_apply_params: add_and_apply_params.clone(),
+            hire: hire,
+        }
+    }
+}
+
+#[derive(Clone)]
+pub struct AddMemberAndApplyOnOpeningParams {
+    pub curator_applicant_root_and_controller_account: <Test as system::Trait>::AccountId,
+    pub handle: Vec<u8>,
+    pub curator_applicant_role_account: <Test as system::Trait>::AccountId,
+    pub source_account: <Test as system::Trait>::AccountId,
+    pub human_readable_text: Vec<u8>,
+}
+
+impl AddMemberAndApplyOnOpeningParams {
+    pub fn new(
+        curator_applicant_root_and_controller_account: <Test as system::Trait>::AccountId,
+        handle: Vec<u8>,
+        curator_applicant_role_account: <Test as system::Trait>::AccountId,
+        source_account: <Test as system::Trait>::AccountId,
+        human_readable_text: Vec<u8>,
+    ) -> Self {
+        Self {
+            curator_applicant_root_and_controller_account,
+            handle,
+            curator_applicant_role_account,
+            source_account,
+            human_readable_text,
+        }
+    }
+}
+
+fn add_members_and_apply_on_opening(
+    curator_opening_id: CuratorOpeningId<Test>,
+    applicants: &Vec<AddMemberAndApplyOnOpeningParams>,
+) -> Vec<NewMemberAppliedResult> {
+    applicants
+        .iter()
+        .cloned()
+        .map(|params| -> NewMemberAppliedResult {
+            add_member_and_apply_on_opening(
+                curator_opening_id,
+                params.curator_applicant_root_and_controller_account,
+                params.handle,
+                params.curator_applicant_role_account,
+                params.source_account,
+                params.human_readable_text,
+            )
+        })
+        .collect()
+}
+
+#[derive(Clone)]
+struct NewMemberAppliedResult {
+    pub member_id: <Test as members::Trait>::MemberId,
+    pub curator_application_id: lib::CuratorApplicationId<Test>,
+}
+
+fn add_member_and_apply_on_opening(
+    curator_opening_id: CuratorOpeningId<Test>,
+    curator_applicant_root_and_controller_account: <Test as system::Trait>::AccountId,
+    handle: Vec<u8>,
+    curator_applicant_role_account: <Test as system::Trait>::AccountId,
+    source_account: <Test as system::Trait>::AccountId,
+    human_readable_text: Vec<u8>,
+) -> NewMemberAppliedResult {
+    // Make membership
+    let curator_applicant_member_id =
+        add_member(curator_applicant_root_and_controller_account, handle);
+
+    // Guarantee sufficient stake
+    let role_stake_balance = if let Some(policy) = get_baseline_opening_policy().role_staking_policy
+    {
+        policy.amount
+    } else {
+        0
+    };
+
+    let application_stake_balance =
+        if let Some(policy) = get_baseline_opening_policy().application_staking_policy {
+            policy.amount
+        } else {
+            0
+        };
+
+    let total_balance = role_stake_balance + application_stake_balance;
+
+    // Credit staking source account if required
+    if total_balance > 0 {
+        let _ = balances::Module::<Test>::deposit_creating(&source_account, total_balance);
     }
-    .into();
+
+    let expected_curator_application_id = NextCuratorApplicationId::<Test>::get();
+
+    let old_curator_opening = CuratorOpeningById::<Test>::get(curator_opening_id);
+
+    let new_curator_application_id = NextCuratorApplicationId::<Test>::get();
+
+    /*
+     * Test
+     */
+
     assert_eq!(
-        message,
-        "Role stake amount less than minimum currency balance"
+        ContentWorkingGroup::apply_on_curator_opening(
+            Origin::signed(curator_applicant_root_and_controller_account),
+            curator_applicant_member_id,
+            curator_opening_id,
+            curator_applicant_role_account,
+            source_account,
+            Some(role_stake_balance),
+            Some(application_stake_balance),
+            human_readable_text
+        )
+        .unwrap(),
+        ()
     );
 
-    message = super::lib::WrappedError {
-        error: hiring::AddOpeningError::StakeAmountLessThanMinimumCurrencyBalance(
-            hiring::StakePurpose::Application,
-        ),
+    assert_eq!(
+        get_last_event_or_panic(),
+        lib::RawEvent::AppliedOnCuratorOpening(curator_opening_id, new_curator_application_id)
+    );
+
+    assert!(CuratorApplicationById::<Test>::exists(
+        new_curator_application_id
+    ));
+
+    // Assert that appropriate application has been added
+    let new_curator_application = CuratorApplicationById::<Test>::get(new_curator_application_id);
+
+    let expected_curator_application = CuratorApplication {
+        role_account: curator_applicant_role_account,
+        curator_opening_id: curator_opening_id,
+        member_id: curator_applicant_member_id,
+        application_id: expected_curator_application_id,
+    };
+
+    assert_eq!(expected_curator_application, new_curator_application);
+
+    // Assert that the opening has had the application added to application list
+    let mut singleton = BTreeSet::new(); // Unavoidable mutable, BTreeSet can only be populated this way.
+    singleton.insert(new_curator_application_id);
+
+    let new_curator_applications = old_curator_opening
+        .curator_applications
+        .union(&singleton)
+        .cloned()
+        .collect();
+
+    let expected_curator_opening = CuratorOpening {
+        curator_applications: new_curator_applications,
+        ..old_curator_opening
+    };
+
+    let new_curator_opening = CuratorOpeningById::<Test>::get(curator_opening_id);
+
+    assert_eq!(expected_curator_opening, new_curator_opening);
+
+    NewMemberAppliedResult {
+        member_id: curator_applicant_member_id,
+        curator_application_id: new_curator_application_id,
+    }
+}
+
+struct NormalOpeningConstructed {
+    pub curator_opening_id: CuratorOpeningId<Test>,
+    pub new_member_as_lead: NewMemberAsLead,
+}
+
+fn setup_normal_opening() -> NormalOpeningConstructed {
+    let new_member_as_lead = add_member_and_set_as_lead();
+
+    let expected_curator_opening_id = NextCuratorOpeningId::<Test>::get();
+
+    assert_eq!(
+        ContentWorkingGroup::add_curator_opening(
+            Origin::signed(LEAD_ROLE_ACCOUNT),
+            hiring::ActivateOpeningAt::ExactBlock(34),
+            get_baseline_opening_policy(),
+            generate_valid_length_buffer(&OpeningHumanReadableText::get())
+        )
+        .unwrap(),
+        ()
+    );
+
+    assert_eq!(
+        get_last_event_or_panic(),
+        lib::RawEvent::CuratorOpeningAdded(expected_curator_opening_id)
+    );
+
+    NormalOpeningConstructed {
+        curator_opening_id: expected_curator_opening_id,
+        new_member_as_lead,
+    }
+}
+
+fn setup_normal_accepting_opening() -> NormalOpeningConstructed {
+    let normal_opening_constructed = setup_normal_opening();
+
+    assert_eq!(
+        ContentWorkingGroup::accept_curator_applications(
+            Origin::signed(LEAD_ROLE_ACCOUNT), // <== get dynamic value from somewhere else later
+            normal_opening_constructed.curator_opening_id
+        )
+        .unwrap(),
+        ()
+    );
+
+    normal_opening_constructed
+}
+
+struct SetupOpeningInReview {
+    //pub curator_opening_id: lib::CuratorOpeningId<Test>,
+    pub normal_opening_constructed: NormalOpeningConstructed,
+    pub added_members_application_result: Vec<NewMemberAppliedResult>,
+}
+
+fn setup_opening_in_review(
+    applicants: &Vec<AddMemberAndApplyOnOpeningParams>,
+) -> SetupOpeningInReview {
+    let normal_opening_constructed = setup_normal_accepting_opening();
+
+    let added_members_application_result =
+        add_members_and_apply_on_opening(normal_opening_constructed.curator_opening_id, applicants);
+
+    assert_eq!(
+        ContentWorkingGroup::begin_curator_applicant_review(
+            Origin::signed(LEAD_ROLE_ACCOUNT),
+            normal_opening_constructed.curator_opening_id
+        )
+        .unwrap(),
+        ()
+    );
+
+    // TODO: assert event stuff !!!!
+
+    SetupOpeningInReview {
+        normal_opening_constructed,
+        added_members_application_result,
     }
-    .into();
+}
+
+enum FillOpeningApplicantOutcome {
+    NotHired,
+    Hired { curator_id: CuratorId<Test> },
+}
+
+struct SetupAndFillOpeningResult {
+    setup_opening_in_review: SetupOpeningInReview,
+    application_outomes: Vec<FillOpeningApplicantOutcome>,
+}
+
+fn setup_and_fill_opening(
+    applicants: &Vec<FillOpeningApplicantParams>,
+) -> SetupAndFillOpeningResult {
+    let setup_opening_params = applicants
+        .iter()
+        .cloned()
+        .map(|param| param.add_and_apply_params)
+        .collect::<Vec<_>>();
+
+    let setup_opening_in_review = setup_opening_in_review(&setup_opening_params);
+
+    let curator_opening = CuratorOpeningById::<Test>::get(
+        setup_opening_in_review
+            .normal_opening_constructed
+            .curator_opening_id,
+    );
+
+    // Set whom to hire
+    let applicants_to_hire_iter = applicants.iter().filter(|params| params.hire);
+
+    let num_applicants_hired = applicants_to_hire_iter.cloned().count();
+    //let num_applicants_not_to_hire = (applicants.len() - num_applicants_hired) as usize;
+
+    let hired_applicant_and_result = setup_opening_in_review
+        .added_members_application_result
+        .iter()
+        .zip(applicants.iter())
+        .filter(|(_, fill_opening_applicant_params)| fill_opening_applicant_params.hire)
+        .collect::<Vec<_>>();
+
+    let successful_curator_application_ids = hired_applicant_and_result
+        .iter()
+        .map(|(new_member_applied_result, _)| new_member_applied_result.curator_application_id)
+        .collect::<BTreeSet<_>>();
+
+    // Remember original id counters
+    let original_next_curator_id = NextCuratorId::<Test>::get();
+    let original_next_principal_id = NextPrincipalId::<Test>::get();
+
+    /*
+     * Call
+     */
+
+    assert_eq!(
+        ContentWorkingGroup::fill_curator_opening(
+            Origin::signed(LEAD_ROLE_ACCOUNT),
+            setup_opening_in_review
+                .normal_opening_constructed
+                .curator_opening_id,
+            successful_curator_application_ids.clone()
+        ),
+        Ok(())
+    );
+
+    /*
+     * Asserts
+     */
+
+    let successful_curator_application_id_to_curator_id = successful_curator_application_ids
+        .iter()
+        .enumerate()
+        .map(
+            |(index, item)| -> (CuratorApplicationId<Test>, CuratorId<Test>) {
+                let curator_id = original_next_curator_id + (index as CuratorId<Test>);
+
+                (*item, curator_id)
+            },
+        )
+        .collect::<BTreeMap<_, _>>();
+
     assert_eq!(
-        message,
-        "Application stake amount less than minimum currency balance"
+        get_last_event_or_panic(),
+        lib::RawEvent::CuratorOpeningFilled(
+            setup_opening_in_review
+                .normal_opening_constructed
+                .curator_opening_id,
+            successful_curator_application_id_to_curator_id
+        )
     );
 
-    message = super::lib::WrappedError {
-        error: hiring::AddOpeningError::ApplicationRationingZeroMaxApplicants,
+    // The right number of curators have been created
+    let num_curators_created = NextCuratorId::<Test>::get() - original_next_curator_id;
+
+    assert_eq!(num_curators_created, (num_applicants_hired as u64));
+
+    // The right numbe of prinipals were created
+    let num_principals_created = NextPrincipalId::<Test>::get() - original_next_principal_id;
+
+    assert_eq!(num_principals_created, (num_applicants_hired as u64));
+
+    // Inspect all expected curators and principal added
+    for (hired_index, item) in hired_applicant_and_result.iter().enumerate() {
+        let (new_member_applied_result, fill_opening_applicant_params) = item;
+
+        // Curator
+        let expected_added_curator_id: u64 = (hired_index as u64) + original_next_curator_id;
+
+        // Principal
+        let expected_added_principal_id: u64 = (hired_index as u64) + original_next_principal_id;
+
+        // Curator added
+        assert!(CuratorById::<Test>::exists(expected_added_curator_id));
+
+        let added_curator = CuratorById::<Test>::get(expected_added_curator_id);
+
+        // expected_curator
+        let reward_relationship = None::<<Test as recurringrewards::Trait>::RewardRelationshipId>;
+
+        let curator_application =
+            CuratorApplicationById::<Test>::get(new_member_applied_result.curator_application_id);
+        let application_id = curator_application.application_id;
+        let application = hiring::ApplicationById::<Test>::get(application_id);
+
+        let role_stake_profile = if let Some(ref stake_id) = application.active_role_staking_id {
+            // get_baseline_opening_policy().role_staking_policy {
+
+            Some(CuratorRoleStakeProfile::new(
+                stake_id,
+                &curator_opening
+                    .policy_commitment
+                    .terminate_curator_role_stake_unstaking_period,
+                &curator_opening
+                    .policy_commitment
+                    .exit_curator_role_stake_unstaking_period,
+            ))
+        } else {
+            None
+        };
+
+        let expected_curator = Curator {
+            role_account: fill_opening_applicant_params
+                .add_and_apply_params
+                .curator_applicant_role_account,
+            reward_relationship: reward_relationship,
+            role_stake_profile: role_stake_profile, //  added_curator.role_stake_profile.clone(),
+            stage: CuratorRoleStage::Active,
+            induction: CuratorInduction::new(
+                &setup_opening_in_review
+                    .normal_opening_constructed
+                    .new_member_as_lead
+                    .lead_id,
+                &new_member_applied_result.curator_application_id,
+                &1,
+            ),
+            principal_id: expected_added_principal_id,
+        };
+
+        assert_eq!(expected_curator, added_curator);
+
+        // Principal added
+        assert!(PrincipalById::<Test>::exists(expected_added_principal_id));
+
+        let added_principal = PrincipalById::<Test>::get(expected_added_principal_id);
+
+        let expected_added_principal = Principal::Curator(expected_added_principal_id);
+
+        assert_eq!(added_principal, expected_added_principal);
+    }
+
+    /*
+     * TODO: add assertion abouot side-effect in !hiring & membership! module,
+     * this is where state of application has fundamentally changed.
+     */
+
+    let application_outomes = applicants
+        .iter()
+        .enumerate()
+        .map(|(index, params)| {
+            if params.hire {
+                FillOpeningApplicantOutcome::Hired {
+                    curator_id: (index as u64) + original_next_curator_id,
+                }
+            } else {
+                FillOpeningApplicantOutcome::NotHired
+            }
+        })
+        .collect::<Vec<_>>();
+
+    SetupAndFillOpeningResult {
+        setup_opening_in_review,
+        application_outomes,
+    }
+}
+
+struct SetupLeadAndHireCuratorResult {
+    pub curator_params: AddMemberAndApplyOnOpeningParams,
+    pub setup_and_fill_opening_result: SetupAndFillOpeningResult,
+}
+
+impl SetupLeadAndHireCuratorResult {
+    fn curator_params(&self) -> AddMemberAndApplyOnOpeningParams {
+        self.curator_params.clone()
+    }
+
+    pub fn curator_id(&self) -> CuratorId<Test> {
+        match self.setup_and_fill_opening_result.application_outomes[0] {
+            FillOpeningApplicantOutcome::Hired { curator_id } => curator_id,
+            _ => panic!(),
+        }
+    }
+
+    pub fn curator_member_id(&self) -> <Test as members::Trait>::MemberId {
+        self.setup_and_fill_opening_result
+            .setup_opening_in_review
+            .added_members_application_result[0]
+            .member_id
+    }
+}
+
+fn setup_lead_and_hire_curator() -> SetupLeadAndHireCuratorResult {
+    let curator_params = make_generic_add_member_params();
+
+    // Hire curator
+    let setup_and_fill_opening_result =
+        setup_and_fill_opening(&vec![FillOpeningApplicantParams::new(
+            curator_params.clone(),
+            true,
+        )]);
+
+    SetupLeadAndHireCuratorResult {
+        curator_params,
+        setup_and_fill_opening_result,
+    }
+}
+
+struct CreateChannelFixture {
+    pub channel_creator_member_id: <Test as members::Trait>::MemberId,
+    pub controller_account: <Test as system::Trait>::AccountId,
+    pub channel_creator_role_account: <Test as system::Trait>::AccountId,
+    pub channel_handle: Vec<u8>,
+    pub channel_title: Vec<u8>,
+    pub description: Vec<u8>,
+    pub avatar: Vec<u8>,
+    pub banner: Vec<u8>,
+    pub content: ChannelContentType,
+    pub publishing_status: ChannelPublishingStatus,
+}
+
+impl CreateChannelFixture {
+    pub fn make_valid_unpulished_video_channel_for(
+        channel_creator_member_id: <Test as members::Trait>::MemberId,
+        override_controller_account: Option<<Test as system::Trait>::AccountId>,
+    ) -> Self {
+        let controller_account = if let Some(account) = override_controller_account {
+            account
+        } else {
+            members::Module::<Test>::ensure_profile(channel_creator_member_id)
+                .unwrap()
+                .controller_account
+        };
+
+        Self {
+            channel_creator_member_id,
+            controller_account,
+            channel_creator_role_account: 527489,
+            channel_handle: generate_valid_length_buffer(&ChannelHandleConstraint::get()),
+            channel_title: generate_valid_length_buffer(&ChannelTitleConstraint::get()),
+            avatar: generate_valid_length_buffer(&ChannelAvatarConstraint::get()),
+            banner: generate_valid_length_buffer(&ChannelBannerConstraint::get()),
+            description: generate_valid_length_buffer(&ChannelDescriptionConstraint::get()),
+            content: ChannelContentType::Video,
+            publishing_status: ChannelPublishingStatus::NotPublished,
+        }
+    }
+
+    fn create_channel(&self) -> Result<(), &'static str> {
+        ContentWorkingGroup::create_channel(
+            Origin::signed(self.controller_account),
+            self.channel_creator_member_id,
+            self.channel_creator_role_account,
+            self.channel_handle.clone(),
+            self.channel_title.clone(),
+            self.description.clone(),
+            self.avatar.clone(),
+            self.banner.clone(),
+            self.content.clone(),
+            self.publishing_status.clone(),
+        )
+    }
+
+    pub fn call_and_assert_error(&self, err_message: &'static str) {
+        let number_of_events_before_call = System::events().len();
+
+        let call_result = self.create_channel();
+
+        assert_eq!(call_result, Err(err_message));
+
+        // No new events deposited
+        assert_eq!(System::events().len(), number_of_events_before_call);
+    }
+
+    pub fn call_and_assert_success(&self) -> ChannelId<Test> {
+        let old_next_channel_id = NextChannelId::<Test>::get();
+
+        let call_result = self.create_channel();
+
+        // Call result was Ok
+        assert_eq!(call_result, Ok(()));
+
+        // Assert that event was triggered,
+        // keep channel id.
+        assert_eq!(
+            get_last_event_or_panic(),
+            lib::RawEvent::ChannelCreated(old_next_channel_id)
+        );
+
+        let channel_id = old_next_channel_id;
+
+        // Assert that given channel id has been added,
+        // and has the right properties.
+        assert!(lib::ChannelById::<Test>::exists(channel_id));
+
+        let created_channel = lib::ChannelById::<Test>::get(channel_id);
+
+        let expected_channel = Channel {
+            verified: false,
+            handle: self.channel_handle.clone(),
+            title: self.channel_title.clone(),
+            avatar: self.avatar.clone(),
+            banner: self.banner.clone(),
+            description: self.description.clone(),
+            content: self.content.clone(),
+            owner: self.channel_creator_member_id,
+            role_account: self.channel_creator_role_account,
+            publishing_status: self.publishing_status.clone(),
+            curation_status: ChannelCurationStatus::Normal,
+            created: 1, // <== replace with now()
+
+            // We have no expectation here, so we just copy what was added
+            principal_id: created_channel.principal_id,
+        };
+
+        assert_eq!(created_channel, expected_channel);
+
+        // Assert that next id incremented.
+        assert_eq!(lib::NextChannelId::<Test>::get(), channel_id + 1);
+
+        // Assert that there is a mapping established for handle
+        assert_eq!(
+            lib::ChannelIdByHandle::<Test>::get(self.channel_handle.clone()),
+            channel_id
+        );
+
+        // Check that principal actually has been added
+        assert!(lib::PrincipalById::<Test>::exists(
+            created_channel.principal_id
+        ));
+
+        let created_principal = lib::PrincipalById::<Test>::get(created_channel.principal_id);
+
+        assert!(match created_principal {
+            Principal::Lead => false,
+            Principal::Curator(_) => false,
+            Principal::ChannelOwner(created_principal_channel_id) =>
+                created_principal_channel_id == channel_id,
+        });
+
+        channel_id
     }
-    .into();
+}
+
+struct NewMemberAsLead {
+    pub member_id: <Test as members::Trait>::MemberId,
+    pub lead_id: LeadId<Test>,
+}
+
+fn add_member_and_set_as_lead() -> NewMemberAsLead {
+    let member_id = add_member(LEAD_ROOT_AND_CONTROLLER_ACCOUNT, to_vec(LEAD_MEMBER_HANDLE));
+
+    let lead_id = set_lead(member_id, LEAD_ROLE_ACCOUNT);
+
+    NewMemberAsLead { member_id, lead_id }
+}
+
+pub fn set_channel_creation_enabled(enabled: bool) {
+    lib::Module::<Test>::set_channel_creation_enabled(Origin::signed(LEAD_ROLE_ACCOUNT), enabled)
+        .unwrap()
+}
+
+pub fn add_channel_creator_member() -> <Test as members::Trait>::MemberId {
+    let channel_creator_member_id = add_member(
+        CHANNEL_CREATOR_ROOT_AND_CONTROLLER_ACCOUNT,
+        to_vec(CHANNEL_CREATOR_HANDLE),
+    );
+
+    channel_creator_member_id
+}
+
+pub fn add_member(
+    root_and_controller_account: <Test as system::Trait>::AccountId,
+    handle: Vec<u8>,
+) -> <Test as members::Trait>::MemberId {
+    let next_member_id = members::MembersCreated::<Test>::get();
+
+    assert_eq!(
+        members::Module::<Test>::buy_membership(
+            Origin::signed(root_and_controller_account),
+            0,
+            members::UserInfo {
+                handle: Some(handle),
+                avatar_uri: None,
+                about: None,
+            }
+        )
+        .unwrap(),
+        ()
+    );
+
+    next_member_id
+}
+
+pub fn set_lead(
+    member_id: <Test as members::Trait>::MemberId,
+    new_role_account: <Test as system::Trait>::AccountId,
+) -> LeadId<Test> {
+    // Get controller account
+    //let lead_member_controller_account = members::Module::<Test>::ensure_profile(member_id).unwrap().controller_account;
+
+    let expected_lead_id = NextLeadId::<Test>::get();
+
+    // Set lead
+    assert_eq!(
+        ContentWorkingGroup::set_lead(
+            mock::Origin::system(system::RawOrigin::Root),
+            member_id,
+            new_role_account
+        )
+        .unwrap(),
+        ()
+    );
+
+    assert_eq!(
+        get_last_event_or_panic(),
+        lib::RawEvent::LeadSet(expected_lead_id)
+    );
+
+    expected_lead_id
+}
+
+// lead_role_account: <Test as system::Trait>::AccountId
+pub fn add_curator_opening() -> CuratorOpeningId<Test> {
+    let activate_at = hiring::ActivateOpeningAt::ExactBlock(34);
+
+    let human_readable_text = generate_valid_length_buffer(&OpeningHumanReadableText::get());
+
+    let expected_curator_opening_id = NextCuratorOpeningId::<Test>::get();
+
+    assert_eq!(
+        ContentWorkingGroup::add_curator_opening(
+            Origin::signed(LEAD_ROLE_ACCOUNT),
+            activate_at.clone(),
+            get_baseline_opening_policy(),
+            human_readable_text.clone()
+        )
+        .unwrap(),
+        ()
+    );
+
     assert_eq!(
-        message,
-        "Application rationing policy: maximum active applicant number must be greater than zero"
+        get_last_event_or_panic(),
+        lib::RawEvent::CuratorOpeningAdded(expected_curator_opening_id)
     );
+
+    expected_curator_opening_id
+}
+
+/*
+ * Buffer generators
+ */
+
+pub fn generate_text(len: usize) -> Vec<u8> {
+    vec![b'x'; len]
+}
+
+pub fn generate_valid_length_buffer(constraint: &InputValidationLengthConstraint) -> Vec<u8> {
+    generate_text(constraint.min as usize)
+}
+
+pub fn generate_too_short_length_buffer(constraint: &InputValidationLengthConstraint) -> Vec<u8> {
+    generate_text((constraint.min - 1) as usize)
+}
+
+pub fn generate_too_long_length_buffer(constraint: &InputValidationLengthConstraint) -> Vec<u8> {
+    generate_text((constraint.max() + 1) as usize)
 }

+ 47 - 0
src/membership/genesis.rs

@@ -0,0 +1,47 @@
+#![cfg(test)]
+
+use crate::currency::BalanceOf;
+use rstd::prelude::*;
+//pub use super::members::{GenesisConfig, Trait};
+
+use super::members::{self, Trait};
+
+/// Builder fo membership module genesis configuration.
+pub struct GenesisConfigBuilder<T: Trait> {
+    default_paid_membership_fee: BalanceOf<T>,
+    members: Vec<T::AccountId>,
+}
+
+impl<T: Trait> Default for GenesisConfigBuilder<T> {
+    fn default() -> Self {
+        Self {
+            default_paid_membership_fee: BalanceOf::<T>::default(), // Was 100, will this break any tests??
+            members: vec![],
+        }
+    }
+}
+
+impl<T: Trait> GenesisConfigBuilder<T> {
+    pub fn default_paid_membership_fee(
+        mut self,
+        default_paid_membership_fee: BalanceOf<T>,
+    ) -> Self {
+        self.default_paid_membership_fee = default_paid_membership_fee;
+        self
+    }
+    pub fn members(mut self, members: Vec<T::AccountId>) -> Self {
+        self.members = members;
+        self
+    }
+
+    pub fn build(&self) -> members::GenesisConfig<T> {
+        members::GenesisConfig::<T> {
+            default_paid_membership_fee: self.default_paid_membership_fee,
+            members: self
+                .members
+                .iter()
+                .map(|account_id| (account_id.clone(), "".into(), "".into(), "".into()))
+                .collect(),
+        }
+    }
+}

+ 0 - 2
src/membership/members.rs

@@ -207,8 +207,6 @@ decl_storage! {
                 // Give member starting balance
                 T::Currency::deposit_creating(&who, T::InitialMembersBalance::get());
             }
-
-            <MembersCreated<T>>::put(T::MemberId::from(config.members.len() as u32));
         });
     }
 }

+ 25 - 24
src/membership/mock.rs

@@ -1,6 +1,6 @@
 #![cfg(test)]
 
-pub use super::members::{self, DEFAULT_PAID_TERM_ID};
+pub use super::members::{self, Trait, DEFAULT_PAID_TERM_ID};
 pub use crate::currency::GovernanceCurrency;
 pub use srml_support::traits::Currency;
 pub use system;
@@ -93,43 +93,44 @@ impl members::Trait for Test {
     type InitialMembersBalance = InitialMembersBalance;
 }
 
-pub struct ExtBuilder {
-    default_paid_membership_fee: u64,
-    members: Vec<(u64)>,
+pub struct TestExternalitiesBuilder<T: Trait> {
+    system_config: Option<system::GenesisConfig>,
+    membership_config: Option<members::GenesisConfig<T>>,
 }
-impl Default for ExtBuilder {
+
+impl<T: Trait> Default for TestExternalitiesBuilder<T> {
     fn default() -> Self {
         Self {
-            default_paid_membership_fee: 100,
-            members: vec![],
+            system_config: None,
+            membership_config: None,
         }
     }
 }
 
-impl ExtBuilder {
-    pub fn default_paid_membership_fee(mut self, default_paid_membership_fee: u64) -> Self {
-        self.default_paid_membership_fee = default_paid_membership_fee;
+impl<T: Trait> TestExternalitiesBuilder<T> {
+    /*
+    pub fn set_system_config(mut self, system_config: system::GenesisConfig) -> Self {
+        self.system_config = Some(system_config);
         self
     }
-    pub fn members(mut self, members: Vec<u64>) -> Self {
-        self.members = members;
+    */
+    pub fn set_membership_config(mut self, membership_config: members::GenesisConfig<T>) -> Self {
+        self.membership_config = Some(membership_config);
         self
     }
     pub fn build(self) -> runtime_io::TestExternalities {
-        let mut t = system::GenesisConfig::default()
-            .build_storage::<Test>()
+        // Add system
+        let mut t = self
+            .system_config
+            .unwrap_or(system::GenesisConfig::default())
+            .build_storage::<T>()
             .unwrap();
 
-        members::GenesisConfig::<Test> {
-            default_paid_membership_fee: self.default_paid_membership_fee,
-            members: self
-                .members
-                .iter()
-                .map(|account_id| (*account_id, "".into(), "".into(), "".into()))
-                .collect(),
-        }
-        .assimilate_storage(&mut t)
-        .unwrap();
+        // Add membership
+        self.membership_config
+            .unwrap_or(members::GenesisConfig::default())
+            .assimilate_storage(&mut t)
+            .unwrap();
 
         t.into()
     }

+ 1 - 0
src/membership/mod.rs

@@ -1,3 +1,4 @@
+pub mod genesis;
 pub mod members;
 pub mod role_types;
 

+ 84 - 44
src/membership/tests.rs

@@ -1,5 +1,6 @@
 #![cfg(test)]
 
+use super::genesis;
 use super::mock::*;
 
 use srml_support::*;
@@ -66,9 +67,13 @@ fn initial_state() {
     const DEFAULT_FEE: u64 = 500;
     let initial_members = [1, 2, 3];
 
-    ExtBuilder::default()
-        .default_paid_membership_fee(DEFAULT_FEE)
-        .members(initial_members.to_vec())
+    TestExternalitiesBuilder::<Test>::default()
+        .set_membership_config(
+            genesis::GenesisConfigBuilder::default()
+                .default_paid_membership_fee(DEFAULT_FEE)
+                .members(initial_members.to_vec())
+                .build(),
+        )
         .build()
         .execute_with(|| {
             let default_terms = assert_ok_unwrap(
@@ -91,8 +96,12 @@ fn buy_membership() {
     const DEFAULT_FEE: u64 = 500;
     const SURPLUS_BALANCE: u64 = 500;
 
-    ExtBuilder::default()
-        .default_paid_membership_fee(DEFAULT_FEE)
+    TestExternalitiesBuilder::<Test>::default()
+        .set_membership_config(
+            genesis::GenesisConfigBuilder::default()
+                .default_paid_membership_fee(DEFAULT_FEE)
+                .build(),
+        )
         .build()
         .execute_with(|| {
             let initial_balance = DEFAULT_FEE + SURPLUS_BALANCE;
@@ -129,8 +138,12 @@ fn buy_membership() {
 fn buy_membership_fails_without_enough_balance() {
     const DEFAULT_FEE: u64 = 500;
 
-    ExtBuilder::default()
-        .default_paid_membership_fee(DEFAULT_FEE)
+    TestExternalitiesBuilder::<Test>::default()
+        .set_membership_config(
+            genesis::GenesisConfigBuilder::default()
+                .default_paid_membership_fee(DEFAULT_FEE)
+                .build(),
+        )
         .build()
         .execute_with(|| {
             let initial_balance = DEFAULT_FEE - 1;
@@ -147,8 +160,12 @@ fn buy_membership_fails_without_enough_balance() {
 fn new_memberships_allowed_flag() {
     const DEFAULT_FEE: u64 = 500;
 
-    ExtBuilder::default()
-        .default_paid_membership_fee(DEFAULT_FEE)
+    TestExternalitiesBuilder::<Test>::default()
+        .set_membership_config(
+            genesis::GenesisConfigBuilder::default()
+                .default_paid_membership_fee(DEFAULT_FEE)
+                .build(),
+        )
         .build()
         .execute_with(|| {
             let initial_balance = DEFAULT_FEE + 1;
@@ -168,8 +185,12 @@ fn unique_handles() {
     const DEFAULT_FEE: u64 = 500;
     const SURPLUS_BALANCE: u64 = 500;
 
-    ExtBuilder::default()
-        .default_paid_membership_fee(DEFAULT_FEE)
+    TestExternalitiesBuilder::<Test>::default()
+        .set_membership_config(
+            genesis::GenesisConfigBuilder::default()
+                .default_paid_membership_fee(DEFAULT_FEE)
+                .build(),
+        )
         .build()
         .execute_with(|| {
             let initial_balance = DEFAULT_FEE + SURPLUS_BALANCE;
@@ -191,8 +212,12 @@ fn update_profile() {
     const DEFAULT_FEE: u64 = 500;
     const SURPLUS_BALANCE: u64 = 500;
 
-    ExtBuilder::default()
-        .default_paid_membership_fee(DEFAULT_FEE)
+    TestExternalitiesBuilder::<Test>::default()
+        .set_membership_config(
+            genesis::GenesisConfigBuilder::default()
+                .default_paid_membership_fee(DEFAULT_FEE)
+                .build(),
+        )
         .build()
         .execute_with(|| {
             let initial_balance = DEFAULT_FEE + SURPLUS_BALANCE;
@@ -221,31 +246,34 @@ fn update_profile() {
 
 #[test]
 fn add_screened_member() {
-    ExtBuilder::default().build().execute_with(|| {
-        let screening_authority = 5;
-        <members::ScreeningAuthority<Test>>::put(&screening_authority);
-
-        let next_member_id = Members::members_created();
-
-        assert_ok!(Members::add_screened_member(
-            Origin::signed(screening_authority),
-            ALICE_ACCOUNT_ID,
-            get_alice_info()
-        ));
-
-        let profile = assert_ok_unwrap(
-            Members::member_profile(&next_member_id),
-            "member profile not created",
-        );
-
-        assert_eq!(Some(profile.handle), get_alice_info().handle);
-        assert_eq!(Some(profile.avatar_uri), get_alice_info().avatar_uri);
-        assert_eq!(Some(profile.about), get_alice_info().about);
-        assert_eq!(
-            members::EntryMethod::Screening(screening_authority),
-            profile.entry
-        );
-    });
+    TestExternalitiesBuilder::<Test>::default()
+        .set_membership_config(genesis::GenesisConfigBuilder::default().build())
+        .build()
+        .execute_with(|| {
+            let screening_authority = 5;
+            <members::ScreeningAuthority<Test>>::put(&screening_authority);
+
+            let next_member_id = Members::members_created();
+
+            assert_ok!(Members::add_screened_member(
+                Origin::signed(screening_authority),
+                ALICE_ACCOUNT_ID,
+                get_alice_info()
+            ));
+
+            let profile = assert_ok_unwrap(
+                Members::member_profile(&next_member_id),
+                "member profile not created",
+            );
+
+            assert_eq!(Some(profile.handle), get_alice_info().handle);
+            assert_eq!(Some(profile.avatar_uri), get_alice_info().avatar_uri);
+            assert_eq!(Some(profile.about), get_alice_info().about);
+            assert_eq!(
+                members::EntryMethod::Screening(screening_authority),
+                profile.entry
+            );
+        });
 }
 
 #[test]
@@ -253,8 +281,12 @@ fn set_controller_key() {
     let initial_members = [ALICE_ACCOUNT_ID];
     const ALICE_CONTROLLER_ID: u64 = 2;
 
-    ExtBuilder::default()
-        .members(initial_members.to_vec())
+    TestExternalitiesBuilder::<Test>::default()
+        .set_membership_config(
+            genesis::GenesisConfigBuilder::default()
+                .members(initial_members.to_vec())
+                .build(),
+        )
         .build()
         .execute_with(|| {
             let member_id = Members::member_ids_by_root_account_id(&ALICE_ACCOUNT_ID)[0];
@@ -284,8 +316,12 @@ fn set_root_account() {
     let initial_members = [ALICE_ACCOUNT_ID];
     const ALICE_NEW_ROOT_ACCOUNT: u64 = 2;
 
-    ExtBuilder::default()
-        .members(initial_members.to_vec())
+    TestExternalitiesBuilder::<Test>::default()
+        .set_membership_config(
+            genesis::GenesisConfigBuilder::default()
+                .members(initial_members.to_vec())
+                .build(),
+        )
         .build()
         .execute_with(|| {
             let member_id_1 = Members::member_ids_by_root_account_id(&ALICE_ACCOUNT_ID)[0];
@@ -308,8 +344,12 @@ fn set_root_account() {
 fn registering_and_unregistering_roles_on_member() {
     let initial_members = [1, 2];
 
-    ExtBuilder::default()
-        .members(initial_members.to_vec())
+    TestExternalitiesBuilder::<Test>::default()
+        .set_membership_config(
+            genesis::GenesisConfigBuilder::default()
+                .members(initial_members.to_vec())
+                .build(),
+        )
         .build()
         .execute_with(|| {
             const DUMMY_ACTOR_ID: u32 = 100;

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff