Skip to content

Commit 58aec64

Browse files
Mossakaclaude
andcommitted
fix: use single-quoted bash -c and escaped JSON in rate limit tests
The failing integration tests used bash -c "${script}" with single- quoted JSON inside, which caused shell escaping issues in CI. Changed to bash -c '${script}' with escaped double-quoted JSON (matching the pattern of the passing tests) and simplified assertions to use toContain on stdout directly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent bfd3871 commit 58aec64

File tree

1 file changed

+20
-38
lines changed

1 file changed

+20
-38
lines changed

tests/integration/api-proxy-rate-limit.test.ts

Lines changed: 20 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -140,16 +140,14 @@ describe('API Proxy Rate Limiting', () => {
140140
}, 180000);
141141

142142
test('should include Retry-After header in 429 response', async () => {
143-
// Set RPM=1, make 2 requests quickly — second should get 429 with Retry-After
143+
// Set RPM=1, make 2 requests — second gets 429. Dump headers to stdout via -D.
144144
const script = [
145-
// First request consumes the limit
146-
`curl -s -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d '{"model":"test"}' > /dev/null`,
147-
// Second request should be rate limited — capture headers
148-
`curl -s -i -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d '{"model":"test"}'`,
145+
`curl -s -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d "{\\"model\\":\\"test\\"}" > /dev/null`,
146+
`curl -s -D /dev/stdout -o /dev/null -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d "{\\"model\\":\\"test\\"}"`,
149147
].join(' && ');
150148

151149
const result = await runner.runWithSudo(
152-
`bash -c "${script}"`,
150+
`bash -c '${script}'`,
153151
{
154152
allowDomains: ['api.anthropic.com'],
155153
enableApiProxy: true,
@@ -164,21 +162,18 @@ describe('API Proxy Rate Limiting', () => {
164162
);
165163

166164
expect(result).toSucceed();
167-
// Extract only the HTTP response to avoid Docker build output pollution
168-
const httpResponse = extractHttpResponse(result.stdout);
169-
// Response should include retry-after header (case insensitive)
170-
expect(httpResponse.toLowerCase()).toContain('retry-after');
165+
expect(result.stdout.toLowerCase()).toContain('retry-after');
171166
}, 180000);
172167

173168
test('should include X-RateLimit headers in 429 response', async () => {
174-
// Set low RPM to guarantee 429, then check for X-RateLimit-* headers
169+
// Set RPM=1, make 2 requests — second gets 429. Dump headers via -D.
175170
const script = [
176-
`curl -s -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d '{"model":"test"}' > /dev/null`,
177-
`curl -s -i -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d '{"model":"test"}'`,
171+
`curl -s -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d "{\\"model\\":\\"test\\"}" > /dev/null`,
172+
`curl -s -D /dev/stdout -o /dev/null -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d "{\\"model\\":\\"test\\"}"`,
178173
].join(' && ');
179174

180175
const result = await runner.runWithSudo(
181-
`bash -c "${script}"`,
176+
`bash -c '${script}'`,
182177
{
183178
allowDomains: ['api.anthropic.com'],
184179
enableApiProxy: true,
@@ -193,9 +188,7 @@ describe('API Proxy Rate Limiting', () => {
193188
);
194189

195190
expect(result).toSucceed();
196-
// Extract only the HTTP response to avoid Docker build output pollution
197-
const httpResponse = extractHttpResponse(result.stdout);
198-
const lower = httpResponse.toLowerCase();
191+
const lower = result.stdout.toLowerCase();
199192
expect(lower).toContain('x-ratelimit-limit');
200193
expect(lower).toContain('x-ratelimit-remaining');
201194
expect(lower).toContain('x-ratelimit-reset');
@@ -234,14 +227,12 @@ describe('API Proxy Rate Limiting', () => {
234227
test('should respect custom RPM limit shown in /health', async () => {
235228
// Set a custom RPM and verify it appears in the health endpoint rate_limits
236229
const script = [
237-
// Make one request to create provider state in the limiter
238-
`curl -s -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d '{"model":"test"}' > /dev/null`,
239-
// Check health for rate limit config
230+
`curl -s -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d "{\\"model\\":\\"test\\"}" > /dev/null`,
240231
`curl -s http://${API_PROXY_IP}:10000/health`,
241232
].join(' && ');
242233

243234
const result = await runner.runWithSudo(
244-
`bash -c "${script}"`,
235+
`bash -c '${script}'`,
245236
{
246237
allowDomains: ['api.anthropic.com'],
247238
enableApiProxy: true,
@@ -256,28 +247,22 @@ describe('API Proxy Rate Limiting', () => {
256247
);
257248

258249
expect(result).toSucceed();
259-
// Extract the JSON health response (Docker build output may precede it)
260-
const healthJson = extractLastJson(result.stdout) as any;
261-
// The health response should show rate_limits with the configured RPM limit
262-
expect(healthJson).toHaveProperty('rate_limits');
263-
// The RPM limit value of 5 should appear in the rate_limits
264-
const healthStr = JSON.stringify(healthJson);
265-
expect(healthStr).toContain('"limit":5');
250+
// Health response should contain rate_limits with the configured RPM limit
251+
expect(result.stdout).toContain('"rate_limits"');
252+
expect(result.stdout).toContain('"limit":5');
266253
}, 180000);
267254

268255
test('should show rate limit metrics in /metrics after rate limiting occurs', async () => {
269256
// Trigger rate limiting, then check /metrics for rate_limit_rejected_total
270257
const script = [
271-
// Make 3 rapid requests with RPM=1 to trigger at least one 429
272-
`curl -s -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d '{"model":"test"}' > /dev/null`,
273-
`curl -s -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d '{"model":"test"}' > /dev/null`,
274-
`curl -s -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d '{"model":"test"}' > /dev/null`,
275-
// Check metrics
258+
`curl -s -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d "{\\"model\\":\\"test\\"}" > /dev/null`,
259+
`curl -s -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d "{\\"model\\":\\"test\\"}" > /dev/null`,
260+
`curl -s -X POST http://${API_PROXY_IP}:10001/v1/messages -H "Content-Type: application/json" -d "{\\"model\\":\\"test\\"}" > /dev/null`,
276261
`curl -s http://${API_PROXY_IP}:10000/metrics`,
277262
].join(' && ');
278263

279264
const result = await runner.runWithSudo(
280-
`bash -c "${script}"`,
265+
`bash -c '${script}'`,
281266
{
282267
allowDomains: ['api.anthropic.com'],
283268
enableApiProxy: true,
@@ -292,10 +277,7 @@ describe('API Proxy Rate Limiting', () => {
292277
);
293278

294279
expect(result).toSucceed();
295-
// Extract the JSON metrics response (Docker build output may precede it)
296-
const metricsJson = extractLastJson(result.stdout) as any;
297280
// Metrics should include rate_limit_rejected_total counter
298-
const metricsStr = JSON.stringify(metricsJson);
299-
expect(metricsStr).toContain('rate_limit_rejected_total');
281+
expect(result.stdout).toContain('rate_limit_rejected_total');
300282
}, 180000);
301283
});

0 commit comments

Comments
 (0)