]> git.immae.eu Git - github/wallabag/wallabag.git/blame - tests/Wallabag/ImportBundle/Import/PocketImportTest.php
Merge pull request #2879 from matteocoder/matteocoder-patch-1
[github/wallabag/wallabag.git] / tests / Wallabag / ImportBundle / Import / PocketImportTest.php
CommitLineData
7ec2897e
JB
1<?php
2
23634d5d 3namespace Tests\Wallabag\ImportBundle\Import;
7ec2897e
JB
4
5use Wallabag\UserBundle\Entity\User;
79d0e38e 6use Wallabag\CoreBundle\Entity\Entry;
ebe0787e 7use Wallabag\CoreBundle\Entity\Config;
7ec2897e 8use Wallabag\ImportBundle\Import\PocketImport;
7ec2897e
JB
9use GuzzleHttp\Client;
10use GuzzleHttp\Subscriber\Mock;
11use GuzzleHttp\Message\Response;
12use GuzzleHttp\Stream\Stream;
b3437d58 13use Wallabag\ImportBundle\Redis\Producer;
252ebd60
JB
14use Monolog\Logger;
15use Monolog\Handler\TestHandler;
b3437d58
JB
16use Simpleue\Queue\RedisQueue;
17use M6Web\Component\RedisMock\RedisMockFactory;
252ebd60 18
7ec2897e
JB
19class PocketImportTest extends \PHPUnit_Framework_TestCase
20{
21 protected $token;
22 protected $user;
7ec2897e 23 protected $em;
252ebd60
JB
24 protected $contentProxy;
25 protected $logHandler;
7ec2897e 26
7816eb62 27 private function getPocketImport($consumerKey = 'ConsumerKey', $dispatched = 0)
7ec2897e
JB
28 {
29 $this->user = new User();
30
ebe0787e
JB
31 $config = new Config($this->user);
32 $config->setPocketConsumerKey('xxx');
33
34 $this->user->setConfig($config);
35
252ebd60
JB
36 $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy')
37 ->disableOriginalConstructor()
38 ->getMock();
39
7ec2897e
JB
40 $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
41 ->disableOriginalConstructor()
42 ->getMock();
43
40113585
JB
44 $this->uow = $this->getMockBuilder('Doctrine\ORM\UnitOfWork')
45 ->disableOriginalConstructor()
46 ->getMock();
47
48 $this->em
49 ->expects($this->any())
50 ->method('getUnitOfWork')
51 ->willReturn($this->uow);
52
53 $this->uow
54 ->expects($this->any())
55 ->method('getScheduledEntityInsertions')
56 ->willReturn([]);
57
7816eb62
JB
58 $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcher')
59 ->disableOriginalConstructor()
60 ->getMock();
61
62 $dispatcher
63 ->expects($this->exactly($dispatched))
64 ->method('dispatch');
65
66 $pocket = new PocketImport($this->em, $this->contentProxy, $dispatcher);
ef75e122 67 $pocket->setUser($this->user);
252ebd60
JB
68
69 $this->logHandler = new TestHandler();
4094ea47 70 $logger = new Logger('test', [$this->logHandler]);
252ebd60
JB
71 $pocket->setLogger($logger);
72
73 return $pocket;
7ec2897e
JB
74 }
75
76 public function testInit()
77 {
78 $pocketImport = $this->getPocketImport();
79
80 $this->assertEquals('Pocket', $pocketImport->getName());
7019c7cf 81 $this->assertNotEmpty($pocketImport->getUrl());
0d42217e 82 $this->assertEquals('import.pocket.description', $pocketImport->getDescription());
7ec2897e
JB
83 }
84
85 public function testOAuthRequest()
86 {
87 $client = new Client();
88
89 $mock = new Mock([
252ebd60 90 new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['code' => 'wunderbar_code']))),
7ec2897e
JB
91 ]);
92
93 $client->getEmitter()->attach($mock);
94
95 $pocketImport = $this->getPocketImport();
96 $pocketImport->setClient($client);
97
252ebd60 98 $code = $pocketImport->getRequestToken('http://0.0.0.0/redirect');
7ec2897e 99
252ebd60
JB
100 $this->assertEquals('wunderbar_code', $code);
101 }
102
103 public function testOAuthRequestBadResponse()
104 {
105 $client = new Client();
106
107 $mock = new Mock([
108 new Response(403),
109 ]);
110
111 $client->getEmitter()->attach($mock);
112
113 $pocketImport = $this->getPocketImport();
114 $pocketImport->setClient($client);
115
116 $code = $pocketImport->getRequestToken('http://0.0.0.0/redirect');
117
118 $this->assertFalse($code);
119
120 $records = $this->logHandler->getRecords();
121 $this->assertContains('PocketImport: Failed to request token', $records[0]['message']);
122 $this->assertEquals('ERROR', $records[0]['level_name']);
7ec2897e
JB
123 }
124
125 public function testOAuthAuthorize()
126 {
127 $client = new Client();
128
129 $mock = new Mock([
252ebd60 130 new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))),
7ec2897e
JB
131 ]);
132
133 $client->getEmitter()->attach($mock);
134
135 $pocketImport = $this->getPocketImport();
136 $pocketImport->setClient($client);
137
252ebd60 138 $res = $pocketImport->authorize('wunderbar_code');
7ec2897e 139
252ebd60
JB
140 $this->assertTrue($res);
141 $this->assertEquals('wunderbar_token', $pocketImport->getAccessToken());
7ec2897e
JB
142 }
143
252ebd60
JB
144 public function testOAuthAuthorizeBadResponse()
145 {
146 $client = new Client();
147
148 $mock = new Mock([
149 new Response(403),
150 ]);
151
152 $client->getEmitter()->attach($mock);
153
154 $pocketImport = $this->getPocketImport();
155 $pocketImport->setClient($client);
156
157 $res = $pocketImport->authorize('wunderbar_code');
158
159 $this->assertFalse($res);
160
161 $records = $this->logHandler->getRecords();
162 $this->assertContains('PocketImport: Failed to authorize client', $records[0]['message']);
163 $this->assertEquals('ERROR', $records[0]['level_name']);
164 }
165
166 /**
167 * Will sample results from https://getpocket.com/developer/docs/v3/retrieve.
168 */
7ec2897e
JB
169 public function testImport()
170 {
171 $client = new Client();
172
173 $mock = new Mock([
252ebd60
JB
174 new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))),
175 new Response(200, ['Content-Type' => 'application/json'], Stream::factory('
176 {
177 "status": 1,
178 "list": {
179 "229279689": {
180 "item_id": "229279689",
181 "resolved_id": "229279689",
182 "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
183 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
184 "favorite": "1",
185 "status": "1",
7f753117
JB
186 "time_added": "1473020899",
187 "time_updated": "1473020899",
188 "time_read": "0",
189 "time_favorited": "0",
190 "sort_id": 0,
252ebd60
JB
191 "resolved_title": "The Massive Ryder Cup Preview",
192 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
193 "excerpt": "The list of things I love about the Ryder Cup is so long that it could fill a (tedious) novel, and golf fans can probably guess most of them.",
194 "is_article": "1",
7f753117 195 "is_index": "0",
252ebd60
JB
196 "has_video": "1",
197 "has_image": "1",
198 "word_count": "3197",
199 "images": {
200 "1": {
201 "item_id": "229279689",
202 "image_id": "1",
203 "src": "http://a.espncdn.com/combiner/i?img=/photo/2012/0927/grant_g_ryder_cr_640.jpg&w=640&h=360",
204 "width": "0",
205 "height": "0",
206 "credit": "Jamie Squire/Getty Images",
207 "caption": ""
208 }
209 },
210 "videos": {
211 "1": {
212 "item_id": "229279689",
213 "video_id": "1",
214 "src": "http://www.youtube.com/v/Er34PbFkVGk?version=3&hl=en_US&rel=0",
215 "width": "420",
216 "height": "315",
217 "type": "1",
218 "vid": "Er34PbFkVGk"
219 }
220 },
221 "tags": {
222 "grantland": {
223 "item_id": "1147652870",
224 "tag": "grantland"
225 },
226 "Ryder Cup": {
227 "item_id": "1147652870",
228 "tag": "Ryder Cup"
229 }
230 }
231 },
232 "229279690": {
233 "item_id": "229279689",
234 "resolved_id": "229279689",
235 "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
236 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
237 "favorite": "1",
238 "status": "1",
7f753117
JB
239 "time_added": "1473020899",
240 "time_updated": "1473020899",
241 "time_read": "0",
242 "time_favorited": "0",
243 "sort_id": 1,
252ebd60
JB
244 "resolved_title": "The Massive Ryder Cup Preview",
245 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
246 "excerpt": "The list of things I love about the Ryder Cup is so long that it could fill a (tedious) novel, and golf fans can probably guess most of them.",
247 "is_article": "1",
7f753117 248 "is_index": "0",
252ebd60
JB
249 "has_video": "0",
250 "has_image": "0",
251 "word_count": "3197"
252 }
253 }
254 }
255 ')),
256 ]);
257
258 $client->getEmitter()->attach($mock);
259
7816eb62 260 $pocketImport = $this->getPocketImport('ConsumerKey', 1);
252ebd60
JB
261
262 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
263 ->disableOriginalConstructor()
264 ->getMock();
265
266 $entryRepo->expects($this->exactly(2))
78833672 267 ->method('findByUrlAndUserId')
252ebd60
JB
268 ->will($this->onConsecutiveCalls(false, true));
269
252ebd60 270 $this->em
c2656f96 271 ->expects($this->exactly(2))
252ebd60 272 ->method('getRepository')
c2656f96 273 ->willReturn($entryRepo);
252ebd60 274
79d0e38e 275 $entry = new Entry($this->user);
252ebd60
JB
276
277 $this->contentProxy
278 ->expects($this->once())
279 ->method('updateEntry')
280 ->willReturn($entry);
281
282 $pocketImport->setClient($client);
283 $pocketImport->authorize('wunderbar_code');
284
285 $res = $pocketImport->import();
286
287 $this->assertTrue($res);
c80cc01a 288 $this->assertEquals(['skipped' => 1, 'imported' => 1, 'queued' => 0], $pocketImport->getSummary());
252ebd60
JB
289 }
290
79d0e38e
JB
291 /**
292 * Will sample results from https://getpocket.com/developer/docs/v3/retrieve.
293 */
294 public function testImportAndMarkAllAsRead()
295 {
296 $client = new Client();
297
298 $mock = new Mock([
299 new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))),
300 new Response(200, ['Content-Type' => 'application/json'], Stream::factory('
301 {
302 "status": 1,
303 "list": {
304 "229279689": {
305 "item_id": "229279689",
306 "resolved_id": "229279689",
307 "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
308 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
309 "favorite": "1",
310 "status": "1",
7f753117
JB
311 "time_added": "1473020899",
312 "time_updated": "1473020899",
313 "time_read": "0",
314 "time_favorited": "0",
315 "sort_id": 0,
79d0e38e
JB
316 "excerpt": "The list of things I love about the Ryder Cup is so long that it could fill a (tedious) novel, and golf fans can probably guess most of them.",
317 "is_article": "1",
318 "has_video": "1",
319 "has_image": "1",
320 "word_count": "3197"
321 },
322 "229279690": {
323 "item_id": "229279689",
324 "resolved_id": "229279689",
325 "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview/2",
326 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
327 "favorite": "1",
328 "status": "0",
7f753117
JB
329 "time_added": "1473020899",
330 "time_updated": "1473020899",
331 "time_read": "0",
332 "time_favorited": "0",
333 "sort_id": 1,
79d0e38e
JB
334 "excerpt": "The list of things I love about the Ryder Cup is so long that it could fill a (tedious) novel, and golf fans can probably guess most of them.",
335 "is_article": "1",
336 "has_video": "0",
337 "has_image": "0",
338 "word_count": "3197"
339 }
340 }
341 }
342 ')),
343 ]);
344
345 $client->getEmitter()->attach($mock);
346
7816eb62 347 $pocketImport = $this->getPocketImport('ConsumerKey', 2);
79d0e38e
JB
348
349 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
350 ->disableOriginalConstructor()
351 ->getMock();
352
353 $entryRepo->expects($this->exactly(2))
354 ->method('findByUrlAndUserId')
355 ->will($this->onConsecutiveCalls(false, false));
356
357 $this->em
358 ->expects($this->exactly(2))
359 ->method('getRepository')
360 ->willReturn($entryRepo);
361
362 // check that every entry persisted are archived
363 $this->em
364 ->expects($this->any())
365 ->method('persist')
cebb4223 366 ->with($this->callback(function ($persistedEntry) {
79d0e38e
JB
367 return $persistedEntry->isArchived();
368 }));
369
370 $entry = new Entry($this->user);
371
372 $this->contentProxy
373 ->expects($this->exactly(2))
374 ->method('updateEntry')
375 ->willReturn($entry);
376
377 $pocketImport->setClient($client);
378 $pocketImport->authorize('wunderbar_code');
379
380 $res = $pocketImport->setMarkAsRead(true)->import();
381
382 $this->assertTrue($res);
c80cc01a 383 $this->assertEquals(['skipped' => 0, 'imported' => 2, 'queued' => 0], $pocketImport->getSummary());
79d0e38e
JB
384 }
385
13470c35
JB
386 /**
387 * Will sample results from https://getpocket.com/developer/docs/v3/retrieve.
388 */
389 public function testImportWithRabbit()
390 {
391 $client = new Client();
392
393 $body = <<<'JSON'
394{
395 "item_id": "229279689",
396 "resolved_id": "229279689",
397 "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
398 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
399 "favorite": "1",
400 "status": "1",
7f753117
JB
401 "time_added": "1473020899",
402 "time_updated": "1473020899",
403 "time_read": "0",
404 "time_favorited": "0",
405 "sort_id": 0,
13470c35
JB
406 "resolved_title": "The Massive Ryder Cup Preview",
407 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
408 "excerpt": "The list of things I love about the Ryder Cup is so long that it could fill a (tedious) novel, and golf fans can probably guess most of them.",
409 "is_article": "1",
410 "has_video": "0",
411 "has_image": "0",
412 "word_count": "3197"
413}
414JSON;
415
416 $mock = new Mock([
417 new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))),
418 new Response(200, ['Content-Type' => 'application/json'], Stream::factory('
419 {
420 "status": 1,
421 "list": {
422 "229279690": '.$body.'
423 }
424 }
425 ')),
426 ]);
427
428 $client->getEmitter()->attach($mock);
429
430 $pocketImport = $this->getPocketImport();
431
432 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
433 ->disableOriginalConstructor()
434 ->getMock();
435
436 $entryRepo->expects($this->never())
437 ->method('findByUrlAndUserId');
438
439 $this->em
440 ->expects($this->never())
441 ->method('getRepository');
442
443 $entry = new Entry($this->user);
444
445 $this->contentProxy
446 ->expects($this->never())
447 ->method('updateEntry');
448
449 $producer = $this->getMockBuilder('OldSound\RabbitMqBundle\RabbitMq\Producer')
450 ->disableOriginalConstructor()
451 ->getMock();
452
453 $bodyAsArray = json_decode($body, true);
454 // because with just use `new User()` so it doesn't have an id
455 $bodyAsArray['userId'] = null;
456
457 $producer
458 ->expects($this->once())
459 ->method('publish')
460 ->with(json_encode($bodyAsArray));
461
462 $pocketImport->setClient($client);
b3437d58 463 $pocketImport->setProducer($producer);
13470c35
JB
464 $pocketImport->authorize('wunderbar_code');
465
466 $res = $pocketImport->setMarkAsRead(true)->import();
467
468 $this->assertTrue($res);
c80cc01a 469 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 1], $pocketImport->getSummary());
13470c35
JB
470 }
471
b3437d58
JB
472 /**
473 * Will sample results from https://getpocket.com/developer/docs/v3/retrieve.
474 */
475 public function testImportWithRedis()
476 {
477 $client = new Client();
478
479 $body = <<<'JSON'
480{
481 "item_id": "229279689",
482 "resolved_id": "229279689",
483 "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
484 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
485 "favorite": "1",
486 "status": "1",
487 "time_added": "1473020899",
488 "time_updated": "1473020899",
489 "time_read": "0",
490 "time_favorited": "0",
491 "sort_id": 0,
492 "resolved_title": "The Massive Ryder Cup Preview",
493 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
494 "excerpt": "The list of things I love about the Ryder Cup is so long that it could fill a (tedious) novel, and golf fans can probably guess most of them.",
495 "is_article": "1",
496 "has_video": "0",
497 "has_image": "0",
498 "word_count": "3197"
499}
500JSON;
501
502 $mock = new Mock([
503 new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))),
504 new Response(200, ['Content-Type' => 'application/json'], Stream::factory('
505 {
506 "status": 1,
507 "list": {
508 "229279690": '.$body.'
509 }
510 }
511 ')),
512 ]);
513
514 $client->getEmitter()->attach($mock);
515
516 $pocketImport = $this->getPocketImport();
517
518 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
519 ->disableOriginalConstructor()
520 ->getMock();
521
522 $entryRepo->expects($this->never())
523 ->method('findByUrlAndUserId');
524
525 $this->em
526 ->expects($this->never())
527 ->method('getRepository');
528
529 $entry = new Entry($this->user);
530
531 $this->contentProxy
532 ->expects($this->never())
533 ->method('updateEntry');
534
535 $factory = new RedisMockFactory();
536 $redisMock = $factory->getAdapter('Predis\Client', true);
537
538 $queue = new RedisQueue($redisMock, 'pocket');
539 $producer = new Producer($queue);
540
541 $pocketImport->setClient($client);
542 $pocketImport->setProducer($producer);
543 $pocketImport->authorize('wunderbar_code');
544
545 $res = $pocketImport->setMarkAsRead(true)->import();
546
547 $this->assertTrue($res);
c80cc01a 548 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 1], $pocketImport->getSummary());
b3437d58
JB
549
550 $this->assertNotEmpty($redisMock->lpop('pocket'));
551 }
552
252ebd60
JB
553 public function testImportBadResponse()
554 {
555 $client = new Client();
556
557 $mock = new Mock([
558 new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))),
559 new Response(403),
7ec2897e
JB
560 ]);
561
562 $client->getEmitter()->attach($mock);
563
564 $pocketImport = $this->getPocketImport();
565 $pocketImport->setClient($client);
252ebd60
JB
566 $pocketImport->authorize('wunderbar_code');
567
568 $res = $pocketImport->import();
7ec2897e 569
252ebd60 570 $this->assertFalse($res);
7ec2897e 571
252ebd60
JB
572 $records = $this->logHandler->getRecords();
573 $this->assertContains('PocketImport: Failed to import', $records[0]['message']);
574 $this->assertEquals('ERROR', $records[0]['level_name']);
7ec2897e 575 }
19d9efab
JB
576
577 public function testImportWithExceptionFromGraby()
578 {
579 $client = new Client();
580
581 $mock = new Mock([
582 new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))),
583 new Response(200, ['Content-Type' => 'application/json'], Stream::factory('
584 {
585 "status": 1,
586 "list": {
587 "229279689": {
59b97fae
JB
588 "status": "1",
589 "favorite": "1",
19d9efab
JB
590 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview"
591 }
592 }
593 }
594 ')),
595 ]);
596
597 $client->getEmitter()->attach($mock);
598
7816eb62 599 $pocketImport = $this->getPocketImport('ConsumerKey', 1);
19d9efab
JB
600
601 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
602 ->disableOriginalConstructor()
603 ->getMock();
604
605 $entryRepo->expects($this->once())
606 ->method('findByUrlAndUserId')
607 ->will($this->onConsecutiveCalls(false, true));
608
609 $this->em
610 ->expects($this->once())
611 ->method('getRepository')
612 ->willReturn($entryRepo);
613
614 $entry = new Entry($this->user);
615
616 $this->contentProxy
617 ->expects($this->once())
618 ->method('updateEntry')
619 ->will($this->throwException(new \Exception()));
620
621 $pocketImport->setClient($client);
622 $pocketImport->authorize('wunderbar_code');
623
624 $res = $pocketImport->import();
625
626 $this->assertTrue($res);
59b97fae 627 $this->assertEquals(['skipped' => 0, 'imported' => 1, 'queued' => 0], $pocketImport->getSummary());
19d9efab 628 }
7ec2897e 629}