def periodic(self): start_time = compat.monotonic() try: self.flush() finally: self.interval = max( 0, self._configured_interval - (compat.monotonic() - start_time))
def test_rate_liimter_effective_rate_rates(): limiter = RateLimiter(rate_limit=100) # Static rate limit window starting_window = compat.monotonic() with mock.patch("ddtrace.compat.monotonic") as mock_time: mock_time.return_value = starting_window for _ in range(100): assert limiter.is_allowed() is True assert limiter.effective_rate == 1.0 assert limiter.current_window == starting_window for i in range(1, 101): assert limiter.is_allowed() is False rate = 100 / (100 + i) assert limiter.effective_rate == rate assert limiter.current_window == starting_window prev_rate = 0.5 with mock.patch("ddtrace.compat.monotonic") as mock_time: window = starting_window + 1.0 mock_time.return_value = window for i in range(100): assert limiter.is_allowed() is True assert limiter.effective_rate == 0.75 assert limiter.current_window == window for i in range(1, 101): assert limiter.is_allowed() is False rate = 100 / (100 + i) assert limiter.effective_rate == (rate + prev_rate) / 2 assert limiter.current_window == window
def test_rate_limiter_rate_limit_negative(): limiter = RateLimiter(rate_limit=-1) assert limiter.rate_limit == -1 assert limiter.tokens == -1 assert limiter.max_tokens == -1 now = compat.monotonic() with mock.patch("ddtrace.compat.monotonic") as mock_time: for i in range(10000): # Make sure the time is different for every check mock_time.return_value = now + i assert limiter.is_allowed() is True
def test_rate_limiter_rate_limit_0(): limiter = RateLimiter(rate_limit=0) assert limiter.rate_limit == 0 assert limiter.tokens == 0 assert limiter.max_tokens == 0 now = compat.monotonic() with mock.patch('ddtrace.compat.monotonic') as mock_time: for i in range(10000): # Make sure the time is different for every check mock_time.return_value = now + i assert limiter.is_allowed() is False
def test_rate_limiter_is_allowed_small_gaps(): limiter = RateLimiter(rate_limit=100) # Start time now = compat.monotonic() gap = 1.0 / 100.0 # Keep incrementing by a gap to keep us at our rate limit with mock.patch("ddtrace.compat.monotonic") as mock_time: for i in range(10000): # Keep the same timeframe mock_time.return_value = now + (gap * i) assert limiter.is_allowed() is True
def test_rate_liimter_effective_rate_starting_rate(): limiter = RateLimiter(rate_limit=1) now = compat.monotonic() with mock.patch("ddtrace.compat.monotonic") as mock_time: mock_time.return_value = now # Default values assert limiter.current_window == 0 assert limiter.prev_window_rate is None # Accessing the effective rate doesn't change anything assert limiter.effective_rate == 1.0 assert limiter.current_window == 0 assert limiter.prev_window_rate is None # Calling `.is_allowed()` updates the values assert limiter.is_allowed() is True assert limiter.effective_rate == 1.0 assert limiter.current_window == now assert limiter.prev_window_rate is None # Gap of 0.9999 seconds, same window mock_time.return_value = now + 0.9999 assert limiter.is_allowed() is False # DEV: We have rate_limit=1 set assert limiter.effective_rate == 0.5 assert limiter.current_window == now assert limiter.prev_window_rate is None # Gap of 1.0 seconds, new window mock_time.return_value = now + 1.0 assert limiter.is_allowed() is True assert limiter.effective_rate == 0.75 assert limiter.current_window == (now + 1.0) assert limiter.prev_window_rate == 0.5 # Gap of 1.9999 seconds, same window mock_time.return_value = now + 1.9999 assert limiter.is_allowed() is False assert limiter.effective_rate == 0.5 assert limiter.current_window == (now + 1.0) # Same as old window assert limiter.prev_window_rate == 0.5 # Large gap of 100 seconds, new window mock_time.return_value = now + 100.0 assert limiter.is_allowed() is True assert limiter.effective_rate == 0.75 assert limiter.current_window == (now + 100.0) assert limiter.prev_window_rate == 0.5
def test_rate_limiter_is_allowed_large_gap(): limiter = RateLimiter(rate_limit=100) # Start time now = compat.monotonic() with mock.patch("ddtrace.compat.monotonic") as mock_time: # Keep the same timeframe mock_time.return_value = now for _ in range(100): assert limiter.is_allowed() is True # Large gap before next call to `is_allowed()` with mock.patch("ddtrace.compat.monotonic") as mock_time: mock_time.return_value = now + 100 for _ in range(100): assert limiter.is_allowed() is True
def test_worker_http_error_logging(self): # Tests the logging http error logic tracer = self.tracer self.tracer.writer.api = FlawedAPI(Tracer.DEFAULT_HOSTNAME, Tracer.DEFAULT_PORT) tracer.trace("client.testing").finish() log = logging.getLogger("ddtrace.internal.writer") log_handler = MockedLogHandler(level="DEBUG") log.addHandler(log_handler) self._wait_thread_flush() assert tracer.writer._last_error_ts < monotonic() logged_errors = log_handler.messages["error"] assert len(logged_errors) == 1 assert ( "Failed to send traces to Datadog Agent at http://localhost:8126: " "HTTP error status 400, reason Bad Request, message Content-Type:" in logged_errors[0] )
def test_rate_limiter_is_allowed(rate_limit): limiter = RateLimiter(rate_limit=rate_limit) def check_limit(): # Up to the allowed limit is allowed for _ in range(rate_limit): assert limiter.is_allowed() is True # Any over the limit is disallowed for _ in range(1000): assert limiter.is_allowed() is False # Start time now = compat.monotonic() # Check the limit for 5 time frames for i in range(5): with mock.patch("ddtrace.compat.monotonic") as mock_time: # Keep the same timeframe mock_time.return_value = now + i check_limit()
def test_rate_limiter_init(): limiter = RateLimiter(rate_limit=100) assert limiter.rate_limit == 100 assert limiter.tokens == 100 assert limiter.max_tokens == 100 assert limiter.last_update <= compat.monotonic()