diff --git a/.github/workflows/rust.yml b/.github/workflows/ci.yml similarity index 79% rename from .github/workflows/rust.yml rename to .github/workflows/ci.yml index d422a95..f4c72be 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: uses: creyD/prettier_action@v4.2 with: dry: true - prettier_options: --check **/*.{html,css,js,md} --ignore-path .gitignore + prettier_options: --check amqp_dashboard/assets/* --ignore-path .gitignore - name: Build run: cargo build --verbose - name: Run clippy -D clippy::all @@ -29,3 +29,5 @@ jobs: run: cargo fmt --verbose --all -- --check - name: Run tests run: cargo test --verbose --all + - name: Run client integration tests + run: cargo xtask test-js diff --git a/Cargo.lock b/Cargo.lock index 5b62f3e..f07d9c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "aho-corasick" version = "0.7.18" @@ -25,7 +19,6 @@ dependencies = [ "amqp_dashboard", "amqp_transport", "anyhow", - "console-subscriber", "tokio", "tracing", "tracing-subscriber", @@ -35,7 +28,9 @@ dependencies = [ name = "amqp_core" version = "0.1.0" dependencies = [ + "bytes", "parking_lot", + "smallvec", "uuid", ] @@ -55,7 +50,6 @@ name = "amqp_messaging" version = "0.1.0" dependencies = [ "amqp_core", - "tokio", "tracing", ] @@ -66,11 +60,13 @@ dependencies = [ "amqp_core", "amqp_messaging", "anyhow", + "bytes", "criterion", "nom", "once_cell", "rand", "regex", + "smallvec", "thiserror", "tokio", "tracing", @@ -92,27 +88,6 @@ version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a99269dff3bc004caa411f38845c20303f1e393ca2bd6581576fa3a7f59577d" -[[package]] -name = "async-stream" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" -dependencies = [ - "async-stream-impl", - "futures-core", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "async-trait" version = "0.1.52" @@ -186,12 +161,6 @@ dependencies = [ "mime", ] -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - [[package]] name = "bitflags" version = "1.3.2" @@ -216,12 +185,6 @@ version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - [[package]] name = "bytes" version = "1.1.0" @@ -250,54 +213,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "bitflags", - "textwrap", + "textwrap 0.11.0", "unicode-width", ] [[package]] -name = "console-api" -version = "0.1.2" +name = "clap" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc347c19eb5b940f396ac155822caee6662f850d97306890ac3773ed76c90c5a" +checksum = "6d76c22c9b9b215eeb8d016ad3a90417bd13cb24cf8142756e6472445876cab7" dependencies = [ - "prost", - "prost-types", - "tonic", - "tonic-build", - "tracing-core", + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim", + "termcolor", + "textwrap 0.14.2", ] [[package]] -name = "console-subscriber" -version = "0.1.3" +name = "clap_derive" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "565a7dfea2d10dd0e5c57cc394d5d441b1910960d8c9211ed14135e0e6ec3a20" +checksum = "5fd1122e63869df2cb309f449da1ad54a7c6dfeb7c7e6ccd8e0825d9eb93bb72" dependencies = [ - "console-api", - "crossbeam-channel", - "crossbeam-utils", - "futures", - "hdrhistogram", - "humantime", - "prost-types", - "serde", - "serde_json", - "thread_local", - "tokio", - "tokio-stream", - "tonic", - "tracing", - "tracing-core", - "tracing-subscriber", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -308,7 +255,7 @@ checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" dependencies = [ "atty", "cast", - "clap", + "clap 2.34.0", "criterion-plot", "csv", "itertools", @@ -408,33 +355,6 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" -[[package]] -name = "fastrand" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" -dependencies = [ - "instant", -] - -[[package]] -name = "fixedbitset" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" - -[[package]] -name = "flate2" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" -dependencies = [ - "cfg-if", - "crc32fast", - "libc", - "miniz_oxide", -] - [[package]] name = "fnv" version = "1.0.7" @@ -451,20 +371,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "futures" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.21" @@ -472,7 +378,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", - "futures-sink", ] [[package]] @@ -481,12 +386,6 @@ version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" -[[package]] -name = "futures-io" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" - [[package]] name = "futures-sink" version = "0.3.21" @@ -506,7 +405,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ "futures-core", - "futures-sink", "futures-task", "pin-project-lite", "pin-utils", @@ -523,25 +421,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "h2" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util 0.6.9", - "tracing", -] - [[package]] name = "half" version = "1.8.2" @@ -554,28 +433,6 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -[[package]] -name = "hdrhistogram" -version = "7.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31672b7011be2c4f7456c4ddbcb40e7e9a4a9fad8efe49a6ebaf5f307d0109c0" -dependencies = [ - "base64", - "byteorder", - "flate2", - "nom", - "num-traits", -] - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "heck" version = "0.4.0" @@ -631,12 +488,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "hyper" version = "0.14.17" @@ -647,7 +498,6 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", "http", "http-body", "httparse", @@ -661,18 +511,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - [[package]] name = "indexmap" version = "1.8.0" @@ -683,15 +521,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "itertools" version = "0.10.3" @@ -806,16 +635,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg", -] - [[package]] name = "mio" version = "0.8.0" @@ -838,12 +657,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - [[package]] name = "nom" version = "7.1.0" @@ -895,6 +708,15 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +dependencies = [ + "memchr", +] + [[package]] name = "parking_lot" version = "0.12.0" @@ -924,16 +746,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" -[[package]] -name = "petgraph" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" -dependencies = [ - "fixedbitset", - "indexmap", -] - [[package]] name = "pin-project" version = "1.0.10" @@ -1000,6 +812,30 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.36" @@ -1009,59 +845,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "prost" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" -dependencies = [ - "bytes", - "heck 0.3.3", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prost", - "prost-types", - "regex", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "prost-types" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" -dependencies = [ - "bytes", - "prost", -] - [[package]] name = "quote" version = "1.0.15" @@ -1171,15 +954,6 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "rustc_version" version = "0.4.0" @@ -1287,12 +1061,6 @@ dependencies = [ "libc", ] -[[package]] -name = "slab" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" - [[package]] name = "smallvec" version = "1.8.0" @@ -1333,6 +1101,12 @@ dependencies = [ "syn", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" version = "1.0.86" @@ -1351,17 +1125,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" [[package]] -name = "tempfile" -version = "3.3.0" +name = "termcolor" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", + "winapi-util", ] [[package]] @@ -1373,6 +1142,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "textwrap" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" + [[package]] name = "thiserror" version = "1.0.30" @@ -1429,20 +1204,9 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "tracing", "winapi", ] -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-macros" version = "1.7.0" @@ -1454,17 +1218,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-stream" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" version = "0.6.9" @@ -1493,49 +1246,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tonic" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff08f4649d10a70ffa3522ca559031285d8e421d727ac85c60825761818f5d0a" -dependencies = [ - "async-stream", - "async-trait", - "base64", - "bytes", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost", - "prost-derive", - "tokio", - "tokio-stream", - "tokio-util 0.6.9", - "tower", - "tower-layer", - "tower-service", - "tracing", - "tracing-futures", -] - -[[package]] -name = "tonic-build" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9403f1bafde247186684b230dc6f38b5cd514584e8bec1dd32514be4745fa757" -dependencies = [ - "proc-macro2", - "prost-build", - "quote", - "syn", -] - [[package]] name = "tower" version = "0.4.12" @@ -1544,11 +1254,8 @@ checksum = "9a89fd63ad6adf737582df5db40d286574513c69a11dac5214dc3b5603d6713e" dependencies = [ "futures-core", "futures-util", - "indexmap", "pin-project", "pin-project-lite", - "rand", - "slab", "tokio", "tokio-util 0.7.0", "tower-layer", @@ -1620,16 +1327,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-log" version = "0.1.2" @@ -1665,12 +1362,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" -[[package]] -name = "unicode-segmentation" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" - [[package]] name = "unicode-width" version = "0.1.9" @@ -1792,17 +1483,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "which" -version = "4.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2" -dependencies = [ - "either", - "lazy_static", - "libc", -] - [[package]] name = "winapi" version = "0.3.9" @@ -1888,7 +1568,8 @@ name = "xtask" version = "0.1.0" dependencies = [ "anyhow", - "heck 0.4.0", + "clap 3.1.1", + "heck", "itertools", "strong-xml", ] diff --git a/amqp_core/Cargo.toml b/amqp_core/Cargo.toml index cec72f4..4a10592 100644 --- a/amqp_core/Cargo.toml +++ b/amqp_core/Cargo.toml @@ -6,5 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +bytes = "1.1.0" parking_lot = "0.12.0" +smallvec = { version = "1.8.0", features = ["union"] } uuid = "0.8.2" diff --git a/amqp_core/src/lib.rs b/amqp_core/src/lib.rs index 8dfb2f7..f92416d 100644 --- a/amqp_core/src/lib.rs +++ b/amqp_core/src/lib.rs @@ -1,5 +1,6 @@ #![warn(rust_2018_idioms)] +mod message; pub mod methods; use parking_lot::Mutex; diff --git a/amqp_core/src/message.rs b/amqp_core/src/message.rs new file mode 100644 index 0000000..eba4c8d --- /dev/null +++ b/amqp_core/src/message.rs @@ -0,0 +1,23 @@ +#![allow(dead_code)] + +use crate::methods; +use bytes::Bytes; +use smallvec::SmallVec; +use std::sync::Arc; +use uuid::Uuid; + +pub type Message = Arc; + +pub struct RawMessage { + id: Uuid, + properties: methods::Table, + routing: RoutingInformation, + content: SmallVec<[Bytes; 1]>, +} + +pub struct RoutingInformation { + pub exchange: String, + pub routing_key: String, + pub mandatory: bool, + pub immediate: bool, +} diff --git a/amqp_transport/Cargo.toml b/amqp_transport/Cargo.toml index 9c89663..5387136 100644 --- a/amqp_transport/Cargo.toml +++ b/amqp_transport/Cargo.toml @@ -9,10 +9,12 @@ edition = "2021" amqp_core = { path = "../amqp_core" } amqp_messaging = { path = "../amqp_messaging" } anyhow = "1.0.53" +bytes = "1.1.0" nom = "7.1.0" once_cell = "1.9.0" rand = "0.8.4" regex = "1.5.4" +smallvec = { version = "1.8.0", features = ["union"] } thiserror = "1.0.30" tokio = { version = "1.16.1", features = ["full", "tracing"] } tracing = "0.1.30" diff --git a/amqp_transport/src/connection.rs b/amqp_transport/src/connection.rs index 3a02055..f772013 100644 --- a/amqp_transport/src/connection.rs +++ b/amqp_transport/src/connection.rs @@ -1,19 +1,25 @@ -use crate::error::{ConException, ProtocolError, Result}; -use crate::frame::{Frame, FrameType}; -use crate::{frame, methods, sasl}; -use amqp_core::methods::{FieldValue, Method, Table}; -use amqp_core::GlobalData; -use anyhow::Context; +use std::cmp::Ordering; use std::collections::HashMap; use std::net::SocketAddr; use std::pin::Pin; use std::time::Duration; + +use anyhow::Context; +use bytes::Bytes; +use smallvec::SmallVec; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::TcpStream; use tokio::time; use tracing::{debug, error, info, warn}; use uuid::Uuid; +use amqp_core::methods::{FieldValue, Method, Table}; +use amqp_core::GlobalData; + +use crate::error::{ConException, ProtocolError, Result}; +use crate::frame::{ContentHeader, Frame, FrameType}; +use crate::{frame, methods, sasl}; + fn ensure_conn(condition: bool) -> Result<()> { if condition { Ok(()) @@ -47,6 +53,12 @@ pub struct Connection { const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); +enum WaitForBodyStatus { + Method(Method), + Header(Method, ContentHeader, SmallVec<[Bytes; 1]>), + None, +} + impl Connection { pub fn new( id: Uuid, @@ -95,7 +107,7 @@ impl Connection { &Frame { kind: FrameType::Method, channel, - payload, + payload: payload.into(), }, &mut self.stream, ) @@ -196,15 +208,46 @@ impl Connection { } async fn main_loop(&mut self) -> Result<()> { + // todo: find out how header/body frames can interleave between channels + let mut wait_for_body = WaitForBodyStatus::None; + loop { debug!("Waiting for next frame"); let frame = frame::read_frame(&mut self.stream, self.max_frame_size).await?; self.reset_timeout(); match frame.kind { - FrameType::Method => self.dispatch_method(frame).await?, + FrameType::Method => wait_for_body = self.dispatch_method(frame).await?, FrameType::Heartbeat => {} - _ => warn!(frame_type = ?frame.kind, "TODO"), + FrameType::Header => match wait_for_body { + WaitForBodyStatus::None => warn!(channel = %frame.channel, "unexpected header"), + WaitForBodyStatus::Method(method) => { + wait_for_body = + WaitForBodyStatus::Header(method, ContentHeader::new(), SmallVec::new()) + } + WaitForBodyStatus::Header(_, _, _) => { + warn!(channel = %frame.channel, "already got header") + } + }, + FrameType::Body => match &mut wait_for_body { + WaitForBodyStatus::None => warn!(channel = %frame.channel, "unexpected body"), + WaitForBodyStatus::Method(_) => { + warn!(channel = %frame.channel, "unexpected body") + } + WaitForBodyStatus::Header(_, header, vec) => { + vec.push(frame.payload); + match vec + .iter() + .map(Bytes::len) + .sum::() + .cmp(&usize::try_from(header.body_size).unwrap()) + { + Ordering::Equal => todo!("process body"), + Ordering::Greater => todo!("too much data!"), + Ordering::Less => {} // wait for next body + } + } + }, } } } @@ -219,6 +262,7 @@ impl Connection { } Method::ChannelOpen { .. } => self.channel_open(frame.channel).await?, Method::ChannelClose { .. } => self.channel_close(frame.channel, method).await?, + Method::BasicPublish { .. } => return Ok(WaitForBodyStatus::Method(method)), _ => { let channel_handle = self .channels @@ -235,7 +279,7 @@ impl Connection { } } - Ok(()) + Ok(WaitForBodyStatus::None) } async fn channel_open(&mut self, num: u16) -> Result<()> { diff --git a/amqp_transport/src/frame.rs b/amqp_transport/src/frame.rs index 689b5de..cd9c53c 100644 --- a/amqp_transport/src/frame.rs +++ b/amqp_transport/src/frame.rs @@ -1,5 +1,8 @@ use crate::error::{ConException, ProtocolError, Result}; +use amqp_core::methods::FieldValue; use anyhow::Context; +use bytes::Bytes; +use smallvec::SmallVec; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tracing::trace; @@ -18,7 +21,7 @@ pub struct Frame { pub kind: FrameType, pub channel: u16, /// Includes the whole payload, also including the metadata from each type. - pub payload: Vec, + pub payload: Bytes, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -30,6 +33,21 @@ pub enum FrameType { Heartbeat = 8, } +#[derive(Debug, Clone, PartialEq)] +pub struct ContentHeader { + pub class_id: u16, + pub weight: u16, + pub body_size: u64, + pub property_flags: SmallVec<[u16; 1]>, + pub property_fields: Vec, +} + +impl ContentHeader { + pub fn new() -> Self { + todo!() + } +} + pub async fn write_frame(frame: &Frame, mut w: W) -> Result<()> where W: AsyncWriteExt + Unpin, @@ -72,7 +90,7 @@ where let frame = Frame { kind, channel, - payload, + payload: payload.into(), }; trace!(?frame, "Received frame"); @@ -99,6 +117,7 @@ fn parse_frame_type(kind: u8, channel: u16) -> Result { #[cfg(test)] mod tests { use crate::frame::{Frame, FrameType}; + use bytes::Bytes; #[tokio::test] async fn read_small_body() { @@ -127,7 +146,7 @@ mod tests { Frame { kind: FrameType::Method, channel: 0, - payload: vec![1, 2, 3], + payload: Bytes::from_static(&[1, 2, 3]), } ); } diff --git a/amqp_transport/src/sasl.rs b/amqp_transport/src/sasl.rs index 986dcb0..970d113 100644 --- a/amqp_transport/src/sasl.rs +++ b/amqp_transport/src/sasl.rs @@ -1,6 +1,6 @@ //! (Very) partial implementation of SASL Authentication (see [RFC 4422](https://datatracker.ietf.org/doc/html/rfc4422)) //! -//! Currently only supports PLAN (see [RFC 4616](https://datatracker.ietf.org/doc/html/rfc4616)) +//! Currently only supports PLAIN (see [RFC 4616](https://datatracker.ietf.org/doc/html/rfc4616)) use crate::error::{ConException, Result}; diff --git a/amqp_transport/src/tests.rs b/amqp_transport/src/tests.rs index 1f6dc71..b6af887 100644 --- a/amqp_transport/src/tests.rs +++ b/amqp_transport/src/tests.rs @@ -22,7 +22,7 @@ async fn write_start_ok_frame() { let frame = frame::Frame { kind: FrameType::Method, channel: 0, - payload, + payload: payload.into(), }; let mut output = Vec::new(); diff --git a/test-js/.gitignore b/test-js/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/test-js/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/test-js/.prettierrc.json b/test-js/.prettierrc.json new file mode 100644 index 0000000..544138b --- /dev/null +++ b/test-js/.prettierrc.json @@ -0,0 +1,3 @@ +{ + "singleQuote": true +} diff --git a/test-js/package.json b/test-js/package.json new file mode 100644 index 0000000..a300bce --- /dev/null +++ b/test-js/package.json @@ -0,0 +1,18 @@ +{ + "name": "tests-js", + "version": "0.0.0", + "main": "index.ts", + "type": "module", + "license": "MIT", + "scripts": { + "fmt": "prettier -w .", + "test": "node test-all.js" + }, + "dependencies": { + "@types/amqplib": "^0.8.2", + "amqplib": "^0.8.0" + }, + "devDependencies": { + "prettier": "^2.5.1" + } +} diff --git a/test-js/src/dummy-test.js b/test-js/src/dummy-test.js new file mode 100644 index 0000000..01668bd --- /dev/null +++ b/test-js/src/dummy-test.js @@ -0,0 +1 @@ +console.log('Passed :)'); diff --git a/test-js/src/open-channel.js b/test-js/src/open-channel.js new file mode 100644 index 0000000..b276f62 --- /dev/null +++ b/test-js/src/open-channel.js @@ -0,0 +1,15 @@ +import { connect } from 'amqplib'; +import { sleep } from './utils/utils.js'; + +const connection = await connect('amqp://localhost'); + +const channel = await connection.createChannel(); + +console.log('Successfully opened channel'); + +await sleep(100_000); + +await channel.close(); +await connection.close(); + +console.log('Successfully shut down connection'); diff --git a/test-js/src/send-single-message.js b/test-js/src/send-single-message.js new file mode 100644 index 0000000..f1070d5 --- /dev/null +++ b/test-js/src/send-single-message.js @@ -0,0 +1,14 @@ +import { connect } from 'amqplib'; + +const connection = await connect('amqp://localhost'); + +const channel = await connection.createChannel(); + +channel.publish('exchange-1', 'queue-1', Buffer.from('hello')); + +console.log('Published message'); + +await channel.close(); +await connection.close(); + +console.log('Successfully shut down connection'); diff --git a/test-js/src/utils/utils.js b/test-js/src/utils/utils.js new file mode 100644 index 0000000..0e51ee3 --- /dev/null +++ b/test-js/src/utils/utils.js @@ -0,0 +1 @@ +export const sleep = (ms) => new Promise((res) => setTimeout(res, ms)); diff --git a/test-js/test-all.js b/test-js/test-all.js new file mode 100644 index 0000000..1e7343e --- /dev/null +++ b/test-js/test-all.js @@ -0,0 +1,58 @@ +import * as childProcess from 'child_process'; +import * as fsSync from 'fs'; +import * as fs from 'fs/promises'; +import * as path from 'path'; +import * as url from 'url'; + +const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); + +const srcDir = path.join(__dirname, 'src'); + +const src = await fs.readdir(srcDir); + +const tests = src + .map((test) => [path.join(srcDir, test), test]) + .filter(([testPath]) => { + const stats = fsSync.statSync(testPath); + return !stats.isDirectory(); + }); + +let done = 0; +const successes = []; +const failures = []; + +function maybeDone() { + if (done === tests.length) { + for (const success of successes) { + console.log(`✔️ Test ${success} successful`); + } + for (const { name, stderr } of failures) { + console.log( + `------------------- stderr test ${name} -------------------` + ); + console.log(stderr); + console.log(`------------------- stderr test ${name} ------------------- +❌ Test ${name} failed`); + } + + if (failures.length > 0) { + process.exit(1); + } + } +} + +function runTest(path, name) { + childProcess.exec(`node ${path}`, {}, (error, _, stderr) => { + if (!error) { + successes.push(name); + } else { + failures.push({ name, stderr }); + } + done += 1; + maybeDone(); + }); +} + +for (const [test, name] of tests) { + runTest(test, name); +} diff --git a/test-js/yarn.lock b/test-js/yarn.lock new file mode 100644 index 0000000..f489366 --- /dev/null +++ b/test-js/yarn.lock @@ -0,0 +1,127 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/amqplib@^0.8.2": + version "0.8.2" + resolved "https://registry.yarnpkg.com/@types/amqplib/-/amqplib-0.8.2.tgz#9c46f2c7fac381e4f81bcb612c00d54549697d22" + integrity sha512-p+TFLzo52f8UanB+Nq6gyUi65yecAcRY3nYowU6MPGFtaJvEDxcnFWrxssSTkF+ts1W3zyQDvgVICLQem5WxRA== + dependencies: + "@types/bluebird" "*" + "@types/node" "*" + +"@types/bluebird@*": + version "3.5.36" + resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.36.tgz#00d9301d4dc35c2f6465a8aec634bb533674c652" + integrity sha512-HBNx4lhkxN7bx6P0++W8E289foSu8kO8GCk2unhuVggO+cE7rh9DhZUyPhUxNRG9m+5B5BTKxZQ5ZP92x/mx9Q== + +"@types/node@*": + version "17.0.19" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.19.tgz#726171367f404bfbe8512ba608a09ebad810c7e6" + integrity sha512-PfeQhvcMR4cPFVuYfBN4ifG7p9c+Dlh3yUZR6k+5yQK7wX3gDgVxBly4/WkBRs9x4dmcy1TVl08SY67wwtEvmA== + +amqplib@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/amqplib/-/amqplib-0.8.0.tgz#088d10bc61cc5ac5a49ac72033c7ac66c23aeb61" + integrity sha512-icU+a4kkq4Y1PS4NNi+YPDMwdlbFcZ1EZTQT2nigW3fvOb6AOgUQ9+Mk4ue0Zu5cBg/XpDzB40oH10ysrk2dmA== + dependencies: + bitsyntax "~0.1.0" + bluebird "^3.7.2" + buffer-more-ints "~1.0.0" + readable-stream "1.x >=1.1.9" + safe-buffer "~5.2.1" + url-parse "~1.5.1" + +bitsyntax@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/bitsyntax/-/bitsyntax-0.1.0.tgz#b0c59acef03505de5a2ed62a2f763c56ae1d6205" + integrity sha512-ikAdCnrloKmFOugAfxWws89/fPc+nw0OOG1IzIE72uSOg/A3cYptKCjSUhDTuj7fhsJtzkzlv7l3b8PzRHLN0Q== + dependencies: + buffer-more-ints "~1.0.0" + debug "~2.6.9" + safe-buffer "~5.1.2" + +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +buffer-more-ints@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz#ef4f8e2dddbad429ed3828a9c55d44f05c611422" + integrity sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +debug@~2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +inherits@~2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +prettier@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" + integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +"readable-stream@1.x >=1.1.9": + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +safe-buffer@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@~5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +url-parse@~1.5.1: + version "1.5.9" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.9.tgz#05ff26484a0b5e4040ac64dcee4177223d74675e" + integrity sha512-HpOvhKBvre8wYez+QhHcYiVvVmeF6DVnuSOOPhe3cTum3BnqHhvKaZm8FU5yTiOu/Jut2ZpB2rA/SbBA1JIGlQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index be38f42..ed4adde 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] anyhow = "1.0.54" +clap = { version = "3.1.1", features = ["derive"] } heck = "0.4.0" itertools = "0.10.3" -strong-xml = "0.6.3" \ No newline at end of file +strong-xml = "0.6.3" diff --git a/xtask/src/codegen/mod.rs b/xtask/src/codegen/mod.rs index f7a0d95..9600df1 100644 --- a/xtask/src/codegen/mod.rs +++ b/xtask/src/codegen/mod.rs @@ -4,13 +4,14 @@ mod parser; mod random; mod write; -use anyhow::Context; +use anyhow::{bail, Context}; use heck::ToUpperCamelCase; use std::fs; use std::fs::File; use std::io::Write; use std::iter::Peekable; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; +use std::process::Command; use std::str::FromStr; use strong_xml::XmlRead; @@ -105,6 +106,15 @@ struct Codegen { output: Box, } +fn fmt(path: &Path) -> anyhow::Result<()> { + println!("Formatting {path:?}..."); + let status = Command::new("rustfmt").arg(path).status()?; + if !status.success() { + bail!("error formatting {path:?}"); + } + Ok(()) +} + pub fn main() -> anyhow::Result<()> { let this_file = PathBuf::from_str(file!()).context("own file path")?; let xtask_root = this_file @@ -125,8 +135,8 @@ pub fn main() -> anyhow::Result<()> { let amqp = Amqp::from_str(&content).context("parse amqp spec file")?; let transport_output = - File::create(transport_generated_path).context("transport output file create")?; - let core_output = File::create(core_generated_path).context("core output file create")?; + File::create(&transport_generated_path).context("transport output file create")?; + let core_output = File::create(&core_generated_path).context("core output file create")?; Codegen { output: Box::new(transport_output), @@ -138,6 +148,9 @@ pub fn main() -> anyhow::Result<()> { } .core_codegen(&amqp); + fmt(&transport_generated_path)?; + fmt(&core_generated_path)?; + Ok(()) } impl Codegen { diff --git a/xtask/src/main.rs b/xtask/src/main.rs index dfdacf5..0430f19 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -1,24 +1,41 @@ +use std::path::PathBuf; + mod codegen; +mod test_js; + +use clap::{Parser, Subcommand}; + +#[derive(Parser)] +#[clap(author)] +struct Args { + #[clap(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + /// Generate method definitions/parser/writer + Generate, + /// Run Javascript integration tests + TestJs, +} fn main() -> anyhow::Result<()> { - let command = std::env::args().nth(1).unwrap_or_else(|| { - eprintln!("Error: No task provided"); - help(); - std::process::exit(1); - }); + let args: Args = Args::parse(); - match command.as_str() { - "generate" | "gen" => codegen::main(), - _ => { - eprintln!("Unknown command {command}."); - Ok(()) - } + match args.command { + Commands::Generate => codegen::main(), + Commands::TestJs => test_js::main(), } } -fn help() { - println!( - "Available tasks: - generate, gen - Generate amqp method code in `amqp_transport/src/methods/generated.rs and amqp_core/src/methods/generated.rs" - ); +pub fn project_root() -> PathBuf { + PathBuf::from(file!()) + .parent() + .expect("src directory path") + .parent() + .expect("xtask root path") + .parent() + .expect("project root path") + .to_path_buf() } diff --git a/xtask/src/test_js.rs b/xtask/src/test_js.rs new file mode 100644 index 0000000..f61343f --- /dev/null +++ b/xtask/src/test_js.rs @@ -0,0 +1,24 @@ +use crate::project_root; +use anyhow::{bail, Context, Result}; +use std::process::Command; + +pub fn main() -> Result<()> { + let test_js_root = project_root().join("test-js"); + let status = Command::new("yarn") + .current_dir(&test_js_root) + .status() + .context("yarn install tests")?; + if !status.success() { + bail!("yarn install failed"); + } + let status = Command::new("yarn") + .arg("test") + .current_dir(&test_js_root) + .status() + .context("yarn test tests")?; + if !status.success() { + bail!("yarn tests failed"); + } + + Ok(()) +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..fb57ccd --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + +