|
@@ -0,0 +1,83 @@
|
|
|
+# Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
|
|
|
+
|
|
|
+require 'rails_helper'
|
|
|
+
|
|
|
+RSpec.describe OperationsRateLimiter do
|
|
|
+ before { freeze_time }
|
|
|
+
|
|
|
+ describe '#ensure_within_limits!' do
|
|
|
+ context 'with an IP address' do
|
|
|
+ it 'passes' do
|
|
|
+ expect { described_class.new(limit: 5, period: 1.hour, operation: 'test').ensure_within_limits!(by_ip: '1.2.3.4') }
|
|
|
+ .not_to raise_error
|
|
|
+ end
|
|
|
+
|
|
|
+ context 'with many operations' do
|
|
|
+ before do
|
|
|
+ 5.times do
|
|
|
+ described_class.new(limit: 5, period: 1.hour, operation: 'test').ensure_within_limits!(by_ip: '1.2.3.4')
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ it 'raises error due to too many operations from same IP in short time' do
|
|
|
+ expect { described_class.new(limit: 5, period: 1.hour, operation: 'test').ensure_within_limits!(by_ip: '1.2.3.4') }
|
|
|
+ .to raise_error(described_class::ThrottleLimitExceeded)
|
|
|
+ end
|
|
|
+
|
|
|
+ it 'passes after period is over' do
|
|
|
+ travel 2.hours
|
|
|
+
|
|
|
+ expect { described_class.new(limit: 5, period: 1.hour, operation: 'test').ensure_within_limits!(by_ip: '1.2.3.4') }
|
|
|
+ .not_to raise_error
|
|
|
+ end
|
|
|
+
|
|
|
+ it 'passes with a different IP address' do
|
|
|
+ expect { described_class.new(limit: 5, period: 1.hour, operation: 'test').ensure_within_limits!(by_ip: '4.5.6.7') }
|
|
|
+ .not_to raise_error
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ context 'with a field' do
|
|
|
+ it 'passes' do
|
|
|
+ expect { described_class.new(limit: 5, period: 1.hour, operation: 'test').ensure_within_limits!(by_ip: '1.2.3.4', by_identifier: 'bar') }
|
|
|
+ .not_to raise_error
|
|
|
+ end
|
|
|
+
|
|
|
+ context 'with many operations' do
|
|
|
+ before do
|
|
|
+ 5.times do
|
|
|
+ described_class.new(limit: 5, period: 1.hour, operation: 'test').ensure_within_limits!(by_ip: '1.2.3.4', by_identifier: 'bar')
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ it 'raises error due too many operations with the same value from different IPs' do
|
|
|
+ expect { described_class.new(limit: 5, period: 1.hour, operation: 'test').ensure_within_limits!(by_ip: '4.5.6.7', by_identifier: 'bar') }
|
|
|
+ .to raise_error(described_class::ThrottleLimitExceeded)
|
|
|
+ end
|
|
|
+
|
|
|
+ it 'raises error due too many operations with upercase value' do
|
|
|
+ expect { described_class.new(limit: 5, period: 1.hour, operation: 'test').ensure_within_limits!(by_ip: '4.5.6.7', by_identifier: 'BAR') }
|
|
|
+ .to raise_error(described_class::ThrottleLimitExceeded)
|
|
|
+ end
|
|
|
+
|
|
|
+ it 'raises error due too many operations with trailing space' do
|
|
|
+ expect { described_class.new(limit: 5, period: 1.hour, operation: 'test').ensure_within_limits!(by_ip: '4.5.6.7', by_identifier: 'bar ') }
|
|
|
+ .to raise_error(described_class::ThrottleLimitExceeded)
|
|
|
+ end
|
|
|
+
|
|
|
+ it 'passes after period is over' do
|
|
|
+ travel 2.hours
|
|
|
+
|
|
|
+ expect { described_class.new(limit: 5, period: 1.hour, operation: 'test').ensure_within_limits!(by_ip: '4.5.6.7', by_identifier: 'bar') }
|
|
|
+ .not_to raise_error
|
|
|
+ end
|
|
|
+
|
|
|
+ it 'passes with a different value' do
|
|
|
+ expect { described_class.new(limit: 5, period: 1.hour, operation: 'test').ensure_within_limits!(by_ip: '4.5.6.7', by_identifier: 'baz') }
|
|
|
+ .not_to raise_error
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+end
|