(wasm) basic working unit tests
This commit is contained in:
		
							
								
								
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -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", | ||||||
|   | |||||||
| @@ -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" | ||||||
|   | |||||||
| @@ -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 []; |  | ||||||
|             case "tablestore.directory": return ""; |  | ||||||
|             case "network.routing_table.node_id": return []; |  | ||||||
|             case "network.routing_table.node_id_secret": return []; |  | ||||||
|             case "network.routing_table.bootstrap": return []; |  | ||||||
|             case "network.routing_table.limit_over_attached": return 64; |  | ||||||
|             case "network.routing_table.limit_fully_attached": return 32; |  | ||||||
|             case "network.routing_table.limit_attached_strong": return 16; |  | ||||||
|             case "network.routing_table.limit_attached_good": return 8; |  | ||||||
|             case "network.routing_table.limit_attached_weak": return 4; |  | ||||||
|             case "network.rpc.concurrency": return 2; |  | ||||||
|             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; |  | ||||||
|             case "network.rpc.default_route_hop_count": return 1; |  | ||||||
|             case "network.dht.max_find_node_count": return 20; |  | ||||||
|             case "network.dht.resolve_node_timeout": return 10000; |  | ||||||
|             case "network.dht.resolve_node_count": return 1; |  | ||||||
|             case "network.dht.resolve_node_fanout": return 4; |  | ||||||
|             case "network.dht.get_value_timeout": return 10000; |  | ||||||
|             case "network.dht.get_value_count": return 3; |  | ||||||
|             case "network.dht.get_value_fanout": return 4; |  | ||||||
|             case "network.dht.set_value_timeout": return 10000; |  | ||||||
|             case "network.dht.set_value_count": return 5; |  | ||||||
|             case "network.dht.set_value_fanout": return 4; |  | ||||||
|             case "network.dht.min_peer_count": return 20; |  | ||||||
|             case "network.dht.min_peer_refresh_time": return 2000000; |  | ||||||
|             case "network.dht.validate_dial_info_receipt_time": return 5000000; |  | ||||||
|             case "network.upnp": return false; |  | ||||||
|             case "network.detect_address_changes": return true; |  | ||||||
|             case "network.address_filter": return true; |  | ||||||
|             case "network.restricted_nat_retries": return 3; |  | ||||||
|             case "network.tls.certificate_path": return ""; |  | ||||||
|             case "network.tls.private_key_path": return ""; |  | ||||||
|             case "network.application.path": return "/app"; |  | ||||||
|             case "network.application.https.enabled": return false; |  | ||||||
|             case "network.application.https.listen_address": return ""; |  | ||||||
|             case "network.application.http.enabled": return false; |  | ||||||
|             case "network.application.http.listen_address": return ""; |  | ||||||
|             case "network.protocol.udp.enabled": return false; |  | ||||||
|             case "network.protocol.udp.socket_pool_size": return 0; |  | ||||||
|             case "network.protocol.udp.listen_address": return ""; |  | ||||||
|             case "network.protocol.udp.public_address": return ""; |  | ||||||
|             case "network.protocol.tcp.connect": return false; |  | ||||||
|             case "network.protocol.tcp.listen": return false; |  | ||||||
|             case "network.protocol.tcp.max_connections": return 32; |  | ||||||
|             case "network.protocol.tcp.listen_address": return ""; |  | ||||||
|             case "network.protocol.tcp.public_address": return ""; |  | ||||||
|             case "network.protocol.ws.connect": return true; |  | ||||||
|             case "network.protocol.ws.listen": return false; |  | ||||||
|             case "network.protocol.ws.max_connections": return 16; |  | ||||||
|             case "network.protocol.ws.listen_address": return ""; |  | ||||||
|             case "network.protocol.ws.path": return "/ws"; |  | ||||||
|             case "network.protocol.ws.public_address": return ""; |  | ||||||
|             case "network.protocol.wss.connect": return true; |  | ||||||
|             case "network.protocol.wss.listen": return false; |  | ||||||
|             case "network.protocol.wss.max_connections": return 16; |  | ||||||
|             case "network.protocol.wss.listen_address": return ""; |  | ||||||
|             case "network.protocol.wss.path": return "/ws"; |  | ||||||
|             case "network.protocol.wss.public_address": return ""; |  | ||||||
|             default:  |  | ||||||
|                 console.log("config key '" + key +"' doesn't exist"); break; |  | ||||||
|         } |  | ||||||
|     }; |     }; | ||||||
|  |     window.veilidCoreInitConfig = { | ||||||
|  |         logging: { | ||||||
|  |           api: { | ||||||
|  |             enabled: true, | ||||||
|  |             level: 'Info', | ||||||
|  |           }, | ||||||
|  |           performance: { | ||||||
|  |             enabled: false, | ||||||
|  |             level: 'Info', | ||||||
|  |             logs_in_timings: false, | ||||||
|  |             logs_in_console: false, | ||||||
|  |           }, | ||||||
|  |         }, | ||||||
|  |       }; | ||||||
|  |        | ||||||
|  |     window.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_whitelist_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, | ||||||
|  |           }, | ||||||
|  |           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 { | ||||||
|  |     JsFuture::from( | ||||||
| #[wasm_bindgen_test] |         eval(source) | ||||||
| fn test_construct() { |             .expect("Failed to eval") | ||||||
|     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( |  | ||||||
|             js_sys::eval( |  | ||||||
|                 r#" |  | ||||||
|         (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( |         r#" | ||||||
|             js_sys::eval( |             (async function () { | ||||||
|                 r#" |                 const { veilidClient } = wasm_bindgen; // only accessible in no_module mode. | ||||||
|         (async function() { |                 veilidClient.initializeCore(window.veilidCoreInitConfig); | ||||||
|             let vc = new VeilidCore(); |                 await veilidClient.startupCore(window.stateChangeCallback, JSON.stringify(window.veilidCoreStartupConfig)); | ||||||
|             await vc.startup(window.stateChangeCallback, window.configCallback); |  | ||||||
|             await vc.attach(); |                 console.log(veilidClient.versionString()); | ||||||
|             await window.sleep(1000); |                 await veilidClient.attach(); | ||||||
|             await vc.detach(); |  | ||||||
|             await vc.shutdown(); |                 await sleep(10000); | ||||||
|             return true; |                 await veilidClient.detach(); | ||||||
|         })().then(v => { |                 await veilidClient.shutdownCore(); | ||||||
|             console.log("finished: " + v); |  | ||||||
|             return v; |                 return true; | ||||||
|         }); |             })(); | ||||||
|     "# |         "#, | ||||||
|             ) |     ).await; | ||||||
|             .expect("failed to eval") |  | ||||||
|             .dyn_into::<Promise>() |     assert_eq!(res, JsValue::TRUE); | ||||||
|             .unwrap() |  | ||||||
|         ) |  | ||||||
|         .await, |  | ||||||
|         Ok(JsValue::TRUE) |  | ||||||
|     ); |  | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								veilid-wasm/wasm_test.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								veilid-wasm/wasm_test.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | #!/bin/bash | ||||||
|  | set -eo pipefail | ||||||
|  |  | ||||||
|  | WASM_BINDGEN_USE_NO_MODULE=true wasm-pack test --firefox "$@" | ||||||
		Reference in New Issue
	
	Block a user