lib

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

job_request.rs (5189B)


      1 #[path = "../src/test_fixtures.rs"]
      2 mod test_fixtures;
      3 
      4 use radroots_events::job::JobInputType;
      5 use radroots_events::job_request::{RadrootsJobInput, RadrootsJobParam, RadrootsJobRequest};
      6 use radroots_events::kinds::{KIND_JOB_FEEDBACK, KIND_JOB_REQUEST_MIN, KIND_JOB_RESULT_MIN};
      7 use radroots_events_codec::job::encode::JobEncodeError;
      8 use radroots_events_codec::job::error::JobParseError;
      9 use radroots_events_codec::job::request::decode::{job_request_from_tags, parsed_from_event};
     10 use radroots_events_codec::job::request::encode::to_wire_parts;
     11 use test_fixtures::{APP_PRIMARY_HTTPS, RELAY_PRIMARY_WSS};
     12 
     13 fn sample_request() -> RadrootsJobRequest {
     14     RadrootsJobRequest {
     15         kind: (KIND_JOB_REQUEST_MIN + 1) as u16,
     16         inputs: vec![RadrootsJobInput {
     17             data: APP_PRIMARY_HTTPS.to_string(),
     18             input_type: JobInputType::Url,
     19             relay: Some(RELAY_PRIMARY_WSS.to_string()),
     20             marker: Some("source".to_string()),
     21         }],
     22         output: Some("json".to_string()),
     23         params: vec![RadrootsJobParam {
     24             key: "foo".to_string(),
     25             value: "bar".to_string(),
     26         }],
     27         bid_sat: Some(250),
     28         relays: vec![RELAY_PRIMARY_WSS.to_string()],
     29         providers: vec!["provider".to_string()],
     30         topics: vec!["topic".to_string()],
     31         encrypted: false,
     32     }
     33 }
     34 
     35 #[test]
     36 fn job_request_roundtrip_from_tags() {
     37     let req = sample_request();
     38     let parts = to_wire_parts(&req, "payload").unwrap();
     39 
     40     let decoded = job_request_from_tags(parts.kind, &parts.tags).unwrap();
     41     assert_eq!(decoded, req);
     42 }
     43 
     44 #[test]
     45 fn job_request_requires_valid_kind() {
     46     let mut req = sample_request();
     47     req.kind = KIND_JOB_FEEDBACK as u16;
     48 
     49     let err = to_wire_parts(&req, "payload").unwrap_err();
     50     assert!(matches!(
     51         err,
     52         JobEncodeError::InvalidKind(KIND_JOB_FEEDBACK)
     53     ));
     54 }
     55 
     56 #[test]
     57 fn job_request_requires_providers_when_encrypted() {
     58     let mut req = sample_request();
     59     req.encrypted = true;
     60     req.providers.clear();
     61 
     62     let err = to_wire_parts(&req, "payload").unwrap_err();
     63     assert!(matches!(err, JobEncodeError::MissingProvidersForEncrypted));
     64 
     65     let tags = vec![vec!["encrypted".to_string()]];
     66     let err = job_request_from_tags(KIND_JOB_REQUEST_MIN + 1, &tags).unwrap_err();
     67     assert!(matches!(err, JobParseError::MissingTag("p")));
     68 }
     69 
     70 #[test]
     71 fn job_request_from_tags_accepts_encrypted_with_provider() {
     72     let request = job_request_from_tags(
     73         KIND_JOB_REQUEST_MIN + 1,
     74         &[
     75             vec!["encrypted".to_string()],
     76             vec!["p".to_string(), "provider".to_string()],
     77         ],
     78     )
     79     .unwrap();
     80     assert!(request.encrypted);
     81     assert_eq!(request.providers, vec!["provider".to_string()]);
     82 }
     83 
     84 #[test]
     85 fn job_request_to_wire_parts_allows_encrypted_when_provider_present() {
     86     let mut req = sample_request();
     87     req.encrypted = true;
     88     let parts = to_wire_parts(&req, "payload").unwrap();
     89     assert!(
     90         parts
     91             .tags
     92             .iter()
     93             .any(|tag| tag.first().map(|v| v.as_str()) == Some("encrypted"))
     94     );
     95 }
     96 
     97 #[test]
     98 fn job_request_from_tags_rejects_invalid_bid_tag() {
     99     let err = job_request_from_tags(
    100         KIND_JOB_REQUEST_MIN + 1,
    101         &[vec!["bid".to_string(), "not-a-number".to_string()]],
    102     )
    103     .unwrap_err();
    104     assert!(matches!(err, JobParseError::InvalidNumber("bid", _)));
    105 }
    106 
    107 #[test]
    108 fn job_request_metadata_rejects_wrong_kind() {
    109     let err = radroots_events_codec::job::request::decode::data_from_event(
    110         "id".to_string(),
    111         "author".to_string(),
    112         1,
    113         KIND_JOB_RESULT_MIN,
    114         Vec::new(),
    115     )
    116     .unwrap_err();
    117 
    118     assert!(matches!(
    119         err,
    120         JobParseError::InvalidTag("kind (expected 5000-5999)")
    121     ));
    122 }
    123 
    124 #[test]
    125 fn job_request_data_from_event_success_path() {
    126     let request = sample_request();
    127     let parts = to_wire_parts(&request, "payload").expect("wire parts");
    128     let data = radroots_events_codec::job::request::decode::data_from_event(
    129         "id".to_string(),
    130         "author".to_string(),
    131         1,
    132         parts.kind,
    133         parts.tags,
    134     )
    135     .expect("job request data");
    136     assert_eq!(data.id, "id");
    137     assert_eq!(data.author, "author");
    138     assert_eq!(data.kind, KIND_JOB_REQUEST_MIN + 1);
    139     assert_eq!(data.data.providers, vec!["provider".to_string()]);
    140 }
    141 
    142 #[test]
    143 fn job_request_data_from_event_propagates_decode_errors_with_valid_kind() {
    144     let err = radroots_events_codec::job::request::decode::data_from_event(
    145         "id".to_string(),
    146         "author".to_string(),
    147         1,
    148         KIND_JOB_REQUEST_MIN + 1,
    149         vec![vec!["bid".to_string(), "not-a-number".to_string()]],
    150     )
    151     .unwrap_err();
    152     assert!(matches!(err, JobParseError::InvalidNumber("bid", _)));
    153 }
    154 
    155 #[test]
    156 fn job_request_index_from_event_propagates_parse_errors() {
    157     let err = parsed_from_event(
    158         "id".to_string(),
    159         "author".to_string(),
    160         1,
    161         KIND_JOB_RESULT_MIN,
    162         "payload".to_string(),
    163         Vec::new(),
    164         "sig".to_string(),
    165     )
    166     .unwrap_err();
    167     assert!(matches!(
    168         err,
    169         JobParseError::InvalidTag("kind (expected 5000-5999)")
    170     ));
    171 }