diff --git a/Cargo.lock b/Cargo.lock index d10fa736..4c37ce35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4121,6 +4121,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "process_macros" +version = "0.1.0" +source = "git+https://github.com/kinode-dao/process_macros?rev=626e501#626e501d351e3365480ec6f770d474ed4ae339bf" +dependencies = [ + "quote", + "syn 2.0.60", +] + [[package]] name = "proptest" version = "1.4.0" @@ -5327,27 +5336,14 @@ dependencies = [ "wit-bindgen", ] -[[package]] -name = "test_runner" -version = "0.1.0" -dependencies = [ - "anyhow", - "bincode", - "kinode_process_lib 0.8.0 (git+https://github.com/kinode-dao/process_lib?rev=09dc9f9)", - "serde", - "serde_json", - "thiserror", - "wit-bindgen", -] - [[package]] name = "tester" version = "0.1.1" dependencies = [ "anyhow", "bincode", - "indexmap", "kinode_process_lib 0.8.0 (git+https://github.com/kinode-dao/process_lib?rev=09dc9f9)", + "process_macros", "serde", "serde_json", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index a244dbab..fd11adba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ members = [ "kinode/packages/terminal/terminal", "kinode/packages/terminal/alias", "kinode/packages/terminal/cat", "kinode/packages/terminal/echo", "kinode/packages/terminal/hi", "kinode/packages/terminal/kfetch", "kinode/packages/terminal/kill", "kinode/packages/terminal/m", "kinode/packages/terminal/top", "kinode/packages/terminal/namehash_to_name", "kinode/packages/terminal/net_diagnostics", "kinode/packages/terminal/peer", "kinode/packages/terminal/peers", - "kinode/packages/tester/tester", "kinode/packages/tester/test_runner", + "kinode/packages/tester/tester", ] default-members = ["lib"] resolver = "2" diff --git a/kinode/packages/tester/api/tester:sys-v0.wit b/kinode/packages/tester/api/tester:sys-v0.wit new file mode 100644 index 00000000..7fe0574b --- /dev/null +++ b/kinode/packages/tester/api/tester:sys-v0.wit @@ -0,0 +1,27 @@ +interface tester { + variant request { + run(run-request), + } + + variant response { + run(result<_, fail-response>) + } + + record run-request { + input-node-names: list, + test-names: list, + test-timeout: u64, + } + + record fail-response { + test: string, + file: string, + line: u32, + column: u32, + } +} + +world tester-sys-v0 { + import tester; + include process-v0; +} diff --git a/kinode/packages/tester/test_runner/Cargo.lock b/kinode/packages/tester/test_runner/Cargo.lock deleted file mode 100644 index 1ce06f46..00000000 --- a/kinode/packages/tester/test_runner/Cargo.lock +++ /dev/null @@ -1,556 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "getrandom" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "http" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "id-arena" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b" -dependencies = [ - "equivalent", - "hashbrown", - "serde", -] - -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - -[[package]] -name = "kinode_process_lib" -version = "0.5.6" -source = "git+https://github.com/kinode-dao/process_lib?rev=fccb6a0#fccb6a0c07ebda3e385bff7f76e4984b741f01c7" -dependencies = [ - "anyhow", - "bincode", - "http", - "mime_guess", - "rand", - "serde", - "serde_json", - "thiserror", - "url", - "wit-bindgen", -] - -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - -[[package]] -name = "libc" -version = "0.2.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro2" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "semver" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" - -[[package]] -name = "serde" -version = "1.0.196" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.196" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.113" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "smallvec" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" - -[[package]] -name = "spdx" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bde1398b09b9f93fc2fc9b9da86e362693e999d3a54a8ac47a99a5a73f638b" -dependencies = [ - "smallvec", -] - -[[package]] -name = "syn" -version = "2.0.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "test_runner" -version = "0.1.0" -dependencies = [ - "anyhow", - "bincode", - "kinode_process_lib", - "serde", - "serde_json", - "thiserror", - "wit-bindgen", -] - -[[package]] -name = "thiserror" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "url" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-encoder" -version = "0.38.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f" -dependencies = [ - "leb128", -] - -[[package]] -name = "wasm-encoder" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e09bca7d6388637d27fb5edbeab11f56bfabcef8743c55ae34370e1e5030a071" -dependencies = [ - "leb128", -] - -[[package]] -name = "wasm-metadata" -version = "0.10.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c853d3809fc9fccf3bc0ad63f4f51d8eefad0bacf88f957aa991c1d9b88b016e" -dependencies = [ - "anyhow", - "indexmap", - "serde", - "serde_derive", - "serde_json", - "spdx", - "wasm-encoder 0.41.0", - "wasmparser 0.121.0", -] - -[[package]] -name = "wasmparser" -version = "0.118.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9" -dependencies = [ - "indexmap", - "semver", -] - -[[package]] -name = "wasmparser" -version = "0.121.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953cf6a7606ab31382cb1caa5ae403e77ba70c7f8e12eeda167e7040d42bfda8" -dependencies = [ - "bitflags", - "indexmap", - "semver", -] - -[[package]] -name = "wit-bindgen" -version = "0.16.0" -source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322" -dependencies = [ - "bitflags", - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.16.0" -source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322" -dependencies = [ - "anyhow", - "wit-component", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.16.0" -source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322" -dependencies = [ - "anyhow", - "heck", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.16.0" -source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322" -dependencies = [ - "anyhow", - "proc-macro2", - "quote", - "syn", - "wit-bindgen-core", - "wit-bindgen-rust", - "wit-component", -] - -[[package]] -name = "wit-component" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a35a2a9992898c9d27f1664001860595a4bc99d32dd3599d547412e17d7e2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder 0.38.1", - "wasm-metadata", - "wasmparser 0.118.1", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df4913a2219096373fd6512adead1fb77ecdaa59d7fc517972a7d30b12f625be" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", -] diff --git a/kinode/packages/tester/test_runner/Cargo.toml b/kinode/packages/tester/test_runner/Cargo.toml deleted file mode 100644 index 3c25e662..00000000 --- a/kinode/packages/tester/test_runner/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "test_runner" -version = "0.1.0" -edition = "2021" - -[features] -simulation-mode = [] - -[dependencies] -anyhow = "1.0" -bincode = "1.3.3" -kinode_process_lib = { git = "https://github.com/kinode-dao/process_lib", rev = "09dc9f9" } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -thiserror = "1.0" -wit-bindgen = "0.24.0" - -[lib] -crate-type = ["cdylib"] - -[package.metadata.component] -package = "kinode:process" diff --git a/kinode/packages/tester/test_runner/src/lib.rs b/kinode/packages/tester/test_runner/src/lib.rs deleted file mode 100644 index 35def261..00000000 --- a/kinode/packages/tester/test_runner/src/lib.rs +++ /dev/null @@ -1,172 +0,0 @@ -use std::str::FromStr; - -use kinode_process_lib::{ - await_message, call_init, our_capabilities, println, spawn, vfs, - vfs::{DirEntry, FileType}, - Address, Message, OnExit, ProcessId, Request, Response, -}; - -mod tester_types; -use tester_types as tt; - -wit_bindgen::generate!({ - path: "target/wit", - world: "process-v0", -}); - -fn make_vfs_address(our: &Address) -> anyhow::Result
{ - Ok(Address::new( - our.node.clone(), - ProcessId::from_str("vfs:distro:sys")?, - )) -} - -fn handle_message(our: &Address) -> anyhow::Result<()> { - let message = await_message()?; - - match message { - Message::Response { .. } => { - return Err(tt::TesterError::UnexpectedResponse.into()); - } - Message::Request { ref body, .. } => { - match serde_json::from_slice(body)? { - tt::TesterRequest::Run { - ref test_names, - test_timeout, - .. - } => { - println!("test_runner: got Run"); - - let dir_prefix = "tester:sys/tests"; - - let response = Request::new() - .target(make_vfs_address(&our)?) - .body(serde_json::to_vec(&vfs::VfsRequest { - path: dir_prefix.into(), - action: vfs::VfsAction::ReadDir, - })?) - .send_and_await_response(test_timeout)??; - - let Message::Response { body: vfs_body, .. } = response else { - fail!("test_runner"); - }; - let vfs::VfsResponse::ReadDir(mut children) = - serde_json::from_slice(&vfs_body)? - else { - println!( - "{:?}", - serde_json::from_slice::(&vfs_body)? - ); - fail!("test_runner"); - }; - - for test_name in test_names { - let test_entry = DirEntry { - path: format!("{}/{}.wasm", dir_prefix, test_name), - file_type: FileType::File, - }; - if !children.contains(&test_entry) { - return Err(anyhow::anyhow!( - "test {} not found amongst {:?}", - test_name, - children, - )); - } - } - - let caps_file_path = format!("{}/grant_capabilities.json", dir_prefix); - let caps_index = children.iter().position(|i| *i.path == *caps_file_path); - let caps_by_child: std::collections::HashMap> = - match caps_index { - None => std::collections::HashMap::new(), - Some(caps_index) => { - children.remove(caps_index); - let file = vfs::file::open_file(&caps_file_path, false, None)?; - let file_contents = file.read()?; - serde_json::from_slice(&file_contents)? - } - }; - - println!("test_runner: running {:?}...", children); - - for test_name in test_names { - let test_path = format!("{}/{}.wasm", dir_prefix, test_name); - let grant_caps = caps_by_child - .get(test_name) - .and_then(|caps| { - Some( - caps.iter() - .map(|cap| ProcessId::from_str(cap).unwrap()) - .collect(), - ) - }) - .unwrap_or(vec![]); - let child_process_id = match spawn( - None, - &test_path, - OnExit::None, // TODO: notify us - our_capabilities(), - grant_caps, - false, // not public - ) { - Ok(child_process_id) => child_process_id, - Err(e) => { - println!("couldn't spawn {}: {}", test_path, e); - fail!("test_runner"); - } - }; - - let response = Request::new() - .target(Address { - node: our.node.clone(), - process: child_process_id, - }) - .body(body.clone()) - .send_and_await_response(test_timeout)??; - - let Message::Response { body, .. } = response else { - fail!("test_runner"); - }; - match serde_json::from_slice(&body)? { - tt::TesterResponse::Pass => {} - tt::TesterResponse::GetFullMessage(_) => {} - tt::TesterResponse::Fail { - test, - file, - line, - column, - } => { - fail!(test, file, line, column); - } - } - } - - println!("test_runner: done running {:?}", children); - - Response::new() - .body(serde_json::to_vec(&tt::TesterResponse::Pass)?) - .send()?; - } - tt::TesterRequest::KernelMessage(_) | tt::TesterRequest::GetFullMessage(_) => { - fail!("test_runner"); - } - } - Ok(()) - } - } -} - -call_init!(init); -fn init(our: Address) { - println!("{}: begin", our); - - loop { - match handle_message(&our) { - Ok(()) => {} - Err(e) => { - println!("test_runner: error: {:?}", e); - fail!("test_runner"); - } - }; - } -} diff --git a/kinode/packages/tester/test_runner/src/tester_types.rs b/kinode/packages/tester/test_runner/src/tester_types.rs deleted file mode 120000 index 24792c5a..00000000 --- a/kinode/packages/tester/test_runner/src/tester_types.rs +++ /dev/null @@ -1 +0,0 @@ -../../tester_types.rs \ No newline at end of file diff --git a/kinode/packages/tester/tester/Cargo.toml b/kinode/packages/tester/tester/Cargo.toml index 07a8f030..44ce68a0 100644 --- a/kinode/packages/tester/tester/Cargo.toml +++ b/kinode/packages/tester/tester/Cargo.toml @@ -9,8 +9,8 @@ simulation-mode = [] [dependencies] anyhow = "1.0" bincode = "1.3.3" -indexmap = "2.1" kinode_process_lib = { git = "https://github.com/kinode-dao/process_lib", rev = "09dc9f9" } +process_macros = { git = "https://github.com/kinode-dao/process_macros", rev = "626e501" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" diff --git a/kinode/packages/tester/tester/src/lib.rs b/kinode/packages/tester/tester/src/lib.rs index 09880206..8e2d0e65 100644 --- a/kinode/packages/tester/tester/src/lib.rs +++ b/kinode/packages/tester/tester/src/lib.rs @@ -1,21 +1,24 @@ -use indexmap::map::IndexMap; +use std::collections::HashMap; +use std::str::FromStr; +use crate::kinode::process::tester::{ + FailResponse, Request as TesterRequest, Response as TesterResponse, RunRequest, +}; use kinode_process_lib::kernel_types as kt; use kinode_process_lib::{ await_message, call_init, our_capabilities, println, spawn, vfs, Address, Message, OnExit, ProcessId, Request, Response, }; -mod tester_types; -use tester_types as tt; +mod tester_lib; wit_bindgen::generate!({ path: "target/wit", - world: "process-v0", + world: "tester-sys-v0", + generate_unused_types: true, + additional_derives: [PartialEq, serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], }); -type Messages = IndexMap; - fn make_vfs_address(our: &Address) -> anyhow::Result
{ Ok(Address { node: our.node.clone(), @@ -23,88 +26,172 @@ fn make_vfs_address(our: &Address) -> anyhow::Result
{ }) } -fn handle_message( +fn handle_response(message: &Message) -> anyhow::Result<()> { + let TesterResponse::Run(_) = message.body().try_into()?; + let source = message.source(); + if (source.process.package_name != "tester") || (source.process.publisher_node != "sys") { + println!( + "got Response from unexpected source: {}; must be in package test:sys", + source, + ); + fail!("tester"); + } + Response::new().body(message.body()).send().unwrap(); + Ok(()) +} + +fn read_caps_by_child( + dir_prefix: &str, + children: &mut Vec, +) -> anyhow::Result>> { + let caps_file_path = format!("{}/grant_capabilities.json", dir_prefix); + let caps_index = children.iter().position(|i| *i.path == *caps_file_path); + let caps_by_child: HashMap> = match caps_index { + None => HashMap::new(), + Some(caps_index) => { + children.remove(caps_index); + let file = vfs::file::open_file(&caps_file_path, false, None)?; + let file_contents = file.read()?; + serde_json::from_slice(&file_contents)? + } + }; + Ok(caps_by_child) +} + +fn handle_request( our: &Address, - _messages: &mut Messages, + message: &Message, node_names: &mut Vec, ) -> anyhow::Result<()> { + let TesterRequest::Run(RunRequest { + input_node_names, + ref test_names, + test_timeout, + }) = message.body().try_into()?; + println!("got Run"); + + assert!(input_node_names.len() >= 1); + *node_names = input_node_names.clone(); + + if our.node != node_names[0] { + // we are not the master node + Response::new() + .body(TesterResponse::Run(Ok(()))) + .send() + .unwrap(); + return Ok(()); + } + + // we are the master node + let dir_prefix = "tester:sys/tests"; + + let response = Request::new() + .target(make_vfs_address(&our)?) + .body(serde_json::to_vec(&vfs::VfsRequest { + path: dir_prefix.into(), + action: vfs::VfsAction::ReadDir, + })?) + .send_and_await_response(test_timeout)??; + + let Message::Response { body: vfs_body, .. } = response else { + fail!("tester"); + }; + let vfs::VfsResponse::ReadDir(mut children) = serde_json::from_slice(&vfs_body)? else { + println!( + "{:?}", + serde_json::from_slice::(&vfs_body)? + ); + fail!("tester"); + }; + + for test_name in test_names { + let test_entry = vfs::DirEntry { + path: format!("{}/{}.wasm", dir_prefix, test_name), + file_type: vfs::FileType::File, + }; + if !children.contains(&test_entry) { + return Err(anyhow::anyhow!( + "test {} not found amongst {:?}", + test_name, + children, + )); + } + } + + let caps_by_child = read_caps_by_child(dir_prefix, &mut children)?; + + println!("tester: running {:?}...", children); + + for test_name in test_names { + let test_path = format!("{}/{}.wasm", dir_prefix, test_name); + let grant_caps = caps_by_child + .get(test_name) + .and_then(|caps| { + Some( + caps.iter() + .map(|cap| ProcessId::from_str(cap).unwrap()) + .collect(), + ) + }) + .unwrap_or(vec![]); + let child_process_id = match spawn( + None, + &test_path, + OnExit::None, // TODO: notify us + our_capabilities(), + grant_caps, + false, // not public + ) { + Ok(child_process_id) => child_process_id, + Err(e) => { + println!("couldn't spawn {}: {}", test_path, e); + fail!("tester"); + } + }; + + let response = Request::new() + .target(Address { + node: our.node.clone(), + process: child_process_id, + }) + .body(message.body()) + .send_and_await_response(test_timeout)??; + + if response.is_request() { + fail!("tester"); + }; + let TesterResponse::Run(result) = response.body().try_into()?; + if let Err(FailResponse { + test, + file, + line, + column, + }) = result + { + fail!(test, file, line, column); + } + } + + println!("test_runner: done running {:?}", children); + + Response::new().body(TesterResponse::Run(Ok(()))).send()?; + + Ok(()) +} + +fn handle_message(our: &Address, node_names: &mut Vec) -> anyhow::Result<()> { let Ok(message) = await_message() else { return Ok(()); }; - match message { - Message::Response { source, body, .. } => { - match serde_json::from_slice(&body)? { - tt::TesterResponse::Pass | tt::TesterResponse::Fail { .. } => { - if (source.process.package_name != "tester") - | (source.process.publisher_node != "sys") - { - return Err(tt::TesterError::UnexpectedResponse.into()); - } - Response::new().body(body).send().unwrap(); - } - tt::TesterResponse::GetFullMessage(_) => { - fail!("tester"); - } - } - Ok(()) - } - Message::Request { body, .. } => { - match serde_json::from_slice(&body)? { - tt::TesterRequest::Run { - input_node_names, - test_timeout, - .. - } => { - println!("got Run"); - - assert!(input_node_names.len() >= 1); - *node_names = input_node_names.clone(); - - if our.node != node_names[0] { - Response::new() - .body(serde_json::to_vec(&tt::TesterResponse::Pass).unwrap()) - .send() - .unwrap(); - } else { - // we are master node - let child = "/tester:sys/pkg/test_runner.wasm"; - let child_process_id = match spawn( - None, - child, - OnExit::None, // TODO: notify us - our_capabilities(), - vec!["vfs:distro:sys".parse::().unwrap()], - false, // not public - ) { - Ok(child_process_id) => child_process_id, - Err(e) => { - println!("couldn't spawn {}: {}", child, e); - fail!("tester"); - } - }; - Request::new() - .target(Address { - node: our.node.clone(), - process: child_process_id, - }) - .body(body) - .expects_response(test_timeout * 2) - .send()?; - } - } - tt::TesterRequest::KernelMessage(_) | tt::TesterRequest::GetFullMessage(_) => { - fail!("tester"); - } - } - Ok(()) - } + if !message.is_request() { + return handle_response(&message); } + return handle_request(our, &message, node_names); } call_init!(init); fn init(our: Address) { - let mut messages: Messages = IndexMap::new(); let mut node_names: Vec = Vec::new(); match Request::new() .target(make_vfs_address(&our).unwrap()) @@ -154,7 +241,7 @@ fn init(our: Address) { } loop { - match handle_message(&our, &mut messages, &mut node_names) { + match handle_message(&our, &mut node_names) { Ok(()) => {} Err(e) => { println!("tester: error: {:?}", e,); diff --git a/kinode/packages/tester/tester/src/tester_lib.rs b/kinode/packages/tester/tester/src/tester_lib.rs new file mode 100644 index 00000000..171c08c8 --- /dev/null +++ b/kinode/packages/tester/tester/src/tester_lib.rs @@ -0,0 +1,29 @@ +use crate::kinode::process::tester::{FailResponse, Response as TesterResponse}; + +#[macro_export] +macro_rules! fail { + ($test:expr) => { + Response::new() + .body(TesterResponse::Run(Err(FailResponse { + test: $test.into(), + file: file!().into(), + line: line!(), + column: column!(), + }))) + .send() + .unwrap(); + panic!("") + }; + ($test:expr, $file:expr, $line:expr, $column:expr) => { + Response::new() + .body(TesterResponse::Run(Err(FailResponse { + test: $test.into(), + file: $file.into(), + line: $line, + column: $column, + }))) + .send() + .unwrap(); + panic!("") + }; +} diff --git a/kinode/packages/tester/tester/src/tester_types.rs b/kinode/packages/tester/tester/src/tester_types.rs deleted file mode 120000 index 24792c5a..00000000 --- a/kinode/packages/tester/tester/src/tester_types.rs +++ /dev/null @@ -1 +0,0 @@ -../../tester_types.rs \ No newline at end of file diff --git a/kinode/packages/tester/tester_lib.rs b/kinode/packages/tester/tester_lib.rs new file mode 100644 index 00000000..9b367d36 --- /dev/null +++ b/kinode/packages/tester/tester_lib.rs @@ -0,0 +1,31 @@ +use crate::kinode::process::tester::{ + Response as TesterResponse, FailResponse, +}; + +#[macro_export] +macro_rules! fail { + ($test:expr) => { + Response::new() + .body(TesterResponse::Run(Err(FailResponse { + test: $test.into(), + file: file!().into(), + line: line!(), + column: column!(), + }))) + .send() + .unwrap(); + panic!("") + }; + ($test:expr, $file:expr, $line:expr, $column:expr) => { + Response::new() + .body(TesterResponse::Run(Err(FailResponse { + test: $test.into(), + file: $file.into(), + line: $line, + column: $column, + }))) + .send() + .unwrap(); + panic!("") + }; +} diff --git a/kinode/packages/tester/tester_types.rs b/kinode/packages/tester/tester_types.rs deleted file mode 100644 index 73c8c3c7..00000000 --- a/kinode/packages/tester/tester_types.rs +++ /dev/null @@ -1,91 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use kinode_process_lib::kernel_types as kt; -use kinode_process_lib::Address; - -type Rsvp = Option
; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct KernelMessage { - pub id: u64, - pub source: Address, - pub target: Address, - pub rsvp: Rsvp, - pub message: kt::Message, - pub lazy_load_blob: Option, -} - -#[derive(Debug, Serialize, Deserialize)] -pub enum TesterRequest { - Run { - input_node_names: Vec, - test_names: Vec, - test_timeout: u64, - }, - KernelMessage(KernelMessage), - GetFullMessage(kt::Message), -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct TesterFail { - pub test: String, - pub file: String, - pub line: u32, - pub column: u32, -} - -#[derive(Debug, Serialize, Deserialize)] -pub enum TesterResponse { - Pass, - Fail { - test: String, - file: String, - line: u32, - column: u32, - }, - GetFullMessage(Option), -} - -#[derive(Debug, Serialize, Deserialize, thiserror::Error)] -pub enum TesterError { - #[error("RejectForeign")] - RejectForeign, - #[error("UnexpectedResponse")] - UnexpectedResponse, - #[error("FAIL {test} {message}")] - Fail { test: String, message: String }, -} - -#[macro_export] -macro_rules! fail { - ($test:expr) => { - Response::new() - .body( - serde_json::to_vec(&tt::TesterResponse::Fail { - test: $test.into(), - file: file!().into(), - line: line!(), - column: column!(), - }) - .unwrap(), - ) - .send() - .unwrap(); - panic!("") - }; - ($test:expr, $file:expr, $line:expr, $column:expr) => { - Response::new() - .body( - serde_json::to_vec(&tt::TesterResponse::Fail { - test: $test.into(), - file: $file.into(), - line: $line, - column: $column, - }) - .unwrap(), - ) - .send() - .unwrap(); - panic!("") - }; -}