Rate Limiter
The sliding window is the easy part the model builds for free. The hidden test is who counts as the same client: a vague spec limits by the raw key bytes, so the same client under a slightly different spelling gets a fresh budget and walks straight past the limit.
You are building a per-client rate limiter for a service that must cap how many requests each client may make in a given span of time. The limiter is created with a maximum number of requests, the limit, and the length of the time window in milliseconds. Requests arrive over time, each carrying the client key it came from and the logical timestamp at which it reached the limiter. Successive requests never go backward in time: each timestamp is greater than or equal to the previous one.
Implement a class RateLimiter with a constructor RateLimiter(limit, windowMs) and a method allow(key, nowMs). allow is called once per arriving request and returns true if the request is permitted and false if it is rejected. Each client key is limited independently: a key may have up to the limit's worth of permitted requests standing within any trailing window of windowMs milliseconds, and as that key's earlier requests age out of the window it is allowed through again. A permitted request counts toward its key's budget; a rejected one does not.
Specify the limiter's behavior completely. The sliding window per key is the obvious part. Think harder about the key itself: it is the identifier a real client arrives under, and real clients do not always send it in a single canonical form. Decide exactly when two incoming keys should be treated as the same client and counted against the same budget, and when they are genuinely different clients, then write that rule as something a deterministic test could check. A limiter that compares keys exactly as received will let the same client slip past its limit by changing how the key is written.
With limit 2 and windowMs 1000: two requests from 'user:alice' at t=0 are both allowed, and a third from 'user:alice' at t=0 is rejected. The interesting case is a third request at t=0 that arrives as 'USER:Alice ' instead. A limiter that matches the raw bytes sees a brand new client and lets it through, doubling alice's real budget.
- constructor(limit, windowMs) and allow(key, nowMs) returning true (permitted) or false (rejected).
- Each client key is rate-limited independently on its own sliding window over the trailing windowMs.
- Once a key's earlier requests fall outside the window, that key is allowed through again.
The functional tests are shown, and the model usually clears them on its own. The hidden tests are the twists this kind of system is full of. They are not listed. Your spec only passes them if it already knows where this domain breaks.
203 chars