use std::{collections::HashSet, io}; use axum::{ extract::{Json, State}, http::StatusCode, }; use itertools::Itertools; use web_push::{SubscriptionInfo, WebPushError}; use crate::{event::Heartbeat, test::fixtures}; #[tokio::test] async fn ping_without_subscriptions() { let app = fixtures::scratch_app().await; let recipient = fixtures::identity::create(&app, &fixtures::now()).await; let response = super::handler(State(app.push()), recipient, Json(super::Request {})) .await .expect("sending a ping with no subscriptions always succeeds"); assert_eq!(StatusCode::ACCEPTED, response); assert!( app.publisher() .sent() .into_iter() .filter(|publish| publish.message_eq(&Heartbeat::Heartbeat) && publish.recipients.is_empty()) .exactly_one() .is_ok() ); } #[tokio::test] async fn ping() { let app = fixtures::scratch_app().await; let recipient = fixtures::identity::create(&app, &fixtures::now()).await; let vapid = fixtures::vapid::key(&app).await; // Create a subscription let subscription = SubscriptionInfo::new( "https://push.example.com/endpoint", "testing-p256dh-key", "testing-auth", ); app.push() .subscribe(&recipient, &subscription, &vapid) .await .expect("creating a subscription succeeds"); // Send a ping let response = super::handler(State(app.push()), recipient, Json(super::Request {})) .await .expect("sending a ping succeeds"); assert_eq!(StatusCode::ACCEPTED, response); // Confirm that it was actually sent let subscriptions = HashSet::from([subscription]); assert!( app.publisher() .sent() .into_iter() .filter(|publish| publish.message_eq(&Heartbeat::Heartbeat) && publish.recipients == subscriptions) .exactly_one() .is_ok() ); } #[tokio::test] async fn ping_multiple_subscriptions() { let app = fixtures::scratch_app().await; let recipient = fixtures::identity::create(&app, &fixtures::now()).await; let vapid = fixtures::vapid::key(&app).await; // Create a subscription let subscriptions = HashSet::from([ SubscriptionInfo::new( "https://push.example.com/endpoint-1", "testing-p256dh-key-1", "testing-auth-1", ), SubscriptionInfo::new( "https://push.example.com/endpoint-2", "testing-p256dh-key-2", "testing-auth-2", ), ]); for subscription in &subscriptions { app.push() .subscribe(&recipient, subscription, &vapid) .await .expect("creating a subscription succeeds"); } // Send a ping let response = super::handler(State(app.push()), recipient, Json(super::Request {})) .await .expect("sending a ping succeeds"); assert_eq!(StatusCode::ACCEPTED, response); // Confirm that it was actually sent assert!( app.publisher() .sent() .into_iter() .filter(|publish| publish.message_eq(&Heartbeat::Heartbeat) && publish.recipients == subscriptions) .exactly_one() .is_ok() ); } #[tokio::test] async fn ping_recipient_only() { let app = fixtures::scratch_app().await; let recipient = fixtures::identity::create(&app, &fixtures::now()).await; let spectator = fixtures::identity::create(&app, &fixtures::now()).await; let vapid = fixtures::vapid::key(&app).await; // Create subscriptions for each user let recipient_subscription = SubscriptionInfo::new( "https://push.example.com/recipient/endpoint", "recipient-p256dh-key", "recipient-auth", ); app.push() .subscribe(&recipient, &recipient_subscription, &vapid) .await .expect("creating a subscription succeeds"); let spectator_subscription = SubscriptionInfo::new( "https://push.example.com/spectator/endpoint", "spectator-p256dh-key", "spectator-auth", ); app.push() .subscribe(&spectator, &spectator_subscription, &vapid) .await .expect("creating a subscription succeeds"); // Send a ping let response = super::handler(State(app.push()), recipient, Json(super::Request {})) .await .expect("sending a ping succeeds"); assert_eq!(StatusCode::ACCEPTED, response); // Confirm that it was actually sent to the recipient let sent = app.publisher().sent(); let recipient_subscriptions = HashSet::from([recipient_subscription]); assert!( sent.iter() .filter(|publish| publish.message_eq(&Heartbeat::Heartbeat) && publish.recipients == recipient_subscriptions) .exactly_one() .is_ok() ); // Confirm that it was not sent to the spectator assert!( !sent .iter() .any(|publish| publish.recipients.contains(&spectator_subscription)) ); }