diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 36b31041..5f608883 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,6 +11,6 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: nightly + toolchain: 1.54 target: wasm32-unknown-unknown - - run: ./scripts/dna-test.sh \ No newline at end of file + - run: ./scripts/dna-test.sh diff --git a/dna/tests/Cargo.lock b/dna/tests/Cargo.lock index 8607744f..29f6f545 100644 --- a/dna/tests/Cargo.lock +++ b/dna/tests/Cargo.lock @@ -372,12 +372,17 @@ dependencies = [ [[package]] name = "bit-set" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e1e6fb1c9e3d6fcdec57216a74eaa03e41f52a22f13a16438251d8e88b89da" +source = "git+https://github.com/timotree3/bit-set.git?branch=fix-bit-vec-dep#050fed0734794e98383ea13f928e0f66e056a28b" dependencies = [ - "bit-vec", + "bit-vec 0.4.4", ] +[[package]] +name = "bit-vec" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" + [[package]] name = "bit-vec" version = "0.6.3" @@ -430,7 +435,7 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cffe85a8b173164000edb6570ff7cf429acc9460b41d963e797df413f1765b4" dependencies = [ - "bit-vec", + "bit-vec 0.6.3", "rand 0.8.4", "siphasher", ] @@ -1372,9 +1377,9 @@ dependencies = [ [[package]] name = "hdk_crud" -version = "0.0.103" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664c37d5b7f8db5acd708620dbfd0128d1e870d31bde3a80fd40c23c2b1de5a2" +checksum = "bb27016cc4d4efd783cac46469bea5356881242d78f7da58a81f3b805c04833a" dependencies = [ "hdk", "mockall 0.9.1", @@ -2984,6 +2989,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "profiles" +version = "0.0.1" +dependencies = [ + "hdk", + "hdk_crud", + "paste", + "serde", + "thiserror", +] + [[package]] name = "projects" version = "0.0.1" @@ -3999,6 +4015,7 @@ dependencies = [ "holochain_types", "mockall 0.9.1", "paste", + "profiles", "projects", "rand 0.7.3", "serde", diff --git a/dna/tests/Cargo.toml b/dna/tests/Cargo.toml index 3fadc5d0..b807e721 100644 --- a/dna/tests/Cargo.toml +++ b/dna/tests/Cargo.toml @@ -6,9 +6,10 @@ edition = "2018" [lib] [dependencies] -hdk_crud = "0.0.103" +hdk_crud = "0.2.0" hdk = "0.0.103" projects = { path = "../zomes/projects" } +profiles = { path = "../zomes/profiles" } paste = "*" # use whatever serde hdk uses serde = "*" @@ -26,3 +27,6 @@ strum_macros = "0.18.0" [features] default = ["mock"] mock = ["hdk/mock", "hdk/test_utils"] + +[patch.crates-io] +bit-set = { git = "https://github.com/timotree3/bit-set.git", branch = "fix-bit-vec-dep" } diff --git a/dna/tests/src/fixtures.rs b/dna/tests/src/fixtures.rs new file mode 100644 index 00000000..27c577e2 --- /dev/null +++ b/dna/tests/src/fixtures.rs @@ -0,0 +1,189 @@ +// in this file, you will see instances of setting up a type alias, such as `type OptionVecString = Option>;` +// this is done to enable passing those to constructor functions for fixturators, like +// ``` +// fixturator!( +// Goal; +// constructor fn new(..., OptionVecString, ...); +// ); +// ``` +#[cfg(test)] +pub(crate) mod fixtures { + use ::fixt::prelude::*; + use hdk::prelude::*; + use hdk_crud::{WrappedAgentPubKey, WrappedHeaderHash}; + use profiles::profile::{Profile, Status as ProfileStatus}; + use projects::project::goal::crud::{Goal, Hierarchy, Status}; + use projects::project::{ + edge::crud::Edge, + entry_point::crud::EntryPoint, + goal::crud::TimeFrame, + goal_comment::crud::GoalComment, + goal_member::crud::GoalMember, + goal_vote::crud::GoalVote, + member::entry::Member, + project_meta::crud::{PriorityMode, ProjectMeta}, + }; + + fixturator!( + WrappedHeaderHash; + constructor fn new(HeaderHash); + ); + + fixturator!( + WrappedAgentPubKey; + constructor fn new(AgentPubKey); + ); + + fixturator!( + Edge; + constructor fn new(WrappedHeaderHash, WrappedHeaderHash, f64, bool); + ); + + fixturator!( + EntryPoint; + constructor fn new(String, WrappedAgentPubKey, f64, WrappedHeaderHash, bool); + ); + + fixturator!( + GoalMember; + constructor fn new(WrappedHeaderHash, WrappedAgentPubKey, WrappedAgentPubKey, f64, bool); + ); + + fixturator!( + GoalComment; + constructor fn new(WrappedHeaderHash, String, WrappedAgentPubKey, f64, bool); + ); + + fixturator!( + GoalVote; + constructor fn new(WrappedHeaderHash, f64, f64, f64, f64, WrappedAgentPubKey, f64, bool); + ); + + fixturator!( + Member; + constructor fn new(WrappedAgentPubKey); + ); + + fixturator!( + ProjectMeta; + constructor fn new(WrappedAgentPubKey, f64, String, OptionString, String, bool, PriorityMode, VecWrappedHeaderHash); + ); + + type VecWrappedHeaderHash = Vec; + type OptionWrappedAgentPubKey = Option; + type OptionString = Option; + type Optionf64 = Option; + type OptionVecString = Option>; + type OptionTimeFrame = Option; + + fixturator!( + PriorityMode; + unit variants [ Universal Vote ] empty Universal; + ); + + fixturator!( + TimeFrame; + constructor fn new(f64, f64); + ); + + fixturator!( + Status; + unit variants [ Uncertain Incomplete InProcess Complete InReview ] empty Uncertain; + ); + + fixturator!( + Hierarchy; + unit variants [Root Trunk Branch Leaf NoHierarchy ] empty NoHierarchy; + ); + + fixturator!( + VecWrappedHeaderHash; + curve Empty { + Vec::new() + }; + curve Unpredictable { + vec![WrappedHeaderHashFixturator::new(Unpredictable).next().unwrap()] + }; + curve Predictable { + vec![WrappedHeaderHashFixturator::new(Predictable).next().unwrap()] + }; + ); + + fixturator!( + OptionWrappedAgentPubKey; + curve Empty { + None + }; + curve Unpredictable { + Some(WrappedAgentPubKeyFixturator::new(Unpredictable).next().unwrap()) + }; + curve Predictable { + Some(WrappedAgentPubKeyFixturator::new(Predictable).next().unwrap()) + }; + ); + + fixturator!( + OptionString; + curve Empty { + None + }; + curve Unpredictable { + Some(fixt!(String)) + }; + curve Predictable { + Some(fixt!(String, Predictable)) + }; + ); + + fixturator!( + Optionf64; + curve Empty { + None + }; + curve Unpredictable { + Some(fixt!(f64)) + }; + curve Predictable { + Some(fixt!(f64, Predictable)) + }; + ); + + fixturator!( + OptionVecString; + curve Empty { + None + }; + curve Unpredictable { + Some(Vec::new()) + }; + curve Predictable { + Some(Vec::new()) + }; + ); + + fixturator!( + OptionTimeFrame; + curve Empty { + None + }; + curve Unpredictable { + Some(TimeFrameFixturator::new(Unpredictable).next().unwrap()) + }; + curve Predictable { + Some(TimeFrameFixturator::new(Predictable).next().unwrap()) + }; + ); + + fixturator!( + Goal; + constructor fn new(String, WrappedAgentPubKey, OptionWrappedAgentPubKey, f64, Optionf64, Hierarchy, Status, OptionVecString, String, OptionTimeFrame, bool); + ); + fixturator!( + ProfileStatus; + unit variants [ Online Away Offline ] empty Offline; + ); + fixturator!( + Profile; + constructor fn new(String, String, String, ProfileStatus, String, WrappedAgentPubKey, bool); + ); +} diff --git a/dna/tests/src/lib.rs b/dna/tests/src/lib.rs index b696c34e..6743e3bb 100644 --- a/dna/tests/src/lib.rs +++ b/dna/tests/src/lib.rs @@ -1 +1,4 @@ -mod project; \ No newline at end of file +mod project; +mod profiles; +mod test_lib; +mod fixtures; \ No newline at end of file diff --git a/dna/tests/src/profiles/mod.rs b/dna/tests/src/profiles/mod.rs new file mode 100644 index 00000000..5b3bafd8 --- /dev/null +++ b/dna/tests/src/profiles/mod.rs @@ -0,0 +1 @@ +pub mod profile; \ No newline at end of file diff --git a/dna/tests/src/profiles/profile.rs b/dna/tests/src/profiles/profile.rs new file mode 100644 index 00000000..3297e918 --- /dev/null +++ b/dna/tests/src/profiles/profile.rs @@ -0,0 +1,182 @@ +#[cfg(test)] +pub mod tests { + use crate::fixtures::fixtures::{ + EdgeFixturator, ProfileFixturator, WrappedAgentPubKeyFixturator, + WrappedHeaderHashFixturator, + }; + use crate::test_lib::*; + use ::fixt::prelude::*; + use assert_matches::assert_matches; + use hdk::prelude::*; + use hdk_crud::{ActionType, WrappedAgentPubKey, WrappedHeaderHash}; + use holochain_types::prelude::ValidateDataFixturator; + use profiles::profile::{ + agent_signal_entry_type, create_imported_profile, inner_create_whoami, inner_update_whoami, + AgentSignal, Profile, SignalData, Status, WireEntry, + }; + use projects::project::edge::validate::*; + use projects::project::error::Error; + + #[test] + fn test_create_whoami() { + let mut mock_hdk = MockHdkT::new(); + let mock_hdk_ref = &mut mock_hdk; + + let wire_entry = generate_wire_entry(); + let profile = wire_entry.clone().entry; + let profile_entry = EntryWithDefId::try_from(profile.clone()).unwrap(); + let profile_header_hash = wire_entry.clone().address.0; + mock_create(mock_hdk_ref, profile_entry, Ok(profile_header_hash.clone())); + + let profile_hash = fixt!(EntryHash); + mock_hash_entry( + mock_hdk_ref, + Entry::try_from(profile.clone()).unwrap(), + Ok(profile_hash.clone()), + ); + + let agent_path = Path::from("agents"); + let agent_path_hash = fixt!(EntryHash); + mock_hash_entry( + mock_hdk_ref, + Entry::try_from(agent_path).unwrap(), + Ok(agent_path_hash.clone()), + ); + + let create_link_input = CreateLinkInput::new( + agent_path_hash.clone(), + profile_hash.clone(), + LinkTag::from(()), + ); + let link_header_hash = fixt!(HeaderHash); + mock_create_link( + mock_hdk_ref, + create_link_input, + Ok(link_header_hash.clone()), + ); + + let agent_info = fixt!(AgentInfo); + let agent_entry_hash = EntryHash::from(agent_info.clone().agent_initial_pubkey); + mock_agent_info(mock_hdk_ref, Ok(agent_info)); + let create_link_input = + CreateLinkInput::new(agent_entry_hash, profile_hash, LinkTag::from(())); + mock_create_link( + mock_hdk_ref, + create_link_input, + Ok(link_header_hash.clone()), + ); + + let signal = AgentSignal { + entry_type: agent_signal_entry_type(), + action: ActionType::Create, + data: SignalData::Create(wire_entry.clone()), + }; + + let payload = ExternIO::encode(signal).unwrap(); + let agents = vec![]; + let remote_signal = RemoteSignal { + signal: ExternIO::encode(payload).unwrap(), + agents, + }; + mock_remote_signal(mock_hdk_ref, remote_signal, Ok(())); + + set_hdk(mock_hdk); + fn get_peers() -> ExternResult> { + Ok(vec![]) + } + let result = inner_create_whoami(profile, get_peers); + assert_matches!(result, Ok(wire_entry)); + } + #[test] + fn test_create_imported_profile() { + let mut mock_hdk = MockHdkT::new(); + let mock_hdk_ref = &mut mock_hdk; + + let wire_entry = generate_wire_entry(); + let profile = wire_entry.clone().entry; + let profile_entry = EntryWithDefId::try_from(profile.clone()).unwrap(); + let profile_header_hash = wire_entry.clone().address.0; + + mock_create(mock_hdk_ref, profile_entry, Ok(profile_header_hash.clone())); + + let profile_hash = fixt!(EntryHash); + mock_hash_entry( + mock_hdk_ref, + Entry::try_from(profile.clone()).unwrap(), + Ok(profile_hash.clone()), + ); + + let agent_path = Path::from("agents"); + let agent_path_hash = fixt!(EntryHash); + mock_hash_entry( + mock_hdk_ref, + Entry::try_from(agent_path).unwrap(), + Ok(agent_path_hash.clone()), + ); + + let create_link_input = CreateLinkInput::new( + agent_path_hash.clone(), + profile_hash.clone(), + LinkTag::from(()), + ); + let link_header_hash = fixt!(HeaderHash); + mock_create_link( + mock_hdk_ref, + create_link_input, + Ok(link_header_hash.clone()), + ); + + set_hdk(mock_hdk); + let result = create_imported_profile(profile); + assert_matches!(result, Ok(wire_entry)); + } + #[test] + fn test_update_whoami() { + let mut mock_hdk = MockHdkT::new(); + let mock_hdk_ref = &mut mock_hdk; + + let wire_entry = generate_wire_entry(); + let profile_address = wire_entry.address.0.clone(); + let profile = wire_entry.entry.clone(); + let update_input = + UpdateInput::new(profile_address, EntryWithDefId::try_from(profile).unwrap()); + let update_header_hash = fixt!(HeaderHash); + mock_update(mock_hdk_ref, update_input, Ok(update_header_hash)); + + let signal = AgentSignal { + entry_type: agent_signal_entry_type(), + action: ActionType::Update, + data: SignalData::Update(wire_entry.clone()), + }; + + let payload = ExternIO::encode(signal).unwrap(); + let agents = vec![]; + let remote_signal = RemoteSignal { + signal: ExternIO::encode(payload).unwrap(), + agents, + }; + mock_remote_signal(mock_hdk_ref, remote_signal, Ok(())); + + set_hdk(mock_hdk); + fn get_peers() -> ExternResult> { + Ok(vec![]) + } + let result = inner_update_whoami(wire_entry, get_peers); + assert_matches!(result, Ok(wire_entry)); + } + // #[test] + // fn test_whoami() {} + // #[test] + // fn test_fetch_agents() {} + + /// generate an arbitrary `WireEntry` for unit testing + fn generate_wire_entry() -> WireEntry { + let profile = fixt!(Profile); + let profile_header_hash = fixt!(HeaderHash); + let wire_entry = WireEntry { + entry: profile, + address: WrappedHeaderHash(profile_header_hash), + }; + wire_entry + } +} diff --git a/dna/tests/src/project/edge.rs b/dna/tests/src/project/edge.rs index 483ad039..245cc126 100644 --- a/dna/tests/src/project/edge.rs +++ b/dna/tests/src/project/edge.rs @@ -1,6 +1,6 @@ #[cfg(test)] pub mod tests { - use crate::project::fixtures::fixtures::{EdgeFixturator, WrappedHeaderHashFixturator}; + use crate::fixtures::fixtures::{EdgeFixturator, WrappedHeaderHashFixturator}; use ::fixt::prelude::*; use hdk::prelude::*; use hdk_crud::WrappedHeaderHash; diff --git a/dna/tests/src/project/entry_point.rs b/dna/tests/src/project/entry_point.rs index bea2ca8b..2fea2c12 100644 --- a/dna/tests/src/project/entry_point.rs +++ b/dna/tests/src/project/entry_point.rs @@ -1,6 +1,6 @@ #[cfg(test)] pub mod tests { - use crate::project::fixtures::fixtures::{EntryPointFixturator, WrappedAgentPubKeyFixturator}; + use crate::fixtures::fixtures::{EntryPointFixturator, WrappedAgentPubKeyFixturator}; use ::fixt::prelude::*; use hdk::prelude::*; use hdk_crud::WrappedAgentPubKey; diff --git a/dna/tests/src/project/fixtures.rs b/dna/tests/src/project/fixtures.rs deleted file mode 100644 index a323f54a..00000000 --- a/dna/tests/src/project/fixtures.rs +++ /dev/null @@ -1,167 +0,0 @@ -#[cfg(test)] -pub(crate) mod fixtures { - use projects::project::goal::crud::{Goal, Hierarchy, Status}; - use projects::project::{ - edge::crud::Edge, entry_point::crud::EntryPoint, goal::crud::TimeFrame, - goal_comment::crud::GoalComment, goal_member::crud::GoalMember, goal_vote::crud::GoalVote, - member::entry::Member, project_meta::crud::{ProjectMeta, PriorityMode}, - }; - use ::fixt::prelude::*; - use hdk_crud::{WrappedAgentPubKey, WrappedHeaderHash}; - use hdk::prelude::*; - - fixturator!( - WrappedHeaderHash; - constructor fn new(HeaderHash); - ); - - fixturator!( - WrappedAgentPubKey; - constructor fn new(AgentPubKey); - ); - - fixturator!( - Edge; - constructor fn new(WrappedHeaderHash, WrappedHeaderHash, f64, bool); - ); - - fixturator!( - EntryPoint; - constructor fn new(String, WrappedAgentPubKey, f64, WrappedHeaderHash, bool); - ); - - fixturator!( - GoalMember; - constructor fn new(WrappedHeaderHash, WrappedAgentPubKey, WrappedAgentPubKey, f64, bool); - ); - - fixturator!( - GoalComment; - constructor fn new(WrappedHeaderHash, String, WrappedAgentPubKey, f64, bool); - ); - - fixturator!( - GoalVote; - constructor fn new(WrappedHeaderHash, f64, f64, f64, f64, WrappedAgentPubKey, f64, bool); - ); - - fixturator!( - Member; - constructor fn new(WrappedAgentPubKey); - ); - - fixturator!( - ProjectMeta; - constructor fn new(WrappedAgentPubKey, f64, String, OptionString, String, bool, PriorityMode, VecWrappedHeaderHash); - ); - - type VecWrappedHeaderHash = Vec; - type OptionWrappedAgentPubKey = Option; - type OptionString = Option; - type Optionf64 = Option; - type OptionVecString = Option>; - type OptionTimeFrame = Option; - - fixturator!( - PriorityMode; - unit variants [ Universal Vote ] empty Universal; - ); - - fixturator!( - TimeFrame; - constructor fn new(f64, f64); - ); - - fixturator!( - Status; - unit variants [ Uncertain Incomplete InProcess Complete InReview ] empty Uncertain; - ); - - fixturator!( - Hierarchy; - unit variants [Root Trunk Branch Leaf NoHierarchy ] empty NoHierarchy; - ); - - fixturator!( - VecWrappedHeaderHash; - curve Empty { - Vec::new() - }; - curve Unpredictable { - vec![WrappedHeaderHashFixturator::new(Unpredictable).next().unwrap()] - }; - curve Predictable { - vec![WrappedHeaderHashFixturator::new(Predictable).next().unwrap()] - }; - ); - - fixturator!( - OptionWrappedAgentPubKey; - curve Empty { - None - }; - curve Unpredictable { - Some(WrappedAgentPubKeyFixturator::new(Unpredictable).next().unwrap()) - }; - curve Predictable { - Some(WrappedAgentPubKeyFixturator::new(Predictable).next().unwrap()) - }; - ); - - fixturator!( - OptionString; - curve Empty { - None - }; - curve Unpredictable { - Some(fixt!(String)) - }; - curve Predictable { - Some(fixt!(String, Predictable)) - }; - ); - - fixturator!( - Optionf64; - curve Empty { - None - }; - curve Unpredictable { - Some(fixt!(f64)) - }; - curve Predictable { - Some(fixt!(f64, Predictable)) - }; - ); - - fixturator!( - OptionVecString; - curve Empty { - None - }; - curve Unpredictable { - Some(Vec::new()) - }; - curve Predictable { - Some(Vec::new()) - }; - ); - - fixturator!( - OptionTimeFrame; - curve Empty { - None - }; - curve Unpredictable { - Some(TimeFrameFixturator::new(Unpredictable).next().unwrap()) - }; - curve Predictable { - Some(TimeFrameFixturator::new(Predictable).next().unwrap()) - }; - ); - - fixturator!( - Goal; - constructor fn new(String, WrappedAgentPubKey, OptionWrappedAgentPubKey, f64, Optionf64, Hierarchy, Status, OptionVecString, String, OptionTimeFrame, bool); - ); -} diff --git a/dna/tests/src/project/goal.rs b/dna/tests/src/project/goal.rs index 11b4bbb3..a58cbf9c 100644 --- a/dna/tests/src/project/goal.rs +++ b/dna/tests/src/project/goal.rs @@ -1,6 +1,6 @@ #[cfg(test)] pub mod tests { - use crate::project::fixtures::fixtures::{GoalFixturator, WrappedAgentPubKeyFixturator}; + use crate::fixtures::fixtures::{GoalFixturator, WrappedAgentPubKeyFixturator}; use ::fixt::prelude::*; use hdk::prelude::*; use hdk_crud::WrappedAgentPubKey; @@ -235,4 +235,6 @@ pub mod tests { Ok(ValidateCallbackResult::Valid), ); } + #[test] + fn test_create_goal_with_edge() {} } diff --git a/dna/tests/src/project/goal_comment.rs b/dna/tests/src/project/goal_comment.rs index c09530ee..95d4a5e9 100644 --- a/dna/tests/src/project/goal_comment.rs +++ b/dna/tests/src/project/goal_comment.rs @@ -1,6 +1,6 @@ #[cfg(test)] pub mod tests { - use crate::project::fixtures::fixtures::{ + use crate::fixtures::fixtures::{ GoalCommentFixturator, WrappedAgentPubKeyFixturator, WrappedHeaderHashFixturator, }; use ::fixt::prelude::*; diff --git a/dna/tests/src/project/goal_member.rs b/dna/tests/src/project/goal_member.rs index a4f8b569..e7a01731 100644 --- a/dna/tests/src/project/goal_member.rs +++ b/dna/tests/src/project/goal_member.rs @@ -1,6 +1,6 @@ #[cfg(test)] pub mod tests { - use crate::project::fixtures::fixtures::{ + use crate::fixtures::fixtures::{ GoalMemberFixturator, WrappedAgentPubKeyFixturator, WrappedHeaderHashFixturator, }; diff --git a/dna/tests/src/project/goal_vote.rs b/dna/tests/src/project/goal_vote.rs index 272654c6..31019b26 100644 --- a/dna/tests/src/project/goal_vote.rs +++ b/dna/tests/src/project/goal_vote.rs @@ -1,6 +1,6 @@ #[cfg(test)] pub mod tests { - use crate::project::fixtures::fixtures::{ + use crate::fixtures::fixtures::{ GoalVoteFixturator, WrappedAgentPubKeyFixturator, WrappedHeaderHashFixturator, }; diff --git a/dna/tests/src/project/member.rs b/dna/tests/src/project/member.rs index 87a81048..6f44ad3e 100644 --- a/dna/tests/src/project/member.rs +++ b/dna/tests/src/project/member.rs @@ -1,6 +1,6 @@ #[cfg(test)] pub mod tests { - use crate::project::fixtures::fixtures::MemberFixturator; + use crate::fixtures::fixtures::MemberFixturator; use ::fixt::prelude::*; use hdk::prelude::*; use hdk_crud::WrappedAgentPubKey; diff --git a/dna/tests/src/project/mod.rs b/dna/tests/src/project/mod.rs index 173161a7..6d2a8ca7 100644 --- a/dna/tests/src/project/mod.rs +++ b/dna/tests/src/project/mod.rs @@ -6,5 +6,4 @@ pub mod goal_member; pub mod goal_vote; pub mod member; pub mod project_meta; -pub mod fixtures; pub mod project_init; diff --git a/dna/tests/src/project/project_init.rs b/dna/tests/src/project/project_init.rs index a153dd56..cfae6fe7 100644 --- a/dna/tests/src/project/project_init.rs +++ b/dna/tests/src/project/project_init.rs @@ -1,6 +1,6 @@ #[cfg(test)] pub mod tests { - use crate::project::fixtures::fixtures::ProjectMetaFixturator; + use crate::fixtures::fixtures::ProjectMetaFixturator; use ::fixt::prelude::*; use assert_matches::assert_matches; use hdk::prelude::*; diff --git a/dna/tests/src/project/project_meta.rs b/dna/tests/src/project/project_meta.rs index 1c519ed2..a3906f55 100644 --- a/dna/tests/src/project/project_meta.rs +++ b/dna/tests/src/project/project_meta.rs @@ -1,6 +1,6 @@ #[cfg(test)] pub mod tests { - use crate::project::fixtures::fixtures::ProjectMetaFixturator; + use crate::fixtures::fixtures::ProjectMetaFixturator; use ::fixt::prelude::*; use hdk::prelude::*; use hdk_crud::WrappedAgentPubKey; diff --git a/dna/tests/src/test_lib.rs b/dna/tests/src/test_lib.rs new file mode 100644 index 00000000..d9d219db --- /dev/null +++ b/dna/tests/src/test_lib.rs @@ -0,0 +1,56 @@ +use hdk::prelude::*; + +pub fn mock_create( + mock_hdk: &mut MockHdkT, + input: EntryWithDefId, + output: ExternResult, +) { + mock_hdk + .expect_create() + .with(mockall::predicate::eq(input)) + .times(1) + .return_const(output); +} + +pub fn mock_hash_entry(mock_hdk: &mut MockHdkT, input: Entry, output: ExternResult) { + mock_hdk + .expect_hash_entry() + .with(mockall::predicate::eq(input)) + .times(1) + .return_const(output); +} + +pub fn mock_create_link( + mock_hdk: &mut MockHdkT, + create_link_input: CreateLinkInput, + output: ExternResult, +) { + mock_hdk + .expect_create_link() + .with(mockall::predicate::eq(create_link_input)) + .times(1) + .return_const(output); +} + +pub fn mock_agent_info(mock_hdk: &mut MockHdkT, output: ExternResult) { + mock_hdk + .expect_agent_info() + .times(1) + .return_const(output); +} + +pub fn mock_remote_signal(mock_hdk: &mut MockHdkT, input: RemoteSignal, output: ExternResult<()>) { + mock_hdk + .expect_remote_signal() + .with(mockall::predicate::eq(input)) + .times(1) + .return_const(output); +} + +pub fn mock_update(mock_hdk: &mut MockHdkT, expected_input: UpdateInput, expected_output: ExternResult) { + mock_hdk + .expect_update() + .with(mockall::predicate::eq(expected_input)) + .times(1) + .return_const(expected_output); +} \ No newline at end of file diff --git a/dna/workdir/profiles.dna b/dna/workdir/profiles.dna index 68099f4f..efb4e2a3 100644 Binary files a/dna/workdir/profiles.dna and b/dna/workdir/profiles.dna differ diff --git a/dna/workdir/projects.dna b/dna/workdir/projects.dna index b928fe39..715dd585 100644 Binary files a/dna/workdir/projects.dna and b/dna/workdir/projects.dna differ diff --git a/dna/zomes/profiles/Cargo.lock b/dna/zomes/profiles/Cargo.lock index 91de7fd1..3d6469ed 100644 --- a/dna/zomes/profiles/Cargo.lock +++ b/dna/zomes/profiles/Cargo.lock @@ -302,9 +302,9 @@ dependencies = [ [[package]] name = "hdk_crud" -version = "0.0.103" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664c37d5b7f8db5acd708620dbfd0128d1e870d31bde3a80fd40c23c2b1de5a2" +checksum = "bb27016cc4d4efd783cac46469bea5356881242d78f7da58a81f3b805c04833a" dependencies = [ "hdk", "mockall", diff --git a/dna/zomes/profiles/Cargo.toml b/dna/zomes/profiles/Cargo.toml index 16dba46d..e3d1f2aa 100644 --- a/dna/zomes/profiles/Cargo.toml +++ b/dna/zomes/profiles/Cargo.toml @@ -8,7 +8,7 @@ name = "profiles" crate-type = [ "cdylib", "rlib" ] [dependencies] -hdk_crud = "0.0.103" +hdk_crud = "0.2.0" hdk = "0.0.103" paste = "*" serde = "*" diff --git a/dna/zomes/profiles/src/profile/mod.rs b/dna/zomes/profiles/src/profile/mod.rs index 5e0684da..9be536ed 100644 --- a/dna/zomes/profiles/src/profile/mod.rs +++ b/dna/zomes/profiles/src/profile/mod.rs @@ -9,15 +9,36 @@ pub const AGENTS_PATH: &str = "agents"; #[hdk_entry(id = "profile")] #[derive(Clone, PartialEq)] pub struct Profile { - first_name: String, - last_name: String, - handle: String, - status: Status, - avatar_url: String, - address: WrappedAgentPubKey, - is_imported: bool, + pub first_name: String, + pub last_name: String, + pub handle: String, + pub status: Status, + pub avatar_url: String, + pub address: WrappedAgentPubKey, + pub is_imported: bool, } +impl Profile { + pub fn new( + first_name: String, + last_name: String, + handle: String, + status: Status, + avatar_url: String, + address: WrappedAgentPubKey, + is_imported: bool, + ) -> Self { + Self { + first_name, + last_name, + handle, + status, + avatar_url, + address, + is_imported, + } + } +} impl From for AgentPubKey { fn from(profile: Profile) -> Self { profile.address.0 @@ -114,6 +135,10 @@ impl<'de> Deserialize<'de> for Status { #[hdk_extern] pub fn create_whoami(entry: Profile) -> ExternResult { + // commit this new profile + inner_create_whoami(entry, get_peers) +} +pub fn inner_create_whoami(entry: Profile, get_peers_to_signal: fn() -> ExternResult>) -> ExternResult { // commit this new profile let header_hash = create_entry(&entry)?; @@ -139,7 +164,7 @@ pub fn create_whoami(entry: Profile) -> ExternResult { action: ActionType::Create, data: SignalData::Create(wire_entry.clone()), }; - let _ = send_agent_signal(signal); + let _ = send_agent_signal(signal, get_peers_to_signal); Ok(wire_entry) } @@ -167,12 +192,16 @@ pub fn create_imported_profile(entry: Profile) -> ExternResult { }) } -fn agent_signal_entry_type() -> String { +pub fn agent_signal_entry_type() -> String { "agent".to_string() } #[hdk_extern] pub fn update_whoami(update: WireEntry) -> ExternResult { + inner_update_whoami(update, get_peers) +} + +pub fn inner_update_whoami(update: WireEntry, get_peers_to_signal: fn() -> ExternResult>) -> ExternResult { update_entry(update.address.0.clone(), &update.entry)?; // // send update to peers // we don't want to cause real failure for inability to send to peers @@ -181,7 +210,7 @@ pub fn update_whoami(update: WireEntry) -> ExternResult { action: ActionType::Update, data: SignalData::Update(update.clone()), }; - let _ = send_agent_signal(signal); + let _ = send_agent_signal(signal, get_peers_to_signal); Ok(update) } @@ -222,9 +251,9 @@ fn fetch_agent_address(_: ()) -> ExternResult { SIGNALS */ -fn send_agent_signal(signal: AgentSignal) -> ExternResult<()> { +fn send_agent_signal(signal: AgentSignal, get_peers_to_signal: fn() -> ExternResult>) -> ExternResult<()> { let payload = ExternIO::encode(signal)?; - let peers = get_peers()?; + let peers = get_peers_to_signal()?; remote_signal(payload, peers)?; Ok(()) } diff --git a/dna/zomes/projects/Cargo.lock b/dna/zomes/projects/Cargo.lock index 5e02eaa5..4fb64897 100644 --- a/dna/zomes/projects/Cargo.lock +++ b/dna/zomes/projects/Cargo.lock @@ -302,9 +302,9 @@ dependencies = [ [[package]] name = "hdk_crud" -version = "0.0.103" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664c37d5b7f8db5acd708620dbfd0128d1e870d31bde3a80fd40c23c2b1de5a2" +checksum = "bb27016cc4d4efd783cac46469bea5356881242d78f7da58a81f3b805c04833a" dependencies = [ "hdk", "mockall", diff --git a/dna/zomes/projects/Cargo.toml b/dna/zomes/projects/Cargo.toml index 278b6a8c..d590f780 100644 --- a/dna/zomes/projects/Cargo.toml +++ b/dna/zomes/projects/Cargo.toml @@ -8,7 +8,7 @@ name = "projects" crate-type = [ "cdylib", "rlib" ] [dependencies] -hdk_crud = "0.0.103" +hdk_crud = "0.2.0" hdk = "0.0.103" paste = "*" # use whatever serde hdk uses diff --git a/dna/zomes/projects/src/project/entry_point/crud.rs b/dna/zomes/projects/src/project/entry_point/crud.rs index d0a44030..11249d57 100644 --- a/dna/zomes/projects/src/project/entry_point/crud.rs +++ b/dna/zomes/projects/src/project/entry_point/crud.rs @@ -1,9 +1,10 @@ use crate::{ get_peers_content, + project::goal::crud::{fetch_goals, VecGoalWireEntry}, SignalType, }; -use hdk_crud::{crud, WrappedAgentPubKey, WrappedHeaderHash}; use hdk::prelude::*; +use hdk_crud::{crud, FetchOptions, WrappedAgentPubKey, WrappedEntryHash, WrappedHeaderHash}; // The "Entry" in EntryPoint is not a reference to Holochain "Entries" // it is rather the concept of an Entrance, as in a doorway, to the tree @@ -24,13 +25,13 @@ impl EntryPoint { created_at: f64, goal_address: WrappedHeaderHash, is_imported: bool, - ) -> Self { + ) -> Self { Self { - color, - creator_address, - created_at, - goal_address, - is_imported, + color, + creator_address, + created_at, + goal_address, + is_imported, } } } @@ -46,3 +47,59 @@ crud!( get_peers_content, convert_to_receiver_signal ); + +#[derive(Serialize, Deserialize, Debug)] +pub struct EntryPointDetails { + pub entry_points: VecEntryPointWireEntry, + pub goals: VecGoalWireEntry, +} + +#[hdk_extern] +pub fn fetch_entry_point_details(_: ()) -> ExternResult { + // get the list of entry points + let entry_points = inner_fetch_entry_points(hdk_crud::FetchOptions::All, GetOptions::latest())?; + + // convert from header addresses to entry addresses + let goal_entry_addresses = entry_points + .0 + .clone() + .iter() + .map(|e| { + let element = get(e.entry.goal_address.0.clone(), GetOptions::content())?; + match element { + Some(element) => match element.header().entry_hash() { + Some(entry_hash) => Ok(WrappedEntryHash::new(entry_hash.clone())), + None => Err(WasmError::Guest( + "there was no entry_hash on a header for a Goal specified as an entry_point" + .to_string(), + )), + }, + None => Err(WasmError::Guest( + "there was no goal at the address specified by an entry point".to_string(), + )) + } + }) + .collect::>>(); + + // check if there are any errors and return the first error if there are any + let any_error = goal_entry_addresses + .clone() + .into_iter() + .find(|e| e.is_err()); + match any_error { + Some(result_with_error) => Err(result_with_error.unwrap_err()), + None => { + // they are all fine so drop the Result layer + let actual_addresses = goal_entry_addresses + .into_iter() + .filter_map(Result::ok) + .collect::>(); + // use the fetch_goals specific to get only these goals + let goals = fetch_goals(FetchOptions::Specific(actual_addresses))?; + Ok(EntryPointDetails { + entry_points, + goals, + }) + } + } +} diff --git a/dna/zomes/projects/src/project/goal/crud.rs b/dna/zomes/projects/src/project/goal/crud.rs index 568edba5..f6e10402 100644 --- a/dna/zomes/projects/src/project/goal/crud.rs +++ b/dna/zomes/projects/src/project/goal/crud.rs @@ -8,7 +8,7 @@ use crate::project::{ goal_vote::crud::{inner_archive_goal_vote, inner_fetch_goal_votes, GoalVoteWireEntry}, }; use crate::{get_peers_content, SignalType}; -use hdk_crud::{crud, ActionType, WrappedAgentPubKey, WrappedHeaderHash}; +use hdk_crud::{ActionType, FetchOptions, WrappedAgentPubKey, WrappedHeaderHash, crud}; use hdk::prelude::*; use std::fmt; @@ -275,7 +275,7 @@ pub struct ArchiveGoalFullySignal { pub fn archive_goal_fully(address: WrappedHeaderHash) -> ExternResult { inner_archive_goal(address.clone(), false)?; - let archived_edges = inner_fetch_edges(GetOptions::content())? + let archived_edges = inner_fetch_edges(FetchOptions::All, GetOptions::content())? .0 .into_iter() .filter(|wire_entry: &EdgeWireEntry| { @@ -297,7 +297,7 @@ pub fn archive_goal_fully(address: WrappedHeaderHash) -> ExternResult ExternResult ExternResult ExternResult> { - Ok(inner_fetch_goal_members(GetOptions::content())? + Ok(inner_fetch_goal_members(FetchOptions::All, GetOptions::content())? .0 .into_iter() .filter(|wire_entry: &GoalMemberWireEntry| { diff --git a/dna/zomes/projects/src/project/project_meta/crud.rs b/dna/zomes/projects/src/project/project_meta/crud.rs index 5789d436..f1fa7165 100644 --- a/dna/zomes/projects/src/project/project_meta/crud.rs +++ b/dna/zomes/projects/src/project/project_meta/crud.rs @@ -6,7 +6,7 @@ use crate::{ }, SignalType, }; -use hdk_crud::{crud, WrappedAgentPubKey, WrappedEntryHash, WrappedHeaderHash}; +use hdk_crud::{FetchOptions, WrappedAgentPubKey, WrappedEntryHash, WrappedHeaderHash, crud}; use hdk::prelude::*; use std::*; @@ -90,7 +90,7 @@ crud!( pub fn simple_create_project_meta(entry: ProjectMeta) -> ExternResult { // no project_meta entry should exist at least // that we can know about - match inner_fetch_project_metas(GetOptions::latest())?.0.len() { + match inner_fetch_project_metas(FetchOptions::All, GetOptions::latest())?.0.len() { 0 => {}, _ => return Err(WasmError::Guest(Error::OnlyOneOfEntryType.to_string())), }; @@ -111,7 +111,7 @@ pub fn simple_create_project_meta(entry: ProjectMeta) -> ExternResult ExternResult { - match inner_fetch_project_metas(GetOptions::latest())?.0.first() { + match inner_fetch_project_metas(FetchOptions::All, GetOptions::latest())?.0.first() { Some(wire_entry) => Ok(wire_entry.to_owned()), None => Err(WasmError::Guest("no project meta exists".into())), } diff --git a/electron/package.json b/electron/package.json index 0f3ea319..ca37360d 100644 --- a/electron/package.json +++ b/electron/package.json @@ -6,6 +6,7 @@ "scripts": { "start": "tsc && electron .", "build": "tsc && electron-builder build", + "tsc": "tsc", "lint": "eslint --ext .ts ." }, "keywords": [], diff --git a/package.json b/package.json index 3ce0ff2d..85c9dad7 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "electron-install": "cd electron && npm install", "electron": "cd electron && npm run start", "electron2": "cd electron && ACORN_TEST_USER_2=1 npm run start", + "electron-tsc": "cd electron && npm run tsc", "build": ". scripts/build.sh" }, "author": "Connor Turland ", diff --git a/web/src/projects/entry-points/actions.js b/web/src/projects/entry-points/actions.js index 25de8105..0eb73a27 100644 --- a/web/src/projects/entry-points/actions.js +++ b/web/src/projects/entry-points/actions.js @@ -7,6 +7,14 @@ import { PROJECTS_ZOME_NAME } from '../../holochainConfig' import { createCrudActionCreators } from '../../crudRedux' +import { createZomeCallAsyncAction } from 'connoropolous-hc-redux-middleware' + +const FETCH_ENTRY_POINT_DETAILS = 'fetch_entry_point_details' + +const fetchEntryPointDetails = createZomeCallAsyncAction( + PROJECTS_ZOME_NAME, + FETCH_ENTRY_POINT_DETAILS +) const [ createEntryPoint, @@ -20,4 +28,6 @@ export { fetchEntryPoints, updateEntryPoint, archiveEntryPoint, + // non-standard + fetchEntryPointDetails, } diff --git a/web/src/projects/entry-points/reducer.js b/web/src/projects/entry-points/reducer.js index 92bef0c9..48481bbc 100644 --- a/web/src/projects/entry-points/reducer.js +++ b/web/src/projects/entry-points/reducer.js @@ -6,6 +6,7 @@ import { fetchEntryPoints, updateEntryPoint, archiveEntryPoint, + fetchEntryPointDetails } from './actions' import { archiveGoalFully } from '../goals/actions' import { isCrud, crudReducer } from '../../crudRedux' @@ -40,15 +41,35 @@ export default function (state = defaultState, action) { } const { payload, type } = action + let cellIdString switch (type) { + case fetchEntryPointDetails.success().type: + cellIdString = action.meta.cellIdString + const mapped = payload.entry_points.map(r => { + return { + ...r.entry, + address: r.address, + } + }) + // mapped is [ { key: val, address: 'QmAsdFg' }, ...] + const newVals = _.keyBy(mapped, 'address') + // combines pre-existing values of the object with new values from + // Holochain fetch + return { + ...state, + [cellIdString]: { + ...state[cellIdString], + ...newVals, + }, + } case archiveGoalFully.success().type: - const cellId = action.meta.cellIdString + cellIdString = action.meta.cellIdString // filter out the entry points whose addresses are listed as having been // archived on account of having archived its associated Goal return { ...state, - [cellId]: _.pickBy( - state[cellId], + [cellIdString]: _.pickBy( + state[cellIdString], (_value, key) => payload.archived_entry_points.indexOf(key) === -1 ), } diff --git a/web/src/projects/goals/reducer.js b/web/src/projects/goals/reducer.js index 609f2e57..f8c5fed2 100644 --- a/web/src/projects/goals/reducer.js +++ b/web/src/projects/goals/reducer.js @@ -9,6 +9,7 @@ import { archiveGoalFully, } from './actions' import { isCrud, crudReducer } from '../../crudRedux' +import { fetchEntryPointDetails } from '../entry-points/actions' const defaultState = {} @@ -40,6 +41,25 @@ export default function (state = defaultState, action) { }, }, } + case fetchEntryPointDetails.success().type: + cellIdString = action.meta.cellIdString + const mapped = payload.goals.map((r) => { + return { + ...r.entry, + address: r.address, + } + }) + // mapped is [ { key: val, address: 'QmAsdFg' }, ...] + const newVals = _.keyBy(mapped, 'address') + // combines pre-existing values of the object with new values from + // Holochain fetch + return { + ...state, + [cellIdString]: { + ...state[cellIdString], + ...newVals, + }, + } case archiveGoalFully.success().type: cellIdString = action.meta.cellIdString return { diff --git a/web/src/routes/Dashboard/Dashboard.js b/web/src/routes/Dashboard/Dashboard.js index 1be170d6..3b5e1df4 100644 --- a/web/src/routes/Dashboard/Dashboard.js +++ b/web/src/routes/Dashboard/Dashboard.js @@ -17,7 +17,7 @@ import InviteMembersModal from '../../components/InviteMembersModal/InviteMember import { PROJECTS_ZOME_NAME, PROJECT_APP_PREFIX } from '../../holochainConfig' import { passphraseToUid } from '../../secrets' import { getAdminWs, getAppWs, getAgentPubKey } from '../../hcWebsockets' -import { fetchEntryPoints } from '../../projects/entry-points/actions' +import { fetchEntryPointDetails } from '../../projects/entry-points/actions' import { fetchMembers, setMember } from '../../projects/members/actions' import { simpleCreateProjectMeta, @@ -32,7 +32,7 @@ import { } from './DashboardListProject' import { joinProjectCellId, removeProjectCellId } from '../../cells/actions' import importAllProjectData from '../../import' -import PendingProjects from '../../components/PendingProjects/PendingProjects.tsx' +import PendingProjects from '../../components/PendingProjects/PendingProjects' function Dashboard({ existingAgents, @@ -41,7 +41,7 @@ function Dashboard({ profilesCellIdString, cells, projects, - fetchEntryPoints, + fetchEntryPointDetails, fetchMembers, fetchProjectMeta, createProject, @@ -78,7 +78,7 @@ function Dashboard({ }) }) fetchMembers(cellId) - fetchEntryPoints(cellId) + fetchEntryPointDetails(cellId) }) }, [JSON.stringify(cells)]) @@ -443,8 +443,8 @@ function mapDispatchToProps(dispatch) { deactivateApp: (appId, cellId) => { return deactivateApp(appId, cellId, dispatch) }, - fetchEntryPoints: (cellIdString) => { - return dispatch(fetchEntryPoints.create({ cellIdString, payload: null })) + fetchEntryPointDetails: (cellIdString) => { + return dispatch(fetchEntryPointDetails.create({ cellIdString, payload: null })) }, fetchMembers: (cellIdString) => { return dispatch(fetchMembers.create({ cellIdString, payload: null })) diff --git a/web/src/routes/ProjectView/ProjectView.js b/web/src/routes/ProjectView/ProjectView.js index 1c03366d..d3801831 100644 --- a/web/src/routes/ProjectView/ProjectView.js +++ b/web/src/routes/ProjectView/ProjectView.js @@ -100,19 +100,19 @@ function mapDispatchToProps(dispatch, ownProps) { fetchProjectMeta: () => dispatch(fetchProjectMeta.create({ cellIdString, payload: null })), fetchEntryPoints: () => - dispatch(fetchEntryPoints.create({ cellIdString, payload: null })), + dispatch(fetchEntryPoints.create({ cellIdString, payload: { All: null } })), fetchMembers: () => dispatch(fetchMembers.create({ cellIdString, payload: null })), fetchGoals: () => - dispatch(fetchGoals.create({ cellIdString, payload: null })), + dispatch(fetchGoals.create({ cellIdString, payload: { All: null } })), fetchEdges: () => - dispatch(fetchEdges.create({ cellIdString, payload: null })), + dispatch(fetchEdges.create({ cellIdString, payload: { All: null } })), fetchGoalMembers: () => - dispatch(fetchGoalMembers.create({ cellIdString, payload: null })), + dispatch(fetchGoalMembers.create({ cellIdString, payload: { All: null } })), fetchGoalVotes: () => - dispatch(fetchGoalVotes.create({ cellIdString, payload: null })), + dispatch(fetchGoalVotes.create({ cellIdString, payload: { All: null } })), fetchGoalComments: () => - dispatch(fetchGoalComments.create({ cellIdString, payload: null })), + dispatch(fetchGoalComments.create({ cellIdString, payload: { All: null } })), } }