use crate::tests_crypto::*;
use super::*;
use lazy_static::*;
lazy_static! {
static ref BOGUS_KEY: RecordKey = RecordKey::new(
TEST_CRYPTO_KIND,
BareRecordKey::new(
BareOpaqueRecordKey::new(&[0u8; 32]),
Some(BareSharedSecret::new(&[1u8; 32]))
)
);
}
async fn test_get_dht_value_unopened(api: VeilidAPI) {
let rc = api.routing_context().unwrap();
let result = rc.get_dht_value(BOGUS_KEY.clone(), 0, false).await;
assert_err!(result);
}
async fn test_open_dht_record_nonexistent_no_writer(api: VeilidAPI) {
let rc = api.routing_context().unwrap();
let result = rc.get_dht_value(BOGUS_KEY.clone(), 0, false).await;
assert_err!(result);
}
async fn test_close_dht_record_nonexistent(api: VeilidAPI) {
let rc = api.routing_context().unwrap();
let result = rc.close_dht_record(BOGUS_KEY.clone()).await;
assert_err!(result);
}
async fn test_delete_dht_record_nonexistent(api: VeilidAPI) {
let rc = api.routing_context().unwrap();
let result = rc.delete_dht_record(BOGUS_KEY.clone()).await;
assert_err!(result);
}
async fn test_create_delete_dht_record_simple(api: VeilidAPI) {
let rc = api.routing_context().unwrap();
let rec = rc
.create_dht_record(TEST_CRYPTO_KIND, DHTSchema::dflt(1).unwrap(), None)
.await
.unwrap();
let dht_key = rec.key();
rc.close_dht_record(dht_key.clone()).await.unwrap();
rc.delete_dht_record(dht_key).await.unwrap();
}
async fn test_create_dht_record_with_owner(api: VeilidAPI) {
let rc = api.routing_context().unwrap();
let crypto = api.crypto().unwrap();
let cs = crypto.get(TEST_CRYPTO_KIND).unwrap();
let owner_keypair = cs.generate_keypair();
let rec = rc
.create_dht_record(
TEST_CRYPTO_KIND,
DHTSchema::dflt(1).unwrap(),
Some(owner_keypair.clone()),
)
.await
.unwrap();
assert_eq!(rec.ref_owner(), &owner_keypair.key());
let dht_key = rec.key();
rc.close_dht_record(dht_key.clone()).await.unwrap();
rc.delete_dht_record(dht_key.clone()).await.unwrap();
}
async fn test_get_dht_record_key(api: VeilidAPI) {
let rc = api.routing_context().unwrap();
let crypto = api.crypto().unwrap();
let cs = crypto.get(TEST_CRYPTO_KIND).unwrap();
let owner_keypair = cs.generate_keypair();
let schema = DHTSchema::dflt(1).unwrap();
let rec = rc
.create_dht_record(
TEST_CRYPTO_KIND,
schema.clone(),
Some(owner_keypair.clone()),
)
.await
.unwrap();
let key = api
.get_dht_record_key(
schema.clone(),
owner_keypair.key(),
rec.key().encryption_key(),
)
.await
.unwrap();
assert_eq!(key, rec.key());
let dht_key = rec.key();
rc.close_dht_record(dht_key.clone()).await.unwrap();
rc.delete_dht_record(dht_key).await.unwrap();
}
async fn test_get_dht_value_nonexistent(api: VeilidAPI) {
let rc = api.routing_context().unwrap();
let rec = rc
.create_dht_record(TEST_CRYPTO_KIND, DHTSchema::dflt(1).unwrap(), None)
.await
.unwrap();
let dht_key = rec.key();
let result = rc.get_dht_value(dht_key.clone(), 0, false).await;
assert_eq!(result.expect("should not be error"), None);
rc.close_dht_record(dht_key.clone()).await.unwrap();
rc.delete_dht_record(dht_key).await.unwrap();
}
async fn test_set_get_dht_value(api: VeilidAPI) {
let rc = api.routing_context().unwrap();
let rec = rc
.create_dht_record(TEST_CRYPTO_KIND, DHTSchema::dflt(2).unwrap(), None)
.await
.unwrap();
let dht_key = rec.key();
let test_value = String::from("BLAH BLAH BLAH").as_bytes().to_vec();
let set_dht_value_result = rc
.set_dht_value(dht_key.clone(), 0, test_value.clone(), None)
.await;
assert_eq!(set_dht_value_result.expect("should be Ok(None)"), None);
let get_dht_value_result_0_non_force = rc.get_dht_value(dht_key.clone(), 0, false).await;
assert_eq!(
get_dht_value_result_0_non_force
.expect("should not be error")
.expect("should hold a value")
.data(),
test_value.clone()
);
let get_dht_value_result_0_force = rc.get_dht_value(dht_key.clone(), 0, true).await;
assert_eq!(
get_dht_value_result_0_force
.expect("should not be error")
.expect("should hold a value")
.data(),
test_value.clone()
);
let get_dht_value_result_1_non_force = rc.get_dht_value(dht_key.clone(), 1, false).await;
assert_eq!(
get_dht_value_result_1_non_force.expect("should not be error"),
None
);
rc.close_dht_record(dht_key.clone()).await.unwrap();
rc.delete_dht_record(dht_key).await.unwrap();
}
async fn test_open_writer_dht_value(api: VeilidAPI) {
let rc = api.routing_context().unwrap();
let rec = rc
.create_dht_record(TEST_CRYPTO_KIND, DHTSchema::dflt(2).unwrap(), None)
.await
.unwrap();
let key = rec.key();
let owner = rec.owner();
let secret = rec.owner_secret().unwrap();
let keypair = KeyPair::new_from_parts(owner.clone(), secret.value());
let test_value_1 = String::from("Qwertyuiop Asdfghjkl Zxcvbnm")
.as_bytes()
.to_vec();
let test_data_2 = String::from("1234567890").as_bytes().to_vec();
let test_data_3 = String::from("!@#$%^&*()").as_bytes().to_vec();
let set_dht_test_value_1_result = rc
.set_dht_value(key.clone(), 1, test_value_1.clone(), None)
.await;
assert!(set_dht_test_value_1_result.is_ok());
let get_dht_value_result_1_non_force = rc.get_dht_value(key.clone(), 1, false).await;
assert!(get_dht_value_result_1_non_force.is_ok());
let get_dht_value_result_1_non_force = get_dht_value_result_1_non_force
.unwrap()
.expect("should hold value");
assert_eq!(get_dht_value_result_1_non_force.data(), test_value_1);
assert_eq!(get_dht_value_result_1_non_force.seq(), 0.into());
assert_eq!(get_dht_value_result_1_non_force.writer(), owner);
let get_dht_value_result_0_non_force = rc.get_dht_value(key.clone(), 0, false).await;
assert_eq!(
get_dht_value_result_0_non_force.expect("should not be error"),
None
);
let set_dht_test_value_0_result = rc
.set_dht_value(key.clone(), 0, test_data_2.clone(), None)
.await;
assert!(set_dht_test_value_0_result.is_ok());
let get_dht_value_result_0_force = rc.get_dht_value(key.clone(), 0, true).await;
assert_eq!(
get_dht_value_result_0_force
.expect("should be OK(result)")
.expect("should hold value")
.data(),
test_data_2
);
let get_dht_value_result_1_force = rc.get_dht_value(key.clone(), 1, true).await;
assert_eq!(
get_dht_value_result_1_force
.expect("should be OK(result)")
.expect("should hold value")
.data(),
test_value_1
);
let overwrite_value_1_result_1 = rc
.set_dht_value(key.clone(), 1, test_value_1.clone(), None)
.await;
assert!(overwrite_value_1_result_1.is_ok());
let overwrite_value_1_result_2 = rc
.set_dht_value(key.clone(), 1, test_data_2.clone(), None)
.await;
assert!(overwrite_value_1_result_2.is_ok());
rc.close_dht_record(key.clone()).await.unwrap();
rc.delete_dht_record(key.clone()).await.unwrap();
let rec = rc.open_dht_record(key.clone(), Some(keypair.clone())).await;
assert!(rec.is_ok());
let rec = rec.unwrap();
assert_eq!(rec.ref_key().value(), key.value());
assert_eq!(rec.ref_key().kind(), key.kind());
assert_eq!(rec.owner(), owner);
assert_eq!(rec.owner_secret().unwrap(), secret);
assert_eq!(rec.ref_schema(), &DHTSchema::dflt(2).unwrap());
let set_dht_test_value_1_result = rc
.set_dht_value(key.clone(), 1, test_data_3.clone(), None)
.await;
assert!(set_dht_test_value_1_result.is_ok());
let vdtemp = set_dht_test_value_1_result.unwrap().unwrap();
assert_eq!(vdtemp.data(), test_data_2);
assert_eq!(vdtemp.seq(), 1.into());
assert_eq!(vdtemp.writer(), owner);
let set_dht_test_value_1_result = rc
.set_dht_value(key.clone(), 1, test_data_3.clone(), None)
.await;
assert!(set_dht_test_value_1_result.is_ok());
let get_dht_value_result_1_force = rc.get_dht_value(key.clone(), 1, true).await;
assert!(get_dht_value_result_1_force.is_ok());
let get_dht_value_result_1_force = get_dht_value_result_1_force
.expect("should be OK(result)")
.expect("should hold value");
assert_eq!(get_dht_value_result_1_force.data(), test_data_3);
assert_eq!(get_dht_value_result_1_force.seq(), 2.into());
assert_eq!(get_dht_value_result_1_force.writer(), owner);
rc.close_dht_record(key.clone()).await.unwrap();
rc.delete_dht_record(key.clone()).await.unwrap();
let crypto = api.crypto().unwrap();
let cs = crypto.get(key.kind()).unwrap();
assert!(cs
.validate_keypair(&owner, &secret)
.expect("should succeed"));
let other_keypair = cs.generate_keypair();
let rec = rc.open_dht_record(key.clone(), Some(other_keypair)).await;
assert!(rec.is_ok());
let rec = rec.unwrap();
assert_eq!(rec.ref_key().value(), key.value());
assert_eq!(rec.ref_key().kind(), key.kind());
assert_eq!(rec.owner(), owner);
assert_eq!(rec.owner_secret(), None);
assert_eq!(rec.ref_schema(), &DHTSchema::dflt(2).unwrap());
let set_dht_test_value_0_result = rc
.set_dht_value(key.clone(), 1, test_value_1.clone(), None)
.await;
assert_err!(set_dht_test_value_0_result);
let set_dht_test_value_0_result = rc
.set_dht_value(key.clone(), 0, test_value_1.clone(), None)
.await;
assert_err!(set_dht_test_value_0_result);
let set_dht_test_value_0_result = rc
.set_dht_value(
key.clone(),
0,
test_value_1.clone(),
Some(SetDHTValueOptions {
writer: Some(keypair),
allow_offline: None,
}),
)
.await;
assert!(set_dht_test_value_0_result.is_ok());
rc.close_dht_record(key.clone()).await.unwrap();
rc.delete_dht_record(key).await.unwrap();
}
pub async fn test_set_dht_value_allow_offline(api: VeilidAPI) {
let rc = api.routing_context().unwrap();
let rec = rc
.create_dht_record(CRYPTO_KIND_VLD0, DHTSchema::dflt(1).unwrap(), None)
.await
.unwrap();
let dht_key = rec.key();
let test_value = String::from("Test offline value").as_bytes().to_vec();
let set_result = rc
.set_dht_value(dht_key.clone(), 0, test_value.clone(), None)
.await;
assert!(set_result.is_ok());
let set_result = rc
.set_dht_value(
dht_key.clone(),
0,
test_value.clone(),
Some(SetDHTValueOptions {
writer: None,
allow_offline: None,
}),
)
.await;
assert!(set_result.is_ok());
let set_result = rc
.set_dht_value(
dht_key.clone(),
1,
test_value.clone(),
Some(SetDHTValueOptions {
writer: None,
allow_offline: Some(AllowOffline(true)),
}),
)
.await;
assert!(set_result.is_ok());
let set_result = rc
.set_dht_value(
dht_key.clone(),
2,
test_value.clone(),
Some(SetDHTValueOptions {
writer: None,
allow_offline: Some(AllowOffline(false)),
}),
)
.await;
assert!(set_result.is_err());
assert!(set_result.unwrap_err().to_string().contains("offline"));
rc.close_dht_record(dht_key.clone()).await.unwrap();
rc.delete_dht_record(dht_key).await.unwrap();
}
pub async fn test_all() {
let (update_callback, config) = fixture_veilid_core();
let api = api_startup(update_callback, config)
.await
.expect("startup failed");
let _ = api.attach().await;
fixture_wait_for_public_internet_ready(&api).await;
test_get_dht_value_unopened(api.clone()).await;
test_open_dht_record_nonexistent_no_writer(api.clone()).await;
test_close_dht_record_nonexistent(api.clone()).await;
test_delete_dht_record_nonexistent(api.clone()).await;
test_get_dht_value_nonexistent(api.clone()).await;
test_create_delete_dht_record_simple(api.clone()).await;
test_create_dht_record_with_owner(api.clone()).await;
test_get_dht_record_key(api.clone()).await;
test_set_get_dht_value(api.clone()).await;
test_open_writer_dht_value(api.clone()).await;
test_set_dht_value_allow_offline(api.clone()).await;
api.shutdown().await;
}