(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", | ||||
|  "js-sys", | ||||
|  "lazy_static", | ||||
|  "parking_lot 0.12.1", | ||||
|  "send_wrapper 0.6.0", | ||||
|  "serde", | ||||
|  "serde-wasm-bindgen", | ||||
|   | ||||
| @@ -39,3 +39,4 @@ serde-wasm-bindgen = "0.5.0" | ||||
|  | ||||
| [dev-dependencies] | ||||
| wasm-bindgen-test = "^0" | ||||
| parking_lot = "0.12.1" | ||||
|   | ||||
| @@ -1,182 +1,218 @@ | ||||
| //! Test suite for the Web and headless browsers. | ||||
|  | ||||
| //XXXXXXXXXXXXXXX | ||||
| //XXX DOES NOT WORK. | ||||
| //! These tests only work with WASM_BINDGEN_USE_NO_MODULE=true env var, | ||||
| //!     as otherwise there's no way to access the generated wasm bindings from inside JS. | ||||
|  | ||||
| #![cfg(target_arch = "wasm32")] | ||||
|  | ||||
| extern crate alloc; | ||||
| extern crate wasm_bindgen_test; | ||||
| use core::sync::atomic::AtomicBool; | ||||
| use js_sys::*; | ||||
| use parking_lot::Once; | ||||
| use veilid_wasm::*; | ||||
| use wasm_bindgen::*; | ||||
| use wasm_bindgen_futures::*; | ||||
| use wasm_bindgen_test::*; | ||||
|  | ||||
| wasm_bindgen_test_configure!(run_in_browser); | ||||
|  | ||||
| static SETUP_ONCE: AtomicBool = AtomicBool::new(false); | ||||
| static SETUP_ONCE: Once = Once::new(); | ||||
| pub fn setup() -> () { | ||||
|     if SETUP_ONCE | ||||
|         .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) | ||||
|         .is_ok() | ||||
|     { | ||||
|         console_log("setup()"); | ||||
|     SETUP_ONCE.call_once(|| { | ||||
|         console_log!("setup()"); | ||||
|         console_error_panic_hook::set_once(); | ||||
|         wasm_logger::init(wasm_logger::Config::new(Level::Trace)); | ||||
|         init_callbacks(); | ||||
|     } | ||||
|     }) | ||||
| } | ||||
| // xxx needs updating to new keys and veilid_api object | ||||
|  | ||||
| fn init_callbacks() { | ||||
|     assert_eq!(js_sys::eval(r#" | ||||
|     window.sleep = (milliseconds) => { return new Promise(resolve => setTimeout(resolve, milliseconds)) }; | ||||
|     window.stateChangeCallback = async (stateChange) => { console.log("State change: " + stateChange); }; | ||||
|     window.configCallback = (configKey) => {  | ||||
|         switch(configKey) { | ||||
|             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.stateChangeCallback = async (stateChange) => {  | ||||
|         delete stateChange.peers; // makes logs less verbose | ||||
|         console.log("State change: ", JSON.stringify(stateChange, null, 2));  | ||||
|     }; | ||||
|     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 | ||||
|     "#).expect("failed to eval"), JsValue::TRUE); | ||||
| } | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| /// | ||||
|  | ||||
| #[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!( | ||||
| /// Helper for converting an eval Promise result into a JsValue | ||||
| async fn eval_promise(source: &str) -> JsValue { | ||||
|     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") | ||||
|         eval(source) | ||||
|             .expect("Failed to eval") | ||||
|             .dyn_into::<Promise>() | ||||
|             .unwrap() | ||||
|             .unwrap(), | ||||
|     ) | ||||
|         .await, | ||||
|         Ok(JsValue::TRUE) | ||||
|     ); | ||||
|     .await | ||||
|     .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(); | ||||
|  | ||||
|     assert_eq!( | ||||
|         JsFuture::from( | ||||
|             js_sys::eval( | ||||
|     let res = eval_promise( | ||||
|         r#" | ||||
|         (async function() { | ||||
|             let vc = new VeilidCore(); | ||||
|             await vc.startup(window.stateChangeCallback, window.configCallback); | ||||
|             await vc.attach(); | ||||
|             await window.sleep(1000); | ||||
|             await vc.detach(); | ||||
|             await vc.shutdown(); | ||||
|             (async function () { | ||||
|                 const { veilidClient } = wasm_bindgen; // only accessible in no_module mode. | ||||
|                 veilidClient.initializeCore(window.veilidCoreInitConfig); | ||||
|                 await veilidClient.startupCore(window.stateChangeCallback, JSON.stringify(window.veilidCoreStartupConfig)); | ||||
|  | ||||
|                 console.log(veilidClient.versionString()); | ||||
|                 await veilidClient.attach(); | ||||
|  | ||||
|                 await sleep(10000); | ||||
|                 await veilidClient.detach(); | ||||
|                 await veilidClient.shutdownCore(); | ||||
|  | ||||
|                 return true; | ||||
|         })().then(v => { | ||||
|             console.log("finished: " + v); | ||||
|             return v; | ||||
|         }); | ||||
|     "# | ||||
|             ) | ||||
|             .expect("failed to eval") | ||||
|             .dyn_into::<Promise>() | ||||
|             .unwrap() | ||||
|         ) | ||||
|         .await, | ||||
|         Ok(JsValue::TRUE) | ||||
|     ); | ||||
|             })(); | ||||
|         "#, | ||||
|     ).await; | ||||
|  | ||||
|     assert_eq!(res, 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