Skip to content

Commit ac33124

Browse files
committed
Inject free mode rate limiter in completions tests
1 parent 63e3ded commit ac33124

2 files changed

Lines changed: 20 additions & 4 deletions

File tree

web/src/app/api/v1/chat/completions/__tests__/completions.test.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,9 +1104,18 @@ describe('/api/v1/chat/completions POST endpoint', () => {
11041104
it(
11051105
'counts child Gemini thinker requests toward the free-mode request limit',
11061106
async () => {
1107-
expect(checkFreeModeRateLimit('user-gemini-rate-limit').limited).toBe(
1108-
false,
1109-
)
1107+
let rateLimitChecks = 0
1108+
const checkFreeModeRateLimitForTest = mock((userId: string) => {
1109+
expect(userId).toBe('user-gemini-rate-limit')
1110+
rateLimitChecks += 1
1111+
return rateLimitChecks === 1
1112+
? { limited: false as const }
1113+
: {
1114+
limited: true as const,
1115+
windowName: '1 second',
1116+
retryAfterMs: 1_000,
1117+
}
1118+
})
11101119

11111120
const createRequest = () =>
11121121
new NextRequest('http://localhost:3000/api/v1/chat/completions', {
@@ -1135,6 +1144,7 @@ describe('/api/v1/chat/completions POST endpoint', () => {
11351144
insertMessageBigquery: mockInsertMessageBigquery,
11361145
loggerWithContext: mockLoggerWithContext,
11371146
checkSessionAdmissible: mockCheckSessionAdmissibleAllow,
1147+
checkFreeModeRateLimit: checkFreeModeRateLimitForTest,
11381148
})
11391149

11401150
const firstResponse = await postChatCompletions(createPostParams())
@@ -1144,6 +1154,7 @@ describe('/api/v1/chat/completions POST endpoint', () => {
11441154
expect(limitedResponse.status).toBe(429)
11451155
const body = await limitedResponse.json()
11461156
expect(body.error).toBe('free_mode_rate_limited')
1157+
expect(checkFreeModeRateLimitForTest).toHaveBeenCalledTimes(2)
11471158
},
11481159
FETCH_PATH_TEST_TIMEOUT_MS,
11491160
)

web/src/app/api/v1/chat/completions/_post.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ import { getFreeModeCountryAccess } from '@/server/free-mode-country'
7878
import type { SessionGateResult } from '@/server/free-session/public-api'
7979
import { extractApiKeyFromHeader } from '@/util/auth'
8080
import { withDefaultProperties } from '@codebuff/common/analytics'
81-
import { checkFreeModeRateLimit } from './free-mode-rate-limiter'
81+
import { checkFreeModeRateLimit as defaultCheckFreeModeRateLimit } from './free-mode-rate-limiter'
8282

8383
export const formatQuotaResetCountdown = (
8484
nextQuotaReset: string | null | undefined,
@@ -117,6 +117,7 @@ export const formatQuotaResetCountdown = (
117117
}
118118

119119
export type CheckSessionAdmissibleFn = typeof checkSessionAdmissible
120+
export type CheckFreeModeRateLimitFn = typeof defaultCheckFreeModeRateLimit
120121

121122
type GateRejectCode = Extract<SessionGateResult, { ok: false }>['code']
122123

@@ -147,6 +148,9 @@ export async function postChatCompletions(params: {
147148
/** Optional override for the freebuff waiting-room gate. Defaults to the
148149
* real check backed by Postgres; tests inject a no-op. */
149150
checkSessionAdmissible?: CheckSessionAdmissibleFn
151+
/** Optional override for the free-mode rate limiter. Tests inject this to
152+
* avoid coupling to process-global limiter state. */
153+
checkFreeModeRateLimit?: CheckFreeModeRateLimitFn
150154
}) {
151155
const {
152156
req,
@@ -159,6 +163,7 @@ export async function postChatCompletions(params: {
159163
ensureSubscriberBlockGrant,
160164
getUserPreferences,
161165
checkSessionAdmissible: checkSession = checkSessionAdmissible,
166+
checkFreeModeRateLimit = defaultCheckFreeModeRateLimit,
162167
} = params
163168
let { logger } = params
164169
let { trackEvent } = params

0 commit comments

Comments
 (0)