mirror of
https://gitlab.com/veilid/veilid.git
synced 2024-12-24 14:59:31 -05:00
wasm unit tests work and attachment manager fix
This commit is contained in:
parent
ff28273a59
commit
ee54358c27
@ -179,7 +179,14 @@ impl AttachmentManager {
|
||||
fn update_attaching_detaching_state(&self, state: AttachmentState) {
|
||||
let update_callback = {
|
||||
let mut inner = self.inner.lock();
|
||||
|
||||
// Clear routing table health so when we start measuring it we start from scratch
|
||||
inner.last_routing_table_health = None;
|
||||
|
||||
// Set attachment state directly
|
||||
inner.last_attachment_state = state;
|
||||
|
||||
// Set timestamps
|
||||
if state == AttachmentState::Attaching {
|
||||
inner.attach_ts = Some(get_aligned_timestamp());
|
||||
} else if state == AttachmentState::Detached {
|
||||
@ -189,9 +196,12 @@ impl AttachmentManager {
|
||||
} else {
|
||||
unreachable!("don't use this for attached states, use update_attachment()");
|
||||
}
|
||||
|
||||
// Get callback
|
||||
inner.update_callback.clone()
|
||||
};
|
||||
|
||||
// Send update
|
||||
if let Some(update_callback) = update_callback {
|
||||
update_callback(VeilidUpdate::Attachment(Box::new(VeilidStateAttachment {
|
||||
state,
|
||||
|
@ -888,11 +888,16 @@ impl RoutingTableInner {
|
||||
}
|
||||
}
|
||||
|
||||
// Public internet routing domain is ready for app use,
|
||||
// when we have proper dialinfo/networkclass
|
||||
let public_internet_ready = !matches!(
|
||||
self.get_network_class(RoutingDomain::PublicInternet)
|
||||
.unwrap_or_default(),
|
||||
NetworkClass::Invalid
|
||||
);
|
||||
|
||||
// Local internet routing domain is ready for app use
|
||||
// when we have proper dialinfo/networkclass
|
||||
let local_network_ready = !matches!(
|
||||
self.get_network_class(RoutingDomain::LocalNetwork)
|
||||
.unwrap_or_default(),
|
||||
|
@ -531,6 +531,8 @@ impl StorageManager {
|
||||
// Drop the lock for network access
|
||||
drop(inner);
|
||||
|
||||
log_stor!(debug "Writing subkey to the network: {}:{} len={}", key, subkey, signed_value_data.value_data().data().len() );
|
||||
|
||||
// Use the safety selection we opened the record with
|
||||
let result = self
|
||||
.outbound_set_value(
|
||||
|
@ -4,7 +4,11 @@ use super::*;
|
||||
#[derive(
|
||||
Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
|
||||
)]
|
||||
#[cfg_attr(target_arch = "wasm32", derive(Tsify), tsify(from_wasm_abi, namespace))]
|
||||
#[cfg_attr(
|
||||
target_arch = "wasm32",
|
||||
derive(Tsify),
|
||||
tsify(from_wasm_abi, into_wasm_abi, namespace)
|
||||
)]
|
||||
pub enum Sequencing {
|
||||
NoPreference = 0,
|
||||
PreferOrdered = 1,
|
||||
@ -21,7 +25,11 @@ impl Default for Sequencing {
|
||||
#[derive(
|
||||
Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
|
||||
)]
|
||||
#[cfg_attr(target_arch = "wasm32", derive(Tsify), tsify(from_wasm_abi, namespace))]
|
||||
#[cfg_attr(
|
||||
target_arch = "wasm32",
|
||||
derive(Tsify),
|
||||
tsify(from_wasm_abi, into_wasm_abi, namespace)
|
||||
)]
|
||||
pub enum Stability {
|
||||
LowLatency = 0,
|
||||
Reliable = 1,
|
||||
|
@ -222,7 +222,7 @@ impl VeilidClient {
|
||||
veilid_core::veilid_version_string()
|
||||
}
|
||||
|
||||
/// Return the default veilid configuration in json string format.
|
||||
/// Return the default veilid configuration, in string format
|
||||
pub fn defaultConfig() -> String {
|
||||
veilid_core::default_veilid_config()
|
||||
}
|
||||
|
@ -101,6 +101,7 @@ impl VeilidRoutingContext {
|
||||
// --------------------------------
|
||||
// Instance methods
|
||||
// --------------------------------
|
||||
|
||||
fn getRoutingContext(&self) -> APIResult<RoutingContext> {
|
||||
APIResult::Ok(self.inner_routing_context.clone())
|
||||
}
|
||||
@ -323,13 +324,18 @@ impl VeilidRoutingContext {
|
||||
pub async fn watchDhtValues(
|
||||
&self,
|
||||
key: String,
|
||||
subkeys: ValueSubkeyRangeSet,
|
||||
expiration: String,
|
||||
count: u32,
|
||||
subkeys: Option<ValueSubkeyRangeSet>,
|
||||
expiration: Option<String>,
|
||||
count: Option<u32>,
|
||||
) -> APIResult<String> {
|
||||
let key = TypedKey::from_str(&key)?;
|
||||
let expiration =
|
||||
veilid_core::Timestamp::from_str(&expiration).map_err(VeilidAPIError::generic)?;
|
||||
let subkeys = subkeys.unwrap_or_default();
|
||||
let expiration = if let Some(expiration) = expiration {
|
||||
veilid_core::Timestamp::from_str(&expiration).map_err(VeilidAPIError::generic)?
|
||||
} else {
|
||||
veilid_core::Timestamp::default()
|
||||
};
|
||||
let count = count.unwrap_or(u32::MAX);
|
||||
|
||||
let routing_context = self.getRoutingContext()?;
|
||||
let res = routing_context
|
||||
@ -349,9 +355,10 @@ impl VeilidRoutingContext {
|
||||
pub async fn cancelDhtWatch(
|
||||
&self,
|
||||
key: String,
|
||||
subkeys: ValueSubkeyRangeSet,
|
||||
subkeys: Option<ValueSubkeyRangeSet>,
|
||||
) -> APIResult<bool> {
|
||||
let key = TypedKey::from_str(&key)?;
|
||||
let subkeys = subkeys.unwrap_or_default();
|
||||
|
||||
let routing_context = self.getRoutingContext()?;
|
||||
let res = routing_context.cancel_dht_watch(key, subkeys).await?;
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
veilidCrypto,
|
||||
} from 'veilid-wasm';
|
||||
import { textEncoder, textDecoder } from './utils/marshalling-utils';
|
||||
import { waitForMs } from './utils/wait-utils';
|
||||
import { asyncCallWithTimeout, waitForPublicAttachment } from './utils/wait-utils';
|
||||
|
||||
describe('VeilidRoutingContext', () => {
|
||||
before('veilid startup', async () => {
|
||||
@ -23,10 +23,12 @@ describe('VeilidRoutingContext', () => {
|
||||
// }
|
||||
}, JSON.stringify(veilidCoreStartupConfig));
|
||||
await veilidClient.attach();
|
||||
await waitForMs(2000);
|
||||
await asyncCallWithTimeout(waitForPublicAttachment(), 10000);
|
||||
//console.log("---Started Up---");
|
||||
});
|
||||
|
||||
after('veilid shutdown', async () => {
|
||||
//console.log("---Shutting Down---");
|
||||
await veilidClient.detach();
|
||||
await veilidClient.shutdownCore();
|
||||
});
|
||||
@ -35,22 +37,16 @@ describe('VeilidRoutingContext', () => {
|
||||
it('should create using .create()', async () => {
|
||||
const routingContext = VeilidRoutingContext.create();
|
||||
expect(routingContext instanceof VeilidRoutingContext).toBe(true);
|
||||
|
||||
routingContext.free();
|
||||
});
|
||||
|
||||
it('should create using new', async () => {
|
||||
const routingContext = new VeilidRoutingContext();
|
||||
expect(routingContext instanceof VeilidRoutingContext).toBe(true);
|
||||
|
||||
routingContext.free();
|
||||
});
|
||||
|
||||
it('should create with default safety', async () => {
|
||||
const routingContext = VeilidRoutingContext.create().withDefaultSafety();
|
||||
expect(routingContext instanceof VeilidRoutingContext).toBe(true);
|
||||
|
||||
routingContext.free();
|
||||
});
|
||||
|
||||
it('should create with safety', async () => {
|
||||
@ -62,16 +58,12 @@ describe('VeilidRoutingContext', () => {
|
||||
},
|
||||
});
|
||||
expect(routingContext instanceof VeilidRoutingContext).toBe(true);
|
||||
|
||||
routingContext.free();
|
||||
});
|
||||
|
||||
it('should create with sequencing', async () => {
|
||||
const routingContext =
|
||||
VeilidRoutingContext.create().withSequencing('EnsureOrdered');
|
||||
expect(routingContext instanceof VeilidRoutingContext).toBe(true);
|
||||
|
||||
routingContext.free();
|
||||
});
|
||||
});
|
||||
|
||||
@ -79,19 +71,16 @@ describe('VeilidRoutingContext', () => {
|
||||
let routingContext: VeilidRoutingContext;
|
||||
|
||||
before('create routing context', () => {
|
||||
routingContext = VeilidRoutingContext.create()
|
||||
.withSequencing('EnsureOrdered');
|
||||
routingContext = VeilidRoutingContext.create().withSafety({
|
||||
Unsafe: 'EnsureOrdered',
|
||||
});
|
||||
});
|
||||
|
||||
after('free routing context', () => {
|
||||
routingContext.free();
|
||||
});
|
||||
|
||||
describe('DHT kitchen sink', async () => {
|
||||
describe('DHT kitchen sink', () => {
|
||||
let dhtRecord: DHTRecordDescriptor;
|
||||
const data = '🚀 This example DHT data with unicode a Ā 𐀀 文 🚀';
|
||||
|
||||
before('create dht record', async () => {
|
||||
beforeEach('create dht record', async () => {
|
||||
const bestKind = veilidCrypto.bestCryptoKind();
|
||||
dhtRecord = await routingContext.createDhtRecord(
|
||||
{
|
||||
@ -107,7 +96,7 @@ describe('VeilidRoutingContext', () => {
|
||||
expect(dhtRecord.schema).toEqual({ kind: 'DFLT', o_cnt: 1 });
|
||||
});
|
||||
|
||||
after('free dht record', async () => {
|
||||
afterEach('free dht record', async () => {
|
||||
await routingContext.deleteDhtRecord(dhtRecord.key);
|
||||
});
|
||||
|
||||
@ -121,6 +110,14 @@ describe('VeilidRoutingContext', () => {
|
||||
});
|
||||
|
||||
it('should get value with force refresh', async () => {
|
||||
|
||||
const setValueRes = await routingContext.setDhtValue(
|
||||
dhtRecord.key,
|
||||
0,
|
||||
textEncoder.encode(data)
|
||||
);
|
||||
expect(setValueRes).toBeUndefined();
|
||||
|
||||
const getValueRes = await routingContext.getDhtValue(
|
||||
dhtRecord.key,
|
||||
0,
|
||||
@ -192,6 +189,57 @@ describe('VeilidRoutingContext', () => {
|
||||
);
|
||||
expect(setValueRes).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should watch value and cancel watch', async () => {
|
||||
const setValueRes = await routingContext.setDhtValue(
|
||||
dhtRecord.key,
|
||||
0,
|
||||
textEncoder.encode(data)
|
||||
);
|
||||
expect(setValueRes).toBeUndefined();
|
||||
|
||||
// With typical values
|
||||
const watchValueRes = await routingContext.watchDhtValues(
|
||||
dhtRecord.key,
|
||||
[[0, 0]],
|
||||
"0",
|
||||
0xFFFFFFFF,
|
||||
);
|
||||
expect(watchValueRes).toBeDefined();
|
||||
expect(watchValueRes).not.toEqual("");
|
||||
expect(watchValueRes).not.toEqual("0");
|
||||
|
||||
const cancelValueRes = await routingContext.cancelDhtWatch(
|
||||
dhtRecord.key,
|
||||
[],
|
||||
)
|
||||
|
||||
expect(cancelValueRes).toEqual(false);
|
||||
|
||||
});
|
||||
|
||||
it('should watch value and cancel watch with default values', async () => {
|
||||
const setValueRes = await routingContext.setDhtValue(
|
||||
dhtRecord.key,
|
||||
0,
|
||||
textEncoder.encode(data)
|
||||
);
|
||||
expect(setValueRes).toBeUndefined();
|
||||
|
||||
// Again with default values
|
||||
const watchValueRes = await routingContext.watchDhtValues(
|
||||
dhtRecord.key,
|
||||
);
|
||||
expect(watchValueRes).toBeDefined();
|
||||
expect(watchValueRes).not.toEqual("");
|
||||
expect(watchValueRes).not.toEqual("0");
|
||||
|
||||
const cancelValueRes = await routingContext.cancelDhtWatch(
|
||||
dhtRecord.key,
|
||||
)
|
||||
expect(cancelValueRes).toEqual(false);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,5 @@
|
||||
import type { VeilidWASMConfig } from 'veilid-wasm';
|
||||
import { veilidClient } from 'veilid-wasm';
|
||||
|
||||
export const veilidCoreInitConfig: VeilidWASMConfig = {
|
||||
logging: {
|
||||
@ -17,129 +18,10 @@ export const veilidCoreInitConfig: VeilidWASMConfig = {
|
||||
},
|
||||
};
|
||||
|
||||
export const veilidCoreStartupConfig = {
|
||||
program_name: 'veilid-wasm-test',
|
||||
namespace: '',
|
||||
capabilities: {
|
||||
disable: [],
|
||||
},
|
||||
protected_store: {
|
||||
allow_insecure_fallback: true,
|
||||
always_use_insecure_storage: true,
|
||||
directory: '',
|
||||
delete: false,
|
||||
device_encryption_key_password: 'some-user-secret-value',
|
||||
// "new_device_encryption_key_password": "an-updated-user-secret-value"
|
||||
},
|
||||
table_store: {
|
||||
directory: '',
|
||||
delete: false,
|
||||
},
|
||||
block_store: {
|
||||
directory: '',
|
||||
delete: false,
|
||||
},
|
||||
network: {
|
||||
connection_initial_timeout_ms: 2000,
|
||||
connection_inactivity_timeout_ms: 60000,
|
||||
max_connections_per_ip4: 32,
|
||||
max_connections_per_ip6_prefix: 32,
|
||||
max_connections_per_ip6_prefix_size: 56,
|
||||
max_connection_frequency_per_min: 128,
|
||||
client_allowlist_timeout_ms: 300000,
|
||||
reverse_connection_receipt_time_ms: 5000,
|
||||
hole_punch_receipt_time_ms: 5000,
|
||||
network_key_password: '',
|
||||
disable_capabilites: [],
|
||||
routing_table: {
|
||||
node_id: [],
|
||||
node_id_secret: [],
|
||||
bootstrap: ['ws://bootstrap.veilid.net:5150/ws'],
|
||||
limit_over_attached: 64,
|
||||
limit_fully_attached: 32,
|
||||
limit_attached_strong: 16,
|
||||
limit_attached_good: 8,
|
||||
limit_attached_weak: 4,
|
||||
},
|
||||
rpc: {
|
||||
concurrency: 0,
|
||||
queue_size: 1024,
|
||||
max_timestamp_behind_ms: 10000,
|
||||
max_timestamp_ahead_ms: 10000,
|
||||
timeout_ms: 5000,
|
||||
max_route_hop_count: 4,
|
||||
default_route_hop_count: 1,
|
||||
},
|
||||
dht: {
|
||||
max_find_node_count: 20,
|
||||
resolve_node_timeout_ms: 10000,
|
||||
resolve_node_count: 1,
|
||||
resolve_node_fanout: 4,
|
||||
get_value_timeout_ms: 10000,
|
||||
get_value_count: 3,
|
||||
get_value_fanout: 4,
|
||||
set_value_timeout_ms: 10000,
|
||||
set_value_count: 5,
|
||||
set_value_fanout: 4,
|
||||
min_peer_count: 20,
|
||||
min_peer_refresh_time_ms: 60000,
|
||||
validate_dial_info_receipt_time_ms: 2000,
|
||||
local_subkey_cache_size: 128,
|
||||
local_max_subkey_cache_memory_mb: 256,
|
||||
remote_subkey_cache_size: 1024,
|
||||
remote_max_records: 65536,
|
||||
remote_max_subkey_cache_memory_mb: 256,
|
||||
remote_max_storage_space_mb: 0,
|
||||
public_watch_limit: 32,
|
||||
member_watch_limit: 8,
|
||||
max_watch_expiration_ms: 600000,
|
||||
},
|
||||
upnp: true,
|
||||
detect_address_changes: true,
|
||||
restricted_nat_retries: 0,
|
||||
tls: {
|
||||
certificate_path: '',
|
||||
private_key_path: '',
|
||||
connection_initial_timeout_ms: 2000,
|
||||
},
|
||||
application: {
|
||||
https: {
|
||||
enabled: false,
|
||||
listen_address: ':5150',
|
||||
path: 'app',
|
||||
},
|
||||
http: {
|
||||
enabled: false,
|
||||
listen_address: ':5150',
|
||||
path: 'app',
|
||||
},
|
||||
},
|
||||
protocol: {
|
||||
udp: {
|
||||
enabled: false,
|
||||
socket_pool_size: 0,
|
||||
listen_address: '',
|
||||
},
|
||||
tcp: {
|
||||
connect: false,
|
||||
listen: false,
|
||||
max_connections: 32,
|
||||
listen_address: '',
|
||||
},
|
||||
ws: {
|
||||
connect: true,
|
||||
listen: true,
|
||||
max_connections: 16,
|
||||
listen_address: ':5150',
|
||||
path: 'ws',
|
||||
},
|
||||
wss: {
|
||||
connect: true,
|
||||
listen: false,
|
||||
max_connections: 16,
|
||||
listen_address: '',
|
||||
path: 'ws',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
export var veilidCoreStartupConfig = (() => {
|
||||
var defaultConfig = JSON.parse(veilidClient.defaultConfig());
|
||||
defaultConfig.program_name = 'veilid-wasm-test';
|
||||
defaultConfig.network.routing_table.bootstrap = ['ws://bootstrap.dev.veilid.net:5150/ws'];
|
||||
defaultConfig.network.network_key_password = 'dev';
|
||||
return defaultConfig;
|
||||
})();
|
||||
|
@ -1,3 +1,61 @@
|
||||
import { veilidClient } from 'veilid-wasm';
|
||||
|
||||
export const waitForMs = (milliseconds: number) => {
|
||||
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
||||
};
|
||||
|
||||
export const asyncCallWithTimeout = async<T>(asyncPromise: Promise<T>, timeLimit: number) => {
|
||||
let timeoutHandle: ReturnType<typeof setTimeout>;
|
||||
|
||||
const timeoutPromise = new Promise((_resolve, reject) => {
|
||||
timeoutHandle = setTimeout(
|
||||
() => reject(new Error('Async call timeout limit reached')),
|
||||
timeLimit
|
||||
);
|
||||
});
|
||||
|
||||
return Promise.race([asyncPromise, timeoutPromise]).then(result => {
|
||||
clearTimeout(timeoutHandle);
|
||||
return result;
|
||||
})
|
||||
}
|
||||
|
||||
export const waitForPublicAttachment = async () => {
|
||||
while (true) {
|
||||
let state = await veilidClient.getState();
|
||||
if (state.attachment.public_internet_ready) {
|
||||
var attached = false
|
||||
switch (state.attachment.state) {
|
||||
case "Detached":
|
||||
case "Detaching":
|
||||
case "Attaching":
|
||||
break;
|
||||
default:
|
||||
attached = true;
|
||||
break;
|
||||
}
|
||||
if (attached) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
await waitForMs(1000);
|
||||
}
|
||||
}
|
||||
|
||||
export const waitForDetached = async () => {
|
||||
while (true) {
|
||||
let state = await veilidClient.getState();
|
||||
var detached = false
|
||||
switch (state.attachment.state) {
|
||||
case "Detached":
|
||||
detached = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (detached) {
|
||||
break;
|
||||
}
|
||||
await waitForMs(1000);
|
||||
}
|
||||
}
|
||||
|
@ -6,29 +6,29 @@ import {
|
||||
} from './utils/veilid-config';
|
||||
|
||||
import { VeilidState, veilidClient } from 'veilid-wasm';
|
||||
import { waitForMs } from './utils/wait-utils';
|
||||
import { asyncCallWithTimeout, waitForPublicAttachment } from './utils/wait-utils';
|
||||
|
||||
describe('veilidClient', () => {
|
||||
before('veilid startup', async () => {
|
||||
describe('veilidClient', function () {
|
||||
before('veilid startup', async function () {
|
||||
veilidClient.initializeCore(veilidCoreInitConfig);
|
||||
await veilidClient.startupCore((_update) => {
|
||||
await veilidClient.startupCore(function (_update) {
|
||||
// if (_update.kind === 'Log') {
|
||||
// console.log(_update.message);
|
||||
// }
|
||||
}, JSON.stringify(veilidCoreStartupConfig));
|
||||
});
|
||||
|
||||
after('veilid shutdown', async () => {
|
||||
after('veilid shutdown', async function () {
|
||||
await veilidClient.shutdownCore();
|
||||
});
|
||||
|
||||
it('should print version', async () => {
|
||||
it('should print version', async function () {
|
||||
const version = veilidClient.versionString();
|
||||
expect(typeof version).toBe('string');
|
||||
expect(version.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should get config string', async () => {
|
||||
it('should get config string', async function () {
|
||||
const defaultConfig = veilidClient.defaultConfig();
|
||||
expect(typeof defaultConfig).toBe('string');
|
||||
expect(defaultConfig.length).toBeGreaterThan(0);
|
||||
@ -41,29 +41,32 @@ describe('veilidClient', () => {
|
||||
expect(defaultConfigStr).toEqual(defaultConfigStr2);
|
||||
});
|
||||
|
||||
it('should attach and detach', async () => {
|
||||
it('should attach and detach', async function () {
|
||||
await veilidClient.attach();
|
||||
await waitForMs(2000);
|
||||
await asyncCallWithTimeout(waitForPublicAttachment(), 10000);
|
||||
await veilidClient.detach();
|
||||
});
|
||||
|
||||
describe('kitchen sink', () => {
|
||||
before('attach', async () => {
|
||||
describe('kitchen sink', function () {
|
||||
before('attach', async function () {
|
||||
await veilidClient.attach();
|
||||
await waitForMs(2000);
|
||||
await waitForPublicAttachment();
|
||||
|
||||
});
|
||||
after('detach', async function () {
|
||||
await veilidClient.detach();
|
||||
});
|
||||
after('detach', () => veilidClient.detach());
|
||||
|
||||
let state: VeilidState;
|
||||
|
||||
it('should get state', async () => {
|
||||
it('should get state', async function () {
|
||||
state = await veilidClient.getState();
|
||||
expect(state.attachment).toBeDefined();
|
||||
expect(state.config.config).toBeDefined();
|
||||
expect(state.network).toBeDefined();
|
||||
});
|
||||
|
||||
it('should call debug command', async () => {
|
||||
it('should call debug command', async function () {
|
||||
const response = await veilidClient.debug('txtrecord');
|
||||
expect(response).toBeDefined();
|
||||
expect(response.length).toBeGreaterThan(0);
|
||||
|
@ -142,7 +142,7 @@ describe('veilidCrypto', () => {
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
describe('contants', () => {
|
||||
describe('constants', () => {
|
||||
it('CRYPTO_KEY_LENGTH', () => {
|
||||
expect(typeof veilidCrypto.CRYPTO_KEY_LENGTH).toBe('number');
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user