@@ -177,15 +177,16 @@ describe('cleanup soft deletes — archived user tables', () => {
177177 vi . clearAllMocks ( )
178178 mockIsUsingCloudStorage . mockReturnValue ( true )
179179 mockLimit . mockResolvedValue ( [ ] )
180- // selectRowsByIdChunks call order: workflows, file legacy, file multi, doomed tables.
180+ // selectRowsByIdChunks call order: workflows, file legacy, file multi, doomed
181+ // tables. Each test queues the doomed-tables result (4th call) itself.
181182 mockSelectRowsByIdChunks
182183 . mockResolvedValueOnce ( [ ] )
183184 . mockResolvedValueOnce ( [ ] )
184185 . mockResolvedValueOnce ( [ ] )
185- . mockResolvedValueOnce ( [ { id : 'tbl-1' } ] )
186186 } )
187187
188188 it ( 'drains rows before deleting the table definition' , async ( ) => {
189+ mockSelectRowsByIdChunks . mockResolvedValueOnce ( [ { id : 'tbl-1' } ] )
189190 mockDrainRowsByColumn . mockResolvedValue ( { deleted : 5 , fullyDrained : true } )
190191
191192 await runCleanupSoftDeletes ( basePayload )
@@ -200,13 +201,28 @@ describe('cleanup soft deletes — archived user tables', () => {
200201 )
201202 } )
202203
203- it ( 'defers the definition delete when the drain does not fully complete' , async ( ) => {
204- // Budget stop or a drain error both surface as fullyDrained: false.
205- mockDrainRowsByColumn . mockResolvedValue ( { deleted : 200_000 , fullyDrained : false } )
204+ it ( 'defers the definition delete when the budget is exhausted' , async ( ) => {
205+ mockSelectRowsByIdChunks . mockResolvedValueOnce ( [ { id : 'tbl-1' } ] )
206+ // Budget stop consumes the whole budget — deleted equals the per-run cap.
207+ mockDrainRowsByColumn . mockResolvedValue ( { deleted : 1_000_000 , fullyDrained : false } )
206208
207209 await runCleanupSoftDeletes ( basePayload )
208210
209211 expect ( mockDrainRowsByColumn ) . toHaveBeenCalledTimes ( 1 )
210212 expect ( mockDeleteDefinition ) . not . toHaveBeenCalled ( )
211213 } )
214+
215+ it ( 'skips a table that errors mid-drain but keeps cleaning the rest' , async ( ) => {
216+ mockSelectRowsByIdChunks . mockResolvedValueOnce ( [ { id : 'tbl-err' } , { id : 'tbl-ok' } ] )
217+ // First table errors mid-drain (budget remains); second drains fully.
218+ mockDrainRowsByColumn
219+ . mockResolvedValueOnce ( { deleted : 2 , fullyDrained : false } )
220+ . mockResolvedValueOnce ( { deleted : 5 , fullyDrained : true } )
221+
222+ await runCleanupSoftDeletes ( basePayload )
223+
224+ expect ( mockDrainRowsByColumn ) . toHaveBeenCalledTimes ( 2 )
225+ // Only the fully-drained table's definition is deleted.
226+ expect ( mockDeleteDefinition ) . toHaveBeenCalledTimes ( 1 )
227+ } )
212228} )
0 commit comments