Passed
Pull Request — master (#204)
by
unknown
01:59
created

RateLimiterMiddlewareTest.php$0 ➔ handle()   A

Complexity

Conditions 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Yiisoft\Yii\Web\Tests\RateLimiter;
4
5
use Nyholm\Psr7\Factory\Psr17Factory;
6
use Nyholm\Psr7\Response;
7
use Nyholm\Psr7\ServerRequest;
8
use PHPUnit\Framework\TestCase;
9
use Psr\Http\Message\ResponseInterface;
10
use Psr\Http\Message\ServerRequestInterface;
11
use Psr\Http\Server\RequestHandlerInterface;
12
use Yiisoft\Cache\ArrayCache;
13
use Yiisoft\Http\Method;
14
use Yiisoft\Yii\Web\RateLimiter\Counter;
15
use Yiisoft\Yii\Web\RateLimiter\RateLimiterMiddleware;
16
17
final class RateLimiterMiddlewareTest extends TestCase
18
{
19
    /**
20
     * @test
21
     */
22
    public function singleRequestWorksAsExpected(): void
23
    {
24
        $middleware = $this->createRateLimiter($this->getCounter(1000));
25
        $response = $middleware->process($this->createRequest(), $this->createRequestHandler());
26
        $this->assertEquals(200, $response->getStatusCode());
27
        $headers = $response->getHeaders();
28
        $this->assertEquals(['1000'], $headers['X-Rate-Limit-Limit']);
29
        $this->assertEquals(['999'], $headers['X-Rate-Limit-Remaining']);
30
        $this->assertGreaterThanOrEqual(time(), (int)$headers['X-Rate-Limit-Reset'][0]);
31
    }
32
33
    /**
34
     * @test
35
     */
36
    public function limitingIsStartedWhenExpected(): void
37
    {
38
        $middleware = $this->createRateLimiter($this->getCounter(10));
39
40
        for ($i = 0; $i < 8; $i++) {
41
            $middleware->process($this->createRequest(), $this->createRequestHandler());
42
        }
43
44
        // last allowed request
45
        $response = $middleware->process($this->createRequest(), $this->createRequestHandler());
46
        $this->assertEquals(200, $response->getStatusCode());
47
        $headers = $response->getHeaders();
48
        $this->assertEquals(['10'], $headers['X-Rate-Limit-Limit']);
49
        $this->assertEquals(['1'], $headers['X-Rate-Limit-Remaining']);
50
        $this->assertGreaterThanOrEqual(time(), (int)$headers['X-Rate-Limit-Reset'][0]);
51
52
        // first denied request
53
        $response = $middleware->process($this->createRequest(), $this->createRequestHandler());
54
        $this->assertEquals(429, $response->getStatusCode());
55
        $headers = $response->getHeaders();
56
        $this->assertEquals(['10'], $headers['X-Rate-Limit-Limit']);
57
        $this->assertEquals(['0'], $headers['X-Rate-Limit-Remaining']);
58
        $this->assertGreaterThanOrEqual(time(), (int)$headers['X-Rate-Limit-Reset'][0]);
59
    }
60
61
    /**
62
     * @test
63
     */
64
    public function counterIdCouldBeSet(): void
65
    {
66
        $cache = new ArrayCache();
67
        $counter = new Counter(100, 3600, $cache);
68
69
        $middleware = $this->createRateLimiter($counter)->withCounterId('custom-id');
70
        $middleware->process($this->createRequest(), $this->createRequestHandler());
71
72
        $this->assertTrue($cache->has($counter->getCacheKey()));
73
    }
74
75
    /**
76
     * @test
77
     */
78
    public function counterIdCouldBeSetWithCallback(): void
79
    {
80
        $cache = new ArrayCache();
81
        $counter = new Counter(100, 3600, $cache);
82
83
        $middleware = $this->createRateLimiter($counter)->withCounterIdCallback(
84
            static function (ServerRequestInterface $request) {
85
                return $request->getMethod();
86
            }
87
        );
88
89
        $middleware->process($this->createRequest(), $this->createRequestHandler());
90
        $this->assertTrue($cache->has($counter->getCacheKey()));
91
    }
92
93
    private function getCounter(int $limit): Counter
94
    {
95
        return new Counter($limit, 3600, new ArrayCache());
96
    }
97
98
    private function createRequestHandler(): RequestHandlerInterface
99
    {
100
        return new class implements RequestHandlerInterface {
101
            public function handle(ServerRequestInterface $request): ResponseInterface
102
            {
103
                return new Response(200);
104
            }
105
        };
106
    }
107
108
    private function createRequest(string $method = Method::GET, string $uri = '/'): ServerRequestInterface
109
    {
110
        return new ServerRequest($method, $uri);
111
    }
112
113
    private function createRateLimiter(Counter $counter): RateLimiterMiddleware
114
    {
115
        return new RateLimiterMiddleware($counter, new Psr17Factory());
116
    }
117
}
118