diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9bb9c2ac..8bdc8467 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,24 +19,18 @@ jobs: needs: style runs-on: ubuntu-latest + env: + STORE: RocksDb + RUST_MIN_STACK: "16777216" + steps: - name: Checkout uses: actions/checkout@v6.0.1 - - name: Install dependencies - run: | - sudo apt-get update -y - curl -LO https://github.com/glauth/glauth/releases/download/v2.2.0/glauth-linux-arm64 - chmod a+rx glauth-linux-arm64 - nohup ./glauth-linux-arm64 -c tests/resources/ldap.cfg & - curl -Lo minio.deb https://dl.min.io/server/minio/release/linux-amd64/archive/minio_20230629051228.0.0_amd64.deb - sudo dpkg -i minio.deb - mkdir ~/minio - nohup minio server ~/minio --console-address :9090 & - curl -LO https://dl.min.io/client/mc/release/linux-amd64/mc - chmod a+rx mc - ./mc alias set myminio http://localhost:9000 minioadmin minioadmin - ./mc mb tmp + # External services (OpenLDAP, Keycloak, PostgreSQL, MySQL, Redis, NATS, + # MinIO, OpenSearch, Meilisearch) are provisioned on demand by the test + # suite via testcontainers using the Docker daemon available on the + # runner; see tests/src/utils/containers.rs. - name: Rust Cache uses: Swatinem/rust-cache@v2 diff --git a/Cargo.lock b/Cargo.lock index 6d8989e6..4f75b04f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -204,7 +204,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", "synstructure", ] @@ -216,7 +216,23 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", +] + +[[package]] +name = "astral-tokio-tar" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb50a7aae84a03bf55b067832bc376f4961b790c97e64d3eacee97d389b90277" +dependencies = [ + "filetime", + "futures-core", + "libc", + "portable-atomic", + "rustc-hash", + "tokio", + "tokio-stream", + "xattr", ] [[package]] @@ -291,7 +307,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -313,7 +329,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -324,7 +340,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -340,7 +356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e2cdb6d5ed835199484bb92bb8b3edd526effe995c61732580439c1a67e2e9" dependencies = [ "base64 0.22.1", - "http 1.4.1", + "http 1.4.2", "log", "rustls 0.23.40", "serde", @@ -404,6 +420,49 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "axum" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +dependencies = [ + "axum-core", + "bytes", + "futures-util", + "http 1.4.2", + "http-body", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http 1.4.2", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", +] + [[package]] name = "azure_core" version = "0.21.0" @@ -572,7 +631,7 @@ dependencies = [ "regex", "rustc-hash", "shlex 1.3.0", - "syn 2.0.117", + "syn", ] [[package]] @@ -707,9 +766,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" dependencies = [ "hybrid-array", "zeroize", @@ -754,6 +813,80 @@ dependencies = [ "cipher 0.4.4", ] +[[package]] +name = "bollard" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee04c4c84f1f811b017f2fbb7dd8815c976e7ca98593de9c1e2afad0f636bff4" +dependencies = [ + "async-stream", + "base64 0.22.1", + "bitflags", + "bollard-buildkit-proto", + "bollard-stubs", + "bytes", + "futures-core", + "futures-util", + "hex", + "home", + "http 1.4.2", + "http-body-util", + "hyper", + "hyper-named-pipe", + "hyper-rustls", + "hyper-util", + "hyperlocal", + "log", + "num", + "pin-project-lite", + "rand 0.9.4", + "rustls 0.23.40", + "rustls-native-certs", + "rustls-pki-types", + "serde", + "serde_derive", + "serde_json", + "serde_urlencoded", + "thiserror 2.0.18", + "time", + "tokio", + "tokio-stream", + "tokio-util", + "tonic", + "tower-service", + "url", + "winapi", +] + +[[package]] +name = "bollard-buildkit-proto" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a885520bf6249ab931a764ffdb87b0ceef48e6e7d807cfdb21b751e086e1ad" +dependencies = [ + "prost", + "prost-types", + "tonic", + "tonic-prost", + "ureq", +] + +[[package]] +name = "bollard-stubs" +version = "1.52.1-rc.29.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0a8ca8799131c1837d1282c3f81f31e76ceb0ce426e04a7fe1ccee3287c066" +dependencies = [ + "base64 0.22.1", + "bollard-buildkit-proto", + "bytes", + "prost", + "serde", + "serde_json", + "serde_repr", + "time", +] + [[package]] name = "bs58" version = "0.5.1" @@ -807,7 +940,7 @@ checksum = "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -1550,7 +1683,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -1599,7 +1732,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.117", + "syn", ] [[package]] @@ -1612,7 +1745,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.117", + "syn", ] [[package]] @@ -1623,7 +1756,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -1634,7 +1767,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core 0.23.0", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -1815,7 +1948,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -1825,7 +1958,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.117", + "syn", ] [[package]] @@ -1864,7 +1997,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ - "block-buffer 0.12.0", + "block-buffer 0.12.1", "const-oid 0.10.2", "crypto-common 0.2.2", "ctutils", @@ -1941,7 +2074,7 @@ checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -1974,6 +2107,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "docker_credential" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29547a1dc60885a552306986316bc9701ba120c1a8db6769fa68691529ad373d" +dependencies = [ + "base64 0.22.1", + "serde", + "serde_json", +] + [[package]] name = "dsa" version = "0.6.3" @@ -2182,6 +2326,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "etcetera" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96" +dependencies = [ + "cfg-if", + "windows-sys 0.61.2", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -2215,7 +2369,7 @@ version = "0.16.9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2286,6 +2440,17 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +[[package]] +name = "ferroid" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee93edf3c501f0035bbeffeccfed0b79e14c311f12195ec0e661e114a0f60da4" +dependencies = [ + "portable-atomic", + "rand 0.10.1", + "web-time", +] + [[package]] name = "ff" version = "0.13.1" @@ -2303,6 +2468,16 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -2379,7 +2554,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3757d8523a60f4d3516a018e767cd3bea0829a43045d290ace16dcc92ac4f4cd" dependencies = [ "bytes", - "http 1.4.1", + "http 1.4.2", "httparse", "memchr", "mime", @@ -2435,7 +2610,7 @@ checksum = "c4ca5370149145ec3741cd7e82832f17f893b9421ee4e484d9511c6702bd9911" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", "try_map", ] @@ -2542,7 +2717,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2686,7 +2861,7 @@ checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2741,7 +2916,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.4.1", + "http 1.4.2", "indexmap 2.14.0", "slab", "tokio", @@ -2805,7 +2980,7 @@ dependencies = [ "indexmap 2.14.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2852,7 +3027,7 @@ dependencies = [ "futures-util", "h2", "hickory-proto", - "http 1.4.1", + "http 1.4.2", "idna", "ipnet", "jni 0.22.4", @@ -3036,9 +3211,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" dependencies = [ "bytes", "itoa", @@ -3051,7 +3226,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.4.1", + "http 1.4.2", ] [[package]] @@ -3062,7 +3237,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.1", + "http 1.4.2", "http-body", "pin-project-lite", ] @@ -3142,7 +3317,7 @@ dependencies = [ "futures-channel", "futures-core", "h2", - "http 1.4.1", + "http 1.4.2", "http-body", "httparse", "httpdate", @@ -3153,13 +3328,28 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-named-pipe" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278" +dependencies = [ + "hex", + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", + "winapi", +] + [[package]] name = "hyper-rustls" version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ - "http 1.4.1", + "http 1.4.2", "hyper", "hyper-util", "rustls 0.23.40", @@ -3192,7 +3382,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.4.1", + "http 1.4.2", "http-body", "hyper", "ipnet", @@ -3205,6 +3395,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "hyperlocal" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "986c5ce3b994526b3cd75578e62554abd09f0899d6206de48b3e96ab34ccc8c7" +dependencies = [ + "hex", + "http-body-util", + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "iana-time-zone" version = "0.1.65" @@ -3421,7 +3626,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -3750,7 +3955,7 @@ dependencies = [ "quote", "rustc_version", "simd_cesu8", - "syn 2.0.117", + "syn", ] [[package]] @@ -3778,7 +3983,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -3793,13 +3998,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.99" +version = "0.3.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" +checksum = "f2025f20d7a4fa7785846e7b63d10a76d3f1cee98ee5cb79ea59703f95e42162" dependencies = [ "cfg-if", "futures-util", - "once_cell", "wasm-bindgen", ] @@ -4239,6 +4443,12 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + [[package]] name = "maybe-async" version = "0.2.11" @@ -4247,7 +4457,7 @@ checksum = "746873a384ad60adc5db74471dfaba74bd278afbdcfd81db93fafcdfc8b5ca0c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -4413,7 +4623,7 @@ checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -4429,7 +4639,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.117", + "syn", "termcolor", "thiserror 2.0.18", ] @@ -4613,6 +4823,20 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -4639,6 +4863,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.2.2" @@ -4665,6 +4898,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -4704,7 +4948,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -4794,7 +5038,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -4835,7 +5079,7 @@ source = "git+https://github.com/stalwartlabs/opentelemetry-rust#274b4d324794280 dependencies = [ "async-trait", "bytes", - "http 1.4.1", + "http 1.4.2", "opentelemetry", "reqwest 0.13.4", ] @@ -4845,7 +5089,7 @@ name = "opentelemetry-otlp" version = "0.31.0" source = "git+https://github.com/stalwartlabs/opentelemetry-rust#274b4d324794280ce6f4def095a3428197a9e6e3" dependencies = [ - "http 1.4.1", + "http 1.4.2", "opentelemetry", "opentelemetry-http", "opentelemetry-proto", @@ -4973,6 +5217,31 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "parse-display" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914a1c2265c98e2446911282c6ac86d8524f495792c38c5bd884f80499c7538a" +dependencies = [ + "parse-display-derive", + "regex", + "regex-syntax", +] + +[[package]] +name = "parse-display-derive" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae7800a4c974efd12df917266338e79a7a74415173caf7e70aa0a0707345281" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "regex-syntax", + "structmeta", + "syn", +] + [[package]] name = "password-hash" version = "0.5.0" @@ -5067,7 +5336,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -5142,7 +5411,7 @@ dependencies = [ "phf_shared 0.13.1", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -5180,7 +5449,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -5370,7 +5639,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.117", + "syn", ] [[package]] @@ -5420,7 +5689,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -5438,7 +5707,7 @@ version = "0.16.9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -5457,9 +5726,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1" dependencies = [ "bytes", "prost-derive", @@ -5467,22 +5736,22 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" dependencies = [ "anyhow", "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] name = "prost-types" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" +checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a" dependencies = [ "prost", ] @@ -5499,9 +5768,9 @@ dependencies = [ [[package]] name = "psl" -version = "2.1.212" +version = "2.1.213" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f6415ab1b08394487005d41ae7ee69e69903efa1ace538f3b274db605bf8ec" +checksum = "04e78830163eebdf905adb55ba26ba9b3ba554b08bd84c2fbe3b643c8addf22c" dependencies = [ "psl-types", ] @@ -5529,7 +5798,7 @@ checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -5873,7 +6142,7 @@ checksum = "11dcd4dab09ceadedb3e2bedf340deb583f0e25bba9ad966b5655c2fb62b1392" dependencies = [ "proc-macro2", "rasn-derive-impl", - "syn 2.0.117", + "syn", ] [[package]] @@ -5886,7 +6155,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn", "uuid", ] @@ -6032,14 +6301,14 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] name = "regex" -version = "1.12.3" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" dependencies = [ "aho-corasick", "memchr", @@ -6060,9 +6329,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "registry" @@ -6101,7 +6370,7 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http 1.4.1", + "http 1.4.2", "http-body", "http-body-util", "hyper", @@ -6143,7 +6412,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http 1.4.1", + "http 1.4.2", "http-body", "http-body-util", "hyper", @@ -6251,7 +6520,7 @@ checksum = "5d2ed0b54125315fb36bd021e82d314d1c126548f871634b483f46b31d13cac6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -6370,7 +6639,7 @@ dependencies = [ "futures-util", "hex", "hmac 0.12.1", - "http 1.4.1", + "http 1.4.2", "log", "maybe-async", "md5", @@ -6653,7 +6922,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.117", + "syn", ] [[package]] @@ -6836,7 +7105,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -6847,7 +7116,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -6883,7 +7152,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -6927,7 +7196,7 @@ dependencies = [ "darling 0.23.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -6975,7 +7244,7 @@ checksum = "94e153fc76e1c6a068703d6d29c508a0b15c061c4b7e43da59cc097bc342673c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -7314,7 +7583,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -7408,9 +7677,9 @@ dependencies = [ [[package]] name = "stabby" -version = "72.1.2" +version = "72.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec9e9da673d4db1d470fa36cf4483ad5b1fdea349a392d400fea5d3673a9c5ca" +checksum = "da596fe515a75300efdc17bea773f7304a7758e187a0a8013fca4364aa5edacd" dependencies = [ "rustversion", "stabby-abi", @@ -7418,9 +7687,9 @@ dependencies = [ [[package]] name = "stabby-abi" -version = "72.1.2" +version = "72.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a281b17b3cf11531b7dc4e5f1c6be27db86a06e19c477e7a88fa4ee1b6daf3" +checksum = "080815c68b7e997f113fdbe75b726f4187817196a1b7d7f4c13843f40a8dd79c" dependencies = [ "rustc_version", "rustversion", @@ -7430,15 +7699,15 @@ dependencies = [ [[package]] name = "stabby-macros" -version = "72.1.2" +version = "72.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "605b39114a0c132d77ffdd7d179491323dbaa8369e7dcbcdf3da09d0b43c13cf" +checksum = "18084b18318cf35f502f70c5157e86840d9d1b0964316f08d0b3ebf405e4127d" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", "rand 0.8.6", - "syn 1.0.109", + "syn", ] [[package]] @@ -7568,23 +7837,35 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "structmeta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329" +dependencies = [ + "proc-macro2", + "quote", + "structmeta-derive", + "syn", +] + +[[package]] +name = "structmeta-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "subtle" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.117" @@ -7613,7 +7894,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -7681,6 +7962,37 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "testcontainers" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfd5785b5483672915ed5fe3cddf9f546802779fc1eceff0a6fb7321fac81c1e" +dependencies = [ + "astral-tokio-tar", + "async-trait", + "bollard", + "bytes", + "docker_credential", + "either", + "etcetera", + "ferroid", + "futures", + "http 1.4.2", + "itertools 0.14.0", + "log", + "memchr", + "parse-display", + "pin-project-lite", + "serde", + "serde_json", + "serde_with", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tokio-util", + "url", +] + [[package]] name = "tests" version = "0.16.9" @@ -7732,6 +8044,7 @@ dependencies = [ "registry", "reqwest 0.13.4", "rkyv", + "rust-s3", "rustls 0.23.40", "rustls-pemfile", "rustls-pki-types", @@ -7744,6 +8057,7 @@ dependencies = [ "smtp-proto", "spam-filter", "store", + "testcontainers", "tokio", "tokio-rustls", "trc", @@ -7778,7 +8092,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -7789,7 +8103,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -7916,7 +8230,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -8007,7 +8321,7 @@ dependencies = [ "bytes", "futures-core", "futures-sink", - "http 1.4.1", + "http 1.4.2", "httparse", "rand 0.8.6", "rustls-pki-types", @@ -8054,9 +8368,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", + "axum", "base64 0.22.1", "bytes", - "http 1.4.1", + "h2", + "http 1.4.2", "http-body", "http-body-util", "hyper", @@ -8065,6 +8381,7 @@ dependencies = [ "percent-encoding", "pin-project", "rustls-native-certs", + "socket2 0.6.4", "sync_wrapper", "tokio", "tokio-rustls", @@ -8142,7 +8459,7 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http 1.4.1", + "http 1.4.2", "http-body", "http-body-util", "pin-project-lite", @@ -8186,7 +8503,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -8281,7 +8598,7 @@ checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ "bytes", "data-encoding", - "http 1.4.1", + "http 1.4.2", "httparse", "log", "rand 0.9.4", @@ -8471,7 +8788,34 @@ checksum = "3b5bb2756c16fb66f80cfbf5fb0e0c09a7001e739f453c9ec241b9c8b1556fda" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", +] + +[[package]] +name = "ureq" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" +dependencies = [ + "base64 0.22.1", + "log", + "percent-encoding", + "rustls 0.23.40", + "rustls-pki-types", + "ureq-proto", + "utf8-zero", +] + +[[package]] +name = "ureq-proto" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" +dependencies = [ + "base64 0.22.1", + "http 1.4.2", + "httparse", + "log", ] [[package]] @@ -8493,6 +8837,12 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf8-zero" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -8543,9 +8893,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.23.2" +version = "1.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" +checksum = "144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7" dependencies = [ "getrandom 0.4.2", "js-sys", @@ -8574,7 +8924,7 @@ checksum = "8c44ce98e7227a04eeb4cf9c784109a5c9710e54849ceb4f09f8597247897f1e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", "unzip-n", ] @@ -8683,9 +9033,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.122" +version = "0.2.123" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" +checksum = "a254a4b10c19a76f09a27640e7ffbf9bc30bf67e16a3bf28aaefa4920fe81563" dependencies = [ "cfg-if", "once_cell", @@ -8696,9 +9046,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.72" +version = "0.4.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f" +checksum = "54568702fabf5d4849ce2b90fadfa64168a097eaf4b351ce9df8b687a0086aaf" dependencies = [ "js-sys", "wasm-bindgen", @@ -8706,9 +9056,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.122" +version = "0.2.123" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" +checksum = "24a40fc75b0ec6f3746ceb10d36f53a93dcd68a93b11b6445983945d79eba0dc" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -8716,22 +9066,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.122" +version = "0.2.123" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" +checksum = "908f34bd9b9ce3d4caf07b72dfab63d61504d156856c6bd3cd87fa350cf3985b" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.117", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.122" +version = "0.2.123" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" +checksum = "7acbf7616c27b194bbb550bf77ed0c2c3e5b7fd1260a93082b95fb7f47959b92" dependencies = [ "unicode-ident", ] @@ -8798,9 +9148,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.99" +version = "0.3.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" +checksum = "6e0871acf327f283dc6da28a1696cdc64fb355ba9f935d052021fa77f35cce69" dependencies = [ "js-sys", "wasm-bindgen", @@ -8969,7 +9319,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -8980,7 +9330,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -9328,7 +9678,7 @@ dependencies = [ "heck", "indexmap 2.14.0", "prettyplease", - "syn 2.0.117", + "syn", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -9344,7 +9694,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.117", + "syn", "wit-bindgen-core", "wit-bindgen-rust", ] @@ -9430,6 +9780,16 @@ dependencies = [ "time", ] +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + [[package]] name = "xml" version = "1.3.0" @@ -9486,7 +9846,7 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", "synstructure", ] @@ -9804,7 +10164,7 @@ checksum = "9310b02a8f6dc4bd04d9ce6b318b9d00182aeeeeca60410003307d63a2569a3f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", "zenoh-keyexpr", ] @@ -9959,22 +10319,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.50" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" +checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.50" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" +checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -9994,7 +10354,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", "synstructure", ] @@ -10015,7 +10375,7 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -10048,7 +10408,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] diff --git a/crates/store/src/backend/foundationdb/read.rs b/crates/store/src/backend/foundationdb/read.rs index 8b08d624..1c53c0b1 100644 --- a/crates/store/src/backend/foundationdb/read.rs +++ b/crates/store/src/backend/foundationdb/read.rs @@ -55,7 +55,8 @@ impl FdbStore { } Ok(ChunkedValue::None) => return Ok(None), Err(err) => { - self.on_read_error(trx, err, &mut retry_count, start).await?; + self.on_read_error(trx, err, &mut retry_count, start) + .await?; } } } @@ -73,7 +74,8 @@ impl FdbStore { Ok(ChunkedValue::Single(_) | ChunkedValue::Chunked { .. }) => return Ok(true), Ok(ChunkedValue::None) => return Ok(false), Err(err) => { - self.on_read_error(trx, err, &mut retry_count, start).await?; + self.on_read_error(trx, err, &mut retry_count, start) + .await?; } } } diff --git a/tests/Cargo.toml b/tests/Cargo.toml index cdfa3962..847dc379 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -83,6 +83,8 @@ quick-xml = "0.40" jmap-tools = { version = "0.1" } dns-update = { version = "0.5", features = ["test_provider"] } x509-parser = "0.18" +testcontainers = { version = "0.27", features = ["reusable-containers"] } +rust-s3 = { version = "0.37", default-features = false, features = ["tokio-rustls-tls"] } [target.'cfg(not(target_env = "msvc"))'.dependencies] jemallocator = "0.5.0" diff --git a/tests/src/automation/mod.rs b/tests/src/automation/mod.rs index eb126b55..5eab677f 100644 --- a/tests/src/automation/mod.rs +++ b/tests/src/automation/mod.rs @@ -7,6 +7,7 @@ pub mod acme; pub mod dkim; pub mod dns; +pub mod rfc2136; use registry::{ schema::{ @@ -22,6 +23,7 @@ use crate::utils::server::TestServerBuilder; #[tokio::test(flavor = "multi_thread")] async fn automation_tests() { + crate::utils::containers::ensure_acme().await; let mut test = TestServerBuilder::new("automation_tests") .await .with_listener(NetworkListenerProtocol::Http, "http", 8898, false) @@ -116,4 +118,5 @@ async fn automation_tests() { acme::test(&test).await; dkim::test(&test).await; dns::test(&test).await; + rfc2136::test(&test).await; } diff --git a/tests/src/automation/rfc2136.rs b/tests/src/automation/rfc2136.rs new file mode 100644 index 00000000..e83ac5ce --- /dev/null +++ b/tests/src/automation/rfc2136.rs @@ -0,0 +1,179 @@ +/* + * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL + */ + +use std::{net::Ipv4Addr, time::Duration as StdDuration}; + +use common::network::dns::update::DnsUpdater; +use dns_update::{DnsRecord, DnsRecordType, TLSARecord, TlsaCertUsage, TlsaMatching, TlsaSelector}; +use registry::{ + schema::{ + enums::{IpProtocol, TsigAlgorithm}, + structs::{DnsServer, DnsServerTsig, SecretKey, SecretKeyValue}, + }, + types::duration::Duration, +}; + +use crate::utils::server::TestServer; + +const ZONE: &str = "stalwart.test"; +const KEY_B64: &str = "c3RhbHdhcnQtdGVzdC10c2lnLXNlY3JldC1rZXkxMjM0NTY3ODkw"; + +pub async fn test(test: &TestServer) { + println!("Running RFC2136 (PowerDNS) tests..."); + crate::utils::containers::ensure_powerdns().await; + + let udp = DnsUpdater::build(dns_server(IpProtocol::Udp), test.server.core.clone()) + .await + .expect("Failed to build UDP RFC2136 updater"); + + // Create, replace and delete an A record over UDP (TSIG signed) + let a_name = "rfc2136-a.stalwart.test"; + udp.updater + .set_rrset( + a_name, + DnsRecordType::A, + 60, + vec![DnsRecord::A(Ipv4Addr::new(10, 0, 0, 1))], + ZONE, + ) + .await + .expect("set A"); + assert_eq!( + list(&udp, a_name, DnsRecordType::A, 1).await, + vec![DnsRecord::A(Ipv4Addr::new(10, 0, 0, 1))] + ); + + udp.updater + .set_rrset( + a_name, + DnsRecordType::A, + 60, + vec![DnsRecord::A(Ipv4Addr::new(10, 0, 0, 2))], + ZONE, + ) + .await + .expect("replace A"); + assert_eq!( + list(&udp, a_name, DnsRecordType::A, 1).await, + vec![DnsRecord::A(Ipv4Addr::new(10, 0, 0, 2))] + ); + + udp.updater + .set_rrset(a_name, DnsRecordType::A, 0, vec![], ZONE) + .await + .expect("delete A"); + assert!(list(&udp, a_name, DnsRecordType::A, 0).await.is_empty()); + + // Publish two TLSA records at the same owner in a single set_rrset call + let tlsa_name = "_25._tcp.rfc2136-tlsa.stalwart.test"; + let leaf: Vec = (0..32).collect(); + let intermediate: Vec = (32..64).collect(); + udp.updater + .set_rrset( + tlsa_name, + DnsRecordType::TLSA, + 60, + vec![ + DnsRecord::TLSA(TLSARecord { + cert_usage: TlsaCertUsage::DaneEe, + selector: TlsaSelector::Spki, + matching: TlsaMatching::Sha256, + cert_data: leaf.clone(), + }), + DnsRecord::TLSA(TLSARecord { + cert_usage: TlsaCertUsage::DaneTa, + selector: TlsaSelector::Spki, + matching: TlsaMatching::Sha256, + cert_data: intermediate.clone(), + }), + ], + ZONE, + ) + .await + .expect("set TLSA"); + let tlsa = list(&udp, tlsa_name, DnsRecordType::TLSA, 2).await; + let cert_datas: Vec> = tlsa + .iter() + .filter_map(|r| match r { + DnsRecord::TLSA(t) => Some(t.cert_data.clone()), + _ => None, + }) + .collect(); + assert!(cert_datas.contains(&leaf), "leaf TLSA missing: {tlsa:?}"); + assert!( + cert_datas.contains(&intermediate), + "intermediate TLSA missing: {tlsa:?}" + ); + udp.updater + .set_rrset(tlsa_name, DnsRecordType::TLSA, 0, vec![], ZONE) + .await + .expect("cleanup TLSA"); + + // The TCP transport must also attach the TSIG signer + let tcp = DnsUpdater::build(dns_server(IpProtocol::Tcp), test.server.core.clone()) + .await + .expect("Failed to build TCP RFC2136 updater"); + let txt_name = "rfc2136-txt.stalwart.test"; + tcp.updater + .set_rrset( + txt_name, + DnsRecordType::TXT, + 60, + vec![DnsRecord::TXT("rfc2136-tcp-signed".to_string())], + ZONE, + ) + .await + .expect("set TXT over TCP"); + assert_eq!( + list(&tcp, txt_name, DnsRecordType::TXT, 1).await, + vec![DnsRecord::TXT("rfc2136-tcp-signed".to_string())] + ); + tcp.updater + .set_rrset(txt_name, DnsRecordType::TXT, 0, vec![], ZONE) + .await + .expect("cleanup TXT"); +} + +async fn list( + updater: &DnsUpdater, + name: &str, + record_type: DnsRecordType, + expected_len: usize, +) -> Vec { + let mut latest = Vec::new(); + for _ in 0..20 { + latest = updater + .updater + .list_rrset(name, record_type, ZONE) + .await + .unwrap_or_default(); + if latest.len() == expected_len { + return latest; + } + tokio::time::sleep(StdDuration::from_millis(50)).await; + } + latest +} + +fn dns_server(protocol: IpProtocol) -> DnsServer { + DnsServer::Tsig(DnsServerTsig { + host: "127.0.0.1".parse().unwrap(), + port: 5300, + key_name: "stalwart-update-key".to_string(), + key: SecretKey::Value(SecretKeyValue { + secret: KEY_B64.into(), + }), + protocol, + tsig_algorithm: TsigAlgorithm::HmacSha256, + description: "Test RFC2136 DNS server".to_string(), + member_tenant_id: None, + timeout: Duration::from_millis(10_000), + ttl: Duration::from_millis(60_000), + polling_interval: Duration::from_millis(100), + propagation_timeout: Duration::from_millis(10_000), + propagation_delay: None, + }) +} diff --git a/tests/src/cluster/broadcast.rs b/tests/src/cluster/broadcast.rs index 43641e16..948cd4b0 100644 --- a/tests/src/cluster/broadcast.rs +++ b/tests/src/cluster/broadcast.rs @@ -40,15 +40,21 @@ pub async fn cluster_tests() { "COORDINATOR= cargo test`" )); let coordinator = match coordinator_id.as_str() { - "Nats" => Coordinator::Nats(NatsCoordinator { - addresses: Map::new(vec!["127.0.0.1:4222".to_string()]), - use_tls: false, - ..Default::default() - }), - "Redis" => Coordinator::Redis(RedisStore { - url: "redis://127.0.0.1".to_string(), - ..Default::default() - }), + "Nats" => { + crate::utils::containers::ensure_nats().await; + Coordinator::Nats(NatsCoordinator { + addresses: Map::new(vec!["127.0.0.1:4222".to_string()]), + use_tls: false, + ..Default::default() + }) + } + "Redis" => { + crate::utils::containers::ensure_redis().await; + Coordinator::Redis(RedisStore { + url: "redis://127.0.0.1".to_string(), + ..Default::default() + }) + } _ => panic!("Unsupported coordinator type: {}", coordinator_id), }; diff --git a/tests/src/directory/integration.rs b/tests/src/directory/integration.rs index dfde1edd..2d1fef56 100644 --- a/tests/src/directory/integration.rs +++ b/tests/src/directory/integration.rs @@ -15,6 +15,7 @@ use types::id::Id; pub async fn test() { println!("Running directory integration tests..."); + crate::utils::containers::ensure_openldap().await; let test = TestServerBuilder::new("directory_integration_test") .await .with_default_listeners() diff --git a/tests/src/directory/ldap.rs b/tests/src/directory/ldap.rs index 498c0fb0..b3d7cddb 100644 --- a/tests/src/directory/ldap.rs +++ b/tests/src/directory/ldap.rs @@ -12,6 +12,7 @@ use registry::{ pub async fn test() { println!("Running LDAP directory tests..."); + crate::utils::containers::ensure_openldap().await; let mut config = ldap_test_directory(); // Test bind authentication diff --git a/tests/src/directory/oidc.rs b/tests/src/directory/oidc.rs index 8a4175c1..dd0bb0b3 100644 --- a/tests/src/directory/oidc.rs +++ b/tests/src/directory/oidc.rs @@ -13,6 +13,7 @@ use registry::{schema::structs, types::map::Map}; pub async fn test() { println!("Running OIDC directory tests..."); + crate::utils::containers::ensure_keycloak().await; let config = structs::OidcDirectory { description: "Test OIDC directory".to_string(), issuer_url: "http://localhost:9080/realms/stalwart".to_string(), diff --git a/tests/src/utils/containers.rs b/tests/src/utils/containers.rs new file mode 100644 index 00000000..b517a122 --- /dev/null +++ b/tests/src/utils/containers.rs @@ -0,0 +1,455 @@ +/* + * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL + */ + +use std::time::{Duration, Instant}; + +use testcontainers::{ + ContainerAsync, GenericBuildableImage, GenericImage, ImageExt, ReuseDirective, + core::{CmdWaitFor, ExecCommand, Host, IntoContainerPort, WaitFor}, + runners::{AsyncBuilder, AsyncRunner}, +}; +use tokio::{net::TcpStream, sync::OnceCell}; + +const ACME_NETWORK: &str = "stalwart-test-acme"; + +const READY_TIMEOUT: Duration = Duration::from_secs(180); + +static FOUNDATIONDB: OnceCell> = OnceCell::const_new(); +static POSTGRES: OnceCell> = OnceCell::const_new(); +static MYSQL: OnceCell> = OnceCell::const_new(); +static REDIS: OnceCell> = OnceCell::const_new(); +static NATS: OnceCell> = OnceCell::const_new(); +static MINIO: OnceCell> = OnceCell::const_new(); +static OPENSEARCH: OnceCell> = OnceCell::const_new(); +static MEILISEARCH: OnceCell> = OnceCell::const_new(); +static KEYCLOAK: OnceCell> = OnceCell::const_new(); +static OPENLDAP: OnceCell> = OnceCell::const_new(); +static CHALLTESTSRV: OnceCell> = OnceCell::const_new(); +static PEBBLE: OnceCell> = OnceCell::const_new(); +static POWERDNS: OnceCell> = OnceCell::const_new(); + +const POWERDNS_ZONE_INIT: &str = r#"set -e +for i in $(seq 1 60); do + pdnsutil list-all-zones >/dev/null 2>&1 && break + sleep 1 +done +if pdnsutil list-zone stalwart.test >/dev/null 2>&1; then + exit 0 +fi +pdnsutil create-zone stalwart.test ns1.stalwart.test +pdnsutil set-kind stalwart.test native +pdnsutil replace-rrset stalwart.test '' SOA 'ns1.stalwart.test. admin.stalwart.test. 2024010101 3600 900 604800 86400' +pdnsutil add-record stalwart.test 'ns1' A '127.0.0.1' +pdnsutil add-record stalwart.test '' A '127.0.0.1' +pdnsutil add-record stalwart.test '' MX '10 mail.stalwart.test.' +pdnsutil add-record stalwart.test 'mail' A '127.0.0.1' +pdnsutil import-tsig-key stalwart-update-key hmac-sha256 'c3RhbHdhcnQtdGVzdC10c2lnLXNlY3JldC1rZXkxMjM0NTY3ODkw' +pdnsutil activate-tsig-key stalwart.test stalwart-update-key primary +pdnsutil set-meta stalwart.test TSIG-ALLOW-DNSUPDATE stalwart-update-key +pdnsutil set-meta stalwart.test ALLOW-DNSUPDATE-FROM '0.0.0.0/0' +"#; + +pub async fn ensure_foundationdb() { + let container = FOUNDATIONDB + .get_or_init(|| async { + GenericImage::new("foundationdb/foundationdb", "7.4.6") + .with_env_var("FDB_NETWORKING_MODE", "container") + .with_mapped_port(4500, 4500.tcp()) + .with_startup_timeout(READY_TIMEOUT) + .with_container_name("stalwart-test-foundationdb") + .with_reuse(ReuseDirective::Always) + .start() + .await + .expect("Failed to start FoundationDB container") + }) + .await; + + let start = Instant::now(); + loop { + if fdbcli(container, "status minimal") + .await + .contains("The database is available") + { + return; + } + let created = fdbcli(container, "configure new single memory").await; + if created.contains("Database created") || created.contains("Already exists") { + continue; + } + if start.elapsed() > READY_TIMEOUT { + panic!("Timed out configuring FoundationDB: {created}"); + } + tokio::time::sleep(Duration::from_secs(2)).await; + } +} + +async fn fdbcli(container: &ContainerAsync, command: &str) -> String { + let mut result = container + .exec( + ExecCommand::new(["fdbcli", "--exec", command, "--timeout", "5"]) + .with_cmd_ready_condition(CmdWaitFor::exit()), + ) + .await + .expect("Failed to exec fdbcli"); + let stdout = result.stdout_to_vec().await.unwrap_or_default(); + let stderr = result.stderr_to_vec().await.unwrap_or_default(); + format!( + "{}{}", + String::from_utf8_lossy(&stdout), + String::from_utf8_lossy(&stderr) + ) +} + +pub async fn ensure_postgres() { + POSTGRES + .get_or_init(|| async { + GenericImage::new("postgres", "16-alpine") + .with_wait_for(WaitFor::message_on_stderr( + "database system is ready to accept connections", + )) + .with_wait_for(WaitFor::message_on_stderr( + "database system is ready to accept connections", + )) + .with_env_var("POSTGRES_USER", "stalwart") + .with_env_var("POSTGRES_PASSWORD", "stalwart") + .with_env_var("POSTGRES_DB", "stalwart") + .with_mapped_port(5432, 5432.tcp()) + .with_startup_timeout(READY_TIMEOUT) + .with_container_name("stalwart-test-postgres") + .with_reuse(ReuseDirective::Always) + .start() + .await + .expect("Failed to start PostgreSQL container") + }) + .await; + wait_for_tcp(5432).await; +} + +pub async fn ensure_mysql() { + MYSQL + .get_or_init(|| async { + GenericImage::new("mysql", "8.0") + .with_wait_for(WaitFor::message_on_stderr("port: 3306 MySQL")) + .with_env_var("MYSQL_ROOT_PASSWORD", "password") + .with_env_var("MYSQL_DATABASE", "stalwart") + .with_cmd(["--default-authentication-plugin=mysql_native_password"]) + .with_mapped_port(3307, 3306.tcp()) + .with_startup_timeout(READY_TIMEOUT) + .with_container_name("stalwart-test-mysql") + .with_reuse(ReuseDirective::Always) + .start() + .await + .expect("Failed to start MySQL container") + }) + .await; + wait_for_tcp(3307).await; +} + +pub async fn ensure_redis() { + REDIS + .get_or_init(|| async { + GenericImage::new("redis", "7-alpine") + .with_wait_for(WaitFor::message_on_stdout("Ready to accept connections")) + .with_cmd(["redis-server", "--save", "", "--appendonly", "no"]) + .with_mapped_port(6379, 6379.tcp()) + .with_startup_timeout(READY_TIMEOUT) + .with_container_name("stalwart-test-redis") + .with_reuse(ReuseDirective::Always) + .start() + .await + .expect("Failed to start Redis container") + }) + .await; + wait_for_tcp(6379).await; +} + +pub async fn ensure_nats() { + NATS.get_or_init(|| async { + GenericImage::new("nats", "latest") + .with_wait_for(WaitFor::message_on_stderr("Server is ready")) + .with_cmd(["--addr", "0.0.0.0", "--port", "4222", "--http_port", "8222"]) + .with_mapped_port(4222, 4222.tcp()) + .with_mapped_port(8222, 8222.tcp()) + .with_startup_timeout(READY_TIMEOUT) + .with_container_name("stalwart-test-nats") + .with_reuse(ReuseDirective::Always) + .start() + .await + .expect("Failed to start NATS container") + }) + .await; + wait_for_tcp(4222).await; +} + +pub async fn ensure_minio() { + MINIO + .get_or_init(|| async { + GenericImage::new("minio/minio", "latest") + .with_env_var("MINIO_ROOT_USER", "minioadmin") + .with_env_var("MINIO_ROOT_PASSWORD", "minioadmin") + .with_cmd(["server", "/data", "--console-address", ":9001"]) + .with_mapped_port(9000, 9000.tcp()) + .with_mapped_port(9001, 9001.tcp()) + .with_startup_timeout(READY_TIMEOUT) + .with_container_name("stalwart-test-minio") + .with_reuse(ReuseDirective::Always) + .start() + .await + .expect("Failed to start MinIO container") + }) + .await; + wait_for_http("http://localhost:9000/minio/health/live").await; + create_minio_bucket().await; +} + +pub async fn ensure_opensearch() { + OPENSEARCH + .get_or_init(|| async { + GenericImage::new("opensearchproject/opensearch", "2") + .with_env_var("discovery.type", "single-node") + .with_env_var("DISABLE_SECURITY_PLUGIN", "true") + .with_env_var("OPENSEARCH_JAVA_OPTS", "-Xms1g -Xmx1g") + .with_env_var("DISABLE_INSTALL_DEMO_CONFIG", "true") + .with_mapped_port(9200, 9200.tcp()) + .with_startup_timeout(READY_TIMEOUT) + .with_container_name("stalwart-test-opensearch") + .with_reuse(ReuseDirective::Always) + .start() + .await + .expect("Failed to start OpenSearch container") + }) + .await; + wait_for_http("http://localhost:9200").await; +} + +pub async fn ensure_meilisearch() { + MEILISEARCH + .get_or_init(|| async { + GenericImage::new("getmeili/meilisearch", "latest") + .with_env_var("MEILI_ENV", "development") + .with_env_var("MEILI_NO_ANALYTICS", "true") + .with_env_var("MEILI_MASTER_KEY", "stalwart-master-key") + .with_mapped_port(7700, 7700.tcp()) + .with_startup_timeout(READY_TIMEOUT) + .with_container_name("stalwart-test-meilisearch") + .with_reuse(ReuseDirective::Always) + .start() + .await + .expect("Failed to start Meilisearch container") + }) + .await; + wait_for_http("http://localhost:7700/health").await; +} + +pub async fn ensure_keycloak() { + KEYCLOAK + .get_or_init(|| async { + GenericImage::new("quay.io/keycloak/keycloak", "latest") + .with_env_var("KC_BOOTSTRAP_ADMIN_USERNAME", "admin") + .with_env_var("KC_BOOTSTRAP_ADMIN_PASSWORD", "admin") + .with_env_var("KC_HTTP_PORT", "9080") + .with_env_var("KC_HEALTH_ENABLED", "true") + .with_cmd(["start-dev", "--import-realm"]) + .with_copy_to( + "/opt/keycloak/data/import/stalwart-realm.json", + include_bytes!("../../docker/keycloak/stalwart-realm.json").to_vec(), + ) + .with_mapped_port(9080, 9080.tcp()) + .with_startup_timeout(READY_TIMEOUT) + .with_container_name("stalwart-test-keycloak") + .with_reuse(ReuseDirective::Always) + .start() + .await + .expect("Failed to start Keycloak container") + }) + .await; + wait_for_http("http://localhost:9080/realms/stalwart/.well-known/openid-configuration").await; +} + +pub async fn ensure_acme() { + ensure_challtestsrv().await; + ensure_pebble().await; +} + +async fn ensure_challtestsrv() { + CHALLTESTSRV + .get_or_init(|| async { + let image = GenericBuildableImage::new("stalwart-test-challtestsrv", "local") + .with_dockerfile_string(include_str!("../../docker/pebble/Dockerfile.challtestsrv")) + .build_image() + .await + .expect("Failed to build challtestsrv image"); + image + .with_network(ACME_NETWORK) + .with_host("host.docker.internal", Host::HostGateway) + .with_mapped_port(8055, 8055.tcp()) + .with_startup_timeout(READY_TIMEOUT) + .with_container_name("stalwart-test-challtestsrv") + .with_reuse(ReuseDirective::Always) + .start() + .await + .expect("Failed to start challtestsrv container") + }) + .await; + wait_for_tcp(8055).await; +} + +async fn ensure_pebble() { + PEBBLE + .get_or_init(|| async { + GenericImage::new("ghcr.io/letsencrypt/pebble", "latest") + .with_env_var("PEBBLE_VA_NOSLEEP", "1") + .with_env_var("PEBBLE_WFE_NONCEREJECT", "0") + .with_cmd([ + "-config", + "/test/config/pebble-config.json", + "-dnsserver", + "stalwart-test-challtestsrv:8053", + ]) + .with_copy_to( + "/test/config/pebble-config.json", + include_bytes!("../../docker/pebble/pebble-config.json").to_vec(), + ) + .with_network(ACME_NETWORK) + .with_host("host.docker.internal", Host::HostGateway) + .with_mapped_port(14000, 14000.tcp()) + .with_mapped_port(15000, 15000.tcp()) + .with_startup_timeout(READY_TIMEOUT) + .with_container_name("stalwart-test-pebble") + .with_reuse(ReuseDirective::Always) + .start() + .await + .expect("Failed to start Pebble container") + }) + .await; + wait_for_tcp(14000).await; +} + +pub async fn ensure_powerdns() { + let container = POWERDNS + .get_or_init(|| async { + GenericImage::new("powerdns/pdns-auth-49", "latest") + .with_wait_for(WaitFor::message_on_stderr("Creating backend connection")) + .with_env_var("PDNS_AUTH_API_KEY", "stalwart-api-key") + .with_copy_to( + "/etc/powerdns/pdns.d/stalwart.conf", + include_bytes!("../../docker/powerdns/pdns.conf").to_vec(), + ) + .with_mapped_port(5300, 53.tcp()) + .with_mapped_port(5300, 53.udp()) + .with_startup_timeout(READY_TIMEOUT) + .with_container_name("stalwart-test-powerdns") + .with_reuse(ReuseDirective::Always) + .start() + .await + .expect("Failed to start PowerDNS container") + }) + .await; + + let mut result = container + .exec( + ExecCommand::new(["bash", "-c", POWERDNS_ZONE_INIT]) + .with_cmd_ready_condition(CmdWaitFor::exit()), + ) + .await + .expect("Failed to exec PowerDNS zone init"); + if result.exit_code().await.ok().flatten() != Some(0) { + let stdout = + String::from_utf8_lossy(&result.stdout_to_vec().await.unwrap_or_default()).into_owned(); + let stderr = + String::from_utf8_lossy(&result.stderr_to_vec().await.unwrap_or_default()).into_owned(); + panic!("PowerDNS zone init failed:\n{stdout}\n{stderr}"); + } + wait_for_tcp(5300).await; +} + +pub async fn ensure_openldap() { + const BOOTSTRAP_DIR: &str = "/container/service/slapd/assets/config/bootstrap/ldif/custom"; + OPENLDAP + .get_or_init(|| async { + GenericImage::new("osixia/openldap", "1.5.0") + .with_wait_for(WaitFor::message_on_stderr("slapd starting")) + .with_env_var("LDAP_ORGANISATION", "Stalwart Test") + .with_env_var("LDAP_DOMAIN", "stalwart.test") + .with_env_var("LDAP_BASE_DN", "dc=stalwart,dc=test") + .with_env_var("LDAP_ADMIN_PASSWORD", "admin") + .with_env_var("LDAP_TLS", "false") + .with_copy_to( + format!("{BOOTSTRAP_DIR}/50-users.ldif"), + include_bytes!("../../docker/ldap/50-users.ldif").to_vec(), + ) + .with_copy_to( + format!("{BOOTSTRAP_DIR}/60-groups.ldif"), + include_bytes!("../../docker/ldap/60-groups.ldif").to_vec(), + ) + .with_mapped_port(389, 389.tcp()) + .with_startup_timeout(READY_TIMEOUT) + .with_container_name("stalwart-test-openldap") + .with_reuse(ReuseDirective::Always) + .start() + .await + .expect("Failed to start OpenLDAP container") + }) + .await; + wait_for_tcp(389).await; +} + +async fn create_minio_bucket() { + use s3::{Bucket, BucketConfiguration, Region, creds::Credentials}; + + let region = Region::Custom { + region: "eu-central-1".to_string(), + endpoint: "http://localhost:9000".to_string(), + }; + let credentials = Credentials::new(Some("minioadmin"), Some("minioadmin"), None, None, None) + .expect("Failed to build MinIO credentials"); + + match Bucket::create_with_path_style( + "stalwart", + region, + credentials, + BucketConfiguration::default(), + ) + .await + { + Ok(response) if response.success() => {} + Ok(_) => {} + Err(s3::error::S3Error::HttpFailWithBody(409, _)) => {} + Err(err) => panic!("Failed to create MinIO bucket: {err:?}"), + } +} + +async fn wait_for_tcp(port: u16) { + let start = Instant::now(); + loop { + if TcpStream::connect(("127.0.0.1", port)).await.is_ok() { + return; + } + if start.elapsed() > READY_TIMEOUT { + panic!("Timed out waiting for TCP port {port}"); + } + tokio::time::sleep(Duration::from_millis(250)).await; + } +} + +async fn wait_for_http(url: &str) { + let client = reqwest::Client::builder() + .danger_accept_invalid_certs(true) + .build() + .expect("Failed to build HTTP client"); + let start = Instant::now(); + loop { + if let Ok(response) = client.get(url).send().await + && response.status().is_success() + { + return; + } + if start.elapsed() > READY_TIMEOUT { + panic!("Timed out waiting for {url}"); + } + tokio::time::sleep(Duration::from_millis(500)).await; + } +} diff --git a/tests/src/utils/mod.rs b/tests/src/utils/mod.rs index 3766ba68..538fa941 100644 --- a/tests/src/utils/mod.rs +++ b/tests/src/utils/mod.rs @@ -6,6 +6,7 @@ pub mod account; pub mod cleanup; +pub mod containers; pub mod dns; pub mod http; pub mod http_server; diff --git a/tests/src/utils/server.rs b/tests/src/utils/server.rs index 81d117b3..9def710c 100644 --- a/tests/src/utils/server.rs +++ b/tests/src/utils/server.rs @@ -113,7 +113,8 @@ impl TestServerBuilder { "running `STORE= cargo test`" )), &path, - ); + ) + .await; let store = Store::build(data_store).await.unwrap(); store.create_tables().await.unwrap(); diff --git a/tests/src/utils/storage.rs b/tests/src/utils/storage.rs index f067386f..d9bd0a69 100644 --- a/tests/src/utils/storage.rs +++ b/tests/src/utils/storage.rs @@ -14,9 +14,9 @@ use registry::{ prelude::Object, structs::{ BlobStore, DataStore, ElasticSearchStore, FileSystemStore, FoundationDbStore, HttpAuth, - HttpAuthBasic, InMemoryStore, MeilisearchStore, MySqlStore, PostgreSqlStore, - RedisStore, RocksDbStore, S3Store, S3StoreCustomRegion, S3StoreRegion, SearchStore, - SecretKey, SecretKeyOptional, SecretKeyValue, SqliteStore, + HttpAuthBasic, HttpAuthBearer, InMemoryStore, MeilisearchStore, MySqlStore, + PostgreSqlStore, RedisStore, RocksDbStore, S3Store, S3StoreCustomRegion, S3StoreRegion, + SearchStore, SecretKey, SecretKeyOptional, SecretKeyValue, SqliteStore, }, }, types::{EnumImpl, duration::Duration}, @@ -35,21 +35,21 @@ pub trait RegistryEnvStores { impl RegistryEnvStores for RegistryStore { async fn insert_stores_from_env(&self) { let path = self.path().as_os_str().to_str().unwrap(); - let search_store = std::env::var("SEARCH_STORE") - .map(|store| SearchStoreType::parse(&store).expect("Invalid store type")) - .map(|store| build_search_store(store, path)) - .map(Object::from) - .ok(); - let blob_store = std::env::var("BLOB_STORE") - .map(|store| BlobStoreType::parse(&store).expect("Invalid store type")) - .map(|store| build_blob_store(store, path)) - .map(Object::from) - .ok(); - let in_memory = std::env::var("MEMORY_STORE") - .map(|store| InMemoryStoreType::parse(&store).expect("Invalid store type")) - .map(|store| build_in_memory_store(store, path)) - .map(Object::from) - .ok(); + let mut search_store = None; + if let Ok(store) = std::env::var("SEARCH_STORE") { + let store = SearchStoreType::parse(&store).expect("Invalid store type"); + search_store = Some(Object::from(build_search_store(store, path).await)); + } + let mut blob_store = None; + if let Ok(store) = std::env::var("BLOB_STORE") { + let store = BlobStoreType::parse(&store).expect("Invalid store type"); + blob_store = Some(Object::from(build_blob_store(store, path).await)); + } + let mut in_memory = None; + if let Ok(store) = std::env::var("MEMORY_STORE") { + let store = InMemoryStoreType::parse(&store).expect("Invalid store type"); + in_memory = Some(Object::from(build_in_memory_store(store, path).await)); + } for store in [search_store, blob_store, in_memory].into_iter().flatten() { self.write(RegistryWrite::insert(&store)) @@ -60,7 +60,7 @@ impl RegistryEnvStores for RegistryStore { } } -pub fn build_data_store(typ: DataStoreType, path: &str) -> DataStore { +pub async fn build_data_store(typ: DataStoreType, path: &str) -> DataStore { match typ { DataStoreType::RocksDb => DataStore::RocksDb(RocksDbStore { path: format!("{path}/rocks.db"), @@ -70,49 +70,61 @@ pub fn build_data_store(typ: DataStoreType, path: &str) -> DataStore { path: format!("{path}/sqlite.db"), ..Default::default() }), - DataStoreType::FoundationDb => DataStore::FoundationDb(FoundationDbStore::default()), - DataStoreType::PostgreSql => DataStore::PostgreSql(PostgreSqlStore { - host: "localhost".into(), - port: 5432, - auth_username: "stalwart".to_string().into(), - auth_secret: SecretKeyOptional::Value(SecretKeyValue { - secret: "stalwart".into(), - }), - database: "stalwart".into(), - use_tls: false, - allow_invalid_certs: true, - ..Default::default() - }), - DataStoreType::MySql => DataStore::MySql(MySqlStore { - host: "localhost".into(), - port: 3307, - auth_username: "root".to_string().into(), - auth_secret: SecretKeyOptional::Value(SecretKeyValue { - secret: "password".into(), - }), - database: "stalwart".into(), - use_tls: false, - allow_invalid_certs: true, - ..Default::default() - }), + DataStoreType::FoundationDb => { + crate::utils::containers::ensure_foundationdb().await; + DataStore::FoundationDb(FoundationDbStore::default()) + } + DataStoreType::PostgreSql => { + crate::utils::containers::ensure_postgres().await; + DataStore::PostgreSql(PostgreSqlStore { + host: "localhost".into(), + port: 5432, + auth_username: "stalwart".to_string().into(), + auth_secret: SecretKeyOptional::Value(SecretKeyValue { + secret: "stalwart".into(), + }), + database: "stalwart".into(), + use_tls: false, + allow_invalid_certs: true, + ..Default::default() + }) + } + DataStoreType::MySql => { + crate::utils::containers::ensure_mysql().await; + DataStore::MySql(MySqlStore { + host: "localhost".into(), + port: 3307, + auth_username: "root".to_string().into(), + auth_secret: SecretKeyOptional::Value(SecretKeyValue { + secret: "password".into(), + }), + database: "stalwart".into(), + use_tls: false, + allow_invalid_certs: true, + ..Default::default() + }) + } } } -fn build_blob_store(typ: BlobStoreType, path: &str) -> BlobStore { +async fn build_blob_store(typ: BlobStoreType, path: &str) -> BlobStore { match typ { - BlobStoreType::S3 => BlobStore::S3(S3Store { - access_key: "minioadmin".to_string().into(), - bucket: "stalwart".into(), - region: S3StoreRegion::Custom(S3StoreCustomRegion { - custom_endpoint: "http://localhost:9000".into(), - custom_region: "eu-central-1".into(), - }), - secret_key: SecretKeyOptional::Value(SecretKeyValue { - secret: "minioadmin".into(), - }), - allow_invalid_certs: true, - ..Default::default() - }), + BlobStoreType::S3 => { + crate::utils::containers::ensure_minio().await; + BlobStore::S3(S3Store { + access_key: "minioadmin".to_string().into(), + bucket: "stalwart".into(), + region: S3StoreRegion::Custom(S3StoreCustomRegion { + custom_endpoint: "http://localhost:9000".into(), + custom_region: "eu-central-1".into(), + }), + secret_key: SecretKeyOptional::Value(SecretKeyValue { + secret: "minioadmin".into(), + }), + allow_invalid_certs: true, + ..Default::default() + }) + } BlobStoreType::FileSystem => BlobStore::FileSystem(FileSystemStore { path: path.to_string(), ..Default::default() @@ -121,35 +133,49 @@ fn build_blob_store(typ: BlobStoreType, path: &str) -> BlobStore { } } -fn build_in_memory_store(typ: InMemoryStoreType, _path: &str) -> InMemoryStore { +async fn build_in_memory_store(typ: InMemoryStoreType, _path: &str) -> InMemoryStore { match typ { - InMemoryStoreType::Redis => InMemoryStore::Redis(RedisStore { - url: "redis://127.0.0.1".into(), - ..Default::default() - }), + InMemoryStoreType::Redis => { + crate::utils::containers::ensure_redis().await; + InMemoryStore::Redis(RedisStore { + url: "redis://127.0.0.1".into(), + ..Default::default() + }) + } _ => unreachable!(), } } -fn build_search_store(typ: SearchStoreType, _path: &str) -> SearchStore { +async fn build_search_store(typ: SearchStoreType, _path: &str) -> SearchStore { match typ { - SearchStoreType::ElasticSearch => SearchStore::ElasticSearch(ElasticSearchStore { - url: "https://localhost:9200".into(), - allow_invalid_certs: true, - http_auth: HttpAuth::Basic(HttpAuthBasic { - username: "elastic".into(), - secret: SecretKey::Value(SecretKeyValue { - secret: "changeme".into(), + SearchStoreType::ElasticSearch => { + crate::utils::containers::ensure_opensearch().await; + SearchStore::ElasticSearch(ElasticSearchStore { + url: "http://localhost:9200".into(), + allow_invalid_certs: true, + http_auth: HttpAuth::Basic(HttpAuthBasic { + username: "elastic".into(), + secret: SecretKey::Value(SecretKeyValue { + secret: "changeme".into(), + }), }), - }), - ..Default::default() - }), - SearchStoreType::Meilisearch => SearchStore::Meilisearch(MeilisearchStore { - url: "http://localhost:7700".into(), - allow_invalid_certs: true, - poll_interval: Duration::from_millis(100), - ..Default::default() - }), + ..Default::default() + }) + } + SearchStoreType::Meilisearch => { + crate::utils::containers::ensure_meilisearch().await; + SearchStore::Meilisearch(MeilisearchStore { + url: "http://localhost:7700".into(), + allow_invalid_certs: true, + poll_interval: Duration::from_millis(100), + http_auth: HttpAuth::Bearer(HttpAuthBearer { + bearer_token: SecretKey::Value(SecretKeyValue { + secret: "stalwart-master-key".into(), + }), + }), + ..Default::default() + }) + } _ => unreachable!(), } }