use axum::{ extract::{Json, State}, http::StatusCode, }; use crate::{ push::app::SubscribeError, test::{fixtures, fixtures::event}, }; #[tokio::test] async fn accepts_new_subscription() { let app = fixtures::scratch_app().await; let subscriber = fixtures::identity::create(&app, &fixtures::now()).await; // Issue a VAPID key. app.vapid() .refresh_key(&fixtures::now()) .await .expect("refreshing the VAPID key always succeeds"); // Find out what that VAPID key is. let boot = app.boot().snapshot().await.expect("boot always succeeds"); let vapid = boot .events .into_iter() .filter_map(event::vapid) .filter_map(event::vapid::changed) .next_back() .expect("the application will have a vapid key after a refresh"); // Create a dummy subscription with that key. let request = super::Request { subscription: super::Subscription { endpoint: String::from("https://push.example.com/endpoint"), keys: super::Keys { p256dh: String::from("test-p256dh-value"), auth: String::from("test-auth-value"), }, }, vapid: vapid.key, }; let response = super::handler(State(app.push()), subscriber, Json(request)) .await .expect("test request will succeed on a fresh app"); // Check that the response looks as expected. assert_eq!(StatusCode::CREATED, response); } #[tokio::test] async fn accepts_repeat_subscription() { let app = fixtures::scratch_app().await; let subscriber = fixtures::identity::create(&app, &fixtures::now()).await; // Issue a VAPID key. app.vapid() .refresh_key(&fixtures::now()) .await .expect("refreshing the VAPID key always succeeds"); // Find out what that VAPID key is. let boot = app.boot().snapshot().await.expect("boot always succeeds"); let vapid = boot .events .into_iter() .filter_map(event::vapid) .filter_map(event::vapid::changed) .next_back() .expect("the application will have a vapid key after a refresh"); // Create a dummy subscription with that key. let request = super::Request { subscription: super::Subscription { endpoint: String::from("https://push.example.com/endpoint"), keys: super::Keys { p256dh: String::from("test-p256dh-value"), auth: String::from("test-auth-value"), }, }, vapid: vapid.key, }; let response = super::handler(State(app.push()), subscriber.clone(), Json(request.clone())) .await .expect("test request will succeed on a fresh app"); // Check that the response looks as expected. assert_eq!(StatusCode::CREATED, response); // Repeat the request let response = super::handler(State(app.push()), subscriber, Json(request)) .await .expect("test request will succeed twice on a fresh app"); // Check that the second response also looks as expected. assert_eq!(StatusCode::CREATED, response); } #[tokio::test] async fn rejects_duplicate_subscription() { let app = fixtures::scratch_app().await; let subscriber = fixtures::identity::create(&app, &fixtures::now()).await; // Issue a VAPID key. app.vapid() .refresh_key(&fixtures::now()) .await .expect("refreshing the VAPID key always succeeds"); // Find out what that VAPID key is. let boot = app.boot().snapshot().await.expect("boot always succeeds"); let vapid = boot .events .into_iter() .filter_map(event::vapid) .filter_map(event::vapid::changed) .next_back() .expect("the application will have a vapid key after a refresh"); // Create a dummy subscription with that key. let request = super::Request { subscription: super::Subscription { endpoint: String::from("https://push.example.com/endpoint"), keys: super::Keys { p256dh: String::from("test-p256dh-value"), auth: String::from("test-auth-value"), }, }, vapid: vapid.key, }; super::handler(State(app.push()), subscriber.clone(), Json(request)) .await .expect("test request will succeed on a fresh app"); // Repeat the request with different keys let request = super::Request { subscription: super::Subscription { endpoint: String::from("https://push.example.com/endpoint"), keys: super::Keys { p256dh: String::from("different-test-p256dh-value"), auth: String::from("different-test-auth-value"), }, }, vapid: vapid.key, }; let response = super::handler(State(app.push()), subscriber, Json(request)) .await .expect_err("request with duplicate endpoint should fail"); // Make sure we got the error we expected. assert!(matches!(response, super::Error(SubscribeError::Duplicate))); } #[tokio::test] async fn rejects_stale_vapid_key() { let app = fixtures::scratch_app().await; let subscriber = fixtures::identity::create(&app, &fixtures::now()).await; // Issue a VAPID key. app.vapid() .refresh_key(&fixtures::now()) .await .expect("refreshing the VAPID key always succeeds"); // Find out what that VAPID key is. let boot = app.boot().snapshot().await.expect("boot always succeeds"); let vapid = boot .events .into_iter() .filter_map(event::vapid) .filter_map(event::vapid::changed) .next_back() .expect("the application will have a vapid key after a refresh"); // Change the VAPID key. app.vapid() .rotate_key() .await .expect("key rotation always succeeds"); app.vapid() .refresh_key(&fixtures::now()) .await .expect("refreshing the VAPID key always succeeds"); // Find out what the new VAPID key is. let boot = app.boot().snapshot().await.expect("boot always succeeds"); let fresh_vapid = boot .events .into_iter() .filter_map(event::vapid) .filter_map(event::vapid::changed) .next_back() .expect("the application will have a vapid key after a refresh"); // Create a dummy subscription with the original key. let request = super::Request { subscription: super::Subscription { endpoint: String::from("https://push.example.com/endpoint"), keys: super::Keys { p256dh: String::from("test-p256dh-value"), auth: String::from("test-auth-value"), }, }, vapid: vapid.key, }; let response = super::handler(State(app.push()), subscriber, Json(request)) .await .expect_err("test request has a stale vapid key"); // Check that the response looks as expected. assert!(matches!( response, super::Error(SubscribeError::StaleVapidKey(key)) if key == fresh_vapid.key )); }