(wasm) basic working unit tests

This commit is contained in:
Brandon Vandegrift 2023-09-04 22:13:58 -04:00
parent 6b7301a963
commit 5aeda006a4
4 changed files with 195 additions and 153 deletions

1
Cargo.lock generated
View File

@ -5879,6 +5879,7 @@ dependencies = [
"gloo-utils 0.2.0", "gloo-utils 0.2.0",
"js-sys", "js-sys",
"lazy_static", "lazy_static",
"parking_lot 0.12.1",
"send_wrapper 0.6.0", "send_wrapper 0.6.0",
"serde", "serde",
"serde-wasm-bindgen", "serde-wasm-bindgen",

View File

@ -39,3 +39,4 @@ serde-wasm-bindgen = "0.5.0"
[dev-dependencies] [dev-dependencies]
wasm-bindgen-test = "^0" wasm-bindgen-test = "^0"
parking_lot = "0.12.1"

View File

@ -1,182 +1,218 @@
//! Test suite for the Web and headless browsers. //! Test suite for the Web and headless browsers.
//! These tests only work with WASM_BINDGEN_USE_NO_MODULE=true env var,
//XXXXXXXXXXXXXXX //! as otherwise there's no way to access the generated wasm bindings from inside JS.
//XXX DOES NOT WORK.
#![cfg(target_arch = "wasm32")] #![cfg(target_arch = "wasm32")]
extern crate alloc; extern crate alloc;
extern crate wasm_bindgen_test; extern crate wasm_bindgen_test;
use core::sync::atomic::AtomicBool; use js_sys::*;
use parking_lot::Once;
use veilid_wasm::*; use veilid_wasm::*;
use wasm_bindgen::*;
use wasm_bindgen_futures::*;
use wasm_bindgen_test::*; use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser); wasm_bindgen_test_configure!(run_in_browser);
static SETUP_ONCE: AtomicBool = AtomicBool::new(false); static SETUP_ONCE: Once = Once::new();
pub fn setup() -> () { pub fn setup() -> () {
if SETUP_ONCE SETUP_ONCE.call_once(|| {
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) console_log!("setup()");
.is_ok()
{
console_log("setup()");
console_error_panic_hook::set_once(); console_error_panic_hook::set_once();
wasm_logger::init(wasm_logger::Config::new(Level::Trace));
init_callbacks(); init_callbacks();
} })
} }
// xxx needs updating to new keys and veilid_api object
fn init_callbacks() { fn init_callbacks() {
assert_eq!(js_sys::eval(r#" assert_eq!(js_sys::eval(r#"
window.sleep = (milliseconds) => { return new Promise(resolve => setTimeout(resolve, milliseconds)) }; window.sleep = (milliseconds) => { return new Promise(resolve => setTimeout(resolve, milliseconds)) };
window.stateChangeCallback = async (stateChange) => { console.log("State change: " + stateChange); }; window.stateChangeCallback = async (stateChange) => {
window.configCallback = (configKey) => { delete stateChange.peers; // makes logs less verbose
switch(configKey) { console.log("State change: ", JSON.stringify(stateChange, null, 2));
case "namespace": return ""; };
case "capabilities.disable": return []; window.veilidCoreInitConfig = {
case "tablestore.directory": return ""; logging: {
case "network.routing_table.node_id": return []; api: {
case "network.routing_table.node_id_secret": return []; enabled: true,
case "network.routing_table.bootstrap": return []; level: 'Info',
case "network.routing_table.limit_over_attached": return 64; },
case "network.routing_table.limit_fully_attached": return 32; performance: {
case "network.routing_table.limit_attached_strong": return 16; enabled: false,
case "network.routing_table.limit_attached_good": return 8; level: 'Info',
case "network.routing_table.limit_attached_weak": return 4; logs_in_timings: false,
case "network.rpc.concurrency": return 2; logs_in_console: false,
case "network.rpc.queue_size": return 128; },
case "network.rpc.max_timestamp_behind": return 10000000; },
case "network.rpc.max_timestamp_ahead": return 10000000; };
case "network.rpc.timeout": return 10000000;
case "network.rpc.max_route_hop_count": return 4; window.veilidCoreStartupConfig = {
case "network.rpc.default_route_hop_count": return 1; program_name: 'veilid-wasm-test',
case "network.dht.max_find_node_count": return 20; namespace: '',
case "network.dht.resolve_node_timeout": return 10000; capabilities: {
case "network.dht.resolve_node_count": return 1; disable: [],
case "network.dht.resolve_node_fanout": return 4; },
case "network.dht.get_value_timeout": return 10000; protected_store: {
case "network.dht.get_value_count": return 3; allow_insecure_fallback: true,
case "network.dht.get_value_fanout": return 4; always_use_insecure_storage: true,
case "network.dht.set_value_timeout": return 10000; directory: '',
case "network.dht.set_value_count": return 5; delete: false,
case "network.dht.set_value_fanout": return 4; device_encryption_key_password: 'some-user-secret-value',
case "network.dht.min_peer_count": return 20; // "new_device_encryption_key_password": "an-updated-user-secret-value"
case "network.dht.min_peer_refresh_time": return 2000000; },
case "network.dht.validate_dial_info_receipt_time": return 5000000; table_store: {
case "network.upnp": return false; directory: '',
case "network.detect_address_changes": return true; delete: false,
case "network.address_filter": return true; },
case "network.restricted_nat_retries": return 3; block_store: {
case "network.tls.certificate_path": return ""; directory: '',
case "network.tls.private_key_path": return ""; delete: false,
case "network.application.path": return "/app"; },
case "network.application.https.enabled": return false; network: {
case "network.application.https.listen_address": return ""; connection_initial_timeout_ms: 2000,
case "network.application.http.enabled": return false; connection_inactivity_timeout_ms: 60000,
case "network.application.http.listen_address": return ""; max_connections_per_ip4: 32,
case "network.protocol.udp.enabled": return false; max_connections_per_ip6_prefix: 32,
case "network.protocol.udp.socket_pool_size": return 0; max_connections_per_ip6_prefix_size: 56,
case "network.protocol.udp.listen_address": return ""; max_connection_frequency_per_min: 128,
case "network.protocol.udp.public_address": return ""; client_whitelist_timeout_ms: 300000,
case "network.protocol.tcp.connect": return false; reverse_connection_receipt_time_ms: 5000,
case "network.protocol.tcp.listen": return false; hole_punch_receipt_time_ms: 5000,
case "network.protocol.tcp.max_connections": return 32; network_key_password: '',
case "network.protocol.tcp.listen_address": return ""; disable_capabilites: [],
case "network.protocol.tcp.public_address": return ""; routing_table: {
case "network.protocol.ws.connect": return true; node_id: [],
case "network.protocol.ws.listen": return false; node_id_secret: [],
case "network.protocol.ws.max_connections": return 16; bootstrap: [
case "network.protocol.ws.listen_address": return ""; 'ws://bootstrap.veilid.net:5150/ws',
case "network.protocol.ws.path": return "/ws"; ],
case "network.protocol.ws.public_address": return ""; limit_over_attached: 64,
case "network.protocol.wss.connect": return true; limit_fully_attached: 32,
case "network.protocol.wss.listen": return false; limit_attached_strong: 16,
case "network.protocol.wss.max_connections": return 16; limit_attached_good: 8,
case "network.protocol.wss.listen_address": return ""; limit_attached_weak: 4,
case "network.protocol.wss.path": return "/ws"; },
case "network.protocol.wss.public_address": return ""; rpc: {
default: concurrency: 0,
console.log("config key '" + key +"' doesn't exist"); break; 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,
},
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',
},
},
},
}; };
true true
"#).expect("failed to eval"), JsValue::TRUE); "#).expect("failed to eval"), JsValue::TRUE);
} }
/////////////////////////////////////////////////////////////////////////////////////////////////// /// Helper for converting an eval Promise result into a JsValue
/// async fn eval_promise(source: &str) -> JsValue {
#[wasm_bindgen_test]
fn test_construct() {
setup();
assert_eq!(
js_sys::eval(
r#"
let vc = new VeilidCore();
true
"#
)
.expect("failed to eval"),
JsValue::TRUE
);
}
#[wasm_bindgen_test(async)]
async fn test_startup_shutdown() {
setup();
assert_eq!(
JsFuture::from( JsFuture::from(
js_sys::eval( eval(source)
r#" .expect("Failed to eval")
(async function() {
let vc = new VeilidCore();
await vc.startup(window.stateChangeCallback, window.configCallback);
await vc.shutdown();
return true;
})().then(v => {
console.log("finished: " + v);
return v;
});
"#
)
.expect("failed to eval")
.dyn_into::<Promise>() .dyn_into::<Promise>()
.unwrap() .unwrap(),
) )
.await, .await
Ok(JsValue::TRUE) .unwrap()
);
} }
#[wasm_bindgen_test(async)] // ----------------------------------------------------------------
async fn test_attach_detach() {
// TODO: now that veilidClient uses a single instance of VeilidAPI,
// subsequent tests fail because veilidCore has already been initialized.
#[wasm_bindgen_test()]
async fn test_kitchen_sink() {
setup(); setup();
assert_eq!( let res = eval_promise(
JsFuture::from(
js_sys::eval(
r#" r#"
(async function() { (async function () {
let vc = new VeilidCore(); const { veilidClient } = wasm_bindgen; // only accessible in no_module mode.
await vc.startup(window.stateChangeCallback, window.configCallback); veilidClient.initializeCore(window.veilidCoreInitConfig);
await vc.attach(); await veilidClient.startupCore(window.stateChangeCallback, JSON.stringify(window.veilidCoreStartupConfig));
await window.sleep(1000);
await vc.detach(); console.log(veilidClient.versionString());
await vc.shutdown(); await veilidClient.attach();
await sleep(10000);
await veilidClient.detach();
await veilidClient.shutdownCore();
return true; return true;
})().then(v => { })();
console.log("finished: " + v); "#,
return v; ).await;
});
"# assert_eq!(res, JsValue::TRUE);
)
.expect("failed to eval")
.dyn_into::<Promise>()
.unwrap()
)
.await,
Ok(JsValue::TRUE)
);
} }

4
veilid-wasm/wasm_test.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
set -eo pipefail
WASM_BINDGEN_USE_NO_MODULE=true wasm-pack test --firefox "$@"