def test_hit_ratelimits(self) -> None: user = self.example_user('cordelia') email = user.email clear_history(RateLimitedUser(user)) start_time = time.time() for i in range(6): with mock.patch('time.time', return_value=(start_time + i * 0.1)): result = self.send_api_message(email, "some stuff %s" % (i, )) self.assertEqual(result.status_code, 429) json = result.json() self.assertEqual(json.get("result"), "error") self.assertIn("API usage exceeded rate limit", json.get("msg")) self.assertEqual(json.get('retry-after'), 0.5) self.assertTrue('Retry-After' in result) self.assertEqual(result['Retry-After'], '0.5') # We actually wait a second here, rather than force-clearing our history, # to make sure the rate-limiting code automatically forgives a user # after some time has passed. with mock.patch('time.time', return_value=(start_time + 1.0)): result = self.send_api_message(email, "Good message") self.assert_json_success(result)
def test_hit_ratelimits(self) -> None: user = self.example_user('cordelia') email = user.email clear_history(RateLimitedUser(user)) start_time = time.time() for i in range(6): with mock.patch('time.time', return_value=(start_time + i * 0.1)): result = self.send_api_message(email, "some stuff %s" % (i,)) self.assertEqual(result.status_code, 429) json = result.json() self.assertEqual(json.get("result"), "error") self.assertIn("API usage exceeded rate limit", json.get("msg")) self.assertEqual(json.get('retry-after'), 0.5) self.assertTrue('Retry-After' in result) self.assertEqual(result['Retry-After'], '0.5') # We actually wait a second here, rather than force-clearing our history, # to make sure the rate-limiting code automatically forgives a user # after some time has passed. with mock.patch('time.time', return_value=(start_time + 1.0)): result = self.send_api_message(email, "Good message") self.assert_json_success(result)
def test_headers(self) -> None: user = self.example_user('hamlet') clear_history(RateLimitedUser(user)) result = self.send_api_message(user, "some stuff") self.assertTrue('X-RateLimit-Remaining' in result) self.assertTrue('X-RateLimit-Limit' in result) self.assertTrue('X-RateLimit-Reset' in result)
def test_mirror_worker_rate_limiting(self, mock_mirror_email: MagicMock, mock_warn: MagicMock) -> None: fake_client = self.FakeClient() realm = get_realm('zulip') clear_history(RateLimitedRealmMirror(realm)) stream = get_stream('Denmark', realm) stream_to_address = encode_email_address(stream) data = [ dict( message=u'\xf3test', time=time.time(), rcpt_to=stream_to_address ) ] * 5 for element in data: fake_client.queue.append(('email_mirror', element)) with simulated_queue_client(lambda: fake_client): start_time = time.time() with patch('time.time', return_value=start_time): worker = queue_processors.MirrorWorker() worker.setup() worker.start() # Of the first 5 messages, only 2 should be processed # (the rest being rate-limited): self.assertEqual(mock_mirror_email.call_count, 2) # If a new message is sent into the stream mirror, it will get rejected: fake_client.queue.append(('email_mirror', data[0])) worker.start() self.assertEqual(mock_mirror_email.call_count, 2) # However, missed message emails don't get rate limited: with self.settings(EMAIL_GATEWAY_PATTERN="*****@*****.**"): address = 'mm' + ('x' * 32) + '@example.com' event = dict( message=u'\xf3test', time=time.time(), rcpt_to=address ) fake_client.queue.append(('email_mirror', event)) worker.start() self.assertEqual(mock_mirror_email.call_count, 3) # After some times passes, emails get accepted again: with patch('time.time', return_value=(start_time + 11.0)): fake_client.queue.append(('email_mirror', data[0])) worker.start() self.assertEqual(mock_mirror_email.call_count, 4) # If RateLimiterLockingException is thrown, we rate-limit the new message: with patch('zerver.lib.rate_limiter.incr_ratelimit', side_effect=RateLimiterLockingException): fake_client.queue.append(('email_mirror', data[0])) worker.start() self.assertEqual(mock_mirror_email.call_count, 4) expected_warn = "Deadlock trying to incr_ratelimit for RateLimitedRealmMirror:zulip" mock_warn.assert_called_with(expected_warn)
def test_ratelimit_decrease(self) -> None: user = self.example_user('hamlet') clear_history(RateLimitedUser(user)) result = self.send_api_message(user, "some stuff") limit = int(result['X-RateLimit-Remaining']) result = self.send_api_message(user, "some stuff 2") newlimit = int(result['X-RateLimit-Remaining']) self.assertEqual(limit, newlimit + 1)
def test_headers(self) -> None: user = self.example_user('hamlet') email = user.email clear_history(RateLimitedUser(user)) result = self.send_api_message(email, "some stuff") self.assertTrue('X-RateLimit-Remaining' in result) self.assertTrue('X-RateLimit-Limit' in result) self.assertTrue('X-RateLimit-Reset' in result)
def test_hit_ratelimiterlockingexception(self) -> None: user = self.example_user('cordelia') email = user.email clear_history(RateLimitedUser(user)) with mock.patch('zerver.decorator.incr_ratelimit', side_effect=RateLimiterLockingException): result = self.send_api_message(email, "some stuff") self.assertEqual(result.status_code, 429)
def test_ratelimit_decrease(self) -> None: user = self.example_user('hamlet') email = user.email clear_history(RateLimitedUser(user)) result = self.send_api_message(email, "some stuff") limit = int(result['X-RateLimit-Remaining']) result = self.send_api_message(email, "some stuff 2") newlimit = int(result['X-RateLimit-Remaining']) self.assertEqual(limit, newlimit + 1)
def test_hit_ratelimiterlockingexception(self, mock_warn: mock.MagicMock) -> None: user = self.example_user('cordelia') email = user.email clear_history(RateLimitedUser(user)) with mock.patch('zerver.lib.rate_limiter.incr_ratelimit', side_effect=RateLimiterLockingException): result = self.send_api_message(email, "some stuff") self.assertEqual(result.status_code, 429) mock_warn.assert_called_with("Deadlock trying to incr_ratelimit for RateLimitedUser:Id: %s" % (user.id,))