@@ -384,6 +384,168 @@ struct WebPushManagerTests {
384384 }
385385 }
386386
387+ @Test func sendCustomTopic( ) async throws {
388+ try await confirmation { requestWasMade in
389+ let vapidConfiguration = VAPID . Configuration. makeTesting ( )
390+
391+ let subscriberPrivateKey = P256 . KeyAgreement. PrivateKey ( compactRepresentable: false )
392+ var authenticationSecret : [ UInt8 ] = Array ( repeating: 0 , count: 16 )
393+ for index in authenticationSecret. indices { authenticationSecret [ index] = . random( in: . min ... . max) }
394+
395+ let subscriber = Subscriber (
396+ endpoint: URL ( string: " https://example.com/subscriber " ) !,
397+ userAgentKeyMaterial: UserAgentKeyMaterial ( publicKey: subscriberPrivateKey. publicKey, authenticationSecret: Data ( authenticationSecret) ) ,
398+ vapidKeyID: vapidConfiguration. primaryKey!. id
399+ )
400+
401+ var logger = Logger ( label: " WebPushManagerTests " , factory: { PrintLogHandler ( label: $0, metadataProvider: $1) } )
402+ logger. logLevel = . trace
403+
404+ let manager = WebPushManager (
405+ vapidConfiguration: vapidConfiguration,
406+ backgroundActivityLogger: logger,
407+ executor: . httpClient( MockHTTPClient ( { request in
408+ try validateAuthotizationHeader (
409+ request: request,
410+ vapidConfiguration: vapidConfiguration,
411+ origin: " https://example.com "
412+ )
413+ #expect( request. method == . POST)
414+ #expect( request. headers [ " Content-Encoding " ] == [ " aes128gcm " ] )
415+ #expect( request. headers [ " Content-Type " ] == [ " application/octet-stream " ] )
416+ #expect( request. headers [ " TTL " ] == [ " 2592000 " ] )
417+ #expect( request. headers [ " Urgency " ] == [ " high " ] )
418+ #expect( try request. headers [ " Topic " ] == [ Topic ( encodableTopic: " topic-id " , salt: subscriber. userAgentKeyMaterial. authenticationSecret) . topic] )
419+
420+ let message = try await decrypt (
421+ request: request,
422+ userAgentPrivateKey: subscriberPrivateKey,
423+ userAgentKeyMaterial: subscriber. userAgentKeyMaterial
424+ )
425+
426+ #expect( String ( decoding: message, as: UTF8 . self) == " hello " )
427+
428+ requestWasMade ( )
429+ return HTTPClientResponse ( status: . created)
430+ } ) )
431+ )
432+
433+ try await manager. send (
434+ string: " hello " ,
435+ to: subscriber,
436+ deduplicationTopic: Topic ( encodableTopic: " topic-id " , salt: subscriber. userAgentKeyMaterial. authenticationSecret)
437+ )
438+ }
439+ }
440+
441+ @Test func sendCustomExpiration( ) async throws {
442+ try await confirmation { requestWasMade in
443+ let vapidConfiguration = VAPID . Configuration. makeTesting ( )
444+
445+ let subscriberPrivateKey = P256 . KeyAgreement. PrivateKey ( compactRepresentable: false )
446+ var authenticationSecret : [ UInt8 ] = Array ( repeating: 0 , count: 16 )
447+ for index in authenticationSecret. indices { authenticationSecret [ index] = . random( in: . min ... . max) }
448+
449+ let subscriber = Subscriber (
450+ endpoint: URL ( string: " https://example.com/subscriber " ) !,
451+ userAgentKeyMaterial: UserAgentKeyMaterial ( publicKey: subscriberPrivateKey. publicKey, authenticationSecret: Data ( authenticationSecret) ) ,
452+ vapidKeyID: vapidConfiguration. primaryKey!. id
453+ )
454+
455+ var logger = Logger ( label: " WebPushManagerTests " , factory: { PrintLogHandler ( label: $0, metadataProvider: $1) } )
456+ logger. logLevel = . trace
457+
458+ let manager = WebPushManager (
459+ vapidConfiguration: vapidConfiguration,
460+ backgroundActivityLogger: logger,
461+ executor: . httpClient( MockHTTPClient ( { request in
462+ try validateAuthotizationHeader (
463+ request: request,
464+ vapidConfiguration: vapidConfiguration,
465+ origin: " https://example.com "
466+ )
467+ #expect( request. method == . POST)
468+ #expect( request. headers [ " Content-Encoding " ] == [ " aes128gcm " ] )
469+ #expect( request. headers [ " Content-Type " ] == [ " application/octet-stream " ] )
470+ #expect( request. headers [ " TTL " ] == [ " 0 " ] )
471+ #expect( request. headers [ " Urgency " ] == [ " high " ] )
472+ #expect( request. headers [ " Topic " ] == [ ] )
473+
474+ let message = try await decrypt (
475+ request: request,
476+ userAgentPrivateKey: subscriberPrivateKey,
477+ userAgentKeyMaterial: subscriber. userAgentKeyMaterial
478+ )
479+
480+ #expect( String ( decoding: message, as: UTF8 . self) == " hello " )
481+
482+ requestWasMade ( )
483+ return HTTPClientResponse ( status: . created)
484+ } ) )
485+ )
486+
487+ try await manager. send (
488+ string: " hello " ,
489+ to: subscriber,
490+ expiration: . dropIfUndeliverable
491+ )
492+ }
493+ }
494+
495+ @Test func sendCustomUrgency( ) async throws {
496+ try await confirmation { requestWasMade in
497+ let vapidConfiguration = VAPID . Configuration. makeTesting ( )
498+
499+ let subscriberPrivateKey = P256 . KeyAgreement. PrivateKey ( compactRepresentable: false )
500+ var authenticationSecret : [ UInt8 ] = Array ( repeating: 0 , count: 16 )
501+ for index in authenticationSecret. indices { authenticationSecret [ index] = . random( in: . min ... . max) }
502+
503+ let subscriber = Subscriber (
504+ endpoint: URL ( string: " https://example.com/subscriber " ) !,
505+ userAgentKeyMaterial: UserAgentKeyMaterial ( publicKey: subscriberPrivateKey. publicKey, authenticationSecret: Data ( authenticationSecret) ) ,
506+ vapidKeyID: vapidConfiguration. primaryKey!. id
507+ )
508+
509+ var logger = Logger ( label: " WebPushManagerTests " , factory: { PrintLogHandler ( label: $0, metadataProvider: $1) } )
510+ logger. logLevel = . trace
511+
512+ let manager = WebPushManager (
513+ vapidConfiguration: vapidConfiguration,
514+ backgroundActivityLogger: logger,
515+ executor: . httpClient( MockHTTPClient ( { request in
516+ try validateAuthotizationHeader (
517+ request: request,
518+ vapidConfiguration: vapidConfiguration,
519+ origin: " https://example.com "
520+ )
521+ #expect( request. method == . POST)
522+ #expect( request. headers [ " Content-Encoding " ] == [ " aes128gcm " ] )
523+ #expect( request. headers [ " Content-Type " ] == [ " application/octet-stream " ] )
524+ #expect( request. headers [ " TTL " ] == [ " 2592000 " ] )
525+ #expect( request. headers [ " Urgency " ] == [ " low " ] )
526+ #expect( request. headers [ " Topic " ] == [ ] )
527+
528+ let message = try await decrypt (
529+ request: request,
530+ userAgentPrivateKey: subscriberPrivateKey,
531+ userAgentKeyMaterial: subscriber. userAgentKeyMaterial
532+ )
533+
534+ #expect( String ( decoding: message, as: UTF8 . self) == " hello " )
535+
536+ requestWasMade ( )
537+ return HTTPClientResponse ( status: . created)
538+ } ) )
539+ )
540+
541+ try await manager. send (
542+ string: " hello " ,
543+ to: subscriber,
544+ urgency: . low
545+ )
546+ }
547+ }
548+
387549 @Test func sendMessageToSubscriberWithInvalidVAPIDKey( ) async throws {
388550 await confirmation ( expectedCount: 0 ) { requestWasMade in
389551 var subscriber = Subscriber . mockedSubscriber
0 commit comments