Completed
Push — EZP-31044-site-access-provider ( 8220ce )
by
unknown
14:19
created

RouterTest::createRouter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 44
rs 9.216
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the eZ\Publish\Core\MVC\Symfony\SiteAccess\Tests\RouterTest class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\Core\MVC\Symfony\SiteAccess\Tests;
10
11
use eZ\Publish\Core\MVC\Exception\InvalidSiteAccessException;
12
use eZ\Publish\Core\MVC\Symfony\SiteAccess;
13
use PHPUnit\Framework\TestCase;
14
use eZ\Publish\Core\MVC\Symfony\SiteAccess\Router;
15
use eZ\Publish\Core\MVC\Symfony\SiteAccess\MatcherBuilderInterface;
16
use eZ\Publish\Core\MVC\Symfony\SiteAccess\Matcher;
17
use eZ\Publish\Core\MVC\Symfony\Routing\SimplifiedRequest;
18
use eZ\Publish\Core\MVC\Symfony\SiteAccess\VersatileMatcher;
19
use eZ\Publish\Core\MVC\Symfony\SiteAccess\MatcherBuilder;
20
use Psr\Log\LoggerInterface;
21
use Symfony\Component\HttpFoundation\Request;
22
23
class RouterTest extends TestCase
24
{
25
    private const UNDEFINED_SA_NAME = 'undefined_sa';
26
    private const ENV_SA_NAME = 'env_sa';
27
    private const HEADERBASED_SA_NAME = 'headerbased_sa';
28
29
    /** @var \eZ\Publish\Core\MVC\Symfony\SiteAccess\MatcherBuilder */
30
    private $matcherBuilder;
31
32
    /** @var \eZ\Publish\Core\MVC\Symfony\SiteAccess\SiteAccessProviderInterface */
33
    private $siteAccessProvider;
34
35
    protected function setUp(): void
36
    {
37
        parent::setUp();
38
        $this->matcherBuilder = new MatcherBuilder();
39
40
        $this->siteAccessProvider = $this->createMock(SiteAccess\SiteAccessProviderInterface::class);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->createMock(\eZ\Pu...oviderInterface::class) of type object<PHPUnit\Framework\MockObject\MockObject> is incompatible with the declared type object<eZ\Publish\Core\M...ccessProviderInterface> of property $siteAccessProvider.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
41
        $this->siteAccessProvider
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<PHPUnit\Framework\MockObject\MockObject>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
42
            ->method('isDefined')
43
            ->willReturnMap([
44
                ['first_sa', true],
45
                ['second_sa', true],
46
                ['third_sa', true],
47
                ['fourth_sa', true],
48
                ['fr_eng', true],
49
                ['fr_us', true],
50
                [self::HEADERBASED_SA_NAME, true],
51
                [self::ENV_SA_NAME, true],
52
                [self::UNDEFINED_SA_NAME, false],
53
            ]);
54
        $this->siteAccessProvider
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<PHPUnit\Framework\MockObject\MockObject>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
55
            ->method('getSiteAccess')
56
            ->willReturnMap([
57
                ['first_sa', new SiteAccess('first_sa', Router::DEFAULT_SA_MATCHING_TYPE)],
58
                ['second_sa', new SiteAccess('second_sa', Router::DEFAULT_SA_MATCHING_TYPE)],
59
                ['third_sa', new SiteAccess('third_sa', Router::DEFAULT_SA_MATCHING_TYPE)],
60
                ['fourth_sa', new SiteAccess('fourth_sa', Router::DEFAULT_SA_MATCHING_TYPE)],
61
                ['fr_eng', new SiteAccess('fr_eng', Router::DEFAULT_SA_MATCHING_TYPE)],
62
                ['fr_us', new SiteAccess('fr_us', Router::DEFAULT_SA_MATCHING_TYPE)],
63
                [self::HEADERBASED_SA_NAME, new SiteAccess(self::HEADERBASED_SA_NAME, Router::HEADER_SA_MATCHING_TYPE)],
64
                [self::ENV_SA_NAME, new SiteAccess(self::ENV_SA_NAME, Router::ENV_SA_MATCHING_TYPE)],
65
            ]);
66
    }
67
68
    protected function tearDown(): void
69
    {
70
        putenv('EZPUBLISH_SITEACCESS');
71
        parent::tearDown();
72
    }
73
74
    public function testConstructDebug()
75
    {
76
        return $this->createRouter(true);
77
    }
78
79
    public function testConstruct()
80
    {
81
        return $this->createRouter();
82
    }
83
84
    /**
85
     * @dataProvider matchProvider
86
     */
87
    public function testMatch(SimplifiedRequest $request, $siteAccess)
88
    {
89
        $router = $this->createRouter();
90
        $sa = $router->match($request);
91
        $this->assertInstanceOf(SiteAccess::class, $sa);
92
        $this->assertSame($siteAccess, $sa->name);
93
        // SiteAccess must be serializable as a whole
94
        // See https://jira.ez.no/browse/EZP-21613
95
        $this->assertIsString(serialize($sa));
96
        $router->setSiteAccess();
97
    }
98
99
    public function testMatchWithDevEnvFail()
100
    {
101
        $router = $this->createRouter(true);
102
        putenv('EZPUBLISH_SITEACCESS=' . self::UNDEFINED_SA_NAME);
103
104
        $this->expectException(InvalidSiteAccessException::class);
105
        $this->expectExceptionMessageRegExp(
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\TestCa...xceptionMessageRegExp() has been deprecated with message: Use expectExceptionMessageMatches() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
106
            '/^Invalid siteaccess \'' . self::UNDEFINED_SA_NAME .'\', matched by .+\\. Valid siteaccesses are/'
107
        );
108
109
        $router->match(new SimplifiedRequest());
110
    }
111
112
    public function testMatchWithProdEnvFail()
113
    {
114
        $router = $this->createRouter();
115
        putenv('EZPUBLISH_SITEACCESS=' . self::UNDEFINED_SA_NAME);
116
117
        $this->expectException(InvalidSiteAccessException::class);
118
        $this->expectExceptionMessageRegExp(
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\TestCa...xceptionMessageRegExp() has been deprecated with message: Use expectExceptionMessageMatches() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
119
            '/^Invalid siteaccess \'' . self::UNDEFINED_SA_NAME .'\', matched by .+\\.$/'
120
        );
121
122
        $router->match(new SimplifiedRequest());
123
    }
124
125
    public function testMatchWithEnv()
126
    {
127
        $router = $this->createRouter();
128
        putenv("EZPUBLISH_SITEACCESS=" . self::ENV_SA_NAME);
129
        $sa = $router->match(new SimplifiedRequest());
130
        $this->assertInstanceOf(SiteAccess::class, $sa);
131
        $this->assertSame(self::ENV_SA_NAME, $sa->name);
132
        $this->assertSame('env', $sa->matchingType);
133
        $router->setSiteAccess();
134
    }
135
136
    public function testMatchWithRequestHeader(): void
137
    {
138
        $router = $this->createRouter();
139
        $request = Request::create('/foo/bar');
140
        $request->headers->set('X-Siteaccess', self::HEADERBASED_SA_NAME);
141
        $sa = $router->match(
142
            new SimplifiedRequest(
143
                [
144
                    'headers' => $request->headers->all(),
145
                ]
146
            )
147
        );
148
        $this->assertInstanceOf(SiteAccess::class, $sa);
149
        $this->assertSame(self::HEADERBASED_SA_NAME, $sa->name);
150
        $this->assertSame('header', $sa->matchingType);
151
        $router->setSiteAccess();
152
    }
153
154
    public function matchProvider()
155
    {
156
        return [
157
            [SimplifiedRequest::fromUrl('http://example.com'), 'default_sa'],
158
            [SimplifiedRequest::fromUrl('https://example.com'), 'default_sa'],
159
            [SimplifiedRequest::fromUrl('http://example.com/'), 'default_sa'],
160
            [SimplifiedRequest::fromUrl('https://example.com/'), 'default_sa'],
161
            [SimplifiedRequest::fromUrl('http://example.com//'), 'default_sa'],
162
            [SimplifiedRequest::fromUrl('https://example.com//'), 'default_sa'],
163
            [SimplifiedRequest::fromUrl('http://example.com:8080/'), 'default_sa'],
164
            [SimplifiedRequest::fromUrl('http://example.com/first_siteaccess/'), 'default_sa'],
165
            [SimplifiedRequest::fromUrl('http://example.com/?first_siteaccess'), 'default_sa'],
166
            [SimplifiedRequest::fromUrl('http://example.com/?first_sa'), 'default_sa'],
167
            [SimplifiedRequest::fromUrl('http://example.com/first_salt'), 'default_sa'],
168
            [SimplifiedRequest::fromUrl('http://example.com/first_sa.foo'), 'default_sa'],
169
            [SimplifiedRequest::fromUrl('http://example.com/test'), 'default_sa'],
170
            [SimplifiedRequest::fromUrl('http://example.com/test/foo/'), 'default_sa'],
171
            [SimplifiedRequest::fromUrl('http://example.com/test/foo/bar/'), 'default_sa'],
172
            [SimplifiedRequest::fromUrl('http://example.com/test/foo/bar/first_sa'), 'default_sa'],
173
            [SimplifiedRequest::fromUrl('http://example.com/default_sa'), 'default_sa'],
174
175
            [SimplifiedRequest::fromUrl('http://example.com/first_sa'), 'first_sa'],
176
            [SimplifiedRequest::fromUrl('http://example.com/first_sa/'), 'first_sa'],
177
            [SimplifiedRequest::fromUrl('http://example.com/first_sa//'), 'first_sa'],
178
            // Double slashes shouldn't be considered as one
179
            [SimplifiedRequest::fromUrl('http://example.com//first_sa//'), 'default_sa'],
180
            [SimplifiedRequest::fromUrl('http://example.com/first_sa///test'), 'first_sa'],
181
            [SimplifiedRequest::fromUrl('http://example.com/first_sa/foo'), 'first_sa'],
182
            [SimplifiedRequest::fromUrl('http://example.com/first_sa/foo/bar'), 'first_sa'],
183
            [SimplifiedRequest::fromUrl('http://example.com:82/first_sa/'), 'first_sa'],
184
            [SimplifiedRequest::fromUrl('http://third_siteaccess/first_sa/'), 'first_sa'],
185
            [SimplifiedRequest::fromUrl('http://first_sa/'), 'first_sa'],
186
            [SimplifiedRequest::fromUrl('https://first_sa/'), 'first_sa'],
187
            [SimplifiedRequest::fromUrl('http://first_sa:81/'), 'first_sa'],
188
            [SimplifiedRequest::fromUrl('http://first_siteaccess/'), 'first_sa'],
189
            [SimplifiedRequest::fromUrl('http://first_siteaccess:82/'), 'first_sa'],
190
            [SimplifiedRequest::fromUrl('http://first_siteaccess:83/'), 'first_sa'],
191
            [SimplifiedRequest::fromUrl('http://first_siteaccess/foo/'), 'first_sa'],
192
            [SimplifiedRequest::fromUrl('http://first_siteaccess:82/foo/'), 'first_sa'],
193
            [SimplifiedRequest::fromUrl('http://first_siteaccess:83/foo/'), 'first_sa'],
194
195
            [SimplifiedRequest::fromUrl('http://example.com/second_sa'), 'second_sa'],
196
            [SimplifiedRequest::fromUrl('http://example.com/second_sa/'), 'second_sa'],
197
            [SimplifiedRequest::fromUrl('http://example.com/second_sa?param1=foo'), 'second_sa'],
198
            [SimplifiedRequest::fromUrl('http://example.com/second_sa/foo/'), 'second_sa'],
199
            [SimplifiedRequest::fromUrl('http://example.com:82/second_sa/'), 'second_sa'],
200
            [SimplifiedRequest::fromUrl('http://example.com:83/second_sa/'), 'second_sa'],
201
            [SimplifiedRequest::fromUrl('http://first_siteaccess:82/second_sa/'), 'second_sa'],
202
            [SimplifiedRequest::fromUrl('http://first_siteaccess:83/second_sa/'), 'second_sa'],
203
204
            [SimplifiedRequest::fromUrl('http://example.com:81/'), 'third_sa'],
205
            [SimplifiedRequest::fromUrl('https://example.com:81/'), 'third_sa'],
206
            [SimplifiedRequest::fromUrl('http://example.com:81/foo'), 'third_sa'],
207
            [SimplifiedRequest::fromUrl('http://example.com:81/foo/bar'), 'third_sa'],
208
209
            [SimplifiedRequest::fromUrl('http://example.com:82/'), 'fourth_sa'],
210
            [SimplifiedRequest::fromUrl('https://example.com:82/'), 'fourth_sa'],
211
            [SimplifiedRequest::fromUrl('https://example.com:82/foo'), 'fourth_sa'],
212
213
            [SimplifiedRequest::fromUrl('http://fr.ezpublish.dev/eng'), 'fr_eng'],
214
            [SimplifiedRequest::fromUrl('http://us.ezpublish.dev/fre'), 'fr_us'],
215
        ];
216
    }
217
218
    public function testMatchByNameInvalidSiteAccess()
219
    {
220
        $this->expectException(\InvalidArgumentException::class);
221
222
        $matcherBuilder = $this->createMock(MatcherBuilderInterface::class);
223
        $logger = $this->createMock(LoggerInterface::class);
224
        $siteAccessProvider = $this->createMock(SiteAccess\SiteAccessProviderInterface::class);
225
        $siteAccessProvider
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<PHPUnit\Framework\MockObject\MockObject>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
226
            ->method('isDefined')
227
            ->with('bar')
228
            ->willReturn(false);
229
        $router = new Router($matcherBuilder, $logger, 'default_sa', [], $siteAccessProvider);
230
        $router->matchByName('bar');
231
    }
232
233
    public function testMatchByName()
234
    {
235
        $matcherBuilder = $this->createMock(MatcherBuilderInterface::class);
236
        $logger = $this->createMock(LoggerInterface::class);
237
        $matcherClass = 'Map\Host';
238
        $matchedSiteAccess = 'foo';
239
        $matcherConfig = [
240
            'phoenix-rises.fm' => $matchedSiteAccess,
241
        ];
242
        $config = [
243
            'Map\URI' => ['default' => 'default_sa'],
244
            $matcherClass => $matcherConfig,
245
        ];
246
        $siteAccessProvider = $this->createMock(SiteAccess\SiteAccessProviderInterface::class);
247
        $siteAccessProvider
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<PHPUnit\Framework\MockObject\MockObject>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
248
            ->method('isDefined')
249
            ->willReturnMap([
250
                [$matchedSiteAccess, true],
251
                ['default_sa', true],
252
            ]);
253
        $router = new Router($matcherBuilder, $logger, 'default_sa', $config, $siteAccessProvider);
254
        $matcherInitialSA = $this->createMock(SiteAccess\URILexer::class);
255
        $router->setSiteAccess(new SiteAccess('test', 'test', $matcherInitialSA));
256
        $matcherInitialSA
257
            ->expects($this->once())
258
            ->method('analyseURI');
259
260
        $matcher = $this->createMock(VersatileMatcher::class);
261
        $matcherBuilder
262
            ->expects($this->exactly(2))
263
            ->method('buildMatcher')
264
            ->will(
265
                $this->onConsecutiveCalls(
266
                    $this->createMock(Matcher::class),
267
                    $matcher
268
                )
269
            );
270
271
        $reverseMatchedMatcher = $this->createMock(VersatileMatcher::class);
272
        $matcher
273
            ->expects($this->once())
274
            ->method('reverseMatch')
275
            ->with($matchedSiteAccess)
276
            ->will($this->returnValue($reverseMatchedMatcher));
277
278
        $siteAccess = $router->matchByName($matchedSiteAccess);
279
        $this->assertInstanceOf(SiteAccess::class, $siteAccess);
280
        $this->assertSame($reverseMatchedMatcher, $siteAccess->matcher);
281
        $this->assertSame($matchedSiteAccess, $siteAccess->name);
282
    }
283
284
    public function testMatchByNameNoVersatileMatcher()
285
    {
286
        $matcherBuilder = $this->createMock(MatcherBuilderInterface::class);
287
        $logger = $this->createMock(LoggerInterface::class);
288
        $matcherClass = 'Map\Host';
289
        $defaultSiteAccess = 'default_sa';
290
        $matcherConfig = [
291
            'phoenix-rises.fm' => 'foo',
292
        ];
293
        $config = [$matcherClass => $matcherConfig];
294
        $siteAccessProvider = $this->createMock(SiteAccess\SiteAccessProviderInterface::class);
295
        $siteAccessProvider
0 ignored issues
show
Bug introduced by
The method method() does not seem to exist on object<PHPUnit\Framework\MockObject\MockObject>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
296
            ->method('isDefined')
297
            ->willReturnMap([
298
                [$defaultSiteAccess, true],
299
                ['foo', true],
300
            ]);
301
        $router = new Router($matcherBuilder, $logger, $defaultSiteAccess, $config, $siteAccessProvider);
302
        $router->setSiteAccess(new SiteAccess('test', 'test'));
303
        $request = $router->getRequest();
304
        $matcherBuilder
305
            ->expects($this->once())
306
            ->method('buildMatcher')
307
            ->with($matcherClass, $matcherConfig, $request)
308
            ->will($this->returnValue($this->createMock(Matcher::class)));
309
310
        $logger
311
            ->expects($this->once())
312
            ->method('notice');
313
        $this->assertEquals(new SiteAccess($defaultSiteAccess, 'default'), $router->matchByName($defaultSiteAccess));
314
    }
315
316
    private function createRouter($debug = false): Router
317
    {
318
        return new Router(
319
            $this->matcherBuilder,
320
            $this->createMock(LoggerInterface::class),
321
            'default_sa',
322
            [
323
                'Map\\URI' => [
324
                    'first_sa' => 'first_sa',
325
                    'second_sa' => 'second_sa',
326
                ],
327
                'Map\\Host' => [
328
                    'first_sa' => 'first_sa',
329
                    'first_siteaccess' => 'first_sa',
330
                    'third_siteaccess' => 'third_sa',
331
                ],
332
                'Map\\Port' => [
333
                    81 => 'third_sa',
334
                    82 => 'fourth_sa',
335
                    83 => 'first_sa',
336
                    85 => 'first_sa',
337
                ],
338
                'Compound\\LogicalAnd' => [
339
                    [
340
                        'matchers' => [
341
                            'Map\\URI' => ['eng' => true],
342
                            'Map\\Host' => ['fr.ezpublish.dev' => true],
343
                        ],
344
                        'match' => 'fr_eng',
345
                    ],
346
                    [
347
                        'matchers' => [
348
                            'Map\\URI' => ['fre' => true],
349
                            'Map\\Host' => ['us.ezpublish.dev' => true],
350
                        ],
351
                        'match' => 'fr_us',
352
                    ],
353
                ],
354
            ],
355
            $this->siteAccessProvider,
356
            null,
357
            $debug
358
        );
359
    }
360
}
361