switchgear_service/offer/
service.rs

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