Skip to content

Commit db70ca0

Browse files
committed
test(storage): cover both payer kinds in the ledger lock-mode assertions
The lock-mode regression tests only exercised the organization payer, so the user_stats lock branches were never asserted and a revert of just those would have passed. Parameterize both tests over both payer kinds and assert the exact call list, so a lock that stops being taken at all fails too.
1 parent 012df75 commit db70ca0

1 file changed

Lines changed: 54 additions & 26 deletions

File tree

apps/sim/lib/billing/storage/tracking.test.ts

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,42 @@ const ORG_CONTEXT: StorageBillingContext = {
122122
customStorageLimitGB: null,
123123
}
124124

125+
const USER_CONTEXT: StorageBillingContext = {
126+
workspaceId: 'workspace-1',
127+
billedAccountUserId: 'workspace-owner',
128+
billingEntity: { type: 'user', id: 'workspace-owner' },
129+
plan: 'pro',
130+
customStorageLimitGB: null,
131+
}
132+
133+
/**
134+
* Both payer kinds. The workspace lock is shared, but the payer lock branches
135+
* to a different table per kind, so a lock-mode regression on only one of them
136+
* has to fail a test.
137+
*/
138+
const PAYER_CASES = [
139+
{
140+
label: 'organization',
141+
context: ORG_CONTEXT,
142+
workspaceRow: {
143+
billedAccountUserId: 'workspace-owner',
144+
organizationId: 'workspace-org' as string | null,
145+
storageUsedBytes: 1_000,
146+
},
147+
payerLockRows: [{ id: 'workspace-org', storageUsedBytes: 1_000 }],
148+
},
149+
{
150+
label: 'user',
151+
context: USER_CONTEXT,
152+
workspaceRow: {
153+
billedAccountUserId: 'workspace-owner',
154+
organizationId: null as string | null,
155+
storageUsedBytes: 1_000,
156+
},
157+
payerLockRows: [{ id: 'workspace-owner', storageUsedBytes: 1_000 }],
158+
},
159+
] as const
160+
125161
beforeAll(() => {
126162
setEnvFlags({ isBillingEnabled: true })
127163
})
@@ -194,38 +230,30 @@ describe('workspace storage counter mutations', () => {
194230
* two concurrent uploads take on each other. `FOR NO KEY UPDATE` still
195231
* conflicts with itself, so the ledgers stay serialized.
196232
*/
197-
it('takes every ledger lock as FOR NO KEY UPDATE so it never upgrades a key-share lock', async () => {
198-
await incrementStorageUsageForBillingContextInTx(mockTx as unknown as DbOrTx, ORG_CONTEXT, 100)
233+
it.each(PAYER_CASES)(
234+
'locks the workspace and its $label payer as FOR NO KEY UPDATE',
235+
async ({ context, workspaceRow }) => {
236+
mockWorkspaceRow.current = { ...workspaceRow }
199237

200-
expect(mockTxFor).toHaveBeenCalled()
201-
for (const call of mockTxFor.mock.calls) {
202-
expect(call).toEqual(['no key update'])
238+
await incrementStorageUsageForBillingContextInTx(mockTx as unknown as DbOrTx, context, 100)
239+
240+
expect(mockTxFor.mock.calls).toEqual([['no key update'], ['no key update']])
203241
}
204-
})
242+
)
205243

206-
it('takes batch ledger locks as FOR NO KEY UPDATE', async () => {
207-
mockOrderedLockRows.queue = [
208-
[
209-
{
210-
id: 'workspace-1',
211-
billedAccountUserId: 'workspace-owner',
212-
organizationId: 'workspace-org',
213-
storageUsedBytes: 1_000,
214-
},
215-
],
216-
[{ id: 'workspace-org', storageUsedBytes: 1_000 }],
217-
]
244+
it.each(PAYER_CASES)(
245+
'locks batched workspace and $label payer ledgers as FOR NO KEY UPDATE',
246+
async ({ context, workspaceRow, payerLockRows }) => {
247+
mockOrderedLockRows.queue = [[{ id: 'workspace-1', ...workspaceRow }], [...payerLockRows]]
218248

219-
await applyStorageUsageDeltasInTx(mockTx as unknown as DbOrTx, {
220-
workspaceDeltas: [{ context: ORG_CONTEXT, deltaBytes: 100 }],
221-
legacyDeltas: [],
222-
})
249+
await applyStorageUsageDeltasInTx(mockTx as unknown as DbOrTx, {
250+
workspaceDeltas: [{ context, deltaBytes: 100 }],
251+
legacyDeltas: [],
252+
})
223253

224-
expect(mockTxOrderedFor).toHaveBeenCalled()
225-
for (const call of mockTxOrderedFor.mock.calls) {
226-
expect(call).toEqual(['no key update'])
254+
expect(mockTxOrderedFor.mock.calls).toEqual([['no key update'], ['no key update']])
227255
}
228-
})
256+
)
229257

230258
it('serializes quota admission on the locked payer ledger', async () => {
231259
mockGetStorageLimitForBillingContext.mockReturnValue(1_050)

0 commit comments

Comments
 (0)