class TestThrottlerPerformance:
    def setup(self):
        # Fixture setup
        self.clock = TestClock()
        self.logger = Logger(self.clock, bypass_logging=True)

        self.handler = []
        self.throttler = Throttler(
            name="Throttler-1",
            limit=10000,
            interval=timedelta(seconds=1),
            output=self.handler.append,
            clock=self.clock,
            logger=self.logger,
        )

    def send(self):
        self.throttler.send("MESSAGE")

    def test_send_unlimited(self):
        PerformanceHarness.profile_function(self.send, 10000, 1)
        # ~0.0ms / ~0.3μs / 301ns minimum of 10,000 runs @ 1 iteration each run.

    def test_send_when_limited(self):
        PerformanceHarness.profile_function(self.send, 100000, 1)
Example #2
0
    def setup(self):
        # Fixture setup
        self.clock = TestClock()
        self.logger = TestLogger(self.clock)

        self.handler = []
        self.throttler = Throttler(
            name="Throttler-1",
            limit=5,
            interval=timedelta(seconds=1),
            output=self.handler.append,
            clock=self.clock,
            logger=self.logger,
        )
    def setup(self):
        # Fixture Setup
        self.clock = TestClock()
        self.logger = Logger(self.clock)

        self.handler = []
        self.throttler = Throttler(
            name="Buffer",
            limit=5,
            interval=timedelta(seconds=1),
            output_send=self.handler.append,
            output_drop=None,  # <-- no dropping handler so will buffer
            clock=self.clock,
            logger=self.logger,
        )
    def setup(self):
        # Fixture Setup
        self.clock = TestClock()
        self.logger = Logger(self.clock)

        self.handler = []
        self.dropped = []
        self.throttler = Throttler(
            name="Dropper",
            limit=5,
            interval=timedelta(seconds=1),
            output_send=self.handler.append,
            output_drop=self.dropped.append,  # <-- handler for dropping messages
            clock=self.clock,
            logger=self.logger,
        )
def throttler(clock, logger):
    handler = []
    return Throttler(
        name="Throttler-1",
        limit=10000,
        interval=timedelta(seconds=1),
        output=handler.append,
        clock=clock,
        logger=logger,
    )
def buffering_throttler(clock, logger):
    handler = []
    return Throttler(
        name="Throttler-1",
        limit=10000,
        interval=timedelta(seconds=1),
        output_send=handler.append,
        output_drop=None,
        clock=clock,
        logger=logger,
    )
Example #7
0
class TestThrottler:
    def setup(self):
        # Fixture setup
        self.clock = TestClock()
        self.logger = TestLogger(self.clock)

        self.handler = []
        self.throttler = Throttler(
            name="Throttler-1",
            limit=5,
            interval=timedelta(seconds=1),
            output=self.handler.append,
            clock=self.clock,
            logger=self.logger,
        )

    def test_throttler_instantiation(self):
        # Arrange
        # Act
        # Assert
        assert self.throttler.name == "Throttler-1"
        assert self.throttler.qsize == 0
        assert not self.throttler.is_active
        assert not self.throttler.is_throttling

    def test_send_when_not_active_becomes_active(self):
        # Arrange
        item = "MESSAGE"

        # Act
        self.throttler.send(item)

        # Assert
        assert self.throttler.is_active
        assert not self.throttler.is_throttling
        assert self.handler == ["MESSAGE"]

    def test_send_to_limit_becomes_throttled(self):
        # Arrange
        item = "MESSAGE"

        # Act: Send 6 items
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)

        # Assert: Only 5 items are sent
        assert self.clock.timer_names() == ["Throttler-1-REFRESH-TOKEN"]
        assert self.throttler.is_active
        assert self.throttler.is_throttling
        assert self.handler == ["MESSAGE"] * 5
        assert self.throttler.qsize == 1

    def test_refresh_when_at_limit_sends_remaining_items(self):
        # Arrange
        item = "MESSAGE"

        # Act: Send 6 items
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)

        # Act: Trigger refresh token time alert
        events = self.clock.advance_time(UNIX_EPOCH + timedelta(seconds=1))
        events[0].handle_py()

        # Assert: Remaining items sent
        assert self.clock.timer_names() == ["Throttler-1-REFRESH-TOKEN"]
        assert self.throttler.is_active
        assert self.throttler.is_throttling is False
        assert self.handler == ["MESSAGE"] * 6
        assert self.throttler.qsize == 0
