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 #[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 #[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 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 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 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 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 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 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 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 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 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 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 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 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 #[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 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 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 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}