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