Failed Conditions
Pull Request — master (#262)
by Guilherme
10:25 queued 04:26
created

RemoteClaimFetcherTest::getFetcher()   C

Complexity

Conditions 7
Paths 48

Size

Total Lines 32
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 16
nc 48
nop 5
dl 0
loc 32
rs 6.7272
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the login-cidadao project or it's bundles.
4
 *
5
 * (c) Guilherme Donato <guilhermednt on github>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace LoginCidadao\RemoteClaimsBundle\Tests\Fetcher;
12
13
use Doctrine\ORM\EntityManagerInterface;
14
use GuzzleHttp\Client;
15
use GuzzleHttp\Exception\RequestException;
16
use GuzzleHttp\Exception\TransferException;
17
use GuzzleHttp\Psr7\Request;
18
use LoginCidadao\OpenIDBundle\Manager\ClientManager;
19
use LoginCidadao\RemoteClaimsBundle\Entity\RemoteClaim;
20
use LoginCidadao\RemoteClaimsBundle\Entity\RemoteClaimRepository;
21
use LoginCidadao\RemoteClaimsBundle\Exception\ClaimProviderNotFoundException;
22
use LoginCidadao\RemoteClaimsBundle\Exception\ClaimUriUnavailableException;
23
use LoginCidadao\RemoteClaimsBundle\Fetcher\RemoteClaimFetcher;
24
use LoginCidadao\RemoteClaimsBundle\Model\ClaimProviderInterface;
25
use LoginCidadao\RemoteClaimsBundle\Model\HttpUri;
26
use LoginCidadao\RemoteClaimsBundle\Model\RemoteClaimInterface;
27
use LoginCidadao\RemoteClaimsBundle\Model\TagUri;
28
use LoginCidadao\RemoteClaimsBundle\Tests\Http\HttpMocker;
29
use LoginCidadao\RemoteClaimsBundle\Tests\Parser\RemoteClaimParserTest;
30
use PHPUnit\Framework\TestCase;
31
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
32
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
33
34
class RemoteClaimFetcherTest extends TestCase
35
{
36
    /**
37
     * Test the Claim fetch using HTTP URI.
38
     */
39
    public function testFetchByHttpUri()
40
    {
41
        $uri = 'https://dummy.com';
42
43
        $data = RemoteClaimParserTest::$claimMetadata;
44
45
        $fetcher = $this->getFetcher(new HttpMocker($data));
46
        $remoteClaim = $fetcher->fetchRemoteClaim($uri);
47
48
        $this->assertInstanceOf(RemoteClaimInterface::class, $remoteClaim);
49
        $this->assertEquals($data['claim_display_name'], $remoteClaim->getDisplayName());
50
    }
51
52
    /**
53
     * Test the Claim fetch using Tag URI.
54
     */
55
    public function testFetchByTagUri()
56
    {
57
        $uri = 'https://dummy.com';
58
59
        $data = RemoteClaimParserTest::$claimMetadata;
60
        $tagUri = $data['claim_name'];
61
62
        $httpMocker = new HttpMocker($data, $uri);
63
        $fetcher = $this->getFetcher($httpMocker);
64
        $remoteClaim = $fetcher->fetchRemoteClaim($tagUri);
65
66
        $requests = $httpMocker->getRequests();
67
        $firstRequest = $requests[0];
68
69
        $this->assertInstanceOf(RemoteClaimInterface::class, $remoteClaim);
70
        $this->assertEquals($data['claim_display_name'], $remoteClaim->getDisplayName());
71
        $this->assertCount(2, $requests);
72
73
        $webFingerUrl = HttpUri::createFromString($firstRequest->getUri());
74
        $this->assertEquals('https', $webFingerUrl->getScheme());
75
        $this->assertEquals('example.com', $webFingerUrl->getHost());
76
        $this->assertEquals('/.well-known/webfinger', $webFingerUrl->getPath());
77
78
        $webFingerParams = explode('&', $webFingerUrl->getQuery());
79
        $this->assertContains('rel=http%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fclaim', $webFingerParams);
80
        $encodedTag = urlencode($tagUri);
81
        $this->assertContains("resource={$encodedTag}", $webFingerParams);
82
    }
83
84
    public function testFetchTagNotFound()
85
    {
86
        $this->expectException(NotFoundHttpException::class);
87
88
        $tagUri = 'tag:example.com,2018:my_claim';
89
        $fetcher = $this->getFetcher();
90
        $fetcher->fetchRemoteClaim($tagUri);
91
    }
92
93
    public function testFetchUriNotFound()
94
    {
95
        $this->expectException(NotFoundHttpException::class);
96
97
        $httpClient = new HttpMocker(null, null, [
98
            new RequestException('Not found', new Request('GET', 'dummy')),
99
        ]);
100
101
        $tagUri = 'https://claim.uri/dummy';
102
        $fetcher = $this->getFetcher($httpClient);
103
        $fetcher->fetchRemoteClaim($tagUri);
104
    }
105
106
    /**
107
     * This test assumes the Remote Claim is already known by the IdP.
108
     * The existing Remote Claim is expected to be returned.
109
     */
110
    public function testExistingClaim()
111
    {
112
        $claimUri = 'https://dummy.com';
113
114
        /** @var ClaimProviderInterface|\PHPUnit_Framework_MockObject_MockObject $provider */
115
        $provider = $this->createMock(ClaimProviderInterface::class);
116
        $provider->expects($this->once())->method('getClientId')->willReturn(['https://redirect.uri']);
117
118
        $existingClaim = new RemoteClaim();
119
        $existingClaim->setProvider($provider);
120
121
        $claimRepository = $this->getClaimRepository();
122
        $claimRepository->expects($this->once())->method('findOneBy')->willReturn($existingClaim);
123
124
        $clientManager = $this->getClientManager();
125
        $clientManager->expects($this->once())->method('getClientById')->willReturn($provider);
126
127
        $em = $this->getEntityManager();
128
        $em->expects($this->never())->method('persist');
129
130
        $data = RemoteClaimParserTest::$claimMetadata;
131
        $fetcher = $this->getFetcher(new HttpMocker($data), $em, $claimRepository, $clientManager);
132
        $actual = $fetcher->getRemoteClaim($claimUri);
133
134
        $this->assertEquals($existingClaim, $actual);
135
    }
136
137
    /**
138
     * This method tests a new Remote Claim, unknown by the IdP.
139
     * The Claim MUST be fetched and persisted.
140
     */
141
    public function testNewClaim()
142
    {
143
        $claimUri = 'https://dummy.com';
144
145
        $provider = $this->createMock(ClaimProviderInterface::class);
146
147
        $existingClaim = null;
148
149
        $claimRepository = $this->getClaimRepository();
150
        $claimRepository->expects($this->once())->method('findOneBy')->willReturn($existingClaim);
151
152
        $clientManager = $this->getClientManager();
153
        $clientManager->expects($this->once())->method('getClientById')->willReturn($provider);
154
155
        $em = $this->getEntityManager();
156
        $em->expects($this->once())->method('persist')
157
            ->with($this->isInstanceOf(RemoteClaimInterface::class));
158
159
        $data = RemoteClaimParserTest::$claimMetadata;
160
        $fetcher = $this->getFetcher(new HttpMocker($data), $em, $claimRepository, $clientManager);
161
        $actual = $fetcher->getRemoteClaim($claimUri);
162
163
        $this->assertInstanceOf(RemoteClaimInterface::class, $actual);
164
    }
165
166
    /**
167
     * Test that the method fails when the Claim Provider is not already persisted.
168
     */
169
    public function testNonExistentProvider()
170
    {
171
        $this->expectException(ClaimProviderNotFoundException::class);
172
        $claimUri = 'https://dummy.com';
173
174
        $clientManager = $this->getClientManager();
175
        $clientManager->expects($this->once())->method('getClientById')->willReturn(null);
176
177
        $em = $this->getEntityManager();
178
        $em->expects($this->never())->method('persist');
179
180
        $httpMocker = new HttpMocker(RemoteClaimParserTest::$claimMetadata);
181
        $fetcher = $this->getFetcher($httpMocker, $em, null, $clientManager);
182
        $fetcher->getRemoteClaim($claimUri);
183
    }
184
185
    public function testHttpErrorOnFetch()
186
    {
187
        $tagUri = 'tag:example.com,2018:my_claim';
188
189
        $httpClient = new HttpMocker(null, null, [
190
            new RequestException('Not found', new Request('GET', 'dummy')),
191
        ]);
192
193
        $fetcher = $this->getFetcher($httpClient);
194
        $this->expectException(ClaimUriUnavailableException::class);
195
        $fetcher->discoverClaimUri($tagUri);
196
    }
197
198
    public function testDiscoveryFallback()
199
    {
200
        $tagUri = TagUri::createFromString('tag:example.com,2018:my_claim');
201
202
        $httpClient = new HttpMocker(null, null, [
203
            new RequestException('Error discovering URI', new Request('GET', 'dummy')),
204
        ]);
205
206
        $uri = 'https://my.claim.uri/';
207
        $remoteClaim = (new RemoteClaim())->setUri($uri);
208
209
        $claimRepo = $this->getClaimRepository();
210
        $claimRepo->expects($this->once())->method('findOneBy')->with(['name' => $tagUri])
211
            ->willReturn($remoteClaim);
212
213
        $fetcher = $this->getFetcher($httpClient, null, $claimRepo);
214
        $this->assertSame($uri, $fetcher->discoverClaimUri($tagUri));
215
    }
216
217
    public function testProviderNotFound()
218
    {
219
        $this->expectException(ClaimProviderNotFoundException::class);
220
221
        $claimUri = 'https://dummy.com';
222
223
        $clientManager = $this->getClientManager();
224
        $clientManager->expects($this->once())->method('getClientById')->willReturn(null);
225
226
        $httpMocker = new HttpMocker(RemoteClaimParserTest::$claimMetadata);
227
        $fetcher = $this->getFetcher($httpMocker, null, null, $clientManager, null);
228
        $fetcher->getRemoteClaim($claimUri);
229
    }
230
231
    /**
232
     * @param HttpMocker|Client|null $httpMocker
233
     * @param EntityManagerInterface|null $em
234
     * @param RemoteClaimRepository|null $claimRepository
235
     * @param ClientManager|null $clientManager
236
     * @param EventDispatcherInterface|null $dispatcher
237
     * @return RemoteClaimFetcher
238
     */
239
    private function getFetcher(
240
        $httpMocker = null,
241
        EntityManagerInterface $em = null,
242
        RemoteClaimRepository $claimRepository = null,
243
        ClientManager $clientManager = null,
244
        EventDispatcherInterface $dispatcher = null
245
    ) {
246
        if ($httpMocker instanceof Client) {
247
            $httpClient = $httpMocker;
248
        } else {
249
            if ($httpMocker === null) {
250
                $httpMocker = new HttpMocker();
251
            }
252
            $httpClient = $httpMocker->getClient();
253
        }
254
255
        if ($em === null) {
256
            $em = $this->getEntityManager();
257
        }
258
        if ($claimRepository === null) {
259
            $claimRepository = $this->getClaimRepository();
260
        }
261
        if ($clientManager === null) {
262
            $clientManager = $this->getClientManager();
263
        }
264
        if ($dispatcher === null) {
265
            $dispatcher = $this->getDispatcher();
266
        }
267
268
        $fetcher = new RemoteClaimFetcher($httpClient, $em, $claimRepository, $clientManager, $dispatcher);
269
270
        return $fetcher;
271
    }
272
273
    /**
274
     * @return \PHPUnit_Framework_MockObject_MockObject|EntityManagerInterface
275
     */
276
    private function getEntityManager()
277
    {
278
        $em = $this->createMock(EntityManagerInterface::class);
279
280
        return $em;
281
    }
282
283
    /**
284
     * @return RemoteClaimRepository|\PHPUnit_Framework_MockObject_MockObject
285
     */
286
    private function getClaimRepository()
287
    {
288
        return $this->getMockBuilder(RemoteClaimRepository::class)
289
            ->disableOriginalConstructor()
290
            ->getMock();
291
    }
292
293
    /**
294
     * @return ClientManager|\PHPUnit_Framework_MockObject_MockObject
295
     */
296
    private function getClientManager()
297
    {
298
        $manager = $this->getMockBuilder(ClientManager::class)
299
            ->disableOriginalConstructor()->getMock();
300
301
        return $manager;
302
    }
303
304
    /**
305
     * @return EventDispatcherInterface|\PHPUnit_Framework_MockObject_MockObject
306
     */
307
    private function getDispatcher()
308
    {
309
        return $this->createMock(EventDispatcherInterface::class);
310
    }
311
}
312