ashleywnj's avatar

Test Rate Limit (throttling) - catch 22

Thanks in advance for any insights or hints on how to develop a test for throttling an api using the 5.2 middleware option. I am using Laravel Spark - my controller is setup to use the auth middleware - I had a few tests setup for authentication, all passed. Using httpie in exec() to test the rate limit.

To the middleware I added "throttle"

 public function __construct()
    {
        $this->middleware(['auth', 'throttle:3']);
    }

And in my tests I added

 public function test_api_throttle()
        {
            $this->be(User::find(1));
            //$this->withoutMiddleware();
            $a = 1;
            while ($a <= 4) {
                $result = exec('http --follow  --auth [email protected]:test123 http://art-t.dev/adrs');
                $a++;
            };
            $this->assertContains('Too Many Attempts.', $result);       
        }  

The throttle test fails because of the auth middleware, which I need for my other tests - I can disable middleware for this specific test by using

$this->withoutMiddleware();

But this is a catch 22 as the actual throttling requires middleware. Compounded by the fact that I cannot use $this->be(User::find(1)); because to test the throttle requires exec on a command. If I manually test the rate limit in the browser it works fine.

Thanks for any ideas.

0 likes
5 replies
ashleywnj's avatar

So I moved to the obvious answer - which accomplishes the test - but does not give access to the httpie information. There may be a better way - I was hoping to have access to the httpie header information so that I did not need to hit the page so many times, but rather could just look for the rate limit set that httpie provides data on.

  public function test_api_throttle()
        {
            $this->be(User::find(1));
            $a = 1;
                while ($a < 61) {                
                    $this->be(User::find(1));
                    $this->visit('http://art-t.dev/adrs');   
                $a++;
            }; 
                $this->get('/adrs')
                ->seeStatusCode(429)
                ->see('Too Many Attempts.'); 
        } 
ohffs's avatar
ohffs
Best Answer
Level 50

You can do things like :

$response = $this->call('GET', '/api/whatever');
$this->assertEquals(200, $response->status());
$header_value = $response->headers->get('x-some-header');
// etc
2 likes
ashleywnj's avatar

Thanks @ohffs ... I got so caught up in playing with httpie and thinking that I had to execute that from within my test that I missed the obvious. Thanks for your time and example.

ohffs's avatar

No problem - we've all been there! :-)

ashleywnj's avatar

For anyone stumbling on this thread - I used the solution recommended by ohffs in the following way:

    public function test_api_throttle_limit()
        {
          $this->be(User::find(1));    
          $response = $this->call('GET', '/adrs');
          $header_value = $response->headers->get('X-Ratelimit-Limit');
          $this->assertEquals(50, $header_value);
                //  "X-Ratelimit-Limit" => "50"
         }

I also tried playing with assertArraySubset, but could not get past the authentication, as 'get_headers' requires a url string - one to tuck away fro the future.

    public function test_api_throttle_limit()
        {
          $this->be(User::find(1));    
          $url = 'http://art-t.dev/adrs';
          $headers = get_headers($url, 2);  
          $this->assertArraySubset(['X-Ratelimit-Limit' => '50'], $headers); 
        }
2 likes

Please or to participate in this conversation.