3 namespace Tests\Wallabag\ImportBundle\Import
;
6 use GuzzleHttp\Message\Response
;
7 use GuzzleHttp\Stream\Stream
;
8 use GuzzleHttp\Subscriber\Mock
;
9 use M6Web\Component\RedisMock\RedisMockFactory
;
10 use Monolog\Handler\TestHandler
;
12 use PHPUnit\Framework\TestCase
;
13 use Simpleue\Queue\RedisQueue
;
14 use Wallabag\CoreBundle\Entity\Config
;
15 use Wallabag\CoreBundle\Entity\Entry
;
16 use Wallabag\ImportBundle\Import\PocketImport
;
17 use Wallabag\ImportBundle\Redis\Producer
;
18 use Wallabag\UserBundle\Entity\User
;
20 class PocketImportTest
extends TestCase
25 protected $contentProxy;
26 protected $logHandler;
27 protected $tagsAssigner;
30 public function testInit()
32 $pocketImport = $this->getPocketImport();
34 $this->assertSame('Pocket', $pocketImport->getName());
35 $this->assertNotEmpty($pocketImport->getUrl());
36 $this->assertSame('import.pocket.description', $pocketImport->getDescription());
39 public function testOAuthRequest()
41 $client = new Client();
44 new Response(200, ['Content-Type' => 'application/json'], Stream
::factory(json_encode(['code' => 'wunderbar_code']))),
47 $client->getEmitter()->attach($mock);
49 $pocketImport = $this->getPocketImport();
50 $pocketImport->setClient($client);
52 $code = $pocketImport->getRequestToken('http://0.0.0.0/redirect');
54 $this->assertSame('wunderbar_code', $code);
57 public function testOAuthRequestBadResponse()
59 $client = new Client();
65 $client->getEmitter()->attach($mock);
67 $pocketImport = $this->getPocketImport();
68 $pocketImport->setClient($client);
70 $code = $pocketImport->getRequestToken('http://0.0.0.0/redirect');
72 $this->assertFalse($code);
74 $records = $this->logHandler
->getRecords();
75 $this->assertContains('PocketImport: Failed to request token', $records[0]['message']);
76 $this->assertSame('ERROR', $records[0]['level_name']);
79 public function testOAuthAuthorize()
81 $client = new Client();
84 new Response(200, ['Content-Type' => 'application/json'], Stream
::factory(json_encode(['access_token' => 'wunderbar_token']))),
87 $client->getEmitter()->attach($mock);
89 $pocketImport = $this->getPocketImport();
90 $pocketImport->setClient($client);
92 $res = $pocketImport->authorize('wunderbar_code');
94 $this->assertTrue($res);
95 $this->assertSame('wunderbar_token', $pocketImport->getAccessToken());
98 public function testOAuthAuthorizeBadResponse()
100 $client = new Client();
106 $client->getEmitter()->attach($mock);
108 $pocketImport = $this->getPocketImport();
109 $pocketImport->setClient($client);
111 $res = $pocketImport->authorize('wunderbar_code');
113 $this->assertFalse($res);
115 $records = $this->logHandler
->getRecords();
116 $this->assertContains('PocketImport: Failed to authorize client', $records[0]['message']);
117 $this->assertSame('ERROR', $records[0]['level_name']);
121 * Will sample results from https://getpocket.com/developer/docs/v3/retrieve.
123 public function testImport()
125 $client = new Client();
128 new Response(200, ['Content-Type' => 'application/json'], Stream
::factory(json_encode(['access_token' => 'wunderbar_token']))),
129 new Response(200, ['Content-Type' => 'application/json'], Stream
::factory('
134 "item_id": "229279689",
135 "resolved_id": "229279689",
136 "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
137 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
140 "time_added": "1473020899",
141 "time_updated": "1473020899",
143 "time_favorited": "0",
145 "resolved_title": "The Massive Ryder Cup Preview",
146 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
147 "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.",
152 "word_count": "3197",
155 "item_id": "229279689",
157 "src": "http://a.espncdn.com/combiner/i?img=/photo/2012/0927/grant_g_ryder_cr_640.jpg&w=640&h=360",
160 "credit": "Jamie Squire/Getty Images",
166 "item_id": "229279689",
168 "src": "http://www.youtube.com/v/Er34PbFkVGk?version=3&hl=en_US&rel=0",
177 "item_id": "1147652870",
181 "item_id": "1147652870",
187 "item_id": "229279689",
188 "resolved_id": "229279689",
189 "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
190 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
193 "time_added": "1473020899",
194 "time_updated": "1473020899",
196 "time_favorited": "0",
198 "resolved_title": "The Massive Ryder Cup Preview",
199 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
200 "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.",
212 $client->getEmitter()->attach($mock);
214 $pocketImport = $this->getPocketImport('ConsumerKey', 1);
216 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
217 ->disableOriginalConstructor()
220 $entryRepo->expects($this->exactly(2))
221 ->method('findByUrlAndUserId')
222 ->will($this->onConsecutiveCalls(false, true));
225 ->expects($this->exactly(2))
226 ->method('getRepository')
227 ->willReturn($entryRepo);
230 ->expects($this->any())
232 ->with($this->callback(function ($persistedEntry) {
233 return $persistedEntry->isArchived() && $persistedEntry->isStarred();
236 $entry = new Entry($this->user
);
239 ->expects($this->once())
240 ->method('updateEntry')
241 ->willReturn($entry);
243 $pocketImport->setClient($client);
244 $pocketImport->authorize('wunderbar_code');
246 $res = $pocketImport->import();
248 $this->assertTrue($res);
249 $this->assertSame(['skipped' => 1, 'imported' => 1, 'queued' => 0], $pocketImport->getSummary());
253 * Will sample results from https://getpocket.com/developer/docs/v3/retrieve.
255 public function testImportAndMarkAllAsRead()
257 $client = new Client();
260 new Response(200, ['Content-Type' => 'application/json'], Stream
::factory(json_encode(['access_token' => 'wunderbar_token']))),
261 new Response(200, ['Content-Type' => 'application/json'], Stream
::factory('
266 "item_id": "229279689",
267 "resolved_id": "229279689",
268 "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
269 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
272 "time_added": "1473020899",
273 "time_updated": "1473020899",
275 "time_favorited": "0",
277 "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.",
284 "item_id": "229279689",
285 "resolved_id": "229279689",
286 "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview/2",
287 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
290 "time_added": "1473020899",
291 "time_updated": "1473020899",
293 "time_favorited": "0",
295 "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.",
306 $client->getEmitter()->attach($mock);
308 $pocketImport = $this->getPocketImport('ConsumerKey', 2);
310 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
311 ->disableOriginalConstructor()
314 $entryRepo->expects($this->exactly(2))
315 ->method('findByUrlAndUserId')
316 ->will($this->onConsecutiveCalls(false, false));
319 ->expects($this->exactly(2))
320 ->method('getRepository')
321 ->willReturn($entryRepo);
323 // check that every entry persisted are archived
325 ->expects($this->any())
327 ->with($this->callback(function ($persistedEntry) {
328 return $persistedEntry->isArchived();
331 $entry = new Entry($this->user
);
334 ->expects($this->exactly(2))
335 ->method('updateEntry')
336 ->willReturn($entry);
338 $pocketImport->setClient($client);
339 $pocketImport->authorize('wunderbar_code');
341 $res = $pocketImport->setMarkAsRead(true)->import();
343 $this->assertTrue($res);
344 $this->assertSame(['skipped' => 0, 'imported' => 2, 'queued' => 0], $pocketImport->getSummary());
348 * Will sample results from https://getpocket.com/developer/docs/v3/retrieve.
350 public function testImportWithRabbit()
352 $client = new Client();
356 "item_id": "229279689",
357 "resolved_id": "229279689",
358 "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
359 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
362 "time_added": "1473020899",
363 "time_updated": "1473020899",
365 "time_favorited": "0",
367 "resolved_title": "The Massive Ryder Cup Preview",
368 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
369 "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.",
378 new Response(200, ['Content-Type' => 'application/json'], Stream
::factory(json_encode(['access_token' => 'wunderbar_token']))),
379 new Response(200, ['Content-Type' => 'application/json'], Stream
::factory('
383 "229279690": ' . $body . '
389 $client->getEmitter()->attach($mock);
391 $pocketImport = $this->getPocketImport();
393 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
394 ->disableOriginalConstructor()
397 $entryRepo->expects($this->never())
398 ->method('findByUrlAndUserId');
401 ->expects($this->never())
402 ->method('getRepository');
404 $entry = new Entry($this->user
);
407 ->expects($this->never())
408 ->method('updateEntry');
410 $producer = $this->getMockBuilder('OldSound\RabbitMqBundle\RabbitMq\Producer')
411 ->disableOriginalConstructor()
414 $bodyAsArray = json_decode($body, true);
415 // because with just use `new User()` so it doesn't have an id
416 $bodyAsArray['userId'] = null;
419 ->expects($this->once())
421 ->with(json_encode($bodyAsArray));
423 $pocketImport->setClient($client);
424 $pocketImport->setProducer($producer);
425 $pocketImport->authorize('wunderbar_code');
427 $res = $pocketImport->setMarkAsRead(true)->import();
429 $this->assertTrue($res);
430 $this->assertSame(['skipped' => 0, 'imported' => 0, 'queued' => 1], $pocketImport->getSummary());
434 * Will sample results from https://getpocket.com/developer/docs/v3/retrieve.
436 public function testImportWithRedis()
438 $client = new Client();
442 "item_id": "229279689",
443 "resolved_id": "229279689",
444 "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
445 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
448 "time_added": "1473020899",
449 "time_updated": "1473020899",
451 "time_favorited": "0",
453 "resolved_title": "The Massive Ryder Cup Preview",
454 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
455 "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.",
464 new Response(200, ['Content-Type' => 'application/json'], Stream
::factory(json_encode(['access_token' => 'wunderbar_token']))),
465 new Response(200, ['Content-Type' => 'application/json'], Stream
::factory('
469 "229279690": ' . $body . '
475 $client->getEmitter()->attach($mock);
477 $pocketImport = $this->getPocketImport();
479 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
480 ->disableOriginalConstructor()
483 $entryRepo->expects($this->never())
484 ->method('findByUrlAndUserId');
487 ->expects($this->never())
488 ->method('getRepository');
490 $entry = new Entry($this->user
);
493 ->expects($this->never())
494 ->method('updateEntry');
496 $factory = new RedisMockFactory();
497 $redisMock = $factory->getAdapter('Predis\Client', true);
499 $queue = new RedisQueue($redisMock, 'pocket');
500 $producer = new Producer($queue);
502 $pocketImport->setClient($client);
503 $pocketImport->setProducer($producer);
504 $pocketImport->authorize('wunderbar_code');
506 $res = $pocketImport->setMarkAsRead(true)->import();
508 $this->assertTrue($res);
509 $this->assertSame(['skipped' => 0, 'imported' => 0, 'queued' => 1], $pocketImport->getSummary());
511 $this->assertNotEmpty($redisMock->lpop('pocket'));
514 public function testImportBadResponse()
516 $client = new Client();
519 new Response(200, ['Content-Type' => 'application/json'], Stream
::factory(json_encode(['access_token' => 'wunderbar_token']))),
523 $client->getEmitter()->attach($mock);
525 $pocketImport = $this->getPocketImport();
526 $pocketImport->setClient($client);
527 $pocketImport->authorize('wunderbar_code');
529 $res = $pocketImport->import();
531 $this->assertFalse($res);
533 $records = $this->logHandler
->getRecords();
534 $this->assertContains('PocketImport: Failed to import', $records[0]['message']);
535 $this->assertSame('ERROR', $records[0]['level_name']);
538 public function testImportWithExceptionFromGraby()
540 $client = new Client();
543 new Response(200, ['Content-Type' => 'application/json'], Stream
::factory(json_encode(['access_token' => 'wunderbar_token']))),
544 new Response(200, ['Content-Type' => 'application/json'], Stream
::factory('
551 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview"
558 $client->getEmitter()->attach($mock);
560 $pocketImport = $this->getPocketImport('ConsumerKey', 1);
562 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
563 ->disableOriginalConstructor()
566 $entryRepo->expects($this->once())
567 ->method('findByUrlAndUserId')
568 ->will($this->onConsecutiveCalls(false, true));
571 ->expects($this->once())
572 ->method('getRepository')
573 ->willReturn($entryRepo);
575 $entry = new Entry($this->user
);
578 ->expects($this->once())
579 ->method('updateEntry')
580 ->will($this->throwException(new \
Exception()));
582 $pocketImport->setClient($client);
583 $pocketImport->authorize('wunderbar_code');
585 $res = $pocketImport->import();
587 $this->assertTrue($res);
588 $this->assertSame(['skipped' => 0, 'imported' => 1, 'queued' => 0], $pocketImport->getSummary());
591 private function getPocketImport($consumerKey = 'ConsumerKey', $dispatched = 0)
593 $this->user
= new User();
595 $config = new Config($this->user
);
596 $config->setPocketConsumerKey('xxx');
598 $this->user
->setConfig($config);
600 $this->contentProxy
= $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy')
601 ->disableOriginalConstructor()
604 $this->tagsAssigner
= $this->getMockBuilder('Wallabag\CoreBundle\Helper\TagsAssigner')
605 ->disableOriginalConstructor()
608 $this->em
= $this->getMockBuilder('Doctrine\ORM\EntityManager')
609 ->disableOriginalConstructor()
612 $this->uow
= $this->getMockBuilder('Doctrine\ORM\UnitOfWork')
613 ->disableOriginalConstructor()
617 ->expects($this->any())
618 ->method('getUnitOfWork')
619 ->willReturn($this->uow
);
622 ->expects($this->any())
623 ->method('getScheduledEntityInsertions')
626 $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcher')
627 ->disableOriginalConstructor()
631 ->expects($this->exactly($dispatched))
632 ->method('dispatch');
634 $pocket = new PocketImport($this->em
, $this->contentProxy
, $this->tagsAssigner
, $dispatcher);
635 $pocket->setUser($this->user
);
637 $this->logHandler
= new TestHandler();
638 $logger = new Logger('test', [$this->logHandler
]);
639 $pocket->setLogger($logger);