@@ -10,7 +10,11 @@ import { getBreachNotificationSubscribersByHashes } from "./BreachNotificationSu
1010import type { SubscriberRow } from "knex/types/tables" ;
1111
1212describe ( "BreachNotificationSubscriber" , ( ) => {
13- const subscriber = seeds . subscribers ( { primary_verified : true } ) ;
13+ const recentSession = new Date ( ) ;
14+ const subscriber = seeds . subscribers ( {
15+ primary_verified : true ,
16+ fxa_session_expiry : recentSession ,
17+ } ) ;
1418 const chaffSubs = Array . from ( Array ( 10 ) . keys ( ) ) . map ( ( _ ) =>
1519 seeds . subscribers ( ) ,
1620 ) ;
@@ -111,6 +115,7 @@ describe("BreachNotificationSubscriber", () => {
111115 seeds . subscribers ( {
112116 primary_verified : true ,
113117 all_emails_to_primary : true ,
118+ fxa_session_expiry : recentSession ,
114119 } ) ,
115120 )
116121 . returning ( "*" )
@@ -142,6 +147,7 @@ describe("BreachNotificationSubscriber", () => {
142147 seeds . subscribers ( {
143148 primary_verified : true ,
144149 all_emails_to_primary : false ,
150+ fxa_session_expiry : recentSession ,
145151 } ) ,
146152 )
147153 . returning ( "*" )
@@ -166,4 +172,113 @@ describe("BreachNotificationSubscriber", () => {
166172 ] ) ,
167173 ) ;
168174 } ) ;
175+
176+ it ( "excludes subscribers with null fxa_session_expiry" , async ( ) => {
177+ const inactiveSub = (
178+ await conn ( "subscribers" )
179+ . insert (
180+ seeds . subscribers ( {
181+ primary_verified : true ,
182+ fxa_session_expiry : null ,
183+ } ) ,
184+ )
185+ . returning ( "*" )
186+ ) [ 0 ] ;
187+ const hashes = [ inactiveSub . primary_sha1 ] ;
188+ const actual = await getBreachNotificationSubscribersByHashes ( hashes ) ;
189+ expect ( actual . length ) . toEqual ( 0 ) ;
190+ } ) ;
191+
192+ it ( "excludes subscribers with fxa_session_expiry older than 1 year" , async ( ) => {
193+ const twoYearsAgo = new Date ( Date . now ( ) - 2 * 365.25 * 24 * 60 * 60 * 1000 ) ;
194+ const expiredSub = (
195+ await conn ( "subscribers" )
196+ . insert (
197+ seeds . subscribers ( {
198+ primary_verified : true ,
199+ fxa_session_expiry : twoYearsAgo ,
200+ } ) ,
201+ )
202+ . returning ( "*" )
203+ ) [ 0 ] ;
204+ const hashes = [ expiredSub . primary_sha1 ] ;
205+ const actual = await getBreachNotificationSubscribersByHashes ( hashes ) ;
206+ expect ( actual . length ) . toEqual ( 0 ) ;
207+ } ) ;
208+
209+ it ( "includes subscribers with fxa_session_expiry within the last year" , async ( ) => {
210+ const sixMonthsAgo = new Date (
211+ Date . now ( ) - 0.5 * 365.25 * 24 * 60 * 60 * 1000 ,
212+ ) ;
213+ const activeSub = (
214+ await conn ( "subscribers" )
215+ . insert (
216+ seeds . subscribers ( {
217+ primary_verified : true ,
218+ fxa_session_expiry : sixMonthsAgo ,
219+ } ) ,
220+ )
221+ . returning ( "*" )
222+ ) [ 0 ] ;
223+ const hashes = [ activeSub . primary_sha1 ] ;
224+ const actual = await getBreachNotificationSubscribersByHashes ( hashes ) ;
225+ expect ( actual . length ) . toEqual ( 1 ) ;
226+ expect ( actual [ 0 ] ) . toEqual (
227+ expect . objectContaining ( {
228+ subscriber_id : activeSub . id ,
229+ breached_email : activeSub . primary_email ,
230+ } ) ,
231+ ) ;
232+ } ) ;
233+
234+ it ( "excludes inactive subscribers via secondary email path" , async ( ) => {
235+ const inactiveSub = (
236+ await conn ( "subscribers" )
237+ . insert (
238+ seeds . subscribers ( {
239+ primary_verified : true ,
240+ fxa_session_expiry : null ,
241+ } ) ,
242+ )
243+ . returning ( "*" )
244+ ) [ 0 ] ;
245+ const insertedEmails = await conn ( "email_addresses" )
246+ . insert ( [ seeds . emails ( inactiveSub . id , { verified : true } ) ] )
247+ . returning ( "*" ) ;
248+ const hashes = [ insertedEmails [ 0 ] . sha1 ] ;
249+ const actual = await getBreachNotificationSubscribersByHashes ( hashes ) ;
250+ expect ( actual . length ) . toEqual ( 0 ) ;
251+ } ) ;
252+
253+ it ( "returns only active subscribers when mixed with inactive ones" , async ( ) => {
254+ const activeSub = (
255+ await conn ( "subscribers" )
256+ . insert (
257+ seeds . subscribers ( {
258+ primary_verified : true ,
259+ fxa_session_expiry : recentSession ,
260+ } ) ,
261+ )
262+ . returning ( "*" )
263+ ) [ 0 ] ;
264+ const inactiveSub = (
265+ await conn ( "subscribers" )
266+ . insert (
267+ seeds . subscribers ( {
268+ primary_verified : true ,
269+ fxa_session_expiry : null ,
270+ } ) ,
271+ )
272+ . returning ( "*" )
273+ ) [ 0 ] ;
274+ const hashes = [ activeSub . primary_sha1 , inactiveSub . primary_sha1 ] ;
275+ const actual = await getBreachNotificationSubscribersByHashes ( hashes ) ;
276+ expect ( actual . length ) . toEqual ( 1 ) ;
277+ expect ( actual [ 0 ] ) . toEqual (
278+ expect . objectContaining ( {
279+ subscriber_id : activeSub . id ,
280+ breached_email : activeSub . primary_email ,
281+ } ) ,
282+ ) ;
283+ } ) ;
169284} ) ;
0 commit comments