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