Passed
Push — master ( 00967d...334fde )
by Vince
01:45 queued 11s
created

LimiterTest::testWrongRateWindowInputResolves()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 17
c 0
b 0
f 0
nc 2
nop 0
dl 0
loc 29
rs 9.7
1
<?php declare(strict_types=1);
2
3
use PHPUnit\Framework\TestCase;
4
use responsible\responsible;
5
use responsible\core\throttle\limiter;
6
use responsible\core\exception;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, exception. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
7
8
final class LimiterTest extends TestCase
9
{
10
    private $options;
11
    private $limiterConstructor;
12
    private $limiterNoConstructor;
13
14
    public function setUp()
15
    {
16
        $apiOptions = new options;
17
        $this->options = $apiOptions->getApiOptions();
18
19
        $limit = 10;
20
        $rate = 'MINUTE';
21
22
        $this->limiterConstructor = new limiter($limit, $rate);
23
        $this->limiterNoConstructor = new limiter();
24
    }
25
26
    /**
27
     * Test if the Responsible API limiter denies access
28
     */
29
    public function testNoAccountDeny(): void
30
    {
31
        $limiter = $this->limiterConstructor;
32
        $limiter->setOptions($this->options);
33
34
        $this->expectException(\Exception::class);
35
36
        $limiter->throttleRequest();
37
    }
38
39
    /**
40
     * Test if the Responsible API limiter options no constructor
41
     */
42
    public function testCanSetNoConstructorOptions(): void
43
    {
44
        $limiter = $this->limiterNoConstructor;
45
        $limiter->setOptions($this->options);
46
        $limiter->setupOptions();
47
48
        $getOptionsSet = $limiter->getOptions();
49
50
        $expectedKeys = [
51
            'requestType',
52
            'rateLimit',
53
            'rateWindow',
54
            'unlimited',
55
            'leak',
56
            'leakRate',
57
        ];
58
59
        foreach ($expectedKeys as $i => $key) {
60
            $this->assertArrayHasKey($key, $getOptionsSet);
61
        }
62
    }
63
64
    /**
65
     * Test if the Responsible API limiter options with constructor
66
     */
67
    public function testCanSetConstructorOptions(): void
68
    {
69
        $limiter = $this->limiterConstructor;
70
        $limiter->setOptions($this->options);
71
        $limiter->setupOptions();
72
73
        $getOptionsSet = $limiter->getOptions();
74
75
        $expectedKeys = [
76
            'requestType',
77
            'rateLimit',
78
            'rateWindow',
79
            'unlimited',
80
            'leak',
81
            'leakRate',
82
        ];
83
84
        foreach ($expectedKeys as $i => $key) {
85
            $this->assertArrayHasKey($key, $getOptionsSet);
86
        }
87
    }
88
89
    /**
90
     * Test if the Responsible API limiter rate window 
91
     * resolves the value when wrong input is given
92
     */
93
    public function testWrongRateWindowInputResolves(): void
94
    {
95
        $limiter = $this->limiterConstructor;
96
97
        /**
98
         * Key = Expected value
99
         * Value = Actual value
100
         */
101
        $wrongPossibilities = [
102
            60 => [],
103
            60 => new \stdClass,
104
            60 => 'foo/bar',
105
            10 => -10,
106
            1 => 1.03,
107
            60 => 60.03,
108
            230 => 230,
109
        ];
110
111
        $possition = 0;
112
113
        foreach ($wrongPossibilities as $expectedValue => $possibleTest) {
114
            $this->options['rateWindow'] = $possibleTest;
115
            $limiter->setOptions($this->options);
116
            $limiter->setupOptions();
117
            $getOptionsSet = $limiter->getOptions();
0 ignored issues
show
Unused Code introduced by
The assignment to $getOptionsSet is dead and can be removed.
Loading history...
118
119
            $this->assertEquals($expectedValue, $limiter->getTimeframe(), "Time frame did not resolve to {$expectedValue}. Failed at possition {$possition}");
120
121
            $possition++;
122
        }
123
    }
124
125
    /**
126
     * Test if the Responsible API limiter leak rate 
127
     * resolves the value when wrong input is given
128
     */
129
    public function testWrongLeakRateInputResolves(): void
130
    {
131
        $limiter = $this->limiterConstructor;
132
133
        /**
134
         * Key = Expected value
135
         * Value = Actual value
136
         */
137
        $wrongPossibilities = [
138
            'default' => [],
139
            'default' => new \stdClass,
140
            'default' => 'foo/bar',
141
            'default' => -10,
142
            'default' => 1.03
143
        ];
144
145
        $possition = 0;
146
147
        foreach ($wrongPossibilities as $expectedValue => $possibleTest) {
148
            $this->options['leakRate'] = $possibleTest;
149
            $limiter->setOptions($this->options);
150
            $limiter->setupOptions();
151
            $getOptionsSet = $limiter->getOptions();
0 ignored issues
show
Unused Code introduced by
The assignment to $getOptionsSet is dead and can be removed.
Loading history...
152
153
            $this->assertEquals($expectedValue, $limiter->getLeakRate(), "Leak rate did not resolve to {$expectedValue}. Failed at possition {$possition}");
154
155
            $possition++;
156
        }
157
    }
158
159
    /**
160
     * Test the Responsible API limiter throttle
161
     * request works
162
     *
163
     * Rate limiter is in conjunction with leaky bucket drip
164
     * Hitting the server too fast, too offten "many times" 
165
     * will cause the bucket to fill and hult access 
166
     * and return a 426 error code "TOO MANY REQUESTS"
167
     *
168
     */
169
    public function testLimiterThrottle(): void
170
    {
171
        $limiter = $this->limiterConstructor;
172
        $limiter->setOptions($this->options);
173
        $limiter->setupOptions();
174
175
        $this->expectException(\Exception::class);
176
177
        for ($i = 0; $i < $this->options['rateLimit']; $i++) {
178
            $limiter->throttleRequest();
179
        }
180
    }
181
}