Skip to content

Commit f3ae564

Browse files
authored
test(refresh-rate-limiter): add error resilience coverage (JhaSourav07#3046)
## Description Fixes JhaSourav07#2948 Added isolated unit tests for `services/github/refresh-rate-limiter.ts` focusing on error resilience, recovery behavior, and stability under unexpected configurations. ### Changes - Added `services/github/refresh-rate-limiter.error-resilience.test.ts` - Verified fallback behavior when `MAX_REFRESHES_PER_HOUR` contains invalid values - Tested recovery to default limits when environment configuration is malformed or zero - Ensured malformed or whitespace-only client identifiers are handled safely without crashes - Verified limiter state can be reset and reused successfully after exhaustion - Confirmed stable behavior when requests continue after rate limits have been exceeded - Improved coverage around exception safety and fallback execution paths ## Pillar - [ ] 🎨 Pillar 1 — New Theme Design - [ ] 📐 Pillar 2 — Geometric SVG Improvement - [ ] 🕐 Pillar 3 — Timezone Logic Optimization - [x] 🛠️ Other (Bug fix, refactoring, docs) ## Visual Preview N/A (test-only changes) ## Checklist before requesting a review: - [x] I have read the `CONTRIBUTING.md` file. - [x] I have tested these changes locally (`localhost:3000/api/streak?user=YOUR_USERNAME`). - [x] I have run `npm run format` and `npm run lint` locally and resolved all errors (CI will fail otherwise). - [x] My commits follow the Conventional Commits format (e.g., `feat(themes): ...`, `fix(calculate): ...`). - [ ] I have updated `README.md` if I added a new theme or URL parameter. - [x] I have starred the repo. - [x] I have made sure that I have only one commit to merge in this PR. - [x] The SVG output matches the CommitPulse "premium quality" aesthetic standard (no SVG changes made). - [ ] (Recommended) I joined the CommitPulse Discord community for contributor discussions, mentorship, and faster PR support.
2 parents 96b6351 + ddc6c77 commit f3ae564

1 file changed

Lines changed: 81 additions & 0 deletions

File tree

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// services/github/refresh-rate-limiter.error-resilience.test.ts
2+
3+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
4+
import { refreshRateLimiter } from './refresh-rate-limiter';
5+
6+
describe('RefreshRateLimiter Error Resilience', () => {
7+
const originalEnv = process.env.MAX_REFRESHES_PER_HOUR;
8+
9+
beforeEach(() => {
10+
refreshRateLimiter.reset();
11+
delete process.env.MAX_REFRESHES_PER_HOUR;
12+
});
13+
14+
afterEach(() => {
15+
refreshRateLimiter.reset();
16+
17+
if (originalEnv) {
18+
process.env.MAX_REFRESHES_PER_HOUR = originalEnv;
19+
} else {
20+
delete process.env.MAX_REFRESHES_PER_HOUR;
21+
}
22+
});
23+
24+
it('falls back to default limit when environment value is invalid', () => {
25+
process.env.MAX_REFRESHES_PER_HOUR = 'invalid';
26+
27+
const result = refreshRateLimiter.checkLimit('127.0.0.1');
28+
29+
expect(result.success).toBe(true);
30+
expect(result.limit).toBe(3);
31+
expect(result.remaining).toBe(2);
32+
});
33+
34+
it('falls back to default limit when environment value is zero', () => {
35+
process.env.MAX_REFRESHES_PER_HOUR = '0';
36+
37+
const result = refreshRateLimiter.checkLimit('127.0.0.1');
38+
39+
expect(result.success).toBe(true);
40+
expect(result.limit).toBe(3);
41+
});
42+
43+
it('handles malformed or whitespace-only client identifiers safely', () => {
44+
const result = refreshRateLimiter.checkLimit(' ');
45+
46+
expect(result.success).toBe(true);
47+
expect(result.limit).toBe(3);
48+
expect(result.remaining).toBe(2);
49+
});
50+
51+
it('recovers correctly after reset is called', () => {
52+
refreshRateLimiter.setLimit(1);
53+
54+
expect(refreshRateLimiter.checkLimit('192.168.1.1').success).toBe(true);
55+
56+
expect(refreshRateLimiter.checkLimit('192.168.1.1').success).toBe(false);
57+
58+
refreshRateLimiter.reset();
59+
60+
const result = refreshRateLimiter.checkLimit('192.168.1.1');
61+
62+
expect(result.success).toBe(true);
63+
expect(result.limit).toBe(3);
64+
expect(result.remaining).toBe(2);
65+
});
66+
67+
it('maintains stable behavior across repeated checks after limit exhaustion', () => {
68+
refreshRateLimiter.setLimit(1);
69+
70+
expect(refreshRateLimiter.checkLimit('10.0.0.1').success).toBe(true);
71+
72+
const blocked1 = refreshRateLimiter.checkLimit('10.0.0.1');
73+
const blocked2 = refreshRateLimiter.checkLimit('10.0.0.1');
74+
75+
expect(blocked1.success).toBe(false);
76+
expect(blocked2.success).toBe(false);
77+
78+
expect(blocked1.remaining).toBe(0);
79+
expect(blocked2.remaining).toBe(0);
80+
});
81+
});

0 commit comments

Comments
 (0)