Fix a webapi rate limit test and precision errors.

Review Request #12506 — Created Aug. 5, 2022 and submitted

Information

Djblets
release-2.x

Reviewers

We have several API rate limiting tests that check various time
intervals. One checked against a number of failed attempts per hour. One
checked against attempts per minute. And one checked against attempts
per second.

The per second test often failed in CI under load. This was checking
that 3 login attempts were allowed but a 4th would fail. If there was
enough delay, this 4th would often fail as well.

We now staple the timestamp so it doesn't change. This requires a spy on
an internal function from djblets.auth.ratelimit, but as all this is
internal, that should be fine.

Now, regardless of actual clock changes, the time window should not
change, and therefore the test should not fail under load.

However, this uncovered that our actual rate limit logic encountered
problems when the logic operated over a 1 second boundary change. There
were repeated calls to _get_window(), which in turn called
time.time(). The first set of calls was used for the cache key, and
the second set for a calculation. If the second changed in-between
these, there'd be a mismatch. It probably wasn't very harmful in
practice, but was worth fixing.

The rate limiting code now fetches the time and window up-front, once,
before any cache keys or calculations. Unit tests were added to check
for this.

Unit tests pass.

Summary ID
Fix a webapi rate limit test and precision errors.
We have several API rate limiting tests that check various time intervals. One checked against a number of failed attempts per hour. One checked against attempts per minute. And one checked against attempts per second. The per second test often failed in CI under load. This was checking that 3 login attempts were allowed but a 4th would fail. If there was enough delay, this 4th would often fail as well. We now staple the timestamp so it doesn't change. This requires a spy on an internal `_get_window()` function from `djblets.auth.ratelimit`, but as all this is internal, that should be fine. Now, regardless of actual clock changes, the time window should not change, and therefore the test should not fail under load. However, this uncovered that our actual rate limit logic encountered problems when the logic operated over a 1 second boundary change. There were repeated calls to `_get_window()`, which in turn called `time.time()`. The first set of calls was used for the cache key, and the second set for a calculation. If the second changed in-between these, there'd be a mismatch. It probably wasn't very harmful in practice, but was worth fixing. The rate limiting code now fetches the time and window up-front, once, before any cache keys or calculations. Unit tests were added to check for this.
eb8236db6e4a17907bf8169843f9d78d750c0df1
chipx86
david
  1. Ship It!
  2. 
      
chipx86
Review request changed
Status:
Completed
Change Summary:
Pushed to release-2.x (ffd7055)