Passed
Branch feature/polish-proxies (e39c48)
by Quentin
03:39
created

ClientTest::testWhenAgentGoesDown()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 13
nc 1
nop 0
dl 0
loc 22
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
namespace RedirectionIO\Client\Sdk\Tests;
4
5
use PHPUnit\Framework\TestCase;
6
use RedirectionIO\Client\Sdk\Client;
7
use RedirectionIO\Client\Sdk\HttpMessage\RedirectResponse;
8
use RedirectionIO\Client\Sdk\HttpMessage\Request;
9
use RedirectionIO\Client\Sdk\HttpMessage\Response;
10
use Symfony\Component\Process\Exception\ProcessFailedException;
11
use Symfony\Component\Process\PhpExecutableFinder;
12
use Symfony\Component\Process\Process;
13
14
/**
15
 * @covers \RedirectionIO\Client\Sdk\Client
16
 */
17
class ClientTest extends TestCase
18
{
19
    private $host = 'localhost';
20
    private $port = 3100;
21
    private $client;
22
23
    public static function setUpBeforeClass()
24
    {
25
        static::startAgent();
26
    }
27
28
    public function setUp()
29
    {
30
        $this->client = new Client([
31
            'host1' => ['host' => $this->host, 'port' => $this->port],
32
        ]);
33
    }
34
35
    public function testFindRedirectWhenExist()
36
    {
37
        $request = $this->createRequest(['path' => '/foo']);
38
39
        $response = $this->client->findRedirect($request);
40
41
        $this->assertInstanceOf(RedirectResponse::class, $response);
42
        $this->assertSame(301, $response->getStatusCode());
43
        $this->assertSame('/bar', $response->getLocation());
44
    }
45
46
    public function testFindRedirectWhenExistUsingUnixSocket()
47
    {
48
        $agent = static::startAgent(['socket_type' => 'AF_UNIX']);
49
50
        $client = new Client(['host1' => ['remote_socket' => sys_get_temp_dir() . '/fake_agent.sock']]);
51
52
        $request = $this->createRequest(['path' => '/foo']);
53
54
        $response = $client->findRedirect($request);
55
56
        $this->assertInstanceOf(RedirectResponse::class, $response);
57
        $this->assertSame(301, $response->getStatusCode());
58
        $this->assertSame('/bar', $response->getLocation());
59
    }
60
61
    public function testFindRedirectWhenExistTwice()
62
    {
63
        $request = $this->createRequest(['path' => '/foo']);
64
65
        $response = $this->client->findRedirect($request);
66
67
        $this->assertInstanceOf(RedirectResponse::class, $response);
68
        $this->assertSame(301, $response->getStatusCode());
69
        $this->assertSame('/bar', $response->getLocation());
70
71
        $response = $this->client->findRedirect($request);
72
73
        $this->assertInstanceOf(RedirectResponse::class, $response);
74
        $this->assertSame(301, $response->getStatusCode());
75
        $this->assertSame('/bar', $response->getLocation());
76
    }
77
78
    public function testFindRedirectWhenNotExist()
79
    {
80
        $request = $this->createRequest(['path' => '/hello']);
81
82
        $response = $this->client->findRedirect($request);
83
84
        $this->assertNull($response);
85
    }
86
87
    public function testFindRedirectWhenAgentDown()
88
    {
89
        $client = new Client([
90
            'host1' => ['host' => 'unknown-host', 'port' => 80],
91
        ]);
92
93
        $request = $this->createRequest();
94
95
        $response = $client->findRedirect($request);
96
97
        $this->assertNull($response);
98
    }
99
100
    /**
101
     * @expectedException \RedirectionIO\Client\Sdk\Exception\AgentNotFoundException
102
     * @expectedExceptionMessage Agent not found.
103
     */
104
    public function testFindRedirectWhenAgentDownAndDebug()
105
    {
106
        $client = new Client([
107
            'host1' => ['host' => 'unknown-host', 'port' => 80],
108
        ], 1000000, true);
109
110
        $request = $this->createRequest();
111
112
        $client->findRedirect($request);
113
    }
114
115
    public function testLogRedirection()
116
    {
117
        $request = $this->createRequest();
118
        $response = new Response();
119
120
        $this->assertTrue($this->client->log($request, $response));
121
    }
122
123
    public function testLogRedirectionWhenAgentDown()
124
    {
125
        $client = new Client([
126
            'host1' => ['host' => 'unknown-host', 'port' => 80],
127
        ]);
128
129
        $request = $this->createRequest();
130
        $response = new Response();
131
132
        $this->assertFalse($client->log($request, $response));
133
    }
134
135
    /**
136
     * @expectedException \RedirectionIO\Client\Sdk\Exception\AgentNotFoundException
137
     * @expectedExceptionMessage Agent not found.
138
     */
139
    public function testLogRedirectionWhenAgentDownAndDebug()
140
    {
141
        $client = new Client([
142
            'host1' => ['host' => 'unknown-host', 'port' => 80],
143
        ], 1000000, true);
144
145
        $request = $this->createRequest();
146
        $response = new Response();
147
148
        $client->log($request, $response);
149
    }
150
151
    public function testCanFindWorkingHostInMultipleHostsArray()
152
    {
153
        $client = new Client([
154
            'host1' => ['host' => 'unknown-host', 'port' => 80],
155
            'host2' => ['host' => 'unknown-host', 'port' => 81],
156
            'host3' => ['host' => $this->host, 'port' => $this->port],
157
        ]);
158
        $request = $this->createRequest(['path' => '/foo']);
159
160
        $response = $client->findRedirect($request);
161
162
        $this->assertInstanceOf(Response::class, $response);
163
        $this->assertSame(301, $response->getStatusCode());
164
        $this->assertSame('/bar', $response->getLocation());
165
    }
166
167
    public function testWhenAgentGoesDown()
168
    {
169
        $agent = static::startAgent(['port' => 3101]);
170
171
        $client = new Client([
172
            'host1' => ['host' => 'unknown-host', 'port' => 80],
173
            'host2' => ['host' => 'unknown-host', 'port' => 81],
174
            'host3' => ['host' => $this->host, 'port' => 3101],
175
        ]);
176
        $request = $this->createRequest(['path' => '/foo']);
177
178
        $response = $client->findRedirect($request);
179
180
        $this->assertInstanceOf(Response::class, $response);
181
        $this->assertSame(301, $response->getStatusCode());
182
        $this->assertSame('/bar', $response->getLocation());
183
184
        $agent->stop();
185
186
        $response = $client->findRedirect($request);
187
188
        $this->assertNull($response);
189
    }
190
191
    /**
192
     * @expectedException \RedirectionIO\Client\Sdk\Exception\BadConfigurationException
193
     * @expectedExceptionMessage At least one connection is required.
194
     */
195
    public function testCannotAllowInstantiationWithEmptyConnectionsOptions()
196
    {
197
        $client = new Client([]);
198
    }
199
200
    /**
201
     * @expectedException \RedirectionIO\Client\Sdk\Exception\BadConfigurationException
202
     * @expectedExceptionMessage The required options "host", "port" are missing.
203
     */
204
    public function testCannotAllowInstantiationWithEmptyConnectionOptions()
205
    {
206
        $client = new Client([[]]);
207
    }
208
209
    private static function startAgent($options = [])
210
    {
211
        $socket_type = isset($options['socket_type']) ? $options['socket_type'] : 'AF_INET';
212
        $port = isset($options['port']) ? $options['port'] : 3100;
213
214
        $finder = new PhpExecutableFinder();
215
        if (false === $binary = $finder->find()) {
216
            throw new \RuntimeException('Unable to find PHP binary to run a fake agent.');
217
        }
218
219
        $agent = new Process([$binary, __DIR__ . '/../src/Resources/fake_agent.php']);
220
        $agent
221
            ->inheritEnvironmentVariables(true)
222
            ->setEnv(['RIO_SOCKET_TYPE' => $socket_type, 'RIO_PORT' => $port])
223
            ->start()
224
        ;
225
226
        static::waitUntilProcReady($agent);
227
228
        if ($agent->isTerminated() && !$agent->isSuccessful()) {
229
            throw new ProcessFailedException($agent);
230
        }
231
232
        register_shutdown_function(function () use ($agent) {
233
            $agent->stop();
234
        });
235
236
        return $agent;
237
    }
238
239
    private function createRequest($options = [])
240
    {
241
        $host = isset($options['host']) ? $options['host'] : 'host1.com';
242
        $path = isset($options['path']) ? $options['path'] : '';
243
        $userAgent = isset($options['user_agent']) ? $options['user_agent'] : 'redirection-io-client/0.0.1';
244
        $referer = isset($options['referer']) ? $options['referer'] : 'http://host0.com';
245
246
        return new Request($host, $path, $userAgent, $referer);
247
    }
248
249
    private static function waitUntilProcReady(Process $proc)
250
    {
251
        while (true) {
252
            usleep(50000);
253
            foreach ($proc as $type => $data) {
254
                if ($proc::OUT === $type || $proc::ERR === $type) {
255
                    break 2;
256
                }
257
            }
258
        }
259
    }
260
}
261