lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

commit b0240e02c7e0ef9fcbd27e43c3ea138955d9f4cd
parent e974c31239f39fd6f7a7c645aef7f0d18c7d8e02
Author: triesap <tyson@radroots.org>
Date:   Sun, 22 Mar 2026 15:38:05 +0000

tests: add approved fixtures for events-codec

- add the radroots-test-fixtures crate with approved identities and url constants
- wire the fixture crate into the workspace and radroots-events-codec dev-dependencies
- migrate events-codec tests and in-module test blocks to approved fixture imports
- verify with /nix/var/nix/profiles/default/bin/nix develop -c env CARGO_TARGET_DIR=target/rr-bnr-1-noinc CARGO_INCREMENTAL=0 cargo test -p radroots-events-codec -j 1

Diffstat:
MCargo.lock | 5+++++
MCargo.toml | 2++
Mcrates/events-codec/Cargo.toml | 3+++
Mcrates/events-codec/src/coop/list_sets.rs | 7++++---
Mcrates/events-codec/src/document/encode.rs | 13+++++++------
Mcrates/events-codec/src/farm/list_sets.rs | 3++-
Mcrates/events-codec/src/listing/tags.rs | 18++++++++++++------
Mcrates/events-codec/src/message/tags.rs | 9+++++----
Mcrates/events-codec/src/resource_area/list_sets.rs | 5+++--
Mcrates/events-codec/src/resource_cap/encode.rs | 4++--
Mcrates/events-codec/tests/codec_error_job.rs | 15+++++----------
Mcrates/events-codec/tests/domain_encode_non_serde.rs | 3++-
Mcrates/events-codec/tests/event_ref.rs | 30+++++++++++-------------------
Mcrates/events-codec/tests/follow.rs | 13+++++++------
Mcrates/events-codec/tests/gift_wrap.rs | 11++++++-----
Mcrates/events-codec/tests/job_request.rs | 7++++---
Mcrates/events-codec/tests/job_result.rs | 7++++---
Mcrates/events-codec/tests/job_traits.rs | 13+++++--------
Mcrates/events-codec/tests/job_util.rs | 13+++++++------
Mcrates/events-codec/tests/list_set.rs | 14++++++++++----
Mcrates/events-codec/tests/message.rs | 21+++++++++++----------
Mcrates/events-codec/tests/message_file.rs | 147+++++++++++++++++++++++++------------------------------------------------------
Mcrates/events-codec/tests/structured_decode.rs | 5+++--
Mcrates/events-codec/tests/structured_encode_default.rs | 10++++------
Mcrates/events-codec/tests/tag_builders.rs | 35+++++++++++++++++++++--------------
Acrates/test-fixtures/Cargo.toml | 11+++++++++++
Acrates/test-fixtures/src/lib.rs | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
27 files changed, 308 insertions(+), 222 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -2125,6 +2125,7 @@ dependencies = [ "nostr", "radroots-core", "radroots-events", + "radroots-test-fixtures", "serde", "serde_json", ] @@ -2443,6 +2444,10 @@ dependencies = [ ] [[package]] +name = "radroots-test-fixtures" +version = "0.1.0-alpha.1" + +[[package]] name = "radroots-trade" version = "0.1.0-alpha.1" dependencies = [ diff --git a/Cargo.toml b/Cargo.toml @@ -21,6 +21,7 @@ members = [ "crates/sql-wasm-bridge", "crates/sql-wasm-core", "crates/sql-core", + "crates/test-fixtures", "crates/replica-db-schema", "crates/replica-sync", "crates/replica-sync-wasm", @@ -62,6 +63,7 @@ radroots-simplex-smp-proto = { path = "crates/simplex-smp-proto", version = "0.1 radroots-sql-wasm-bridge = { path = "crates/sql-wasm-bridge", version = "0.1.0-alpha.1" } radroots-sql-wasm-core = { path = "crates/sql-wasm-core", version = "0.1.0-alpha.1", default-features = false } radroots-sql-core = { path = "crates/sql-core", version = "0.1.0-alpha.1" } +radroots-test-fixtures = { path = "crates/test-fixtures", version = "0.1.0-alpha.1" } radroots-replica-db-schema = { path = "crates/replica-db-schema", version = "0.1.0-alpha.1", default-features = false } radroots-replica-sync = { path = "crates/replica-sync", version = "0.1.0-alpha.1", default-features = false } radroots-replica-db = { path = "crates/replica-db", version = "0.1.0-alpha.1", default-features = false } diff --git a/crates/events-codec/Cargo.toml b/crates/events-codec/Cargo.toml @@ -30,3 +30,6 @@ serde_json = { workspace = true, default-features = false, features = [ "alloc", ], optional = true } nostr = { workspace = true, optional = true } + +[dev-dependencies] +radroots-test-fixtures = { workspace = true } diff --git a/crates/events-codec/src/coop/list_sets.rs b/crates/events-codec/src/coop/list_sets.rs @@ -182,6 +182,7 @@ where #[cfg(test)] mod tests { use super::*; + use radroots_test_fixtures::FIXTURE_ALICE_PUBLIC_KEY_HEX; #[test] fn coop_list_set_id_validates_coop_id() { @@ -243,7 +244,7 @@ mod tests { )); let err = farm_address(&RadrootsFarmRef { - pubkey: "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62".to_string(), + pubkey: FIXTURE_ALICE_PUBLIC_KEY_HEX.to_string(), d_tag: " ".to_string(), }) .expect_err("expected empty d_tag error"); @@ -253,7 +254,7 @@ mod tests { )); let err = farm_address(&RadrootsFarmRef { - pubkey: "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62".to_string(), + pubkey: FIXTURE_ALICE_PUBLIC_KEY_HEX.to_string(), d_tag: "invalid".to_string(), }) .expect_err("expected invalid d_tag error"); @@ -329,7 +330,7 @@ mod tests { #[test] fn coop_members_farms_list_set_covers_success_and_invalid_coop_id() { let farms = vec![RadrootsFarmRef { - pubkey: "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62".to_string(), + pubkey: FIXTURE_ALICE_PUBLIC_KEY_HEX.to_string(), d_tag: "AAAAAAAAAAAAAAAAAAAAAA".to_string(), }]; let list_set = coop_members_farms_list_set("AAAAAAAAAAAAAAAAAAAAAA", farms.clone()) diff --git a/crates/events-codec/src/document/encode.rs b/crates/events-codec/src/document/encode.rs @@ -91,6 +91,11 @@ pub fn to_wire_parts_with_kind( mod tests { use super::*; use radroots_events::document::RadrootsDocumentSubject; + use radroots_test_fixtures::FIXTURE_ALICE_PUBLIC_KEY_HEX; + + fn sample_document_address() -> String { + format!("30340:{FIXTURE_ALICE_PUBLIC_KEY_HEX}:AAAAAAAAAAAAAAAAAAAAAA") + } fn sample_document() -> RadrootsDocument { RadrootsDocument { @@ -102,12 +107,8 @@ mod tests { effective_at: None, body_markdown: None, subject: RadrootsDocumentSubject { - pubkey: "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62" - .to_string(), - address: Some( - "30340:58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62:AAAAAAAAAAAAAAAAAAAAAA" - .to_string(), - ), + pubkey: FIXTURE_ALICE_PUBLIC_KEY_HEX.to_string(), + address: Some(sample_document_address()), }, tags: None, } diff --git a/crates/events-codec/src/farm/list_sets.rs b/crates/events-codec/src/farm/list_sets.rs @@ -215,6 +215,7 @@ where #[cfg(test)] mod tests { use super::*; + use radroots_test_fixtures::FIXTURE_ALICE_PUBLIC_KEY_HEX; #[test] fn farm_list_set_id_validates_farm_id() { @@ -228,7 +229,7 @@ mod tests { #[test] fn farm_list_set_builders_cover_success_and_error_paths() { let farm_id = "AAAAAAAAAAAAAAAAAAAAAA"; - let farm_pubkey = "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62"; + let farm_pubkey = FIXTURE_ALICE_PUBLIC_KEY_HEX; let err = farm_members_list_set("invalid", ["member-a"]).expect_err("invalid farm id"); assert!(matches!(err, EventEncodeError::InvalidField("farm_id"))); diff --git a/crates/events-codec/src/listing/tags.rs b/crates/events-codec/src/listing/tags.rs @@ -620,13 +620,19 @@ mod tests { use radroots_events::listing::{ RadrootsListingImageSize, RadrootsListingProduct, RadrootsListingStatus, }; + use radroots_test_fixtures::{ + CDN_PRIMARY_HTTPS, FIXTURE_ALICE_NPUB, FIXTURE_ALICE_PUBLIC_KEY_HEX, + }; - const TEST_NPUB: &str = "npub1tr33s4tj2le2kk9yzhfphdtss26gyn8kv7savnnjhj794nqp333q8e7grr"; - const TEST_PUBKEY_HEX: &str = - "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62"; + const TEST_NPUB: &str = FIXTURE_ALICE_NPUB; + const TEST_PUBKEY_HEX: &str = FIXTURE_ALICE_PUBLIC_KEY_HEX; const TEST_D_TAG: &str = "AAAAAAAAAAAAAAAAAAAAAg"; const TEST_FARM_D_TAG: &str = "AAAAAAAAAAAAAAAAAAAAAA"; + fn cdn_url(path: &str) -> String { + format!("{CDN_PRIMARY_HTTPS}/{path}") + } + fn decimal(value: &str) -> RadrootsCoreDecimal { RadrootsCoreDecimal::from_str(value).expect("valid decimal") } @@ -701,7 +707,7 @@ mod tests { }), images: Some(vec![ RadrootsListingImage { - url: "https://example.com/a.jpg".to_string(), + url: cdn_url("a.jpg"), size: Some(RadrootsListingImageSize { w: 1200, h: 800 }), }, RadrootsListingImage { @@ -935,7 +941,7 @@ mod tests { #[test] fn image_and_status_helpers_cover_variants() { let with_size = tag_listing_image(&RadrootsListingImage { - url: " https://example.com/a.jpg ".to_string(), + url: format!(" {CDN_PRIMARY_HTTPS}/a.jpg "), size: Some(RadrootsListingImageSize { w: 10, h: 20 }), }) .expect("image tag"); @@ -943,7 +949,7 @@ mod tests { assert_eq!(with_size[2], "10x20"); let without_size = tag_listing_image(&RadrootsListingImage { - url: "https://example.com/b.jpg".to_string(), + url: cdn_url("b.jpg"), size: None, }) .expect("image tag"); diff --git a/crates/events-codec/src/message/tags.rs b/crates/events-codec/src/message/tags.rs @@ -156,6 +156,7 @@ pub(crate) fn parse_subject_tag(tags: &[Vec<String>]) -> Result<Option<String>, mod tests { use super::*; use radroots_events::{RadrootsNostrEventPtr, message::RadrootsMessageRecipient}; + use radroots_test_fixtures::RELAY_PRIMARY_WSS; #[test] fn parse_recipients_rejects_missing_p_tags() { @@ -199,7 +200,7 @@ mod tests { fn build_and_parse_reply_tags_cover_optional_relay_paths() { let tag = build_reply_tag(&Some(RadrootsNostrEventPtr { id: "reply".to_string(), - relays: Some("wss://relay.example.com".to_string()), + relays: Some(RELAY_PRIMARY_WSS.to_string()), })) .expect("build reply tag") .expect("reply tag"); @@ -207,7 +208,7 @@ mod tests { let parsed = parse_reply_tag(&[tag]).expect("parse reply"); assert_eq!( parsed.and_then(|value| value.relays), - Some("wss://relay.example.com".to_string()) + Some(RELAY_PRIMARY_WSS.to_string()) ); let tag = build_reply_tag(&Some(RadrootsNostrEventPtr { @@ -244,7 +245,7 @@ mod tests { let tags = build_recipient_tags(&[RadrootsMessageRecipient { public_key: "recipient".to_string(), - relay_url: Some("wss://relay.example.com".to_string()), + relay_url: Some(RELAY_PRIMARY_WSS.to_string()), }]) .expect("recipient tag"); assert_eq!(tags.len(), 1); @@ -296,7 +297,7 @@ mod tests { vec![ "p".to_string(), "recipient-2".to_string(), - "wss://relay.example.com".to_string(), + RELAY_PRIMARY_WSS.to_string(), ], ]) .expect("parse recipients"); diff --git a/crates/events-codec/src/resource_area/list_sets.rs b/crates/events-codec/src/resource_area/list_sets.rs @@ -158,6 +158,7 @@ where #[cfg(test)] mod tests { use super::*; + use radroots_test_fixtures::{FIXTURE_ALICE_PUBLIC_KEY_HEX, FIXTURE_BOB_PUBLIC_KEY_HEX}; #[test] fn resource_list_set_id_validates_area_id() { @@ -244,8 +245,8 @@ mod tests { #[test] fn resource_area_list_set_builders_cover_success_and_error_paths() { let area_id = "AAAAAAAAAAAAAAAAAAAAAA"; - let farm_pubkey = "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62"; - let plot_pubkey = "1487cc4a73c21190f2e518314a4f2b8995f546f2f2f56600fdf45be7d1676763"; + let farm_pubkey = FIXTURE_ALICE_PUBLIC_KEY_HEX; + let plot_pubkey = FIXTURE_BOB_PUBLIC_KEY_HEX; let err = resource_area_members_farms_list_set( "invalid", diff --git a/crates/events-codec/src/resource_cap/encode.rs b/crates/events-codec/src/resource_cap/encode.rs @@ -108,13 +108,13 @@ mod tests { use radroots_core::{RadrootsCoreDecimal, RadrootsCoreQuantity, RadrootsCoreUnit}; use radroots_events::resource_area::RadrootsResourceAreaRef; use radroots_events::resource_cap::RadrootsResourceHarvestProduct; + use radroots_test_fixtures::FIXTURE_ALICE_PUBLIC_KEY_HEX; fn sample_cap_with_category(category: Option<&str>) -> RadrootsResourceHarvestCap { RadrootsResourceHarvestCap { d_tag: "AAAAAAAAAAAAAAAAAAAABA".to_string(), resource_area: RadrootsResourceAreaRef { - pubkey: "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62" - .to_string(), + pubkey: FIXTURE_ALICE_PUBLIC_KEY_HEX.to_string(), d_tag: "AAAAAAAAAAAAAAAAAAAAAw".to_string(), }, product: RadrootsResourceHarvestProduct { diff --git a/crates/events-codec/tests/codec_error_job.rs b/crates/events-codec/tests/codec_error_job.rs @@ -7,6 +7,7 @@ use radroots_events_codec::job::encode::{ }; use radroots_events_codec::job::error::JobParseError; use radroots_events_codec::profile::error::ProfileEncodeError; +use radroots_test_fixtures::{FIXTURE_ALICE_PUBLIC_KEY_HEX, RELAY_PRIMARY_WSS}; #[cfg(feature = "serde_json")] use serde::Serialize; #[cfg(feature = "serde_json")] @@ -63,11 +64,8 @@ fn job_encode_helpers_cover_status_provider_relay_and_inputs() { let mut tags: Vec<Vec<String>> = Vec::new(); push_status_tag(&mut tags, "ok", None); push_status_tag(&mut tags, "warning", Some("detail")); - push_provider_tag( - &mut tags, - "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62", - ); - push_relay_tag(&mut tags, "wss://relay.example.com"); + push_provider_tag(&mut tags, FIXTURE_ALICE_PUBLIC_KEY_HEX); + push_relay_tag(&mut tags, RELAY_PRIMARY_WSS); assert_eq!(tags[0], vec!["status".to_string(), "ok".to_string()]); assert_eq!( @@ -80,14 +78,11 @@ fn job_encode_helpers_cover_status_provider_relay_and_inputs() { ); assert_eq!( tags[2], - vec![ - "p".to_string(), - "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62".to_string(), - ] + vec!["p".to_string(), FIXTURE_ALICE_PUBLIC_KEY_HEX.to_string(),] ); assert_eq!( tags[3], - vec!["relays".to_string(), "wss://relay.example.com".to_string()] + vec!["relays".to_string(), RELAY_PRIMARY_WSS.to_string()] ); assert!(assert_no_inputs_when_encrypted(&tags)); diff --git a/crates/events-codec/tests/domain_encode_non_serde.rs b/crates/events-codec/tests/domain_encode_non_serde.rs @@ -39,8 +39,9 @@ use radroots_events_codec::resource_area::list_sets::{ resource_area_stewards_list_set, }; use radroots_events_codec::resource_cap::encode::resource_harvest_cap_build_tags; +use radroots_test_fixtures::FIXTURE_ALICE_PUBLIC_KEY_HEX; -const VALID_PUBKEY: &str = "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62"; +const VALID_PUBKEY: &str = FIXTURE_ALICE_PUBLIC_KEY_HEX; const VALID_FARM_D_TAG: &str = "AAAAAAAAAAAAAAAAAAAAAA"; const VALID_PLOT_D_TAG: &str = "AAAAAAAAAAAAAAAAAAAAAQ"; const VALID_COOP_D_TAG: &str = "BAAAAAAAAAAAAAAAAAAAAA"; diff --git a/crates/events-codec/tests/event_ref.rs b/crates/events-codec/tests/event_ref.rs @@ -6,6 +6,7 @@ use radroots_events_codec::event_ref::{ build_event_ref_tag, find_event_ref_tag, parse_event_ref_tag, parse_nip10_ref_tags, push_nip10_ref_tags, }; +use radroots_test_fixtures::{RELAY_PRIMARY_WSS, RELAY_SECONDARY_WSS, RELAY_TERTIARY_WSS}; #[test] fn build_and_parse_roundtrip_with_d_tag_and_relays() { @@ -135,7 +136,7 @@ fn push_and_parse_nip10_ref_tags_roundtrip_with_and_without_a_tag() { "author", KIND_POST, "AAAAAAAAAAAAAAAAAAAAAA", - Some(vec!["wss://relay.example.com".to_string()]), + Some(vec![RELAY_PRIMARY_WSS.to_string()]), ); let mut tags = Vec::new(); push_nip10_ref_tags(&mut tags, &event, "e", "p", "k", "a"); @@ -252,35 +253,29 @@ fn parse_nip10_ref_tags_prefers_e_relays_and_can_fall_back_to_a_relays() { vec![ "a".to_string(), format!("{}:{}:{}", KIND_POST, "author", "AAAAAAAAAAAAAAAAAAAAAA"), - "wss://relay.a.example.com".to_string(), + RELAY_SECONDARY_WSS.to_string(), ], ]; let parsed = parse_nip10_ref_tags(&tags, "e", "p", "k", "a").unwrap(); assert_eq!(parsed.d_tag.as_deref(), Some("AAAAAAAAAAAAAAAAAAAAAA")); - assert_eq!( - parsed.relays, - Some(vec!["wss://relay.a.example.com".to_string()]) - ); + assert_eq!(parsed.relays, Some(vec![RELAY_SECONDARY_WSS.to_string()])); let tags = vec![ vec![ "e".to_string(), "id".to_string(), - "wss://relay.e.example.com".to_string(), + RELAY_PRIMARY_WSS.to_string(), ], vec!["p".to_string(), "author".to_string()], vec!["k".to_string(), KIND_POST.to_string()], vec![ "a".to_string(), format!("{}:{}:{}", KIND_POST, "author", "AAAAAAAAAAAAAAAAAAAAAA"), - "wss://relay.a.example.com".to_string(), + RELAY_SECONDARY_WSS.to_string(), ], ]; let parsed = parse_nip10_ref_tags(&tags, "e", "p", "k", "a").unwrap(); - assert_eq!( - parsed.relays, - Some(vec!["wss://relay.e.example.com".to_string()]) - ); + assert_eq!(parsed.relays, Some(vec![RELAY_PRIMARY_WSS.to_string()])); } #[test] @@ -298,7 +293,7 @@ fn parse_nip10_ref_tags_skips_invalid_a_tags_until_match() { "author", "AAAAAAAAAAAAAAAAAAAAAA" ), - "wss://relay.bad-kind.example.com".to_string(), + RELAY_PRIMARY_WSS.to_string(), ], vec![ "a".to_string(), @@ -306,21 +301,18 @@ fn parse_nip10_ref_tags_skips_invalid_a_tags_until_match() { "{}:{}:{}", KIND_POST, "other-author", "AAAAAAAAAAAAAAAAAAAAAA" ), - "wss://relay.bad-author.example.com".to_string(), + RELAY_SECONDARY_WSS.to_string(), ], vec![ "a".to_string(), format!("{}:{}:", KIND_POST, "author"), - "wss://relay.empty-d.example.com".to_string(), + RELAY_TERTIARY_WSS.to_string(), ], ]; let parsed = parse_nip10_ref_tags(&tags, "e", "p", "k", "a").unwrap(); assert!(parsed.d_tag.is_none()); - assert_eq!( - parsed.relays, - Some(vec!["wss://relay.empty-d.example.com".to_string()]) - ); + assert_eq!(parsed.relays, Some(vec![RELAY_TERTIARY_WSS.to_string()])); let tags = vec![ vec!["e".to_string(), "id".to_string()], diff --git a/crates/events-codec/tests/follow.rs b/crates/events-codec/tests/follow.rs @@ -9,6 +9,7 @@ use radroots_events_codec::follow::encode::{ FollowMutation, follow_apply, follow_to_wire_parts_after, to_wire_parts, to_wire_parts_with_kind, }; +use radroots_test_fixtures::{RELAY_PRIMARY_WSS, RELAY_SECONDARY_WSS}; #[test] fn follow_to_wire_parts_builds_p_tags() { @@ -147,7 +148,7 @@ fn follow_metadata_and_index_from_event_roundtrip() { let tags = vec![vec![ "p".to_string(), "pubkey".to_string(), - "wss://relay.example.com".to_string(), + RELAY_PRIMARY_WSS.to_string(), "alice".to_string(), "88".to_string(), ]]; @@ -169,7 +170,7 @@ fn follow_metadata_and_index_from_event_roundtrip() { assert_eq!(metadata.data.list[0].public_key, "pubkey"); assert_eq!( metadata.data.list[0].relay_url.as_deref(), - Some("wss://relay.example.com") + Some(RELAY_PRIMARY_WSS) ); assert_eq!(metadata.data.list[0].contact_name.as_deref(), Some("alice")); @@ -443,7 +444,7 @@ fn follow_to_wire_parts_with_kind_and_after_mutation_work() { &follow, FollowMutation::Toggle { public_key: "pubkey-b".to_string(), - relay_url: Some("wss://relay.example.com".to_string()), + relay_url: Some(RELAY_PRIMARY_WSS.to_string()), contact_name: Some("alice".to_string()), }, ) @@ -465,7 +466,7 @@ fn follow_apply_normalizes_optional_fields_and_deduplicates_existing_list() { RadrootsFollowProfile { published_at: 2, public_key: "pubkey-a".to_string(), - relay_url: Some("wss://duplicate.example.com".to_string()), + relay_url: Some(RELAY_SECONDARY_WSS.to_string()), contact_name: Some("duplicate".to_string()), }, ], @@ -493,7 +494,7 @@ fn follow_apply_follow_with_none_preserves_existing_values() { list: vec![RadrootsFollowProfile { published_at: 1, public_key: "pubkey-a".to_string(), - relay_url: Some("wss://relay.example.com".to_string()), + relay_url: Some(RELAY_PRIMARY_WSS.to_string()), contact_name: Some("alice".to_string()), }], }; @@ -510,7 +511,7 @@ fn follow_apply_follow_with_none_preserves_existing_values() { assert_eq!(updated.list.len(), 1); assert_eq!( updated.list[0].relay_url.as_deref(), - Some("wss://relay.example.com") + Some(RELAY_PRIMARY_WSS) ); assert_eq!(updated.list[0].contact_name.as_deref(), Some("alice")); } diff --git a/crates/events-codec/tests/gift_wrap.rs b/crates/events-codec/tests/gift_wrap.rs @@ -8,12 +8,13 @@ use radroots_events_codec::gift_wrap::decode::{ use radroots_events_codec::gift_wrap::encode::{ gift_wrap_build_tags, to_wire_parts, to_wire_parts_with_kind, }; +use radroots_test_fixtures::RELAY_PRIMARY_WSS; fn sample_gift_wrap() -> RadrootsGiftWrap { RadrootsGiftWrap { recipient: RadrootsGiftWrapRecipient { public_key: "pubkey".to_string(), - relay_url: Some("wss://relay.example".to_string()), + relay_url: Some(RELAY_PRIMARY_WSS.to_string()), }, content: "encrypted".to_string(), expiration: Some(1700000000), @@ -45,7 +46,7 @@ fn gift_wrap_to_wire_parts_sets_kind_content_and_tags() { vec![ "p".to_string(), "pubkey".to_string(), - "wss://relay.example".to_string() + RELAY_PRIMARY_WSS.to_string() ], vec!["expiration".to_string(), "1700000000".to_string()], ] @@ -84,7 +85,7 @@ fn gift_wrap_from_tags_rejects_invalid_expiration_and_relay() { vec![ "p".to_string(), "pubkey".to_string(), - "wss://relay.example".to_string(), + RELAY_PRIMARY_WSS.to_string(), ], vec!["expiration".to_string(), " ".to_string()], ], @@ -99,7 +100,7 @@ fn gift_wrap_from_tags_rejects_invalid_expiration_and_relay() { vec![ "p".to_string(), "pubkey".to_string(), - "wss://relay.example".to_string(), + RELAY_PRIMARY_WSS.to_string(), ], vec!["expiration".to_string(), "invalid".to_string()], ], @@ -173,7 +174,7 @@ fn gift_wrap_build_tags_handles_optional_expiration_and_invalid_relay() { vec![vec![ "p".to_string(), "pubkey".to_string(), - "wss://relay.example".to_string() + RELAY_PRIMARY_WSS.to_string() ]] ); diff --git a/crates/events-codec/tests/job_request.rs b/crates/events-codec/tests/job_request.rs @@ -5,14 +5,15 @@ use radroots_events_codec::job::encode::JobEncodeError; use radroots_events_codec::job::error::JobParseError; use radroots_events_codec::job::request::decode::{job_request_from_tags, parsed_from_event}; use radroots_events_codec::job::request::encode::to_wire_parts; +use radroots_test_fixtures::{APP_PRIMARY_HTTPS, RELAY_PRIMARY_WSS}; fn sample_request() -> RadrootsJobRequest { RadrootsJobRequest { kind: (KIND_JOB_REQUEST_MIN + 1) as u16, inputs: vec![RadrootsJobInput { - data: "https://example.com".to_string(), + data: APP_PRIMARY_HTTPS.to_string(), input_type: JobInputType::Url, - relay: Some("wss://relay".to_string()), + relay: Some(RELAY_PRIMARY_WSS.to_string()), marker: Some("source".to_string()), }], output: Some("json".to_string()), @@ -21,7 +22,7 @@ fn sample_request() -> RadrootsJobRequest { value: "bar".to_string(), }], bid_sat: Some(250), - relays: vec!["wss://relay".to_string()], + relays: vec![RELAY_PRIMARY_WSS.to_string()], providers: vec!["provider".to_string()], topics: vec!["topic".to_string()], encrypted: false, diff --git a/crates/events-codec/tests/job_result.rs b/crates/events-codec/tests/job_result.rs @@ -8,14 +8,15 @@ use radroots_events_codec::job::encode::JobEncodeError; use radroots_events_codec::job::error::JobParseError; use radroots_events_codec::job::result::decode::{job_result_from_tags, parsed_from_event}; use radroots_events_codec::job::result::encode::to_wire_parts; +use radroots_test_fixtures::{APP_PRIMARY_HTTPS, RELAY_PRIMARY_WSS, RELAY_SECONDARY_WSS}; fn sample_result() -> RadrootsJobResult { RadrootsJobResult { kind: (KIND_JOB_RESULT_MIN + 1) as u16, - request_event: common::event_ptr("req", Some("wss://relay")), + request_event: common::event_ptr("req", Some(RELAY_PRIMARY_WSS)), request_json: Some("{\"foo\":\"bar\"}".to_string()), inputs: vec![RadrootsJobInput { - data: "https://example.com".to_string(), + data: APP_PRIMARY_HTTPS.to_string(), input_type: JobInputType::Url, relay: None, marker: None, @@ -54,7 +55,7 @@ fn job_result_roundtrip_preserves_input_relay_and_marker() { res.inputs = vec![RadrootsJobInput { data: "note1payload".to_string(), input_type: JobInputType::Event, - relay: Some("wss://relay.input.example.com".to_string()), + relay: Some(RELAY_SECONDARY_WSS.to_string()), marker: Some("root".to_string()), }]; let content = res.content.clone().unwrap(); diff --git a/crates/events-codec/tests/job_traits.rs b/crates/events-codec/tests/job_traits.rs @@ -8,6 +8,7 @@ use radroots_events_codec::job::feedback::encode::to_wire_parts as to_feedback_w use radroots_events_codec::job::request::encode::to_wire_parts as to_request_wire_parts; use radroots_events_codec::job::result::encode::to_wire_parts as to_result_wire_parts; use radroots_events_codec::job::traits::{BorrowedEventAdapter, JobEventLike}; +use radroots_test_fixtures::{FIXTURE_ALICE_PUBLIC_KEY_HEX, RELAY_PRIMARY_WSS}; fn sample_request() -> RadrootsJobRequest { RadrootsJobRequest { @@ -61,7 +62,7 @@ fn sample_result() -> RadrootsJobResult { kind: (KIND_JOB_RESULT_MIN + 1) as u16, request_event: radroots_events::RadrootsNostrEventPtr { id: "req".to_string(), - relays: Some("wss://relay.example.com".to_string()), + relays: Some(RELAY_PRIMARY_WSS.to_string()), }, request_json: Some("{\"foo\":\"bar\"}".to_string()), inputs: vec![RadrootsJobInput { @@ -70,9 +71,7 @@ fn sample_result() -> RadrootsJobResult { relay: None, marker: None, }], - customer_pubkey: Some( - "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62".to_string(), - ), + customer_pubkey: Some(FIXTURE_ALICE_PUBLIC_KEY_HEX.to_string()), payment: Some(JobPaymentRequest { amount_sat: 1, bolt11: None, @@ -89,11 +88,9 @@ fn sample_feedback() -> RadrootsJobFeedback { extra_info: Some("processing".to_string()), request_event: radroots_events::RadrootsNostrEventPtr { id: "req".to_string(), - relays: Some("wss://relay.example.com".to_string()), + relays: Some(RELAY_PRIMARY_WSS.to_string()), }, - customer_pubkey: Some( - "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62".to_string(), - ), + customer_pubkey: Some(FIXTURE_ALICE_PUBLIC_KEY_HEX.to_string()), payment: Some(JobPaymentRequest { amount_sat: 2, bolt11: None, diff --git a/crates/events-codec/tests/job_util.rs b/crates/events-codec/tests/job_util.rs @@ -5,6 +5,7 @@ use radroots_events_codec::job::util::{ parse_amount_tag_sat, parse_bid_tag_sat, parse_bool_encrypted, parse_i_tags, parse_params, push_amount_tag_msat, push_bid_tag_sat, }; +use radroots_test_fixtures::{APP_PRIMARY_HTTPS, RELAY_PRIMARY_WSS}; #[test] fn parse_bool_encrypted_detects_tag() { @@ -70,7 +71,7 @@ fn feedback_status_tag_covers_all_variants() { #[test] fn parse_i_tags_handles_multiple_shapes() { let tags = vec![ - vec!["i".to_string(), "https://example.com".to_string()], + vec!["i".to_string(), APP_PRIMARY_HTTPS.to_string()], vec!["i".to_string(), "note1abcdef".to_string()], vec![ "i".to_string(), @@ -92,7 +93,7 @@ fn parse_i_tags_handles_multiple_shapes() { let inputs = parse_i_tags(&tags); assert_eq!(inputs.len(), 5); - assert_eq!(inputs[0].data, "https://example.com"); + assert_eq!(inputs[0].data, APP_PRIMARY_HTTPS); assert_eq!(inputs[0].input_type, JobInputType::Url); assert!(inputs[0].relay.is_none()); assert!(inputs[0].marker.is_none()); @@ -148,7 +149,7 @@ fn parse_i_tags_covers_marker_and_fallback_shapes() { "i".to_string(), "event-id".to_string(), "event".to_string(), - "wss://relay.example.com".to_string(), + RELAY_PRIMARY_WSS.to_string(), ], vec![ "i".to_string(), @@ -161,7 +162,7 @@ fn parse_i_tags_covers_marker_and_fallback_shapes() { "i".to_string(), "event-id".to_string(), "event".to_string(), - "wss://relay.example.com".to_string(), + RELAY_PRIMARY_WSS.to_string(), "final-marker".to_string(), ], vec!["i".to_string(), "nostr:note1abcdef".to_string()], @@ -184,11 +185,11 @@ fn parse_i_tags_covers_marker_and_fallback_shapes() { assert_eq!(inputs[1].data, "event-id"); assert_eq!(inputs[2].marker.as_deref(), Some("marker-4")); assert_eq!(inputs[2].relay, None); - assert_eq!(inputs[3].relay.as_deref(), Some("wss://relay.example.com")); + assert_eq!(inputs[3].relay.as_deref(), Some(RELAY_PRIMARY_WSS)); assert_eq!(inputs[3].marker, None); assert_eq!(inputs[4].marker.as_deref(), Some("marker-5")); assert_eq!(inputs[4].relay, None); - assert_eq!(inputs[5].relay.as_deref(), Some("wss://relay.example.com")); + assert_eq!(inputs[5].relay.as_deref(), Some(RELAY_PRIMARY_WSS)); assert_eq!(inputs[5].marker.as_deref(), Some("final-marker")); assert_eq!(inputs[6].input_type, JobInputType::Event); assert_eq!(inputs[7].input_type, JobInputType::Event); diff --git a/crates/events-codec/tests/list_set.rs b/crates/events-codec/tests/list_set.rs @@ -8,6 +8,11 @@ use radroots_events_codec::list_set::decode::{ data_from_event, list_set_from_tags, parsed_from_event, }; use radroots_events_codec::list_set::encode::{list_set_build_tags, to_wire_parts_with_kind}; +use radroots_test_fixtures::APP_PRIMARY_HTTPS; + +fn app_url(path: &str) -> String { + format!("{APP_PRIMARY_HTTPS}/{path}") +} fn sample_list_set() -> RadrootsListSet { RadrootsListSet { @@ -25,7 +30,7 @@ fn sample_list_set() -> RadrootsListSet { ], title: Some("owners".to_string()), description: Some("core team".to_string()), - image: Some("https://example.com/team.png".to_string()), + image: Some(app_url("team.png")), } } @@ -217,14 +222,15 @@ fn list_set_decode_keeps_first_optional_display_tags() { vec!["title".to_string(), "ignored".to_string()], vec!["description".to_string(), "team".to_string()], vec!["description".to_string(), "ignored".to_string()], - vec!["image".to_string(), "https://example.com/a.png".to_string()], - vec!["image".to_string(), "https://example.com/b.png".to_string()], + vec!["image".to_string(), app_url("a.png")], + vec!["image".to_string(), app_url("b.png")], vec!["p".to_string(), "owner".to_string()], ]; let decoded = list_set_from_tags(KIND_LIST_SET_FOLLOW, "private".to_string(), &tags).unwrap(); + let expected_image = app_url("a.png"); assert_eq!(decoded.title.as_deref(), Some("owners")); assert_eq!(decoded.description.as_deref(), Some("team")); - assert_eq!(decoded.image.as_deref(), Some("https://example.com/a.png")); + assert_eq!(decoded.image.as_deref(), Some(expected_image.as_str())); } #[test] diff --git a/crates/events-codec/tests/message.rs b/crates/events-codec/tests/message.rs @@ -8,6 +8,7 @@ use radroots_events_codec::message::decode::{ data_from_event, message_from_tags, parsed_from_event, }; use radroots_events_codec::message::encode::{message_build_tags, to_wire_parts}; +use radroots_test_fixtures::{RELAY_PRIMARY_WSS, RELAY_SECONDARY_WSS}; #[test] fn message_build_tags_requires_recipients() { @@ -88,13 +89,13 @@ fn message_to_wire_parts_sets_tags() { }, RadrootsMessageRecipient { public_key: "pub2".to_string(), - relay_url: Some("wss://relay.example".to_string()), + relay_url: Some(RELAY_PRIMARY_WSS.to_string()), }, ], content: "hello".to_string(), reply_to: Some(RadrootsNostrEventPtr { id: "reply".to_string(), - relays: Some("wss://reply.example".to_string()), + relays: Some(RELAY_SECONDARY_WSS.to_string()), }), subject: Some("topic".to_string()), }; @@ -109,12 +110,12 @@ fn message_to_wire_parts_sets_tags() { vec![ "p".to_string(), "pub2".to_string(), - "wss://relay.example".to_string() + RELAY_PRIMARY_WSS.to_string() ], vec![ "e".to_string(), "reply".to_string(), - "wss://reply.example".to_string() + RELAY_SECONDARY_WSS.to_string() ], vec!["subject".to_string(), "topic".to_string()], ] @@ -188,12 +189,12 @@ fn message_roundtrip_from_tags() { vec![ "p".to_string(), "pub2".to_string(), - "wss://relay.example".to_string(), + RELAY_PRIMARY_WSS.to_string(), ], vec![ "e".to_string(), "reply".to_string(), - "wss://reply.example".to_string(), + RELAY_SECONDARY_WSS.to_string(), ], vec!["subject".to_string(), "topic".to_string()], ]; @@ -206,7 +207,7 @@ fn message_roundtrip_from_tags() { assert_eq!(message.recipients[1].public_key, "pub2"); assert_eq!( message.recipients[1].relay_url, - Some("wss://relay.example".to_string()) + Some(RELAY_PRIMARY_WSS.to_string()) ); assert_eq!(message.content, "hello"); assert_eq!( @@ -215,7 +216,7 @@ fn message_roundtrip_from_tags() { ); assert_eq!( message.reply_to.as_ref().and_then(|r| r.relays.as_deref()), - Some("wss://reply.example") + Some(RELAY_SECONDARY_WSS) ); assert_eq!(message.subject.as_deref(), Some("topic")); @@ -241,12 +242,12 @@ fn message_metadata_and_index_from_event_roundtrip() { vec![ "p".to_string(), "pub2".to_string(), - "wss://relay.example".to_string(), + RELAY_PRIMARY_WSS.to_string(), ], vec![ "e".to_string(), "reply".to_string(), - "wss://reply.example".to_string(), + RELAY_SECONDARY_WSS.to_string(), ], vec!["subject".to_string(), "topic".to_string()], ]; diff --git a/crates/events-codec/tests/message_file.rs b/crates/events-codec/tests/message_file.rs @@ -10,6 +10,11 @@ use radroots_events_codec::message_file::decode::{ use radroots_events_codec::message_file::encode::{ message_file_build_tags, to_wire_parts, to_wire_parts_with_kind, }; +use radroots_test_fixtures::{CDN_PRIMARY_HTTPS, RELAY_PRIMARY_WSS, RELAY_SECONDARY_WSS}; + +fn file_url(path: &str) -> String { + format!("{CDN_PRIMARY_HTTPS}/{path}") +} fn sample_message_file() -> RadrootsMessageFile { RadrootsMessageFile { @@ -20,13 +25,13 @@ fn sample_message_file() -> RadrootsMessageFile { }, RadrootsMessageRecipient { public_key: "pub2".to_string(), - relay_url: Some("wss://relay.example".to_string()), + relay_url: Some(RELAY_PRIMARY_WSS.to_string()), }, ], - file_url: "https://files.example/encrypted.bin".to_string(), + file_url: file_url("encrypted.bin"), reply_to: Some(RadrootsNostrEventPtr { id: "reply".to_string(), - relays: Some("wss://reply.example".to_string()), + relays: Some(RELAY_SECONDARY_WSS.to_string()), }), subject: Some("topic".to_string()), file_type: "image/jpeg".to_string(), @@ -38,11 +43,8 @@ fn sample_message_file() -> RadrootsMessageFile { size: Some(1200), dimensions: Some(RadrootsMessageFileDimensions { w: 1200, h: 800 }), blurhash: Some("blurhash".to_string()), - thumb: Some("https://files.example/thumb.bin".to_string()), - fallbacks: vec![ - "https://files.example/fallback-1.bin".to_string(), - "https://files.example/fallback-2.bin".to_string(), - ], + thumb: Some(file_url("thumb.bin")), + fallbacks: vec![file_url("fallback-1.bin"), file_url("fallback-2.bin")], } } @@ -193,12 +195,12 @@ fn message_file_to_wire_parts_sets_kind_content_and_tags() { vec![ "p".to_string(), "pub2".to_string(), - "wss://relay.example".to_string() + RELAY_PRIMARY_WSS.to_string() ], vec![ "e".to_string(), "reply".to_string(), - "wss://reply.example".to_string() + RELAY_SECONDARY_WSS.to_string() ], vec!["subject".to_string(), "topic".to_string()], vec!["file-type".to_string(), "image/jpeg".to_string()], @@ -210,18 +212,9 @@ fn message_file_to_wire_parts_sets_kind_content_and_tags() { vec!["size".to_string(), "1200".to_string()], vec!["dim".to_string(), "1200x800".to_string()], vec!["blurhash".to_string(), "blurhash".to_string()], - vec![ - "thumb".to_string(), - "https://files.example/thumb.bin".to_string() - ], - vec![ - "fallback".to_string(), - "https://files.example/fallback-1.bin".to_string() - ], - vec![ - "fallback".to_string(), - "https://files.example/fallback-2.bin".to_string() - ], + vec!["thumb".to_string(), file_url("thumb.bin")], + vec!["fallback".to_string(), file_url("fallback-1.bin")], + vec!["fallback".to_string(), file_url("fallback-2.bin")], ] ); } @@ -286,7 +279,7 @@ fn message_file_from_tags_rejects_invalid_optional_tags() { vec!["x".to_string(), "hash".to_string()], vec!["dim".to_string(), "10".to_string()], ], - "https://files.example/encrypted.bin", + &file_url("encrypted.bin"), ) .unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("dim"))); @@ -302,7 +295,7 @@ fn message_file_from_tags_rejects_invalid_optional_tags() { vec!["x".to_string(), "hash".to_string()], vec!["fallback".to_string()], ], - "https://files.example/encrypted.bin", + &file_url("encrypted.bin"), ) .unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("fallback"))); @@ -317,7 +310,7 @@ fn message_file_from_tags_rejects_invalid_optional_tags() { vec!["decryption-nonce".to_string(), "nonce".to_string()], vec!["x".to_string(), "hash".to_string()], ], - "https://files.example/encrypted.bin", + &file_url("encrypted.bin"), ) .unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("file-type"))); @@ -333,7 +326,7 @@ fn message_file_from_tags_rejects_invalid_optional_tags() { vec!["x".to_string(), "hash".to_string()], vec!["size".to_string(), " ".to_string()], ], - "https://files.example/encrypted.bin", + &file_url("encrypted.bin"), ) .unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("size"))); @@ -349,7 +342,7 @@ fn message_file_from_tags_rejects_invalid_optional_tags() { vec!["x".to_string(), "hash".to_string()], vec!["dim".to_string(), " ".to_string()], ], - "https://files.example/encrypted.bin", + &file_url("encrypted.bin"), ) .unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("dim"))); @@ -365,7 +358,7 @@ fn message_file_from_tags_rejects_invalid_optional_tags() { vec!["x".to_string(), "hash".to_string()], vec!["thumb".to_string(), " ".to_string()], ], - "https://files.example/encrypted.bin", + &file_url("encrypted.bin"), ) .unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("thumb"))); @@ -381,7 +374,7 @@ fn message_file_from_tags_rejects_invalid_optional_tags() { vec!["x".to_string(), "hash".to_string()], vec!["fallback".to_string(), " ".to_string()], ], - "https://files.example/encrypted.bin", + &file_url("encrypted.bin"), ) .unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("fallback"))); @@ -465,52 +458,32 @@ fn message_file_from_tags_rejects_empty_content() { fn message_file_from_tags_rejects_more_invalid_tag_shapes() { let mut tags = minimal_message_file_tags(); tags[1].truncate(1); - let err = message_file_from_tags( - KIND_MESSAGE_FILE, - &tags, - "https://files.example/encrypted.bin", - ) - .unwrap_err(); + let err = + message_file_from_tags(KIND_MESSAGE_FILE, &tags, &file_url("encrypted.bin")).unwrap_err(); assert!(matches!(err, EventParseError::MissingTag("file-type"))); let mut tags = minimal_message_file_tags(); tags[0][1] = " ".to_string(); - let err = message_file_from_tags( - KIND_MESSAGE_FILE, - &tags, - "https://files.example/encrypted.bin", - ) - .unwrap_err(); + let err = + message_file_from_tags(KIND_MESSAGE_FILE, &tags, &file_url("encrypted.bin")).unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("p"))); let mut tags = minimal_message_file_tags(); tags.push(vec!["e".to_string(), " ".to_string()]); - let err = message_file_from_tags( - KIND_MESSAGE_FILE, - &tags, - "https://files.example/encrypted.bin", - ) - .unwrap_err(); + let err = + message_file_from_tags(KIND_MESSAGE_FILE, &tags, &file_url("encrypted.bin")).unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("e"))); let mut tags = minimal_message_file_tags(); tags.push(vec!["subject".to_string(), " ".to_string()]); - let err = message_file_from_tags( - KIND_MESSAGE_FILE, - &tags, - "https://files.example/encrypted.bin", - ) - .unwrap_err(); + let err = + message_file_from_tags(KIND_MESSAGE_FILE, &tags, &file_url("encrypted.bin")).unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("subject"))); let mut tags = minimal_message_file_tags(); tags[2][1] = " ".to_string(); - let err = message_file_from_tags( - KIND_MESSAGE_FILE, - &tags, - "https://files.example/encrypted.bin", - ) - .unwrap_err(); + let err = + message_file_from_tags(KIND_MESSAGE_FILE, &tags, &file_url("encrypted.bin")).unwrap_err(); assert!(matches!( err, EventParseError::InvalidTag("encryption-algorithm") @@ -518,22 +491,14 @@ fn message_file_from_tags_rejects_more_invalid_tag_shapes() { let mut tags = minimal_message_file_tags(); tags[3][1] = " ".to_string(); - let err = message_file_from_tags( - KIND_MESSAGE_FILE, - &tags, - "https://files.example/encrypted.bin", - ) - .unwrap_err(); + let err = + message_file_from_tags(KIND_MESSAGE_FILE, &tags, &file_url("encrypted.bin")).unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("decryption-key"))); let mut tags = minimal_message_file_tags(); tags[4][1] = " ".to_string(); - let err = message_file_from_tags( - KIND_MESSAGE_FILE, - &tags, - "https://files.example/encrypted.bin", - ) - .unwrap_err(); + let err = + message_file_from_tags(KIND_MESSAGE_FILE, &tags, &file_url("encrypted.bin")).unwrap_err(); assert!(matches!( err, EventParseError::InvalidTag("decryption-nonce") @@ -541,32 +506,20 @@ fn message_file_from_tags_rejects_more_invalid_tag_shapes() { let mut tags = minimal_message_file_tags(); tags[5][1] = " ".to_string(); - let err = message_file_from_tags( - KIND_MESSAGE_FILE, - &tags, - "https://files.example/encrypted.bin", - ) - .unwrap_err(); + let err = + message_file_from_tags(KIND_MESSAGE_FILE, &tags, &file_url("encrypted.bin")).unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("x"))); let mut tags = minimal_message_file_tags(); tags.push(vec!["ox".to_string(), " ".to_string()]); - let err = message_file_from_tags( - KIND_MESSAGE_FILE, - &tags, - "https://files.example/encrypted.bin", - ) - .unwrap_err(); + let err = + message_file_from_tags(KIND_MESSAGE_FILE, &tags, &file_url("encrypted.bin")).unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("ox"))); let mut tags = minimal_message_file_tags(); tags.push(vec!["blurhash".to_string(), " ".to_string()]); - let err = message_file_from_tags( - KIND_MESSAGE_FILE, - &tags, - "https://files.example/encrypted.bin", - ) - .unwrap_err(); + let err = + message_file_from_tags(KIND_MESSAGE_FILE, &tags, &file_url("encrypted.bin")).unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("blurhash"))); } @@ -574,21 +527,13 @@ fn message_file_from_tags_rejects_more_invalid_tag_shapes() { fn message_file_from_tags_rejects_invalid_dimension_components() { let mut tags = minimal_message_file_tags(); tags.push(vec!["dim".to_string(), "badx10".to_string()]); - let err = message_file_from_tags( - KIND_MESSAGE_FILE, - &tags, - "https://files.example/encrypted.bin", - ) - .unwrap_err(); + let err = + message_file_from_tags(KIND_MESSAGE_FILE, &tags, &file_url("encrypted.bin")).unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("dim"))); let mut tags = minimal_message_file_tags(); tags.push(vec!["dim".to_string(), "10xbad".to_string()]); - let err = message_file_from_tags( - KIND_MESSAGE_FILE, - &tags, - "https://files.example/encrypted.bin", - ) - .unwrap_err(); + let err = + message_file_from_tags(KIND_MESSAGE_FILE, &tags, &file_url("encrypted.bin")).unwrap_err(); assert!(matches!(err, EventParseError::InvalidTag("dim"))); } diff --git a/crates/events-codec/tests/structured_decode.rs b/crates/events-codec/tests/structured_decode.rs @@ -42,9 +42,10 @@ use radroots_events_codec::resource_cap::decode::{ data_from_event as resource_cap_metadata_from_event, parsed_from_event as resource_cap_index_from_event, resource_harvest_cap_from_event, }; +use radroots_test_fixtures::{FIXTURE_ALICE_NPUB, FIXTURE_ALICE_PUBLIC_KEY_HEX}; -const TEST_NPUB: &str = "npub1tr33s4tj2le2kk9yzhfphdtss26gyn8kv7savnnjhj794nqp333q8e7grr"; -const TEST_PUBKEY_HEX: &str = "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62"; +const TEST_NPUB: &str = FIXTURE_ALICE_NPUB; +const TEST_PUBKEY_HEX: &str = FIXTURE_ALICE_PUBLIC_KEY_HEX; fn sample_gcs() -> RadrootsGcsLocation { RadrootsGcsLocation { diff --git a/crates/events-codec/tests/structured_encode_default.rs b/crates/events-codec/tests/structured_encode_default.rs @@ -39,8 +39,9 @@ use radroots_events_codec::resource_area::list_sets::{ resource_area_stewards_list_set, }; use radroots_events_codec::resource_cap::encode::resource_harvest_cap_build_tags; +use radroots_test_fixtures::FIXTURE_ALICE_PUBLIC_KEY_HEX; -const TEST_PUBKEY_HEX: &str = "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62"; +const TEST_PUBKEY_HEX: &str = FIXTURE_ALICE_PUBLIC_KEY_HEX; fn sample_gcs() -> RadrootsGcsLocation { RadrootsGcsLocation { @@ -205,7 +206,7 @@ fn structured_build_tags_cover_optional_and_error_paths() { body_markdown: None, subject: RadrootsDocumentSubject { pubkey: TEST_PUBKEY_HEX.to_string(), - address: Some("30340:58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62:AAAAAAAAAAAAAAAAAAAAAA".to_string()), + address: Some(format!("30340:{TEST_PUBKEY_HEX}:AAAAAAAAAAAAAAAAAAAAAA")), }, tags: Some(vec!["policy".to_string(), " ".to_string()]), }; @@ -357,10 +358,7 @@ fn structured_build_tags_cover_required_field_errors() { body_markdown: None, subject: RadrootsDocumentSubject { pubkey: TEST_PUBKEY_HEX.to_string(), - address: Some( - "30340:58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62:AAAAAAAAAAAAAAAAAAAAAA" - .to_string(), - ), + address: Some(format!("30340:{TEST_PUBKEY_HEX}:AAAAAAAAAAAAAAAAAAAAAA")), }, tags: None, }; diff --git a/crates/events-codec/tests/tag_builders.rs b/crates/events-codec/tests/tag_builders.rs @@ -46,9 +46,16 @@ use radroots_events_codec::job::encode::JobEncodeError; use radroots_events_codec::listing::encode::listing_build_tags; use radroots_events_codec::listing::tags::{ListingTagOptions, listing_tags_with_options}; use radroots_events_codec::tag_builders::RadrootsEventTagBuilder; +use radroots_test_fixtures::{ + CDN_PRIMARY_HTTPS, FIXTURE_ALICE_NPUB, FIXTURE_ALICE_PUBLIC_KEY_HEX, RELAY_PRIMARY_WSS, +}; + +const TEST_PUBKEY_HEX: &str = FIXTURE_ALICE_PUBLIC_KEY_HEX; +const TEST_NPUB: &str = FIXTURE_ALICE_NPUB; -const TEST_PUBKEY_HEX: &str = "58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62"; -const TEST_NPUB: &str = "npub1tr33s4tj2le2kk9yzhfphdtss26gyn8kv7savnnjhj794nqp333q8e7grr"; +fn cdn_url(path: &str) -> String { + format!("{CDN_PRIMARY_HTTPS}/{path}") +} fn sample_event_ref(id: &str) -> RadrootsNostrEventRef { RadrootsNostrEventRef { @@ -170,12 +177,12 @@ fn event_tag_builder_impls_build_tags_for_all_supported_types() { let message = RadrootsMessage { recipients: vec![RadrootsMessageRecipient { public_key: TEST_PUBKEY_HEX.to_string(), - relay_url: Some("wss://relay.example.com".to_string()), + relay_url: Some(RELAY_PRIMARY_WSS.to_string()), }], content: "hello".to_string(), reply_to: Some(RadrootsNostrEventPtr { id: "reply".to_string(), - relays: Some("wss://relay.example.com".to_string()), + relays: Some(RELAY_PRIMARY_WSS.to_string()), }), subject: Some("topic".to_string()), }; @@ -186,7 +193,7 @@ fn event_tag_builder_impls_build_tags_for_all_supported_types() { public_key: TEST_PUBKEY_HEX.to_string(), relay_url: None, }], - file_url: "https://files.example.com/blob".to_string(), + file_url: cdn_url("blob"), reply_to: None, subject: None, file_type: "image/jpeg".to_string(), @@ -199,7 +206,7 @@ fn event_tag_builder_impls_build_tags_for_all_supported_types() { dimensions: None, blurhash: None, thumb: None, - fallbacks: vec!["https://files.example.com/fallback".to_string()], + fallbacks: vec![cdn_url("fallback")], }; assert!(!message_file.build_tags().unwrap().is_empty()); @@ -215,7 +222,7 @@ fn event_tag_builder_impls_build_tags_for_all_supported_types() { list: vec![RadrootsFollowProfile { published_at: 1, public_key: TEST_PUBKEY_HEX.to_string(), - relay_url: Some("wss://relay.example.com".to_string()), + relay_url: Some(RELAY_PRIMARY_WSS.to_string()), contact_name: Some("alex".to_string()), }], }; @@ -293,7 +300,7 @@ fn event_tag_builder_impls_build_tags_for_all_supported_types() { body_markdown: None, subject: RadrootsDocumentSubject { pubkey: TEST_PUBKEY_HEX.to_string(), - address: Some("30340:58e318557257f2ab58a415d21bb57082b4824cf667a1d64e72bcbc5acc018c62:AAAAAAAAAAAAAAAAAAAAAA".to_string()), + address: Some(format!("30340:{TEST_PUBKEY_HEX}:AAAAAAAAAAAAAAAAAAAAAA")), }, tags: None, }; @@ -317,7 +324,7 @@ fn event_tag_builder_impls_build_tags_for_all_supported_types() { }], title: Some("owners".to_string()), description: Some("team".to_string()), - image: Some("https://example.com/team.png".to_string()), + image: Some(format!("{CDN_PRIMARY_HTTPS}/team.png")), }; assert!(!list_set.build_tags().unwrap().is_empty()); @@ -348,7 +355,7 @@ fn event_tag_builder_impls_build_tags_for_all_supported_types() { value: "bar".to_string(), }], bid_sat: None, - relays: vec!["wss://relay.example.com".to_string()], + relays: vec![RELAY_PRIMARY_WSS.to_string()], providers: vec![TEST_PUBKEY_HEX.to_string()], topics: vec!["topic".to_string()], encrypted: false, @@ -359,7 +366,7 @@ fn event_tag_builder_impls_build_tags_for_all_supported_types() { kind: (KIND_JOB_RESULT_MIN + 1) as u16, request_event: RadrootsNostrEventPtr { id: "req".to_string(), - relays: Some("wss://relay.example.com".to_string()), + relays: Some(RELAY_PRIMARY_WSS.to_string()), }, request_json: None, inputs: vec![RadrootsJobInput { @@ -384,7 +391,7 @@ fn event_tag_builder_impls_build_tags_for_all_supported_types() { extra_info: Some("queued".to_string()), request_event: RadrootsNostrEventPtr { id: "req".to_string(), - relays: Some("wss://relay.example.com".to_string()), + relays: Some(RELAY_PRIMARY_WSS.to_string()), }, customer_pubkey: Some(TEST_PUBKEY_HEX.to_string()), payment: Some(JobPaymentRequest { @@ -404,7 +411,7 @@ fn event_tag_builder_impls_build_tags_for_all_supported_types() { let gift_wrap = RadrootsGiftWrap { recipient: RadrootsGiftWrapRecipient { public_key: TEST_PUBKEY_HEX.to_string(), - relay_url: Some("wss://relay.example.com".to_string()), + relay_url: Some(RELAY_PRIMARY_WSS.to_string()), }, content: "encrypted".to_string(), expiration: Some(1700000000), @@ -458,7 +465,7 @@ fn listing_and_message_builders_cover_optional_shapes() { geohash: None, }); listing.images = Some(vec![RadrootsListingImage { - url: "https://example.com/a.jpg".to_string(), + url: cdn_url("a.jpg"), size: Some(RadrootsListingImageSize { w: 1200, h: 800 }), }]); assert!(!listing_build_tags(&listing).unwrap().is_empty()); diff --git a/crates/test-fixtures/Cargo.toml b/crates/test-fixtures/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "radroots-test-fixtures" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +readme.workspace = true +publish = false +description = "approved deterministic fixtures for radroots test code" diff --git a/crates/test-fixtures/src/lib.rs b/crates/test-fixtures/src/lib.rs @@ -0,0 +1,106 @@ +#![forbid(unsafe_code)] + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct ApprovedFixtureIdentity { + pub label: &'static str, + pub username: &'static str, + pub email: &'static str, + pub secret_key_hex: &'static str, + pub public_key_hex: &'static str, + pub nsec: &'static str, + pub npub: &'static str, +} + +pub const APPROVED_FIXTURE_NAMESPACE: &str = "radroots-approved-fixture-v1"; + +pub const FIXTURE_ALICE_LABEL: &str = "fixture_alice"; +pub const FIXTURE_ALICE_USERNAME: &str = "fixture_alice"; +pub const FIXTURE_ALICE_EMAIL: &str = "fixture_alice@fixtures.test"; +pub const FIXTURE_ALICE_SECRET_KEY_HEX: &str = + "10c5304d6c9ae3a1a16f7860f1cc8f5e3a76225a2663b3a989a0d775919b7df5"; +pub const FIXTURE_ALICE_PUBLIC_KEY_HEX: &str = + "585591529da0bab31b3b1b1f986611cf5f435dca84f978c89ee8a40cca7103df"; +pub const FIXTURE_ALICE_NSEC: &str = + "nsec1zrznqntvnt36rgt00ps0rny0tca8vgj6ye3m82vf5rthtyvm0h6syu7drz"; +pub const FIXTURE_ALICE_NPUB: &str = + "npub1tp2ez55a5zatxxemrv0eses3ea05xhw2snuh3jy7azjqejn3q00s3vy5a9"; +pub const FIXTURE_ALICE: ApprovedFixtureIdentity = ApprovedFixtureIdentity { + label: FIXTURE_ALICE_LABEL, + username: FIXTURE_ALICE_USERNAME, + email: FIXTURE_ALICE_EMAIL, + secret_key_hex: FIXTURE_ALICE_SECRET_KEY_HEX, + public_key_hex: FIXTURE_ALICE_PUBLIC_KEY_HEX, + nsec: FIXTURE_ALICE_NSEC, + npub: FIXTURE_ALICE_NPUB, +}; + +pub const FIXTURE_BOB_LABEL: &str = "fixture_bob"; +pub const FIXTURE_BOB_USERNAME: &str = "fixture_bob"; +pub const FIXTURE_BOB_EMAIL: &str = "fixture_bob@fixtures.test"; +pub const FIXTURE_BOB_SECRET_KEY_HEX: &str = + "59392e9068f66431b12f70218fb61281cb6b433d7f27c55d61f1a63fe1a96ff8"; +pub const FIXTURE_BOB_PUBLIC_KEY_HEX: &str = + "e0266e3cfb0d2886f91c73f5f868f3b98273713e5fcd97c081663f5518a4b3af"; +pub const FIXTURE_BOB_NSEC: &str = + "nsec1tyujayrg7ejrrvf0wqscldsjs89kksea0unu2htp7xnrlcdfdluqrjya9h"; +pub const FIXTURE_BOB_NPUB: &str = + "npub1uqnxu08mp55gd7guw06ls68nhxp8xuf7tlxe0sypvcl42x9ykwhsd55k2g"; +pub const FIXTURE_BOB: ApprovedFixtureIdentity = ApprovedFixtureIdentity { + label: FIXTURE_BOB_LABEL, + username: FIXTURE_BOB_USERNAME, + email: FIXTURE_BOB_EMAIL, + secret_key_hex: FIXTURE_BOB_SECRET_KEY_HEX, + public_key_hex: FIXTURE_BOB_PUBLIC_KEY_HEX, + nsec: FIXTURE_BOB_NSEC, + npub: FIXTURE_BOB_NPUB, +}; + +pub const FIXTURE_CAROL_LABEL: &str = "fixture_carol"; +pub const FIXTURE_CAROL_USERNAME: &str = "fixture_carol"; +pub const FIXTURE_CAROL_EMAIL: &str = "fixture_carol@fixtures.test"; +pub const FIXTURE_CAROL_SECRET_KEY_HEX: &str = + "4d6c20fdd86857de77ff5cfa5c545751ba2efd126e0b6642dae9764d782d6509"; +pub const FIXTURE_CAROL_PUBLIC_KEY_HEX: &str = + "1952b8c6943898bceffcff1b7699c4a775a4d13b4a9ba0096ba26ef04492bb1c"; +pub const FIXTURE_CAROL_NSEC: &str = + "nsec1f4kzplwcdptaualltna9c4zh2xazalgjdc9kvsk6a9my67pdv5ys2pqkaj"; +pub const FIXTURE_CAROL_NPUB: &str = + "npub1r9ft33558zvtemluludhdxwy5a66f5fmf2d6qztt5fh0q3yjhvwqgzmkl6"; +pub const FIXTURE_CAROL: ApprovedFixtureIdentity = ApprovedFixtureIdentity { + label: FIXTURE_CAROL_LABEL, + username: FIXTURE_CAROL_USERNAME, + email: FIXTURE_CAROL_EMAIL, + secret_key_hex: FIXTURE_CAROL_SECRET_KEY_HEX, + public_key_hex: FIXTURE_CAROL_PUBLIC_KEY_HEX, + nsec: FIXTURE_CAROL_NSEC, + npub: FIXTURE_CAROL_NPUB, +}; + +pub const FIXTURE_DIEGO_LABEL: &str = "fixture_diego"; +pub const FIXTURE_DIEGO_USERNAME: &str = "fixture_diego"; +pub const FIXTURE_DIEGO_EMAIL: &str = "fixture_diego@fixtures.test"; +pub const FIXTURE_DIEGO_SECRET_KEY_HEX: &str = + "9de56c1fdfce9ab00af85b3d7003c1d15cffb84cdf303c3a83c1a3fb1a2d0db0"; +pub const FIXTURE_DIEGO_PUBLIC_KEY_HEX: &str = + "5d3eab6e78eb7e467a9e196a63456c9fafb93fb88b7052b83229870889923aa4"; +pub const FIXTURE_DIEGO_NSEC: &str = + "nsec1nhjkc87le6dtqzhctv7hqq7p69w0lwzvmucrcw5rcx3lkx3dpkcqkrmgp5"; +pub const FIXTURE_DIEGO_NPUB: &str = + "npub1t5l2kmncadlyv757r94xx3tvn7hmj0ac3dc99wpj9xrs3zvj82jqwwcglm"; +pub const FIXTURE_DIEGO: ApprovedFixtureIdentity = ApprovedFixtureIdentity { + label: FIXTURE_DIEGO_LABEL, + username: FIXTURE_DIEGO_USERNAME, + email: FIXTURE_DIEGO_EMAIL, + secret_key_hex: FIXTURE_DIEGO_SECRET_KEY_HEX, + public_key_hex: FIXTURE_DIEGO_PUBLIC_KEY_HEX, + nsec: FIXTURE_DIEGO_NSEC, + npub: FIXTURE_DIEGO_NPUB, +}; + +pub const RELAY_PRIMARY_WSS: &str = "wss://relay.example.com"; +pub const RELAY_SECONDARY_WSS: &str = "wss://relay-2.example.com"; +pub const RELAY_TERTIARY_WSS: &str = "wss://relay-3.example.com"; + +pub const APP_PRIMARY_HTTPS: &str = "https://app.example.com"; +pub const API_PRIMARY_HTTPS: &str = "https://api.example.com"; +pub const CDN_PRIMARY_HTTPS: &str = "https://cdn.example.com";