Passed
Push — issue#666 ( 0a0cb9...d66c4e )
by Guilherme
08:36
created

RemoteClaimFetcherTest::testHttpErrorOnFetch()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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