use std::sync::Arc;
use holo_hash::HasHash;
use holochain_cascade::test_utils::*;
use holochain_cascade::{Cascade, CascadeImpl};
use holochain_p2p::MockHolochainP2pDnaT;
use holochain_state::mutations::insert_op_scratch;
use holochain_state::prelude::*;
async fn assert_can_get(
td_entry: &EntryTestData,
td_record: &RecordTestData,
cascade: &CascadeImpl,
options: GetOptions,
) {
let r = cascade
.dht_get(td_entry.hash.clone().into(), options.clone())
.await
.unwrap()
.expect("Failed to get entry");
assert_eq!(*r.action_address(), td_entry.create_hash);
assert_eq!(r.action().entry_hash(), Some(&td_entry.hash));
let r = cascade
.dht_get(td_record.any_action_hash.clone().into(), options.clone())
.await
.unwrap()
.expect("Failed to get record");
assert_eq!(*r.action_address(), td_record.any_action_hash);
assert_eq!(r.action().entry_hash(), td_record.any_entry_hash.as_ref());
let r = cascade
.get_details(td_entry.hash.clone().into(), options.clone())
.await
.unwrap()
.expect("Failed to get entry");
let expected = Details::Entry(EntryDetails {
entry: td_entry.entry.entry.clone(),
actions: vec![td_entry
.wire_create
.data
.clone()
.into_action(td_entry.entry.entry_type.clone(), td_entry.hash.clone())],
rejected_actions: vec![],
deletes: vec![],
updates: vec![],
entry_dht_status: EntryDhtStatus::Live,
});
assert_eq!(r, expected);
let r = cascade
.get_details(td_record.any_action_hash.clone().into(), options.clone())
.await
.unwrap()
.expect("Failed to get record details");
let expected = Details::Record(RecordDetails {
record: td_record.any_record.clone(),
validation_status: ValidationStatus::Valid,
deletes: vec![],
updates: vec![],
});
assert_eq!(r, expected);
}
async fn assert_is_none(
td_entry: &EntryTestData,
td_record: &RecordTestData,
cascade: &CascadeImpl,
options: GetOptions,
) {
let r = cascade
.dht_get(td_entry.hash.clone().into(), options.clone())
.await
.unwrap();
assert!(r.is_none());
let r = cascade
.dht_get(td_record.any_action_hash.clone().into(), options.clone())
.await
.unwrap();
assert!(r.is_none());
let r = cascade
.get_details(td_entry.hash.clone().into(), options.clone())
.await
.unwrap();
assert!(r.is_none());
let r = cascade
.get_details(td_record.any_action_hash.clone().into(), options.clone())
.await
.unwrap();
assert!(r.is_none());
}
async fn assert_rejected(
td_entry: &EntryTestData,
td_record: &RecordTestData,
cascade: &CascadeImpl,
options: GetOptions,
) {
let r = cascade
.dht_get(td_entry.hash.clone().into(), options.clone())
.await
.unwrap();
assert!(r.is_none());
let r = cascade
.dht_get(td_record.any_action_hash.clone().into(), options.clone())
.await
.unwrap();
assert!(r.is_none());
let r = cascade
.get_details(td_entry.hash.clone().into(), Default::default())
.await
.unwrap()
.expect("Failed to get entry");
let expected = Details::Entry(EntryDetails {
entry: td_entry.entry.entry.clone(),
actions: vec![],
rejected_actions: vec![td_entry
.wire_create
.data
.clone()
.into_action(td_entry.entry.entry_type.clone(), td_entry.hash.clone())],
deletes: vec![],
updates: vec![],
entry_dht_status: EntryDhtStatus::Dead,
});
assert_eq!(r, expected);
let r = cascade
.get_details(td_record.any_action_hash.clone().into(), Default::default())
.await
.unwrap()
.expect("Failed to get entry");
let expected = Details::Record(RecordDetails {
record: td_record.any_record.clone(),
validation_status: ValidationStatus::Rejected,
deletes: vec![],
updates: vec![],
});
assert_eq!(r, expected);
}
async fn assert_can_retrieve(td_entry: &EntryTestData, cascade: &CascadeImpl, options: GetOptions) {
let (r, _) = cascade
.retrieve(td_entry.hash.clone().into(), options.clone().into())
.await
.unwrap()
.expect("Failed to retrieve record");
assert_eq!(*r.action_address(), td_entry.create_hash);
assert_eq!(r.action().entry_hash(), Some(&td_entry.hash));
let (r, _) = cascade
.retrieve(td_entry.create_hash.clone().into(), options.clone().into())
.await
.unwrap()
.expect("Failed to retrieve record");
assert_eq!(*r.action_address(), td_entry.create_hash);
assert_eq!(r.action().entry_hash(), Some(&td_entry.hash));
let (r, _) = cascade
.retrieve_entry(td_entry.hash.clone(), options.clone().into())
.await
.unwrap()
.expect("Failed to retrieve entry");
assert_eq!(*r.as_hash(), td_entry.hash);
let (r, _) = cascade
.retrieve_action(td_entry.create_hash.clone(), options.clone().into())
.await
.unwrap()
.expect("Failed to retrieve action");
assert_eq!(*r.as_hash(), td_entry.create_hash);
}
#[tokio::test(flavor = "multi_thread")]
async fn entry_not_authority_or_authoring() {
holochain_trace::test_run();
let cache = test_cache_db();
let authority = test_dht_db();
let td_entry = EntryTestData::create();
let td_record = RecordTestData::create();
fill_db(&authority.to_db(), td_entry.store_entry_op.clone()).await;
fill_db(&authority.to_db(), td_record.any_store_record_op.clone()).await;
let network = PassThroughNetwork::authority_for_nothing(vec![authority.to_db().clone().into()]);
let cascade = CascadeImpl::empty().with_network(network, cache.to_db());
assert_can_get(&td_entry, &td_record, &cascade, GetOptions::network()).await;
}
#[tokio::test(flavor = "multi_thread")]
async fn entry_authoring() {
holochain_trace::test_run();
let cache = test_cache_db();
let mut scratch = Scratch::new();
let td_entry = EntryTestData::create();
let td_record = RecordTestData::create();
insert_op_scratch(
&mut scratch,
td_entry.store_entry_op.clone(),
ChainTopOrdering::default(),
)
.unwrap();
insert_op_scratch(
&mut scratch,
td_record.any_store_record_op.clone(),
ChainTopOrdering::default(),
)
.unwrap();
let mut mock = MockHolochainP2pDnaT::new();
mock.expect_authority_for_hash().returning(|_| Ok(false));
let mock = Arc::new(mock);
let cascade = CascadeImpl::empty()
.with_scratch(scratch.into_sync())
.with_network(mock, cache.to_db());
assert_can_get(&td_entry, &td_record, &cascade, GetOptions::network()).await;
}
#[tokio::test(flavor = "multi_thread")]
async fn entry_authority() {
holochain_trace::test_run();
let cache = test_cache_db();
let vault = test_authored_db();
let td_entry = EntryTestData::create();
let td_record = RecordTestData::create();
fill_db(&vault.to_db(), td_entry.store_entry_op.clone()).await;
fill_db(&vault.to_db(), td_record.any_store_record_op.clone()).await;
let mut mock = MockHolochainP2pDnaT::new();
mock.expect_authority_for_hash().returning(|_| Ok(true));
let mock = Arc::new(mock);
let cascade = CascadeImpl::empty()
.with_authored(vault.to_db().into())
.with_network(mock, cache.to_db());
assert_can_get(&td_entry, &td_record, &cascade, GetOptions::network()).await;
}
#[tokio::test(flavor = "multi_thread")]
async fn content_not_authority_or_authoring() {
holochain_trace::test_run();
let cache = test_cache_db();
let vault = test_authored_db();
let td_entry = EntryTestData::create();
let td_record = RecordTestData::create();
fill_db(&vault.to_db(), td_entry.store_entry_op.clone()).await;
fill_db(&vault.to_db(), td_record.any_store_record_op.clone()).await;
let mut mock = MockHolochainP2pDnaT::new();
mock.expect_authority_for_hash().returning(|_| Ok(false));
let mock = Arc::new(mock);
let cascade = CascadeImpl::empty()
.with_authored(vault.to_db().into())
.with_network(mock, cache.to_db());
assert_can_get(&td_entry, &td_record, &cascade, GetOptions::local()).await;
}
#[tokio::test(flavor = "multi_thread")]
async fn content_authoring() {
holochain_trace::test_run();
let cache = test_cache_db();
let mut scratch = Scratch::new();
let td_entry = EntryTestData::create();
let td_record = RecordTestData::create();
insert_op_scratch(
&mut scratch,
td_entry.store_entry_op.clone(),
ChainTopOrdering::default(),
)
.unwrap();
insert_op_scratch(
&mut scratch,
td_record.any_store_record_op.clone(),
ChainTopOrdering::default(),
)
.unwrap();
let mut mock = MockHolochainP2pDnaT::new();
mock.expect_authority_for_hash().returning(|_| Ok(false));
let mock = Arc::new(mock);
let cascade = CascadeImpl::empty()
.with_scratch(scratch.into_sync())
.with_network(mock, cache.to_db());
assert_can_get(&td_entry, &td_record, &cascade, GetOptions::local()).await;
}
#[tokio::test(flavor = "multi_thread")]
async fn content_authority() {
holochain_trace::test_run();
let cache = test_cache_db();
let vault = test_authored_db();
let td_entry = EntryTestData::create();
let td_record = RecordTestData::create();
let mut mock = MockHolochainP2pDnaT::new();
mock.expect_authority_for_hash().returning(|_| Ok(true));
let mock = Arc::new(mock);
let cascade = CascadeImpl::empty()
.with_authored(vault.to_db().into())
.with_network(mock, cache.to_db());
assert_is_none(&td_entry, &td_record, &cascade, GetOptions::local()).await;
}
#[tokio::test(flavor = "multi_thread")]
async fn rejected_ops() {
holochain_trace::test_run();
let cache = test_cache_db();
let authority = test_dht_db();
let td_entry = EntryTestData::create();
let td_record = RecordTestData::create();
fill_db_rejected(&authority.to_db(), td_entry.store_entry_op.clone()).await;
fill_db_rejected(&authority.to_db(), td_record.any_store_record_op.clone()).await;
let network = PassThroughNetwork::authority_for_nothing(vec![authority.to_db().clone().into()]);
let cascade = CascadeImpl::empty().with_network(network, cache.to_db());
assert_rejected(&td_entry, &td_record, &cascade, GetOptions::network()).await;
}
#[tokio::test(flavor = "multi_thread")]
async fn check_can_handle_rejected_ops_in_cache() {
holochain_trace::test_run();
let cache = test_cache_db();
let authority = test_dht_db();
let td_entry = EntryTestData::create();
let td_record = RecordTestData::create();
fill_db_rejected(&cache.to_db(), td_entry.store_entry_op.clone()).await;
fill_db_rejected(&cache.to_db(), td_record.any_store_record_op.clone()).await;
let network = PassThroughNetwork::authority_for_nothing(vec![authority.to_db().clone().into()]);
let cascade = CascadeImpl::empty().with_network(network, cache.to_db());
assert_rejected(&td_entry, &td_record, &cascade, GetOptions::network()).await;
}
#[tokio::test(flavor = "multi_thread")]
#[ignore = "todo"]
async fn check_all_queries_still_work() {
todo!()
}
#[tokio::test(flavor = "multi_thread")]
#[ignore = "todo"]
async fn check_all_queries_still_work_with_cache() {
todo!()
}
#[tokio::test(flavor = "multi_thread")]
#[ignore = "todo"]
async fn check_all_queries_still_work_with_scratch() {
todo!()
}
#[tokio::test(flavor = "multi_thread")]
async fn test_pending_data_isnt_returned() {
holochain_trace::test_run();
let cache = test_cache_db();
let authority = test_dht_db();
let vault = test_authored_db();
let td_entry = EntryTestData::create();
let td_record = RecordTestData::create();
fill_db_pending(&authority.to_db(), td_entry.store_entry_op.clone()).await;
fill_db_pending(&authority.to_db(), td_record.any_store_record_op.clone()).await;
fill_db_pending(&vault.to_db(), td_entry.store_entry_op.clone()).await;
fill_db_pending(&vault.to_db(), td_record.any_store_record_op.clone()).await;
fill_db_pending(&cache.to_db(), td_entry.store_entry_op.clone()).await;
fill_db_pending(&cache.to_db(), td_record.any_store_record_op.clone()).await;
let network = PassThroughNetwork::authority_for_nothing(vec![authority.to_db().clone().into()]);
let cascade = CascadeImpl::empty().with_network(network, cache.to_db());
assert_is_none(&td_entry, &td_record, &cascade, GetOptions::network()).await;
assert_can_retrieve(&td_entry, &cascade, GetOptions::network()).await;
let network = PassThroughNetwork::authority_for_all(vec![authority.to_db().clone().into()]);
let cascade = CascadeImpl::empty().with_network(network, cache.to_db());
assert_is_none(&td_entry, &td_record, &cascade, GetOptions::network()).await;
assert_can_retrieve(&td_entry, &cascade, GetOptions::network()).await;
}