use super::*;
use crate::conductor::space::TestSpaces;
use crate::core::workflow::sys_validation_workflow::sys_validate_record;
use crate::sweettest::SweetAgents;
use crate::sweettest::SweetConductor;
use ::fixt::prelude::*;
use error::SysValidationError;
use holo_hash::fixt::ActionHashFixturator;
use holo_hash::fixt::AgentPubKeyFixturator;
use holo_hash::fixt::DnaHashFixturator;
use holo_hash::fixt::EntryHashFixturator;
use holochain_cascade::MockCascade;
use holochain_keystore::test_keystore;
use holochain_keystore::AgentPubKeyExt;
use holochain_serialized_bytes::SerializedBytes;
use holochain_sqlite::prelude::DatabaseResult;
use holochain_types::test_utils::valid_arbitrary_chain;
use holochain_types::test_utils::ActionRefMut;
use holochain_zome_types::Action;
use matches::assert_matches;
use std::time::Duration;
#[test]
fn check_entry_type_test() {
let entry_fixt = EntryFixturator::new(Predictable);
let et_fixt = EntryTypeFixturator::new(Predictable);
for (e, et) in entry_fixt.zip(et_fixt).take(4) {
assert_matches!(check_entry_type(&et, &e), Ok(()));
}
let entry_fixt = EntryFixturator::new(Predictable);
let mut et_fixt = EntryTypeFixturator::new(Predictable);
et_fixt.next().unwrap();
for (e, et) in entry_fixt.zip(et_fixt).take(4) {
assert_matches!(
check_entry_type(&et, &e),
Err(SysValidationError::ValidationOutcome(
ValidationOutcome::EntryTypeMismatch
))
);
}
}
#[test]
fn check_entry_hash_test() {
let mut ec = Create {
author: fixt!(AgentPubKey),
timestamp: Timestamp::now(),
action_seq: 6,
prev_action: fixt!(ActionHash),
entry_type: EntryType::AgentPubKey,
entry_hash: fixt!(EntryHash),
weight: EntryRateWeight::default(),
};
let entry = Entry::App(AppEntryBytes(SerializedBytes::from(UnsafeBytes::from(
vec![1, 3, 5],
))));
let hash = EntryHash::with_data_sync(&entry);
let action: Action = ec.clone().into();
assert_matches!(check_new_entry_action(&action), Ok(()));
let eh = action.entry_data().map(|(h, _)| h).unwrap();
assert_matches!(
check_entry_hash(eh, &entry),
Err(SysValidationError::ValidationOutcome(
ValidationOutcome::EntryHash
))
);
ec.entry_hash = hash;
let action: Action = ec.clone().into();
let eh = action.entry_data().map(|(h, _)| h).unwrap();
assert_matches!(check_entry_hash(eh, &entry), Ok(()));
assert_matches!(
check_new_entry_action(&Action::CreateLink(CreateLink {
author: fixt!(AgentPubKey),
timestamp: Timestamp::now(),
action_seq: 8,
prev_action: fixt!(ActionHash),
base_address: fixt!(EntryHash).into(),
target_address: fixt!(EntryHash).into(),
zome_index: 0.into(),
link_type: LinkType::new(3),
tag: ().into(),
weight: RateWeight::default(),
})),
Err(SysValidationError::ValidationOutcome(
ValidationOutcome::NotNewEntry(_)
))
);
}
#[tokio::test(flavor = "multi_thread")]
async fn incoming_ops_filters_private_entry() {
let dna = fixt!(DnaHash);
let spaces = TestSpaces::new([dna.clone()]).await;
let space = Arc::new(spaces.test_spaces[&dna].space.clone());
let vault = space.dht_db.clone();
let keystore = test_keystore();
let (tx, _rx) = TriggerSender::new();
let private_entry = Entry::App(AppEntryBytes(SerializedBytes::from(UnsafeBytes::from(
vec![1, 3, 5],
))));
let author = keystore.new_sign_keypair_random().await.unwrap();
let app_entry_def = AppEntryDef::new(0.into(), 0.into(), EntryVisibility::Private);
let create = Create {
author: author.clone(),
timestamp: Timestamp::now(),
action_seq: 5,
prev_action: fixt!(ActionHash),
entry_type: EntryType::App(app_entry_def),
entry_hash: EntryHash::with_data_sync(&private_entry),
weight: EntryRateWeight::default(),
};
let action = Action::Create(create);
let signature = author.sign(&keystore, &action).await.unwrap();
let shh =
SignedActionHashed::with_presigned(ActionHashed::from_content_sync(action), signature);
let record = Record::new(shh, Some(private_entry));
let ops_sender = IncomingDhtOpSender::new(space.clone(), tx.clone());
ops_sender.send_store_entry(record.clone()).await.unwrap();
let num_ops: usize = vault
.read_async(move |txn| -> DatabaseResult<usize> {
Ok(txn.query_row("SELECT COUNT(rowid) FROM DhtOp", [], |row| row.get(0))?)
})
.await
.unwrap();
assert_eq!(num_ops, 0);
let ops_sender = IncomingDhtOpSender::new(space.clone(), tx.clone());
ops_sender.send_store_record(record.clone()).await.unwrap();
let num_ops: usize = vault
.read_async(move |txn| -> DatabaseResult<usize> {
Ok(txn.query_row("SELECT COUNT(rowid) FROM DhtOp", [], |row| row.get(0))?)
})
.await
.unwrap();
assert_eq!(num_ops, 1);
let num_entries: usize = vault
.read_async(move |txn| -> DatabaseResult<usize> {
Ok(txn.query_row("SELECT COUNT(rowid) FROM Entry", [], |row| row.get(0))?)
})
.await
.unwrap();
assert_eq!(num_entries, 0);
}
#[tokio::test(flavor = "multi_thread")]
#[ignore = "flaky"]
async fn valid_chain_fact_test() {
let n = 100;
let keystore = SweetConductor::standard().await.keystore();
let author = SweetAgents::one(keystore.clone()).await;
let mut chain = valid_arbitrary_chain(&keystore, author, n).await;
validate_chain(chain.iter().map(|r| r.signed_action()), &None).unwrap();
let mut last = chain.pop().unwrap();
let penult = chain.last().unwrap();
*last.as_action_mut().timestamp_mut() =
(penult.action().timestamp() + Duration::from_secs(1)).unwrap();
last.signed_action = SignedActionHashed::sign(
&keystore,
ActionHashed::from_content_sync(last.action().clone()),
)
.await
.unwrap();
let cascade = MockCascade::with_records(chain);
sys_validate_record(&last, Arc::new(cascade)).await.unwrap();
}