Issues (1)

tests/MiddlewareTest.php (1 issue)

1
<?php
2
namespace RazonYang\Psr\RateLimiter\Tests;
3
4
use Nyholm\Psr7\Factory\Psr17Factory;
5
use PHPUnit\Framework\TestCase;
6
use Psr\Http\Message\ResponseFactoryInterface;
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Psr\Http\Server\RequestHandlerInterface;
10
use Psr\Log\NullLogger;
11
use RazonYang\Psr\RateLimiter\Middleware;
12
use RazonYang\TokenBucket\Manager\MemcachedManager;
13
use RazonYang\TokenBucket\ManagerInterface;
14
15
class MiddlewareTest extends TestCase
16
{
17
    private $httpFactory;
18
19
    public function setUp(): void
20
    {
21
        parent::setUp();
22
23
        $this->httpFactory =  new Psr17Factory();
24
    }
25
26
    public function tearDown(): void
27
    {
28
        $this->httpFactory = null;
29
30
        parent::tearDown();
31
    }
32
33
    private function createManager(int $capacity, float $rate): ManagerInterface
34
    {
35
        $memcached = new \Memcached();
36
        $memcached->addServer('localhost', 11211);
37
        $manager = new MemcachedManager($capacity, $rate, new NullLogger(), $memcached);
38
        return $manager;
39
    }
40
41
    private function createNameCallback(string $name): \Closure
42
    {
43
        return function (ServerRequestInterface $request) use ($name): string {
0 ignored issues
show
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

43
        return function (/** @scrutinizer ignore-unused */ ServerRequestInterface $request) use ($name): string {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
44
            return $name;
45
        };
46
    }
47
48
    private function createRateLimiter(int $capacity, float $rate, \Closure $nameCallback): Middleware
49
    {
50
        return new Middleware($this->createManager($capacity, $rate), $this->httpFactory, $nameCallback);
51
    }
52
53
    /**
54
     * @dataProvider dataLimitPeriod
55
     */
56
    public function testSetLimitPeriod(int $period): void
57
    {
58
        $limiter = $this->createRateLimiter(1, 1, $this->createNameCallback(''));
59
        $limiter->setLimitPeriod($period);
60
        $property = new \ReflectionProperty(Middleware::class, 'limitPeriod');
61
        $property->setAccessible(true);
62
        $this->assertSame($period, $property->getValue($limiter));
63
    }
64
65
    public function dataLimitPeriod(): array
66
    {
67
        return [
68
            [60],
69
            [3600],
70
        ];
71
    }
72
    
73
    public function testGetResponseFactory(): void
74
    {
75
        $limiter = $this->createRateLimiter(1, 1, $this->createNameCallback(''));
76
        $method = new \ReflectionMethod(Middleware::class, 'getResponseFactory');
77
        $method->setAccessible(true);
78
        $this->assertSame($this->httpFactory, $method->invoke($limiter));
79
    }
80
81
    public function testProcess(): void
82
    {
83
        $name = uniqid();
84
        $limiter = $this->createRateLimiter(1, 60, $this->createNameCallback($name));
85
        
86
        $request = $this->httpFactory->createServerRequest('GET', '/');
87
88
        $handler = $this->createHandler();
89
        $response = $limiter->process($request, $handler);
90
        $this->assertTrue($handler->isHandled());
91
        $this->assertSame(200, $response->getStatusCode());
92
        $headers = ['X-Rate-Limit-Limit', 'X-Rate-Limit-Remaining', 'X-Rate-Limit-Reset'];
93
        foreach ($headers as $header) {
94
            $this->assertTrue($response->hasHeader($header));
95
        }
96
97
        $handler2 = $this->createHandler();
98
        $response = $limiter->process($request, $handler2);
99
        $this->assertFalse($handler2->isHandled());
100
        $this->assertSame(429, $response->getStatusCode());
101
        foreach ($headers as $header) {
102
            $this->assertTrue($response->hasHeader($header));
103
        }
104
    }
105
106
    public function testProcessSkip(): void
107
    {
108
        $name = '';
109
        $limiter = $this->createRateLimiter(1, 60, $this->createNameCallback($name));
110
        
111
        $request = $this->httpFactory->createServerRequest('GET', 'http://localhost');
112
113
        $handler = $this->createHandler();
114
        $response = $limiter->process($request, $handler);
115
        $this->assertTrue($handler->isHandled());
116
        $this->assertSame(200, $response->getStatusCode());
117
        $headers = ['X-Rate-Limit-Limit', 'X-Rate-Limit-Remaining', 'X-Rate-Limit-Reset'];
118
        foreach ($headers as $header) {
119
            $this->assertFalse($response->hasHeader($header));
120
        }
121
    }
122
123
    private function createHandler()
124
    {
125
        return new class($this->httpFactory) implements RequestHandlerInterface {
126
            /**
127
             * @var ResponseFactoryInterface $factory
128
             */
129
            private $factory;
130
131
            private $handled = false;
132
133
            public function isHandled(): bool
134
            {
135
                return $this->handled === true;
136
            }
137
138
            public function __construct($factory)
139
            {
140
                $this->factory = $factory;
141
            }
142
143
            public function handle(ServerRequestInterface $request): ResponseInterface
144
            {
145
                $this->handled = true;
146
                return $this->factory->createResponse(200);
147
            }
148
        };
149
    }
150
}
151