@@ -57,6 +57,49 @@ describe('Usage', () => {
5757 const res = ( await usageTracker . get ( { accountId, metric } ) ) . unwrap ( ) ;
5858 expect ( res ) . toEqual ( { accountId, metric, current : 5 } ) ;
5959 } ) ;
60+ it ( 'should trigger revalidation when entry is null' , async ( ) => {
61+ const accountId = 1 ;
62+ const metric = 'connections' ;
63+
64+ const revalidateSpy = vi . spyOn ( usageTracker , 'revalidate' ) ;
65+ revalidateSpy . mockReturnValue ( Promise . resolve ( Ok ( undefined ) ) ) ;
66+
67+ const res = ( await usageTracker . get ( { accountId, metric } ) ) . unwrap ( ) ;
68+ expect ( res ) . toEqual ( { accountId, metric, current : 0 } ) ;
69+ expect ( revalidateSpy ) . toHaveBeenCalledTimes ( 1 ) ;
70+ expect ( revalidateSpy ) . toHaveBeenCalledWith ( { accountId, metric } ) ;
71+ } ) ;
72+ it ( 'should trigger revalidation when revalidateAfter has passed' , async ( ) => {
73+ const accountId = 1 ;
74+ const metric = 'connections' ;
75+
76+ // Set up an entry with a past revalidateAfter
77+ await usageTracker . incr ( { accountId, metric, delta : 5 } ) ;
78+ // Move time forward by 1 day to pass revalidateAfter
79+ vi . advanceTimersByTime ( 24 * 60 * 60 * 1000 ) ;
80+
81+ const revalidateSpy = vi . spyOn ( usageTracker , 'revalidate' ) ;
82+ revalidateSpy . mockReturnValue ( Promise . resolve ( Ok ( undefined ) ) ) ;
83+
84+ const res = ( await usageTracker . get ( { accountId, metric } ) ) . unwrap ( ) ;
85+ expect ( res ) . toEqual ( { accountId, metric, current : 5 } ) ;
86+ expect ( revalidateSpy ) . toHaveBeenCalledTimes ( 1 ) ;
87+ expect ( revalidateSpy ) . toHaveBeenCalledWith ( { accountId, metric } ) ;
88+ } ) ;
89+ it ( 'should not trigger revalidation when entry exists and is not stale' , async ( ) => {
90+ const accountId = 1 ;
91+ const metric = 'connections' ;
92+
93+ await usageTracker . incr ( { accountId, metric, delta : 5 } ) ;
94+
95+ const revalidateSpy = vi . spyOn ( usageTracker , 'revalidate' ) ;
96+ revalidateSpy . mockReturnValue ( Promise . resolve ( Ok ( undefined ) ) ) ;
97+
98+ const res = ( await usageTracker . get ( { accountId, metric } ) ) . unwrap ( ) ;
99+ expect ( res ) . toEqual ( { accountId, metric, current : 5 } ) ;
100+ // revalidateAfter hasn't passed yet
101+ expect ( revalidateSpy ) . not . toHaveBeenCalled ( ) ;
102+ } ) ;
60103 } ) ;
61104
62105 describe ( 'incr' , ( ) => {
@@ -89,4 +132,53 @@ describe('Usage', () => {
89132 expect ( res ) . toEqual ( { accountId, metric, current : 1 } ) ;
90133 } ) ;
91134 } ) ;
135+
136+ describe ( 'getAll' , ( ) => {
137+ it ( 'should trigger revalidation for null entries' , async ( ) => {
138+ const accountId = 1 ;
139+
140+ const revalidateSpy = vi . spyOn ( usageTracker , 'revalidate' ) ;
141+ revalidateSpy . mockReturnValue ( Promise . resolve ( Ok ( undefined ) ) ) ;
142+
143+ const res = ( await usageTracker . getAll ( accountId ) ) . unwrap ( ) ;
144+ expect ( res ) . toBeDefined ( ) ;
145+ // Should trigger revalidation for all metrics that are null
146+ expect ( revalidateSpy ) . toHaveBeenCalled ( ) ;
147+ } ) ;
148+ it ( 'should trigger revalidation for stale entries' , async ( ) => {
149+ const accountId = 1 ;
150+ const metric = 'connections' ;
151+
152+ // Set up an entry with a past revalidateAfter
153+ await usageTracker . incr ( { accountId, metric, delta : 5 } ) ;
154+ // Move time forward by 1 day to pass revalidateAfter
155+ vi . advanceTimersByTime ( 24 * 60 * 60 * 1000 ) ;
156+
157+ const revalidateSpy = vi . spyOn ( usageTracker , 'revalidate' ) ;
158+ revalidateSpy . mockReturnValue ( Promise . resolve ( Ok ( undefined ) ) ) ;
159+
160+ const res = ( await usageTracker . getAll ( accountId ) ) . unwrap ( ) ;
161+ expect ( res ) . toBeDefined ( ) ;
162+ expect ( res [ metric ] ) . toEqual ( { accountId, metric, current : 5 } ) ;
163+ // Should trigger revalidation for the stale metric
164+ expect ( revalidateSpy ) . toHaveBeenCalledWith ( { accountId, metric } ) ;
165+ } ) ;
166+ it ( 'should not trigger revalidation for non-stale entries' , async ( ) => {
167+ const accountId = 1 ;
168+ const metric = 'connections' ;
169+
170+ await usageTracker . incr ( { accountId, metric, delta : 5 } ) ;
171+
172+ const revalidateSpy = vi . spyOn ( usageTracker , 'revalidate' ) ;
173+ revalidateSpy . mockReturnValue ( Promise . resolve ( Ok ( undefined ) ) ) ;
174+
175+ const res = ( await usageTracker . getAll ( accountId ) ) . unwrap ( ) ;
176+ expect ( res ) . toBeDefined ( ) ;
177+ expect ( res [ metric ] ) . toEqual ( { accountId, metric, current : 5 } ) ;
178+ // revalidateAfter hasn't passed yet, so revalidation should not be called for this metric
179+ // (but may be called for other null metrics)
180+ const callsForMetric = revalidateSpy . mock . calls . filter ( ( call ) => call [ 0 ] . metric === metric ) ;
181+ expect ( callsForMetric ) . toHaveLength ( 0 ) ;
182+ } ) ;
183+ } ) ;
92184} ) ;
0 commit comments