class TestBufferingThrottler:
    def setup(self):
        # Fixture Setup
        self.clock = TestClock()
        self.logger = Logger(self.clock)

        self.handler = []
        self.throttler = Throttler(
            name="Buffer",
            limit=5,
            interval=timedelta(seconds=1),
            output_send=self.handler.append,
            output_drop=None,  # <-- no dropping handler so will buffer
            clock=self.clock,
            logger=self.logger,
        )

    def test_throttler_instantiation(self):
        # Arrange, Act, Assert
        assert self.throttler.name == "Buffer"
        assert not self.throttler.is_limiting
        assert self.throttler.qsize == 0
        assert self.throttler.used() == 0
        assert self.throttler.recv_count == 0
        assert self.throttler.sent_count == 0

    def test_send_sends_message_to_handler(self):
        # Arrange
        item = "MESSAGE"

        # Act
        self.throttler.send(item)

        # Assert
        assert not self.throttler.is_limiting
        assert self.handler == ["MESSAGE"]
        assert self.throttler.recv_count == 1
        assert self.throttler.sent_count == 1

    def test_send_to_limit_becomes_throttled(self):
        # Arrange
        item = "MESSAGE"

        # Act: Send 6 items
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)

        # Assert: Only 5 items are sent
        assert self.clock.timer_names() == ["Buffer-DEQUE"]
        assert self.throttler.is_limiting
        assert self.handler == ["MESSAGE"] * 5
        assert self.throttler.qsize == 1
        assert self.throttler.used() == 1
        assert self.throttler.recv_count == 6
        assert self.throttler.sent_count == 5

    def test_used_when_sent_to_limit_returns_one(self):
        # Arrange
        item = "MESSAGE"

        # Act: Send 6 items
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)

        # Act
        used = self.throttler.used()

        # Assert: Remaining items sent
        assert used == 1
        assert self.throttler.recv_count == 5
        assert self.throttler.sent_count == 5

    def test_used_when_half_interval_from_limit_returns_half(self):
        # Arrange
        item = "MESSAGE"

        # Act: Send 6 items
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.clock.advance_time(500_000_000)

        # Act
        used = self.throttler.used()

        # Assert: Remaining items sent
        assert used == 0.5
        assert self.throttler.recv_count == 5
        assert self.throttler.sent_count == 5

    def test_used_before_limit_when_halfway_returns_half(self):
        # Arrange
        item = "MESSAGE"

        # Act: Send 6 items
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)

        # Act
        used = self.throttler.used()

        # Assert
        assert used == 0.6

    def test_refresh_when_at_limit_sends_remaining_items(self):
        # Arrange
        item = "MESSAGE"

        # Act: Send 6 items
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)

        # Act: Trigger refresh token time alert
        events = self.clock.advance_time(1_000_000_000)
        events[0].handle_py()

        # Assert: Remaining items sent
        assert self.clock.timer_names() == []  # No longer timing to process
        assert self.throttler.is_limiting is False
        assert self.handler == ["MESSAGE"] * 6
        assert self.throttler.qsize == 0
        assert self.throttler.used() == 0
        assert self.throttler.recv_count == 6
        assert self.throttler.sent_count == 6
class TestDroppingThrottler:
    def setup(self):
        # Fixture Setup
        self.clock = TestClock()
        self.logger = Logger(self.clock)

        self.handler = []
        self.dropped = []
        self.throttler = Throttler(
            name="Dropper",
            limit=5,
            interval=timedelta(seconds=1),
            output_send=self.handler.append,
            output_drop=self.dropped.
            append,  # <-- handler for dropping messages
            clock=self.clock,
            logger=self.logger,
        )

    def test_throttler_instantiation(self):
        # Arrange, Act, Assert
        assert self.throttler.name == "Dropper"
        assert not self.throttler.is_limiting
        assert self.throttler.qsize == 0
        assert self.throttler.used() == 0
        assert self.throttler.recv_count == 0
        assert self.throttler.sent_count == 0

    def test_send_sends_message_to_handler(self):
        # Arrange
        item = "MESSAGE"

        # Act
        self.throttler.send(item)

        # Assert
        assert not self.throttler.is_limiting
        assert self.handler == ["MESSAGE"]
        assert self.throttler.recv_count == 1
        assert self.throttler.sent_count == 1

    def test_send_to_limit_drops_message(self):
        # Arrange
        item = "MESSAGE"

        # Act: Send 6 items
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)

        # Assert: Only 5 items are sent
        assert self.clock.timer_names() == ["Dropper-DEQUE"]
        assert self.throttler.is_limiting
        assert self.handler == ["MESSAGE"] * 5
        assert self.dropped == ["MESSAGE"]
        assert self.throttler.qsize == 0
        assert self.throttler.used() == 1
        assert self.throttler.recv_count == 6
        assert self.throttler.sent_count == 5

    def test_advance_time_when_at_limit_dropped_message(self):
        # Arrange
        item = "MESSAGE"

        # Act: Send 6 items
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)
        self.throttler.send(item)

        # Act: Trigger refresh token time alert
        events = self.clock.advance_time(1_000_000_000)
        events[0].handle_py()

        # Assert: Remaining items sent
        assert self.clock.timer_names() == []  # No longer timing to process
        assert self.throttler.is_limiting is False
        assert self.handler == ["MESSAGE"] * 5
        assert self.dropped == ["MESSAGE"]
        assert self.throttler.qsize == 0
        assert self.throttler.used() == 0
        assert self.throttler.recv_count == 6
        assert self.throttler.sent_count == 5