public void first_event_is_recorded_in_timeline()
        {
            var timeline = MockRepository.GenerateStub<IEventTimeline>();
            TrickleRateLimiter rateLimiter = new TrickleRateLimiter(timeline);
            
            Assert.DoesNotThrow(() => rateLimiter.CheckAndEnforceRateLimit(DateTime.UtcNow));

            timeline.AssertWasCalled(it => it.RecordEvent(Arg<DateTime>.Is.Anything));
        }
        public void it_asks_the_timeline_for_the_date_and_time_of_the_last_event()
        {
            var timeline = MockRepository.GenerateStub<IEventTimeline>();
            timeline.Stub(it => it.RecordEvent(Arg<DateTime>.Is.Anything));

            TrickleRateLimiter rateLimiter = new TrickleRateLimiter(timeline);

            rateLimiter.CheckAndEnforceRateLimit(DateTime.UtcNow);

            timeline.AssertWasCalled(it => it.GetLastEventDateAndTime());
        }
        public void it_doesnt_trigger_the_rate_limit_when_the_timeline_is_empty()
        {
            var timeline = MockRepository.GenerateStub<IEventTimeline>();
            timeline.Stub(it => it.RecordEvent(Arg<DateTime>.Is.Anything));
            timeline.Stub(it => it.GetLastEventDateAndTime()).Return(null);

            IPauseTime pauseTime = MockRepository.GenerateMock<IPauseTime>();

            TrickleRateLimiter rateLimiter = new TrickleRateLimiter(timeline, pauseTime);
            rateLimiter.CheckAndEnforceRateLimit(DateTime.UtcNow);
            
            pauseTime.AssertWasNotCalled(it => it.Pause(Arg<TimeSpan>.Is.Anything));
        }
        public void it_records_the_event_AFTER_asking_the_timeline_for_the_date_and_time_of_the_last_event()
        {
            var mocks = new MockRepository();

            var timeline = mocks.StrictMock<IEventTimeline>();
            
            using (mocks.Ordered())
            {
                Expect.Call(timeline.GetLastEventDateAndTime()).Return(DateTime.Parse("19-Nov-1976"));
                Expect.Call(() => timeline.RecordEvent(Arg<DateTime>.Is.Anything));
            }

            mocks.ReplayAll();

            TrickleRateLimiter rateLimiter = new TrickleRateLimiter(timeline);
            rateLimiter.CheckAndEnforceRateLimit(DateTime.UtcNow);
            
            mocks.VerifyAll();
        }
        public void it_doesnt_trigger_the_rate_limit_when_the_last_event_date_is_exactly_1_second_ago()
        {
            DateTime firstEventDateTime = new DateTime(2000, 1, 1, 12, 0, 0);
            DateTime secondEventDateTime = firstEventDateTime.AddSeconds(1); 

            var timeline = MockRepository.GenerateStub<IEventTimeline>();
            timeline.Stub(it => it.RecordEvent(Arg<DateTime>.Is.Anything));
            timeline.Stub(it => it.GetLastEventDateAndTime()).Return(firstEventDateTime);

            IPauseTime pauseTime = MockRepository.GenerateMock<IPauseTime>();

            TrickleRateLimiter rateLimiter = new TrickleRateLimiter(timeline, pauseTime);
            rateLimiter.CheckAndEnforceRateLimit(secondEventDateTime);

            pauseTime.AssertWasNotCalled(it => it.Pause(Arg<TimeSpan>.Is.Anything));
        }
        public void it_records_the_updated_timestamp_when_a_pause_was_done()
        {
            DateTime firstEventDateTime = new DateTime(2000, 1, 1, 12, 0, 0);
            DateTime secondEventDateTime = firstEventDateTime.AddMilliseconds(200);

            var timeline = MockRepository.GenerateStub<IEventTimeline>();
            timeline.Stub(it => it.GetLastEventDateAndTime()).Return(firstEventDateTime);

            IPauseTime pauseTime = MockRepository.GenerateMock<IPauseTime>();

            TrickleRateLimiter rateLimiter = new TrickleRateLimiter(timeline, pauseTime);
            rateLimiter.CheckAndEnforceRateLimit(secondEventDateTime);

            timeline.AssertWasCalled(it => it.RecordEvent(Arg<DateTime>.Is.Equal(secondEventDateTime.AddMilliseconds(800))));
            pauseTime.AssertWasCalled(it => it.Pause(Arg<TimeSpan>.Is.Equal(TimeSpan.FromMilliseconds(800))));
        }
        public void it_records_the_event_AFTER_pausing_for_the_current_event()
        {
            DateTime firstEventDateTime = new DateTime(2000, 1, 1, 12, 0, 0);
            DateTime secondEventDateTime = firstEventDateTime.AddMilliseconds(400); // <-- Second event is 400ms after the first event. This should trigger a pause of 600ms.
            
            var mocks = new MockRepository();

            var timeline = mocks.StrictMock<IEventTimeline>();
            var xxx = mocks.StrictMock<IPauseTime>();

            using (mocks.Ordered())
            {
                Expect.Call(timeline.GetLastEventDateAndTime()).Return(firstEventDateTime);
                Expect.Call(() => xxx.Pause(Arg<TimeSpan>.Is.Anything));
                Expect.Call(() => timeline.RecordEvent(Arg<DateTime>.Is.Anything));
            }

            mocks.ReplayAll();

            TrickleRateLimiter rateLimiter = new TrickleRateLimiter(timeline, xxx);
            rateLimiter.CheckAndEnforceRateLimit(secondEventDateTime);

            mocks.VerifyAll();
        }
        public void it_does_trigger_the_rate_limit_for_enough_time_to_maintain_one_event_per_second()
        {
            DateTime firstEventDateTime = new DateTime(2000, 1, 1, 12, 0, 0);
            DateTime secondEventDateTime = firstEventDateTime.AddMilliseconds(400); // <-- Second event is 400ms after the first event. This should trigger a pause of 600ms.

            var timeline = MockRepository.GenerateStub<IEventTimeline>();
            timeline.Stub(it => it.RecordEvent(Arg<DateTime>.Is.Anything));
            timeline.Stub(it => it.GetLastEventDateAndTime()).Return(firstEventDateTime);

            IPauseTime pauseTime = MockRepository.GenerateMock<IPauseTime>();

            TrickleRateLimiter rateLimiter = new TrickleRateLimiter(timeline, pauseTime);
            rateLimiter.CheckAndEnforceRateLimit(secondEventDateTime);

            pauseTime.AssertWasCalled(it => it.Pause(Arg<TimeSpan>.Is.Equal(TimeSpan.FromMilliseconds(600))));
        }
 public void first_event_doesnt_require_rate_limiting()
 {
     TrickleRateLimiter rateLimiter = new TrickleRateLimiter(MockRepository.GenerateStub<IEventTimeline>());
     Assert.DoesNotThrow(() => rateLimiter.CheckAndEnforceRateLimit(DateTime.UtcNow));
 }