<commit_before>require 'spec_helper'
require 'securerandom'

describe Prorate::Throttle do
  describe '#throttle!' do
    let(:throttle_name) { 'leecher-%s' % SecureRandom.hex(4) }
    it 'throttles and raises an exception' do
      r = Redis.new
      t = Prorate::Throttle.new(redis: r, logger: Prorate::NullLogger, limit: 2, period: 2, block_for: 5, name: throttle_name)
      t << 'request-id'
      t << 'user-id'

      t.throttle!
      t.throttle!
      expect {
        t.throttle!
      }.to raise_error(Prorate::Throttled)
    end
    
    it 'uses the given parameters to differentiate between users' do
      r = Redis.new
      4.times { |i|
        t = Prorate::Throttle.new(redis: r, logger: Prorate::NullLogger, limit: 3, period: 2, block_for: 2, name: throttle_name)
        t << i
        3.times { t.throttle! }
      }
    end

    it 'applies a long block, even if the rolling window for the throttle is shorter' do
      r = Redis.new
      # Exhaust the request limit
      t = Prorate::Throttle.new(redis: r, logger: Prorate::NullLogger, limit: 4, period: 1, block_for: 60, name: throttle_name)
      4.times do
        t.throttle!
      end

      expect {
        t.throttle!
      }.to raise_error(Prorate::Throttled)

      sleep 1.5 # The counters have expired and the rolling window has passed, but the block is still set

      expect {
        t.throttle!
      }.to raise_error(Prorate::Throttled)
    end

    it 'raises an error if the block is triggered, and then releases it after block_for seconds' do
      r = Redis.new
      # Exhaust the request limit
      4.times do
        t = Prorate::Throttle.new(redis: r, logger: Prorate::NullLogger, limit: 4, period: 1, block_for: 2, name: throttle_name)
        t.throttle!
      end
      
      expect {
        t = Prorate::Throttle.new(redis: r, logger: Prorate::NullLogger, limit: 4, period: 1, block_for: 1, name: throttle_name)
        t.throttle!
      }.to raise_error(Prorate::Throttled)
      
      sleep 4 # 3 is still too short ????
      
      # This one should pass again
      t = Prorate::Throttle.new(redis: r, logger: Prorate::NullLogger, limit: 4, period: 1, block_for: 1, name: throttle_name)
      t.throttle!
    end
    
    it 'logs all the things' do
      buf = StringIO.new
      logger = Logger.new(buf)
      logger.level = 0
      r = Redis.new
      t = Prorate::Throttle.new(redis: r, logger: logger, limit: 64, period: 15, block_for: 30, name: throttle_name)
      expect(logger).to receive(:info).exactly(32).times.and_call_original<commit_msg>Add comment to test and revert timeout<commit_after>require 'spec_helper'
require 'securerandom'

describe Prorate::Throttle do
  describe '#throttle!' do
    let(:throttle_name) { 'leecher-%s' % SecureRandom.hex(4) }
    it 'throttles and raises an exception' do
      r = Redis.new
      t = Prorate::Throttle.new(redis: r, logger: Prorate::NullLogger, limit: 2, period: 2, block_for: 5, name: throttle_name)
      t << 'request-id'
      t << 'user-id'

      t.throttle!
      t.throttle!
      expect {
        t.throttle!
      }.to raise_error(Prorate::Throttled)
    end
    
    it 'uses the given parameters to differentiate between users' do
      r = Redis.new
      4.times { |i|
        t = Prorate::Throttle.new(redis: r, logger: Prorate::NullLogger, limit: 3, period: 2, block_for: 2, name: throttle_name)
        t << i
        3.times { t.throttle! }
      }
    end

    it 'applies a long block, even if the rolling window for the throttle is shorter' do
      r = Redis.new
      # Exhaust the request limit
      t = Prorate::Throttle.new(redis: r, logger: Prorate::NullLogger, limit: 4, period: 1, block_for: 60, name: throttle_name)
      4.times do
        t.throttle!
      end

      expect {
        t.throttle!
      }.to raise_error(Prorate::Throttled)

      sleep 1.5 # The counters have expired and the rolling window has passed, but the block is still set

      expect {
        t.throttle!
      }.to raise_error(Prorate::Throttled)
    end

    it 'raises an error if the block is triggered, and then releases it after block_for seconds' do
      r = Redis.new
      # Exhaust the request limit
      4.times do
        t = Prorate::Throttle.new(redis: r, logger: Prorate::NullLogger, limit: 4, period: 1, block_for: 2, name: throttle_name)
        t.throttle!
      end
      # bucket is now full; next request will overflow it
      expect {
        t = Prorate::Throttle.new(redis: r, logger: Prorate::NullLogger, limit: 4, period: 1, block_for: 1, name: throttle_name)
        t.throttle!
      }.to raise_error(Prorate::Throttled)
      
      sleep 1.5
      
      # This one should pass again
      t = Prorate::Throttle.new(redis: r, logger: Prorate::NullLogger, limit: 4, period: 1, block_for: 1, name: throttle_name)
      t.throttle!
    end
    
    it 'logs all the things' do
      buf = StringIO.new
      logger = Logger.new(buf)
      logger.level = 0
      r = Redis.new
      t = Prorate::Throttle.new(redis: r, logger: logger, limit: 64, period: 15, block_for: 30, name: throttle_name)
      expect(logger).to receive(:info).exactly(32).times.and_call_original
{'fraction_non_alphanumeric': 0.10721172387196298, 'fraction_numerical': 0.014269186270728885, 'mean_word_length': 2.5625, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1963452', 'n_tokens_mistral': 1879, 'n_tokens_neox': 1749, 'n_words': 523}