myc

Self-custodial remote signer for Radroots apps
git clone https://radroots.dev/git/myc.git
Log | Files | Refs | README | LICENSE

commit 65d5531fc6109cce7580e809f87bb76c67365378
parent ef668a1744c2a08fcb48fcb597d81af36febca9f
Author: triesap <tyson@radroots.org>
Date:   Tue,  4 Aug 2026 13:28:43 +0000

test: isolate NIP-46 relay scenarios

- serialize stateful loopback relay cases
- bound each test runtime to one worker
- refresh the registry release cohort lock
- verify full tests and strict Clippy

Diffstat:
MCargo.lock | 168+++++++++++++++++++++++--------------------------------------------------------
MCargo.toml | 1+
Mtests/nip46_e2e.rs | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
3 files changed, 134 insertions(+), 161 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -1383,6 +1383,7 @@ dependencies = [ "rand 0.9.2", "serde", "serde_json", + "serial_test", "sha2", "sqlx", "tempfile", @@ -1405,9 +1406,9 @@ checksum = "f0efe882e02d206d8d279c20eb40e03baf7cb5136a1476dc084a324fbc3ec42d" [[package]] name = "nostr" -version = "0.44.2" +version = "0.44.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3aa5e3b6a278ed061835fe1ee293b71641e6bf8b401cfe4e1834bbf4ef0a34e1" +checksum = "c7d3d987ea7078dc36947cde532637c472a229426702e4331dd7667325378bd9" dependencies = [ "aes", "base64", @@ -1718,6 +1719,8 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "radroots_blossom" version = "0.1.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786aabfb3b884f1c01a2060c3bba57fed7d83ba6e7cddc2ce4e07d33fcc5a67d" dependencies = [ "mediatype", "serde", @@ -1729,6 +1732,8 @@ dependencies = [ [[package]] name = "radroots_core" version = "0.1.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e43ac2e488444ced1cddd6785d0a43552f887440c3f0506d9d2f90c7be30b26c" dependencies = [ "rust_decimal", "serde", @@ -1737,6 +1742,8 @@ dependencies = [ [[package]] name = "radroots_event" version = "0.1.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b1cfbf17b7c94ee0182c48042438ccc3c6c5979043a6ef300004935780408a2" dependencies = [ "hex", "jiff-tzdb", @@ -1754,6 +1761,8 @@ dependencies = [ [[package]] name = "radroots_event_codec" version = "0.1.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3344dee67769f76754d8713312f57f54301e9eac00584c26c51fb1b1aab9042" dependencies = [ "radroots_blossom", "radroots_core", @@ -1768,6 +1777,8 @@ dependencies = [ [[package]] name = "radroots_identity" version = "0.1.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95d406e0fa84faee0a87493358b4c45151271a12b0bc3d57aa0167b968680eea" dependencies = [ "k256", "serde", @@ -1777,6 +1788,8 @@ dependencies = [ [[package]] name = "radroots_nostr" version = "0.1.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcdd07611e98e10e89ce9ed80e39c6dcfd49b4bb59f72e661c21f47391b9b6e6" dependencies = [ "nostr", "radroots_event", @@ -1784,12 +1797,14 @@ dependencies = [ "radroots_identity", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] name = "radroots_nostr_connect" version = "0.1.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488dc2fbd9012d69672cbd2a34d9c542f9c32b45825645af38793f055bbe0894" dependencies = [ "nostr", "radroots_event", @@ -1805,6 +1820,8 @@ dependencies = [ [[package]] name = "radroots_protocol" version = "0.1.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "979c9e8217ccb11cfe1af3bf85145f3abcd4234dfc45f74801398598fd542d5a" dependencies = [ "serde", ] @@ -1812,6 +1829,8 @@ dependencies = [ [[package]] name = "radroots_secrets" version = "0.1.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd0cd239140eb4006f9adb9fe8037b58d79a12dcec4ff7e179ac78891cee3d8" dependencies = [ "chacha20poly1305", "keyring", @@ -1822,6 +1841,8 @@ dependencies = [ [[package]] name = "radroots_signing" version = "0.1.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3fa5a21d9e3aa6910303b866bcbd466243b6a797d5005fb591cd6e497a06c0b" dependencies = [ "radroots_event", "radroots_identity", @@ -2150,6 +2171,31 @@ dependencies = [ ] [[package]] +name = "serial_test" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "699f4197115b8a7e7ff19c9a315a4bd6fffec26cc4626ef45ecaea389e081c6d" +dependencies = [ + "futures-executor", + "futures-util", + "log", + "once_cell", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e153fc76e1c6a068703d6d29c508a0b15c061c4b7e43da59cc097bc342673c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "sha1" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3334,119 +3380,3 @@ name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" - -[[patch.unused]] -name = "radroots_authority" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_event_store" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_geonames" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_log" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_mesh" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_nostr_accounts" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_nostr_runtime" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_nostr_signer" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_nostrdb" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_outbox" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_protected_store" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_protocol_contract_v1" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_replica_schema" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_replica_store" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_replica_sync" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_runtime" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_runtime_paths" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_runtime_store" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_secret_vault" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_sql_core" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_storage" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_storage_sqlite" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_sync" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_test_fixtures" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_trade" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_transport" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_transport_nostr" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_transport_publish_protocol" -version = "0.1.0-alpha" - -[[patch.unused]] -name = "radroots_transport_reticulum" -version = "0.1.0-alpha" diff --git a/Cargo.toml b/Cargo.toml @@ -46,4 +46,5 @@ zeroize = "1.8" [dev-dependencies] futures-util = "0.3.32" +serial_test = "3" tokio-tungstenite = "0.26.2" diff --git a/tests/nip46_e2e.rs b/tests/nip46_e2e.rs @@ -808,7 +808,8 @@ async fn publish_external_request_and_wait_for_response( .await } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn packaged_final_client_interoperates_with_myc_server() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new(relay.url(), MycConnectionApproval::NotRequired); @@ -1034,7 +1035,8 @@ where .map_err(Into::into) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn live_listener_rejects_denied_clients_without_registering_connection() -> TestResult<()> { let relay = TestRelay::spawn().await?; let client_identity = @@ -1098,7 +1100,8 @@ async fn live_listener_rejects_denied_clients_without_registering_connection() - Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn live_listener_discards_malformed_and_replayed_request_events() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new(relay.url(), MycConnectionApproval::NotRequired); @@ -1205,7 +1208,8 @@ async fn live_listener_discards_malformed_and_replayed_request_events() -> TestR Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn live_listener_enforces_signing_ceiling_and_switch_relay_permission() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new_with_transport_config( @@ -1373,7 +1377,8 @@ async fn live_listener_enforces_signing_ceiling_and_switch_relay_permission() -> Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn external_nostr_client_compatibility_covers_connect_and_base_methods() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new(relay.url(), MycConnectionApproval::NotRequired); @@ -1445,7 +1450,8 @@ async fn external_nostr_client_compatibility_covers_connect_and_base_methods() - Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn external_nostr_client_compatibility_covers_signed_and_crypto_methods() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new(relay.url(), MycConnectionApproval::NotRequired); @@ -1604,7 +1610,8 @@ async fn external_nostr_client_compatibility_covers_signed_and_crypto_methods() Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn external_nostr_client_surfaces_pending_approval_state() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new(relay.url(), MycConnectionApproval::ExplicitUser); @@ -1662,7 +1669,8 @@ async fn external_nostr_client_surfaces_pending_approval_state() -> TestResult<( Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn external_nostr_client_surfaces_auth_challenge_state() -> TestResult<()> { let relay = TestRelay::spawn().await?; let client_identity = @@ -1719,7 +1727,8 @@ async fn external_nostr_client_surfaces_auth_challenge_state() -> TestResult<()> Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn external_nostr_client_ignores_unrelated_signer_events_before_response() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new(relay.url(), MycConnectionApproval::NotRequired); @@ -1764,7 +1773,8 @@ async fn external_nostr_client_ignores_unrelated_signer_events_before_response() Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn live_listener_consumes_connect_secret_only_after_successful_publish() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new(relay.url(), MycConnectionApproval::NotRequired); @@ -1939,7 +1949,8 @@ async fn live_listener_consumes_connect_secret_only_after_successful_publish() - Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn live_listener_acknowledges_logout_before_revoking_session() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new(relay.url(), MycConnectionApproval::NotRequired); @@ -2084,7 +2095,8 @@ async fn live_listener_acknowledges_logout_before_revoking_session() -> TestResu Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn failed_logout_publish_is_retried_and_revoked_during_startup_recovery() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new(relay.url(), MycConnectionApproval::NotRequired); @@ -2189,7 +2201,8 @@ async fn failed_logout_publish_is_retried_and_revoked_during_startup_recovery() Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn published_logout_acknowledgement_is_finalized_without_republish_on_restart() -> TestResult<()> { let relay = TestRelay::spawn().await?; @@ -2270,7 +2283,8 @@ async fn published_logout_acknowledgement_is_finalized_without_republish_on_rest Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn live_listener_works_with_sqlite_signer_state_and_runtime_audit() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new_with_transport_config( @@ -2473,7 +2487,8 @@ async fn live_listener_works_with_sqlite_signer_state_and_runtime_audit() -> Tes Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn external_nostr_client_recovers_connect_response_after_restart() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new(relay.url(), MycConnectionApproval::NotRequired); @@ -2609,7 +2624,8 @@ async fn external_nostr_client_recovers_connect_response_after_restart() -> Test Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn startup_recovery_republishes_queued_listener_connect_secret_job() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new_with_transport_relays( @@ -2711,7 +2727,8 @@ async fn startup_recovery_republishes_queued_listener_connect_secret_job() -> Te Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn startup_recovery_republishes_queued_connect_accept_job() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new(relay.url(), MycConnectionApproval::NotRequired); @@ -2812,7 +2829,8 @@ async fn startup_recovery_republishes_queued_connect_accept_job() -> TestResult< Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn startup_recovery_republishes_queued_auth_replay_job() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new(relay.url(), MycConnectionApproval::ExplicitUser); @@ -2920,7 +2938,8 @@ async fn startup_recovery_republishes_queued_auth_replay_job() -> TestResult<()> Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn trusted_client_reauths_after_authorized_ttl() -> TestResult<()> { let relay = TestRelay::spawn().await?; let client_identity = @@ -3090,7 +3109,8 @@ async fn trusted_client_reauths_after_authorized_ttl() -> TestResult<()> { Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn connect_accept_retries_without_consuming_secret_until_publish_succeeds() -> TestResult<()> { let relay = TestRelay::spawn().await?; @@ -3255,7 +3275,8 @@ async fn connect_accept_retries_without_consuming_secret_until_publish_succeeds( Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn connect_accept_succeeds_with_any_delivery_policy_when_one_relay_acknowledges() -> TestResult<()> { let relay_a = TestRelay::spawn().await?; @@ -3326,7 +3347,8 @@ async fn connect_accept_succeeds_with_any_delivery_policy_when_one_relay_acknowl Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn connect_accept_rejects_when_quorum_delivery_policy_is_not_met() -> TestResult<()> { let relay_a = TestRelay::spawn().await?; let relay_b = TestRelay::spawn().await?; @@ -3420,7 +3442,8 @@ async fn connect_accept_rejects_when_quorum_delivery_policy_is_not_met() -> Test Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn live_listener_retries_until_all_delivery_policy_is_met() -> TestResult<()> { let relay_a = TestRelay::spawn().await?; let relay_b = TestRelay::spawn().await?; @@ -3510,7 +3533,8 @@ async fn live_listener_retries_until_all_delivery_policy_is_met() -> TestResult< Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn auth_replay_restores_pending_request_until_publish_succeeds() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = MycTestRuntime::new(relay.url(), MycConnectionApproval::NotRequired); @@ -3687,7 +3711,8 @@ async fn auth_replay_restores_pending_request_until_publish_succeeds() -> TestRe Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn explicit_nip89_publish_uses_app_identity_and_records_audit() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = @@ -3770,7 +3795,8 @@ async fn explicit_nip89_publish_uses_app_identity_and_records_audit() -> TestRes Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn startup_recovery_republishes_queued_discovery_publish_job() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = @@ -3837,7 +3863,8 @@ async fn startup_recovery_republishes_queued_discovery_publish_job() -> TestResu Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn startup_recovery_finalizes_published_discovery_publish_job() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = @@ -3914,7 +3941,8 @@ async fn startup_recovery_finalizes_published_discovery_publish_job() -> TestRes Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn explicit_nip89_publish_retries_cleanly_after_rejection() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = @@ -4020,7 +4048,8 @@ async fn explicit_nip89_publish_retries_cleanly_after_rejection() -> TestResult< Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn fetch_live_nip89_reports_missing_when_handler_is_unpublished() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = @@ -4040,7 +4069,8 @@ async fn fetch_live_nip89_reports_missing_when_handler_is_unpublished() -> TestR Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn fetch_live_nip89_fails_when_all_discovery_relays_are_unavailable() -> TestResult<()> { let unavailable_a = unavailable_relay_url()?; let unavailable_b = unavailable_relay_url()?; @@ -4072,7 +4102,8 @@ async fn fetch_live_nip89_fails_when_all_discovery_relays_are_unavailable() -> T Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn fetch_live_nip89_parallelizes_relay_fetch_and_preserves_configured_order() -> TestResult<()> { let live_relay = TestRelay::spawn().await?; @@ -4160,7 +4191,8 @@ async fn fetch_live_nip89_parallelizes_relay_fetch_and_preserves_configured_orde Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn diff_live_nip89_reports_matched_after_publish() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = @@ -4203,7 +4235,8 @@ async fn diff_live_nip89_reports_matched_after_publish() -> TestResult<()> { Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn refresh_nip89_publishes_when_live_handler_is_missing() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = @@ -4282,7 +4315,8 @@ async fn refresh_nip89_publishes_when_live_handler_is_missing() -> TestResult<() Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn refresh_nip89_repairs_missing_relays_without_republishing_matched_relays() -> TestResult<()> { let relay_a = TestRelay::spawn().await?; @@ -4370,7 +4404,8 @@ async fn refresh_nip89_repairs_missing_relays_without_republishing_matched_relay Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn refresh_nip89_skips_when_live_handler_matches() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = @@ -4430,7 +4465,8 @@ async fn refresh_nip89_skips_when_live_handler_matches() -> TestResult<()> { Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn refresh_nip89_republishes_when_live_handler_drifted() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = @@ -4506,7 +4542,8 @@ async fn refresh_nip89_republishes_when_live_handler_drifted() -> TestResult<()> Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn refresh_nip89_repairs_drifted_relays_without_force_when_other_relays_match() -> TestResult<()> { let relay_a = TestRelay::spawn().await?; @@ -4598,7 +4635,8 @@ async fn refresh_nip89_repairs_drifted_relays_without_force_when_other_relays_ma Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn refresh_nip89_reports_remaining_relays_after_mixed_targeted_repair() -> TestResult<()> { let relay_a = TestRelay::spawn().await?; let relay_b = TestRelay::spawn().await?; @@ -4714,7 +4752,8 @@ async fn refresh_nip89_reports_remaining_relays_after_mixed_targeted_repair() -> Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn diff_live_nip89_reports_conflicted_when_live_groups_disagree() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime = @@ -4752,7 +4791,8 @@ async fn diff_live_nip89_reports_conflicted_when_live_groups_disagree() -> TestR Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn diff_live_nip89_surfaces_relay_divergence_with_provenance() -> TestResult<()> { let relay_a = TestRelay::spawn().await?; let relay_b = TestRelay::spawn().await?; @@ -4859,7 +4899,8 @@ async fn diff_live_nip89_surfaces_relay_divergence_with_provenance() -> TestResu Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn refresh_nip89_requires_force_when_any_discovery_relay_is_unavailable() -> TestResult<()> { let relay = TestRelay::spawn().await?; let unavailable_relay = unavailable_relay_url()?; @@ -4941,7 +4982,8 @@ async fn refresh_nip89_requires_force_when_any_discovery_relay_is_unavailable() Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[serial_test::serial] async fn refresh_nip89_requires_force_when_live_handler_is_conflicted() -> TestResult<()> { let relay = TestRelay::spawn().await?; let test_runtime =