switchgear_service/offer/
service.rs

1use crate::api::offer::{OfferMetadataStore, OfferStore};
2use crate::api::service::StatusCode;
3use crate::axum::auth::BearerTokenAuthLayer;
4use crate::offer::auth::OfferBearerTokenValidator;
5use crate::offer::handler::OfferHandlers;
6use crate::offer::state::OfferState;
7use axum::routing::{delete, get, post, put};
8use axum::Router;
9
10#[derive(Debug)]
11pub struct OfferService;
12
13impl OfferService {
14    pub fn router<S, M>(state: OfferState<S, M>) -> Router
15    where
16        S: OfferStore + Clone + Send + Sync + 'static,
17        M: OfferMetadataStore + Clone + Send + Sync + 'static,
18    {
19        Router::new()
20            .route("/offers/{partition}/{id}", get(OfferHandlers::get_offer))
21            .route("/offers/{partition}/{id}", put(OfferHandlers::put_offer))
22            .route(
23                "/offers/{partition}/{id}",
24                delete(OfferHandlers::delete_offer),
25            )
26            .route("/offers/{partition}", get(OfferHandlers::get_offers))
27            .route("/offers", post(OfferHandlers::post_offer))
28            .route(
29                "/metadata/{partition}/{id}",
30                get(OfferHandlers::get_metadata),
31            )
32            .route(
33                "/metadata/{partition}/{id}",
34                put(OfferHandlers::put_metadata),
35            )
36            .route(
37                "/metadata/{partition}/{id}",
38                delete(OfferHandlers::delete_metadata),
39            )
40            .route(
41                "/metadata/{partition}",
42                get(OfferHandlers::get_all_metadata),
43            )
44            .route("/metadata", post(OfferHandlers::post_metadata))
45            .layer(BearerTokenAuthLayer::new(
46                OfferBearerTokenValidator::new(state.auth_authority().clone()),
47                "offer",
48            ))
49            .route("/health", get(Self::health_check_handler))
50            .with_state(state)
51    }
52
53    async fn health_check_handler() -> StatusCode {
54        StatusCode::OK
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use crate::api::offer::{
61        OfferMetadata, OfferMetadataIdentifier, OfferMetadataImage, OfferMetadataSparse,
62        OfferMetadataStore, OfferRecord, OfferRecordRest, OfferRecordSparse, OfferStore,
63    };
64    use crate::components::offer::memory::MemoryOfferStore;
65    use crate::offer::service::OfferService;
66    use crate::offer::state::OfferState;
67    use crate::{OfferAudience, OfferClaims};
68    use axum::http::StatusCode;
69    use axum_test::TestServer;
70    use chrono::{Duration, Utc};
71    use jsonwebtoken::{encode, Algorithm, DecodingKey, EncodingKey, Header};
72    use p256::ecdsa::SigningKey;
73    use p256::pkcs8::EncodePrivateKey;
74    use p256::pkcs8::EncodePublicKey;
75    use rand::thread_rng;
76    use std::time::{SystemTime, UNIX_EPOCH};
77    use uuid::Uuid;
78
79    fn create_test_offer_with_metadata_id(metadata_id: Uuid) -> OfferRecord {
80        OfferRecord {
81            partition: "default".to_string(),
82            id: Uuid::new_v4(),
83            offer: OfferRecordSparse {
84                max_sendable: 1000000,
85                min_sendable: 1000,
86                metadata_id,
87                timestamp: Utc::now() - Duration::hours(1),
88                expires: Some(Utc::now() + Duration::hours(1)),
89            },
90        }
91    }
92
93    fn create_test_metadata() -> OfferMetadata {
94        OfferMetadata {
95            id: Uuid::new_v4(),
96            partition: "default".to_string(),
97            metadata: OfferMetadataSparse {
98                text: "Test offer".to_string(),
99                long_text: Some("This is a test offer description".to_string()),
100                image: Some(OfferMetadataImage::Png(vec![0x89, 0x50, 0x4E, 0x47])),
101                identifier: Some(OfferMetadataIdentifier::Email(
102                    "test@example.com".parse().unwrap(),
103                )),
104            },
105        }
106    }
107
108    async fn create_test_server_with_offer(
109        offers: Vec<OfferRecord>,
110        metadata: Vec<OfferMetadata>,
111    ) -> TestServerWithAuthorization {
112        let mut rng = thread_rng();
113        let private_key = SigningKey::random(&mut rng);
114        let public_key = *private_key.verifying_key();
115
116        let private_key = private_key
117            .to_pkcs8_pem(p256::pkcs8::LineEnding::default())
118            .unwrap();
119        let encoding_key = EncodingKey::from_ec_pem(private_key.as_bytes()).unwrap();
120
121        let public_key = public_key
122            .to_public_key_pem(p256::pkcs8::LineEnding::default())
123            .unwrap();
124        let decoding_key = DecodingKey::from_ec_pem(public_key.as_bytes()).unwrap();
125
126        let header = Header::new(Algorithm::ES256);
127        let claims = OfferClaims {
128            aud: OfferAudience::Offer,
129            exp: (SystemTime::now()
130                .duration_since(UNIX_EPOCH)
131                .unwrap()
132                .as_secs()
133                + 3600) as usize,
134        };
135        let authorization = encode(&header, &claims, &encoding_key).unwrap();
136
137        let store = MemoryOfferStore::default();
138
139        for m in metadata {
140            store.put_metadata(m).await.unwrap();
141        }
142
143        for o in offers {
144            store.put_offer(o).await.unwrap();
145        }
146
147        let state = OfferState::new(store.clone(), store, decoding_key, 100);
148
149        let app = OfferService::router(state);
150        TestServerWithAuthorization {
151            server: TestServer::new(app).unwrap(),
152            authorization,
153        }
154    }
155
156    async fn create_test_server_with_metadata(
157        metadata: OfferMetadata,
158    ) -> TestServerWithAuthorization {
159        let mut rng = thread_rng();
160        let private_key = SigningKey::random(&mut rng);
161        let public_key = *private_key.verifying_key();
162
163        let private_key = private_key
164            .to_pkcs8_pem(p256::pkcs8::LineEnding::default())
165            .unwrap();
166        let encoding_key = EncodingKey::from_ec_pem(private_key.as_bytes()).unwrap();
167
168        let public_key = public_key
169            .to_public_key_pem(p256::pkcs8::LineEnding::default())
170            .unwrap();
171        let decoding_key = DecodingKey::from_ec_pem(public_key.as_bytes()).unwrap();
172
173        let header = Header::new(Algorithm::ES256);
174        let claims = OfferClaims {
175            aud: OfferAudience::Offer,
176            exp: (SystemTime::now()
177                .duration_since(UNIX_EPOCH)
178                .unwrap()
179                .as_secs()
180                + 3600) as usize,
181        };
182        let authorization = encode(&header, &claims, &encoding_key).unwrap();
183
184        let store = MemoryOfferStore::default();
185        store.put_metadata(metadata).await.unwrap();
186        let state = OfferState::new(store.clone(), store, decoding_key, 100);
187
188        let app = OfferService::router(state);
189        TestServerWithAuthorization {
190            server: TestServer::new(app).unwrap(),
191            authorization,
192        }
193    }
194
195    fn create_empty_test_server() -> TestServerWithAuthorization {
196        let mut rng = thread_rng();
197        let private_key = SigningKey::random(&mut rng);
198        let public_key = *private_key.verifying_key();
199
200        let private_key = private_key
201            .to_pkcs8_pem(p256::pkcs8::LineEnding::default())
202            .unwrap();
203        let encoding_key = EncodingKey::from_ec_pem(private_key.as_bytes()).unwrap();
204
205        let public_key = public_key
206            .to_public_key_pem(p256::pkcs8::LineEnding::default())
207            .unwrap();
208        let decoding_key = DecodingKey::from_ec_pem(public_key.as_bytes()).unwrap();
209
210        let header = Header::new(Algorithm::ES256);
211        let claims = OfferClaims {
212            aud: OfferAudience::Offer,
213            exp: (SystemTime::now()
214                .duration_since(UNIX_EPOCH)
215                .unwrap()
216                .as_secs()
217                + 3600) as usize,
218        };
219        let authorization = encode(&header, &claims, &encoding_key).unwrap();
220
221        let store = MemoryOfferStore::default();
222        let state = OfferState::new(store.clone(), store, decoding_key, 100);
223
224        let app = OfferService::router(state);
225        TestServerWithAuthorization {
226            server: TestServer::new(app).unwrap(),
227            authorization,
228        }
229    }
230
231    struct TestServerWithAuthorization {
232        server: TestServer,
233        authorization: String,
234    }
235
236    // Health Check Tests
237
238    #[tokio::test]
239    async fn health_check_when_called_then_returns_ok() {
240        let server = create_empty_test_server();
241        let response = server.server.get("/health").await;
242
243        assert_eq!(response.status_code(), StatusCode::OK);
244    }
245
246    // Offer Tests
247
248    #[tokio::test]
249    async fn delete_offer_when_exists_then_removes_and_second_delete_not_found() {
250        let test_metadata = create_test_metadata();
251        let test_offer = create_test_offer_with_metadata_id(test_metadata.id);
252        let offer_id = test_offer.id;
253        let server = create_test_server_with_offer(vec![test_offer], vec![test_metadata]).await;
254        let response = server
255            .server
256            .delete(&format!("/offers/default/{offer_id}"))
257            .authorization_bearer(server.authorization.clone())
258            .await;
259
260        assert_eq!(response.status_code(), StatusCode::NO_CONTENT);
261
262        // Delete again and assert NOT_FOUND
263        let response = server
264            .server
265            .delete(&format!("/offers/default/{offer_id}"))
266            .authorization_bearer(server.authorization.clone())
267            .await;
268        assert_eq!(response.status_code(), StatusCode::NOT_FOUND);
269    }
270
271    #[tokio::test]
272    async fn delete_offer_when_not_exists_then_returns_not_found() {
273        let server = create_empty_test_server();
274        let non_existent_id = Uuid::new_v4();
275        let response = server
276            .server
277            .delete(&format!("/offers/default/{non_existent_id}"))
278            .authorization_bearer(server.authorization.clone())
279            .await;
280
281        assert_eq!(response.status_code(), StatusCode::NOT_FOUND);
282    }
283
284    #[tokio::test]
285    async fn get_offer_when_exists_then_returns_resource() {
286        let test_metadata = create_test_metadata();
287        let test_offer = create_test_offer_with_metadata_id(test_metadata.id);
288        let offer_id = test_offer.id;
289
290        let server =
291            create_test_server_with_offer(vec![test_offer.clone()], vec![test_metadata]).await;
292        let response = server
293            .server
294            .get(&format!("/offers/default/{offer_id}"))
295            .authorization_bearer(server.authorization.clone())
296            .await;
297
298        assert_eq!(response.status_code(), StatusCode::OK);
299        let returned_offer: OfferRecord = response.json();
300        assert_eq!(returned_offer.id, offer_id);
301        assert_eq!(
302            returned_offer.offer.max_sendable,
303            test_offer.offer.max_sendable
304        );
305    }
306
307    #[tokio::test]
308    async fn get_offer_when_invalid_uuid_then_returns_not_found() {
309        let server = create_empty_test_server();
310        let response = server
311            .server
312            .get("/offers/default/invalid-uuid")
313            .authorization_bearer(server.authorization.clone())
314            .await;
315
316        assert_eq!(response.status_code(), StatusCode::NOT_FOUND);
317    }
318
319    #[tokio::test]
320    async fn get_offer_when_not_exists_then_returns_not_found() {
321        let server = create_empty_test_server();
322        let non_existent_id = Uuid::new_v4();
323        let response = server
324            .server
325            .get(&format!("/offers/default/{non_existent_id}"))
326            .authorization_bearer(server.authorization.clone())
327            .await;
328
329        assert_eq!(response.status_code(), StatusCode::NOT_FOUND);
330    }
331
332    #[tokio::test]
333    async fn get_offers_when_empty_then_returns_empty_list() {
334        let server = create_empty_test_server();
335        let response = server
336            .server
337            .get("/offers/default")
338            .authorization_bearer(server.authorization.clone())
339            .await;
340
341        assert_eq!(response.status_code(), StatusCode::OK);
342        let offers: Vec<OfferRecord> = response.json();
343        assert!(offers.is_empty());
344    }
345
346    #[tokio::test]
347    async fn get_offers_when_exists_then_returns_list() {
348        let test_metadata = create_test_metadata();
349        let metadata_id = test_metadata.id;
350
351        let mut expected_offers = Vec::new();
352        for i in 0..10 {
353            let mut offer = create_test_offer_with_metadata_id(metadata_id);
354            offer.id = Uuid::from_u128(i as u128);
355            expected_offers.push(offer);
356        }
357
358        let server =
359            create_test_server_with_offer(expected_offers.clone(), vec![test_metadata]).await;
360
361        let response = server
362            .server
363            .get("/offers/default")
364            .authorization_bearer(server.authorization.clone())
365            .await;
366        assert_eq!(response.status_code(), StatusCode::OK);
367        let all_offers: Vec<OfferRecordRest> = response.json();
368        let all_offers: Vec<OfferRecord> = all_offers.into_iter().map(|r| r.offer).collect();
369        assert_eq!(all_offers.as_slice(), expected_offers.as_slice());
370
371        let response = server
372            .server
373            .get("/offers/default?start=1")
374            .authorization_bearer(server.authorization.clone())
375            .await;
376        assert_eq!(response.status_code(), StatusCode::OK);
377        let next_nine: Vec<OfferRecordRest> = response.json();
378        let next_nine: Vec<OfferRecord> = next_nine.into_iter().map(|r| r.offer).collect();
379        assert_eq!(next_nine.as_slice(), &expected_offers[1..]);
380
381        let response = server
382            .server
383            .get("/offers/default?count=1")
384            .authorization_bearer(server.authorization.clone())
385            .await;
386        assert_eq!(response.status_code(), StatusCode::OK);
387        let first: Vec<OfferRecordRest> = response.json();
388        let first: Vec<OfferRecord> = first.into_iter().map(|r| r.offer).collect();
389        assert_eq!(first.as_slice(), &expected_offers[0..1]);
390
391        let response = server
392            .server
393            .get("/offers/default?start=3&count=4")
394            .authorization_bearer(server.authorization.clone())
395            .await;
396        assert_eq!(response.status_code(), StatusCode::OK);
397        let middle_offers: Vec<OfferRecordRest> = response.json();
398        let middle_offers: Vec<OfferRecord> = middle_offers.into_iter().map(|r| r.offer).collect();
399        assert_eq!(middle_offers.as_slice(), &expected_offers[3..7]);
400
401        let response = server
402            .server
403            .get("/offers/default?count=101")
404            .authorization_bearer(server.authorization.clone())
405            .await;
406        assert_eq!(response.status_code(), StatusCode::BAD_REQUEST);
407    }
408
409    #[tokio::test]
410    async fn post_offer_when_new_then_creates_and_returns_location() {
411        let test_metadata = create_test_metadata();
412        let metadata_id = test_metadata.id;
413        let server = create_test_server_with_metadata(test_metadata).await;
414
415        let test_offer = create_test_offer_with_metadata_id(metadata_id);
416        let response = server
417            .server
418            .post("/offers")
419            .authorization_bearer(server.authorization.clone())
420            .json(&test_offer)
421            .await;
422
423        assert_eq!(response.status_code(), StatusCode::CREATED);
424        assert!(response.headers().contains_key("location"));
425
426        // Get the location header and make a GET request
427        let location = response
428            .headers()
429            .get("location")
430            .unwrap()
431            .to_str()
432            .unwrap();
433        let get_response = server
434            .server
435            .get(&format!("/offers/{location}"))
436            .authorization_bearer(server.authorization.clone())
437            .await;
438
439        assert_eq!(get_response.status_code(), StatusCode::OK);
440        let returned_offer: OfferRecord = get_response.json();
441        assert_eq!(returned_offer.id, test_offer.id);
442        assert_eq!(
443            returned_offer.offer.max_sendable,
444            test_offer.offer.max_sendable
445        );
446        assert_eq!(
447            returned_offer.offer.min_sendable,
448            test_offer.offer.min_sendable
449        );
450        assert_eq!(
451            returned_offer.offer.metadata_id,
452            test_offer.offer.metadata_id
453        );
454
455        // Post again and assert CONFLICT
456        let response = server
457            .server
458            .post("/offers")
459            .json(&test_offer)
460            .authorization_bearer(server.authorization.clone())
461            .await;
462        assert_eq!(response.status_code(), StatusCode::CONFLICT);
463        assert!(response.headers().contains_key("location"));
464    }
465
466    #[tokio::test]
467    async fn put_offer_when_exists_then_updates_no_content() {
468        let test_metadata = create_test_metadata();
469        let test_offer = create_test_offer_with_metadata_id(test_metadata.id);
470        let offer_id = test_offer.id;
471        let server =
472            create_test_server_with_offer(vec![test_offer.clone()], vec![test_metadata]).await;
473
474        let mut updated_offer = test_offer.offer.clone();
475        updated_offer.max_sendable = 2000000;
476
477        let response = server
478            .server
479            .put(&format!("/offers/default/{offer_id}"))
480            .authorization_bearer(server.authorization.clone())
481            .json(&updated_offer)
482            .await;
483
484        assert_eq!(response.status_code(), StatusCode::NO_CONTENT);
485    }
486
487    #[tokio::test]
488    async fn put_offer_when_new_then_created() {
489        let test_metadata = create_test_metadata();
490        let metadata_id = test_metadata.id;
491        let server = create_test_server_with_metadata(test_metadata).await;
492
493        let test_offer = create_test_offer_with_metadata_id(metadata_id);
494        let offer_id = test_offer.id;
495        let response = server
496            .server
497            .put(&format!("/offers/default/{offer_id}"))
498            .authorization_bearer(server.authorization.clone())
499            .json(&test_offer.offer)
500            .await;
501
502        assert_eq!(response.status_code(), StatusCode::CREATED);
503    }
504
505    #[tokio::test]
506    async fn post_offer_when_metadata_missing_then_returns_bad_request() {
507        let server = create_empty_test_server();
508        let non_existent_metadata_id = Uuid::new_v4();
509        let test_offer = create_test_offer_with_metadata_id(non_existent_metadata_id);
510
511        let response = server
512            .server
513            .post("/offers")
514            .authorization_bearer(server.authorization.clone())
515            .json(&test_offer)
516            .await;
517
518        assert_eq!(response.status_code(), StatusCode::BAD_REQUEST);
519    }
520
521    #[tokio::test]
522    async fn put_offer_when_metadata_missing_then_returns_bad_request() {
523        // First create a valid metadata and offer
524        let test_metadata = create_test_metadata();
525        let metadata_id = test_metadata.id;
526        let server = create_test_server_with_metadata(test_metadata).await;
527
528        let test_offer = create_test_offer_with_metadata_id(metadata_id);
529        let offer_id = test_offer.id;
530
531        // Successfully PUT the offer with valid metadata
532        let response = server
533            .server
534            .put(&format!("/offers/default/{offer_id}"))
535            .authorization_bearer(server.authorization.clone())
536            .json(&test_offer.offer)
537            .await;
538
539        assert_eq!(response.status_code(), StatusCode::CREATED);
540
541        // Verify the offer was created successfully
542        let get_response = server
543            .server
544            .get(&format!("/offers/default/{offer_id}"))
545            .authorization_bearer(server.authorization.clone())
546            .await;
547
548        assert_eq!(get_response.status_code(), StatusCode::OK);
549        let created_offer: OfferRecord = get_response.json();
550        assert_eq!(created_offer.id, offer_id);
551        assert_eq!(created_offer.offer.metadata_id, metadata_id);
552
553        // Now try to update the offer with a non-existent metadata_id
554        let non_existent_metadata_id = Uuid::new_v4();
555        let mut invalid_offer = test_offer.offer.clone();
556        invalid_offer.metadata_id = non_existent_metadata_id;
557
558        let response = server
559            .server
560            .put(&format!("/offers/default/{offer_id}"))
561            .authorization_bearer(server.authorization.clone())
562            .json(&invalid_offer)
563            .await;
564
565        assert_eq!(response.status_code(), StatusCode::BAD_REQUEST);
566    }
567
568    #[tokio::test]
569    async fn delete_metadata_when_referenced_by_offers_then_returns_bad_request() {
570        // Create metadata first
571        let test_metadata = create_test_metadata();
572        let metadata_id = test_metadata.id;
573        let server = create_test_server_with_metadata(test_metadata).await;
574
575        // Create offer that references this metadata
576        let test_offer = create_test_offer_with_metadata_id(metadata_id);
577        let response = server
578            .server
579            .put(&format!("/offers/default/{}", test_offer.id))
580            .authorization_bearer(server.authorization.clone())
581            .json(&test_offer.offer)
582            .await;
583
584        assert_eq!(response.status_code(), StatusCode::CREATED);
585
586        // Try to delete the metadata - should fail because offer references it
587        let response = server
588            .server
589            .delete(&format!("/metadata/default/{metadata_id}"))
590            .authorization_bearer(server.authorization.clone())
591            .await;
592
593        assert_eq!(response.status_code(), StatusCode::BAD_REQUEST);
594
595        // Delete the referencing offer
596        let delete_offer_response = server
597            .server
598            .delete(&format!("/offers/default/{}", test_offer.id))
599            .authorization_bearer(server.authorization.clone())
600            .await;
601
602        assert_eq!(delete_offer_response.status_code(), StatusCode::NO_CONTENT);
603
604        // Second attempt to delete the metadata should succeed
605        let second_response = server
606            .server
607            .delete(&format!("/metadata/default/{metadata_id}"))
608            .authorization_bearer(server.authorization.clone())
609            .await;
610
611        assert_eq!(second_response.status_code(), StatusCode::NO_CONTENT);
612    }
613
614    // Metadata Tests
615
616    #[tokio::test]
617    async fn delete_metadata_when_exists_then_removes_and_second_delete_not_found() {
618        let test_metadata = create_test_metadata();
619        let metadata_id = test_metadata.id;
620        let server = create_test_server_with_metadata(test_metadata).await;
621        let response = server
622            .server
623            .delete(&format!("/metadata/default/{metadata_id}"))
624            .authorization_bearer(server.authorization.clone())
625            .await;
626
627        assert_eq!(response.status_code(), StatusCode::NO_CONTENT);
628
629        // Delete again and assert NOT_FOUND
630        let response = server
631            .server
632            .delete(&format!("/metadata/default/{metadata_id}"))
633            .authorization_bearer(server.authorization.clone())
634            .await;
635        assert_eq!(response.status_code(), StatusCode::NOT_FOUND);
636    }
637
638    #[tokio::test]
639    async fn delete_metadata_when_not_exists_then_returns_not_found() {
640        let server = create_empty_test_server();
641        let non_existent_id = Uuid::new_v4();
642        let response = server
643            .server
644            .delete(&format!("/metadata/default/{non_existent_id}"))
645            .authorization_bearer(server.authorization.clone())
646            .await;
647
648        assert_eq!(response.status_code(), StatusCode::NOT_FOUND);
649    }
650
651    #[tokio::test]
652    async fn get_metadata_when_exists_then_returns_resource() {
653        let test_metadata = create_test_metadata();
654        let metadata_id = test_metadata.id;
655        let server = create_test_server_with_metadata(test_metadata.clone()).await;
656        let response = server
657            .server
658            .get(&format!("/metadata/default/{metadata_id}"))
659            .authorization_bearer(server.authorization.clone())
660            .await;
661
662        assert_eq!(response.status_code(), StatusCode::OK);
663        let returned_metadata: OfferMetadata = response.json();
664        assert_eq!(returned_metadata.id, metadata_id);
665        assert_eq!(returned_metadata.metadata.text, test_metadata.metadata.text);
666    }
667
668    #[tokio::test]
669    async fn get_metadata_when_not_exists_then_returns_not_found() {
670        let server = create_empty_test_server();
671        let non_existent_id = Uuid::new_v4();
672        let response = server
673            .server
674            .get(&format!("/metadata/default/{non_existent_id}"))
675            .authorization_bearer(server.authorization.clone())
676            .await;
677
678        assert_eq!(response.status_code(), StatusCode::NOT_FOUND);
679    }
680
681    #[tokio::test]
682    async fn get_all_metadata_when_empty_then_returns_empty_list() {
683        let server = create_empty_test_server();
684        let response = server
685            .server
686            .get("/metadata/default")
687            .authorization_bearer(server.authorization.clone())
688            .await;
689
690        assert_eq!(response.status_code(), StatusCode::OK);
691        let metadata: Vec<OfferMetadata> = response.json();
692        assert!(metadata.is_empty());
693    }
694
695    #[tokio::test]
696    async fn get_all_metadata_when_exists_then_returns_list() {
697        use crate::api::offer::OfferMetadataRest;
698
699        let mut expected_metadata = Vec::new();
700        for i in 0..10 {
701            let mut metadata = create_test_metadata();
702            metadata.id = Uuid::from_u128(i as u128);
703            expected_metadata.push(metadata);
704        }
705
706        let server = create_test_server_with_offer(vec![], expected_metadata.clone()).await;
707
708        let response = server
709            .server
710            .get("/metadata/default")
711            .authorization_bearer(server.authorization.clone())
712            .await;
713        assert_eq!(response.status_code(), StatusCode::OK);
714        let all_metadata: Vec<OfferMetadataRest> = response.json();
715        let all_metadata: Vec<OfferMetadata> =
716            all_metadata.into_iter().map(|r| r.metadata).collect();
717        assert_eq!(all_metadata.as_slice(), expected_metadata.as_slice());
718
719        let response = server
720            .server
721            .get("/metadata/default?start=1")
722            .authorization_bearer(server.authorization.clone())
723            .await;
724        assert_eq!(response.status_code(), StatusCode::OK);
725        let next_nine: Vec<OfferMetadataRest> = response.json();
726        let next_nine: Vec<OfferMetadata> = next_nine.into_iter().map(|r| r.metadata).collect();
727        assert_eq!(next_nine.as_slice(), &expected_metadata[1..]);
728
729        let response = server
730            .server
731            .get("/metadata/default?count=1")
732            .authorization_bearer(server.authorization.clone())
733            .await;
734        assert_eq!(response.status_code(), StatusCode::OK);
735        let first: Vec<OfferMetadataRest> = response.json();
736        let first: Vec<OfferMetadata> = first.into_iter().map(|r| r.metadata).collect();
737        assert_eq!(first.as_slice(), &expected_metadata[0..1]);
738
739        let response = server
740            .server
741            .get("/metadata/default?start=3&count=4")
742            .authorization_bearer(server.authorization.clone())
743            .await;
744        assert_eq!(response.status_code(), StatusCode::OK);
745        let middle_metadata: Vec<OfferMetadataRest> = response.json();
746        let middle_metadata: Vec<OfferMetadata> =
747            middle_metadata.into_iter().map(|r| r.metadata).collect();
748        assert_eq!(middle_metadata.as_slice(), &expected_metadata[3..7]);
749
750        let response = server
751            .server
752            .get("/metadata/default?count=101")
753            .authorization_bearer(server.authorization.clone())
754            .await;
755        assert_eq!(response.status_code(), StatusCode::BAD_REQUEST);
756    }
757
758    #[tokio::test]
759    async fn post_metadata_when_new_then_creates_and_returns_location() {
760        let server = create_empty_test_server();
761        let test_metadata = create_test_metadata();
762        let response = server
763            .server
764            .post("/metadata")
765            .authorization_bearer(server.authorization.clone())
766            .json(&test_metadata)
767            .await;
768
769        assert_eq!(response.status_code(), StatusCode::CREATED);
770        assert!(response.headers().contains_key("location"));
771
772        // Get the location header and make a GET request
773        let location = response
774            .headers()
775            .get("location")
776            .unwrap()
777            .to_str()
778            .unwrap();
779        let get_response = server
780            .server
781            .get(&format!("/metadata/{location}"))
782            .authorization_bearer(server.authorization.clone())
783            .await;
784
785        assert_eq!(get_response.status_code(), StatusCode::OK);
786        let returned_metadata: OfferMetadata = get_response.json();
787        assert_eq!(returned_metadata.id, test_metadata.id);
788        assert_eq!(returned_metadata.metadata.text, test_metadata.metadata.text);
789        assert_eq!(
790            returned_metadata.metadata.long_text,
791            test_metadata.metadata.long_text
792        );
793        assert_eq!(
794            returned_metadata.metadata.image,
795            test_metadata.metadata.image
796        );
797        assert_eq!(
798            returned_metadata.metadata.identifier,
799            test_metadata.metadata.identifier
800        );
801
802        // Post again and assert CONFLICT
803        let response = server
804            .server
805            .post("/metadata")
806            .json(&test_metadata)
807            .authorization_bearer(server.authorization.clone())
808            .await;
809        assert_eq!(response.status_code(), StatusCode::CONFLICT);
810        assert!(response.headers().contains_key("location"));
811    }
812
813    #[tokio::test]
814    async fn put_metadata_when_exists_then_updates_no_content() {
815        let test_metadata = create_test_metadata();
816        let metadata_id = test_metadata.id;
817        let server = create_test_server_with_metadata(test_metadata.clone()).await;
818
819        let mut updated_metadata = test_metadata.metadata.clone();
820        updated_metadata.text = "Updated text".to_string();
821
822        let response = server
823            .server
824            .put(&format!("/metadata/default/{metadata_id}"))
825            .authorization_bearer(server.authorization.clone())
826            .json(&updated_metadata)
827            .await;
828
829        assert_eq!(response.status_code(), StatusCode::NO_CONTENT);
830    }
831
832    #[tokio::test]
833    async fn put_metadata_when_new_then_created() {
834        let server = create_empty_test_server();
835        let test_metadata = create_test_metadata();
836        let metadata_id = test_metadata.id;
837        let response = server
838            .server
839            .put(&format!("/metadata/default/{metadata_id}"))
840            .authorization_bearer(server.authorization.clone())
841            .json(&test_metadata.metadata)
842            .await;
843
844        assert_eq!(response.status_code(), StatusCode::CREATED);
845    }
846
847    #[tokio::test]
848    async fn unauthorized() {
849        let server = create_empty_test_server();
850        let test_metadata = create_test_metadata();
851        let test_offer = create_test_offer_with_metadata_id(test_metadata.id);
852
853        let response = server.server.post("/offers").json(&test_offer).await;
854
855        assert_eq!(response.status_code(), StatusCode::UNAUTHORIZED);
856
857        let response = server.server.get("/offers/default").await;
858
859        assert_eq!(response.status_code(), StatusCode::UNAUTHORIZED);
860
861        let response = server.server.put("/offers/default").json(&test_offer).await;
862
863        assert_eq!(response.status_code(), StatusCode::UNAUTHORIZED);
864
865        let response = server.server.delete("/offers/default").await;
866
867        assert_eq!(response.status_code(), StatusCode::UNAUTHORIZED);
868
869        let response = server.server.post("/metadata").json(&test_offer).await;
870
871        assert_eq!(response.status_code(), StatusCode::UNAUTHORIZED);
872
873        let response = server.server.get("/metadata/default").await;
874
875        assert_eq!(response.status_code(), StatusCode::UNAUTHORIZED);
876
877        let response = server
878            .server
879            .put("/metadata/default")
880            .json(&test_offer)
881            .await;
882
883        assert_eq!(response.status_code(), StatusCode::UNAUTHORIZED);
884
885        let response = server.server.delete("/metadata/default").await;
886
887        assert_eq!(response.status_code(), StatusCode::UNAUTHORIZED);
888    }
889}