job_traits.rs (8182B)
1 #[path = "../src/test_fixtures.rs"] 2 mod test_fixtures; 3 4 use radroots_event::envelope::kind::{ 5 KIND_JOB_FEEDBACK, KIND_JOB_REQUEST_MIN, KIND_JOB_RESULT_MIN, 6 }; 7 use radroots_event::social::job::{JobFeedbackStatus, JobInputType, JobPaymentRequest}; 8 use radroots_event::social::job_feedback::JobFeedback; 9 use radroots_event::social::job_request::{JobInput, JobParam, JobRequest}; 10 use radroots_event::social::job_result::JobResult; 11 use radroots_event::{envelope::EventEnvelope, envelope::EventEnvelopeParts}; 12 use radroots_event_codec::decode::job::{BorrowedEventAdapter, JobEventLike}; 13 use radroots_event_codec::encode::job::feedback::to_wire_parts as to_feedback_wire_parts; 14 use radroots_event_codec::encode::job::request::to_wire_parts as to_request_wire_parts; 15 use radroots_event_codec::encode::job::result::to_wire_parts as to_result_wire_parts; 16 use test_fixtures::{FIXTURE_ALICE_PUBLIC_KEY_HEX, RELAY_PRIMARY_WSS}; 17 18 const EVENT_ID: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 19 const AUTHOR: &str = "585591529da0bab31b3b1b1f986611cf5f435dca84f978c89ee8a40cca7103df"; 20 const EVENT_SIG: &str = concat!( 21 "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", 22 "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" 23 ); 24 25 fn event_envelope(kind: u32, tags: Vec<Vec<String>>, content: &str) -> EventEnvelope { 26 EventEnvelope::new(EventEnvelopeParts { 27 id: EVENT_ID.to_string(), 28 author: AUTHOR.to_string(), 29 created_at: 42, 30 kind, 31 tags, 32 content: content.to_string(), 33 sig: EVENT_SIG.to_string(), 34 }) 35 .unwrap() 36 } 37 38 fn sample_request() -> JobRequest { 39 JobRequest { 40 kind: u16::try_from(KIND_JOB_REQUEST_MIN + 1).expect("request kind must fit NIP-01"), 41 inputs: vec![JobInput { 42 data: "hello".to_string(), 43 input_type: JobInputType::Text, 44 relay: None, 45 marker: None, 46 }], 47 output: None, 48 params: vec![JobParam { 49 key: "foo".to_string(), 50 value: "bar".to_string(), 51 }], 52 bid_sat: None, 53 relays: Vec::new(), 54 providers: vec!["provider".to_string()], 55 topics: Vec::new(), 56 encrypted: false, 57 } 58 } 59 60 #[test] 61 fn borrowed_event_adapter_builds_request_metadata() { 62 let req = sample_request(); 63 let parts = to_request_wire_parts(&req, "payload").unwrap(); 64 65 let event = event_envelope(parts.kind, parts.tags.clone(), "payload"); 66 let tags = event.tags_as_vec(); 67 68 let adapter = 69 BorrowedEventAdapter::new(&event, event.created_at_u64(), &tags, event.signature_hex()); 70 let metadata = adapter.to_job_request_metadata().unwrap(); 71 72 assert_eq!(metadata.id, event.id_hex()); 73 assert_eq!(metadata.author, event.author().to_hex()); 74 assert_eq!(metadata.published_at, event.created_at_u64()); 75 assert_eq!(metadata.kind, event.kind_u32()); 76 assert_eq!(metadata.data, req); 77 } 78 79 fn sample_result() -> JobResult { 80 JobResult { 81 kind: u16::try_from(KIND_JOB_RESULT_MIN + 1).expect("result kind must fit NIP-01"), 82 request_event: radroots_event::tag::EventPtr { 83 id: "req".to_string(), 84 relays: Some(RELAY_PRIMARY_WSS.to_string()), 85 }, 86 request_json: Some("{\"foo\":\"bar\"}".to_string()), 87 inputs: vec![JobInput { 88 data: "hello".to_string(), 89 input_type: JobInputType::Text, 90 relay: None, 91 marker: None, 92 }], 93 customer_pubkey: Some(FIXTURE_ALICE_PUBLIC_KEY_HEX.to_string()), 94 payment: Some(JobPaymentRequest { 95 amount_sat: 1, 96 bolt11: None, 97 }), 98 content: Some("payload".to_string()), 99 encrypted: false, 100 } 101 } 102 103 fn sample_feedback() -> JobFeedback { 104 JobFeedback { 105 kind: u16::try_from(KIND_JOB_FEEDBACK).expect("feedback kind must fit NIP-01"), 106 status: JobFeedbackStatus::Processing, 107 extra_info: Some("processing".to_string()), 108 request_event: radroots_event::tag::EventPtr { 109 id: "req".to_string(), 110 relays: Some(RELAY_PRIMARY_WSS.to_string()), 111 }, 112 customer_pubkey: Some(FIXTURE_ALICE_PUBLIC_KEY_HEX.to_string()), 113 payment: Some(JobPaymentRequest { 114 amount_sat: 2, 115 bolt11: None, 116 }), 117 content: Some("payload".to_string()), 118 encrypted: false, 119 } 120 } 121 122 #[test] 123 fn borrowed_event_adapter_builds_request_metadata_and_index() { 124 let req = sample_request(); 125 let parts = to_request_wire_parts(&req, "payload").unwrap(); 126 let event = event_envelope(parts.kind, parts.tags, "payload"); 127 let tags = event.tags_as_vec(); 128 129 let adapter = 130 BorrowedEventAdapter::new(&event, event.created_at_u64(), &tags, event.signature_hex()); 131 assert_eq!(adapter.raw_id(), EVENT_ID); 132 assert_eq!(adapter.raw_author(), AUTHOR); 133 assert_eq!(adapter.raw_published_at(), 42); 134 assert_eq!(adapter.raw_kind(), event.kind_u32()); 135 assert_eq!(adapter.raw_content(), "payload"); 136 assert_eq!(adapter.raw_tags().len(), tags.len()); 137 assert_eq!(adapter.raw_sig(), EVENT_SIG); 138 139 let index = adapter.to_job_request_event_index().unwrap(); 140 assert_eq!(index.event.id_hex(), event.id_hex()); 141 assert_eq!(index.event.author().to_hex(), event.author().to_hex()); 142 assert_eq!(index.event.created_at_u64(), event.created_at_u64()); 143 assert_eq!(index.event.kind_u32(), event.kind_u32()); 144 assert_eq!(index.event.content(), event.content()); 145 assert_eq!(index.event.signature_hex(), event.signature_hex()); 146 } 147 148 #[test] 149 fn borrowed_event_adapter_builds_result_metadata_and_index() { 150 let result = sample_result(); 151 let parts = to_result_wire_parts(&result, "payload").unwrap(); 152 let event = event_envelope(parts.kind, parts.tags, "payload"); 153 let tags = event.tags_as_vec(); 154 155 let adapter = 156 BorrowedEventAdapter::new(&event, event.created_at_u64(), &tags, event.signature_hex()); 157 let metadata = adapter.to_job_result_metadata().unwrap(); 158 assert_eq!(metadata.id, event.id_hex()); 159 assert_eq!(metadata.author, event.author().to_hex()); 160 assert_eq!(metadata.published_at, event.created_at_u64()); 161 assert_eq!(metadata.kind, event.kind_u32()); 162 assert_eq!(metadata.data.kind, result.kind); 163 assert_eq!(metadata.data.request_event.id, "req"); 164 assert_eq!(metadata.data.content.as_deref(), Some("payload")); 165 166 let index = adapter.to_job_result_event_index().unwrap(); 167 assert_eq!(index.event.id_hex(), event.id_hex()); 168 assert_eq!(index.event.author().to_hex(), event.author().to_hex()); 169 assert_eq!(index.event.created_at_u64(), event.created_at_u64()); 170 assert_eq!(index.event.kind_u32(), event.kind_u32()); 171 assert_eq!(index.event.content(), event.content()); 172 assert_eq!(index.event.signature_hex(), event.signature_hex()); 173 } 174 175 #[test] 176 fn borrowed_event_adapter_builds_feedback_metadata_and_index() { 177 let feedback = sample_feedback(); 178 let parts = to_feedback_wire_parts(&feedback, "payload").unwrap(); 179 let event = event_envelope(parts.kind, parts.tags, "payload"); 180 let tags = event.tags_as_vec(); 181 182 let adapter = 183 BorrowedEventAdapter::new(&event, event.created_at_u64(), &tags, event.signature_hex()); 184 let metadata = adapter.to_job_feedback_metadata().unwrap(); 185 assert_eq!(metadata.id, event.id_hex()); 186 assert_eq!(metadata.author, event.author().to_hex()); 187 assert_eq!(metadata.published_at, event.created_at_u64()); 188 assert_eq!(metadata.kind, event.kind_u32()); 189 assert_eq!(metadata.data.kind, feedback.kind); 190 assert_eq!(metadata.data.request_event.id, "req"); 191 assert_eq!(metadata.data.content.as_deref(), Some("payload")); 192 193 let index = adapter.to_job_feedback_event_index().unwrap(); 194 assert_eq!(index.event.id_hex(), event.id_hex()); 195 assert_eq!(index.event.author().to_hex(), event.author().to_hex()); 196 assert_eq!(index.event.created_at_u64(), event.created_at_u64()); 197 assert_eq!(index.event.kind_u32(), event.kind_u32()); 198 assert_eq!(index.event.content(), event.content()); 199 assert_eq!(index.event.signature_hex(), event.signature_hex()); 200 }