]> git.immae.eu Git - github/wallabag/wallabag.git/blobdiff - tests/Wallabag/ImportBundle/Import/PocketImportTest.php
CS
[github/wallabag/wallabag.git] / tests / Wallabag / ImportBundle / Import / PocketImportTest.php
index 41f9b51f2bd4108438d341ac5aa036d3b4eaacb6..40e1626ba3b3c568fc326b650e5864e22566508d 100644 (file)
 
 namespace Tests\Wallabag\ImportBundle\Import;
 
-use Wallabag\UserBundle\Entity\User;
+use GuzzleHttp\Psr7\Response;
+use Http\Mock\Client as HttpMockClient;
+use M6Web\Component\RedisMock\RedisMockFactory;
+use Monolog\Handler\TestHandler;
+use Monolog\Logger;
+use PHPUnit\Framework\TestCase;
+use Simpleue\Queue\RedisQueue;
+use Wallabag\CoreBundle\Entity\Config;
 use Wallabag\CoreBundle\Entity\Entry;
 use Wallabag\ImportBundle\Import\PocketImport;
-use GuzzleHttp\Client;
-use GuzzleHttp\Subscriber\Mock;
-use GuzzleHttp\Message\Response;
-use GuzzleHttp\Stream\Stream;
-use Monolog\Logger;
-use Monolog\Handler\TestHandler;
-
-class PocketImportMock extends PocketImport
-{
-    public function getAccessToken()
-    {
-        return $this->accessToken;
-    }
-}
+use Wallabag\ImportBundle\Redis\Producer;
+use Wallabag\UserBundle\Entity\User;
 
-class PocketImportTest extends \PHPUnit_Framework_TestCase
+class PocketImportTest extends TestCase
 {
     protected $token;
     protected $user;
     protected $em;
     protected $contentProxy;
     protected $logHandler;
-
-    private function getPocketImport($consumerKey = 'ConsumerKey')
-    {
-        $this->user = new User();
-
-        $this->tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy')
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $token->expects($this->once())
-            ->method('getUser')
-            ->willReturn($this->user);
-
-        $this->tokenStorage->expects($this->once())
-            ->method('getToken')
-            ->willReturn($token);
-
-        $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $config = $this->getMockBuilder('Craue\ConfigBundle\Util\Config')
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $config->expects($this->any())
-            ->method('get')
-            ->with('pocket_consumer_key')
-            ->willReturn($consumerKey);
-
-        $pocket = new PocketImportMock(
-            $this->tokenStorage,
-            $this->em,
-            $this->contentProxy,
-            $config
-        );
-
-        $this->logHandler = new TestHandler();
-        $logger = new Logger('test', [$this->logHandler]);
-        $pocket->setLogger($logger);
-
-        return $pocket;
-    }
+    protected $tagsAssigner;
+    protected $uow;
 
     public function testInit()
     {
         $pocketImport = $this->getPocketImport();
 
-        $this->assertEquals('Pocket', $pocketImport->getName());
+        $this->assertSame('Pocket', $pocketImport->getName());
         $this->assertNotEmpty($pocketImport->getUrl());
-        $this->assertEquals('import.pocket.description', $pocketImport->getDescription());
+        $this->assertSame('import.pocket.description', $pocketImport->getDescription());
     }
 
     public function testOAuthRequest()
     {
-        $client = new Client();
-
-        $mock = new Mock([
-            new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['code' => 'wunderbar_code']))),
-        ]);
-
-        $client->getEmitter()->attach($mock);
+        $httpMockClient = new HttpMockClient();
+        $httpMockClient->addResponse(new Response(200, ['Content-Type' => 'application/json'], json_encode(['code' => 'wunderbar_code'])));
 
         $pocketImport = $this->getPocketImport();
-        $pocketImport->setClient($client);
+        $pocketImport->setClient($httpMockClient);
 
         $code = $pocketImport->getRequestToken('http://0.0.0.0/redirect');
 
-        $this->assertEquals('wunderbar_code', $code);
+        $this->assertSame('wunderbar_code', $code);
     }
 
     public function testOAuthRequestBadResponse()
     {
-        $client = new Client();
-
-        $mock = new Mock([
-            new Response(403),
-        ]);
-
-        $client->getEmitter()->attach($mock);
+        $httpMockClient = new HttpMockClient();
+        $httpMockClient->addResponse(new Response(403));
 
         $pocketImport = $this->getPocketImport();
-        $pocketImport->setClient($client);
+        $pocketImport->setClient($httpMockClient);
 
         $code = $pocketImport->getRequestToken('http://0.0.0.0/redirect');
 
@@ -125,40 +61,30 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
 
         $records = $this->logHandler->getRecords();
         $this->assertContains('PocketImport: Failed to request token', $records[0]['message']);
-        $this->assertEquals('ERROR', $records[0]['level_name']);
+        $this->assertSame('ERROR', $records[0]['level_name']);
     }
 
     public function testOAuthAuthorize()
     {
-        $client = new Client();
-
-        $mock = new Mock([
-            new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))),
-        ]);
-
-        $client->getEmitter()->attach($mock);
+        $httpMockClient = new HttpMockClient();
+        $httpMockClient->addResponse(new Response(200, ['Content-Type' => 'application/json'], json_encode(['access_token' => 'wunderbar_token'])));
 
         $pocketImport = $this->getPocketImport();
-        $pocketImport->setClient($client);
+        $pocketImport->setClient($httpMockClient);
 
         $res = $pocketImport->authorize('wunderbar_code');
 
         $this->assertTrue($res);
-        $this->assertEquals('wunderbar_token', $pocketImport->getAccessToken());
+        $this->assertSame('wunderbar_token', $pocketImport->getAccessToken());
     }
 
     public function testOAuthAuthorizeBadResponse()
     {
-        $client = new Client();
-
-        $mock = new Mock([
-            new Response(403),
-        ]);
-
-        $client->getEmitter()->attach($mock);
+        $httpMockClient = new HttpMockClient();
+        $httpMockClient->addResponse(new Response(403));
 
         $pocketImport = $this->getPocketImport();
-        $pocketImport->setClient($client);
+        $pocketImport->setClient($httpMockClient);
 
         $res = $pocketImport->authorize('wunderbar_code');
 
@@ -166,7 +92,7 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
 
         $records = $this->logHandler->getRecords();
         $this->assertContains('PocketImport: Failed to authorize client', $records[0]['message']);
-        $this->assertEquals('ERROR', $records[0]['level_name']);
+        $this->assertSame('ERROR', $records[0]['level_name']);
     }
 
     /**
@@ -174,84 +100,92 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
      */
     public function testImport()
     {
-        $client = new Client();
-
-        $mock = new Mock([
-            new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))),
-            new Response(200, ['Content-Type' => 'application/json'], Stream::factory('
-                {
-                    "status": 1,
-                    "list": {
-                        "229279689": {
-                            "item_id": "229279689",
-                            "resolved_id": "229279689",
-                            "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
-                            "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
-                            "favorite": "1",
-                            "status": "1",
-                            "resolved_title": "The Massive Ryder Cup Preview",
-                            "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
-                            "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.",
-                            "is_article": "1",
-                            "has_video": "1",
-                            "has_image": "1",
-                            "word_count": "3197",
-                            "images": {
-                                "1": {
-                                    "item_id": "229279689",
-                                    "image_id": "1",
-                                    "src": "http://a.espncdn.com/combiner/i?img=/photo/2012/0927/grant_g_ryder_cr_640.jpg&w=640&h=360",
-                                    "width": "0",
-                                    "height": "0",
-                                    "credit": "Jamie Squire/Getty Images",
-                                    "caption": ""
-                                }
-                            },
-                            "videos": {
-                                "1": {
-                                    "item_id": "229279689",
-                                    "video_id": "1",
-                                    "src": "http://www.youtube.com/v/Er34PbFkVGk?version=3&hl=en_US&rel=0",
-                                    "width": "420",
-                                    "height": "315",
-                                    "type": "1",
-                                    "vid": "Er34PbFkVGk"
-                                }
-                            },
-                            "tags": {
-                                "grantland": {
-                                    "item_id": "1147652870",
-                                    "tag": "grantland"
-                                },
-                                "Ryder Cup": {
-                                    "item_id": "1147652870",
-                                    "tag": "Ryder Cup"
-                                }
+        $httpMockClient = new HttpMockClient();
+        $httpMockClient->addResponse(new Response(200, ['Content-Type' => 'application/json'], json_encode(['access_token' => 'wunderbar_token'])));
+        $httpMockClient->addResponse(new Response(200, ['Content-Type' => 'application/json'], <<<'JSON'
+            {
+                "status": 1,
+                "list": {
+                    "229279689": {
+                        "item_id": "229279689",
+                        "resolved_id": "229279689",
+                        "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
+                        "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
+                        "favorite": "1",
+                        "status": "1",
+                        "time_added": "1473020899",
+                        "time_updated": "1473020899",
+                        "time_read": "0",
+                        "time_favorited": "0",
+                        "sort_id": 0,
+                        "resolved_title": "The Massive Ryder Cup Preview",
+                        "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
+                        "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.",
+                        "is_article": "1",
+                        "is_index": "0",
+                        "has_video": "1",
+                        "has_image": "1",
+                        "word_count": "3197",
+                        "images": {
+                            "1": {
+                                "item_id": "229279689",
+                                "image_id": "1",
+                                "src": "http://a.espncdn.com/combiner/i?img=/photo/2012/0927/grant_g_ryder_cr_640.jpg&w=640&h=360",
+                                "width": "0",
+                                "height": "0",
+                                "credit": "Jamie Squire/Getty Images",
+                                "caption": ""
+                            }
+                        },
+                        "videos": {
+                            "1": {
+                                "item_id": "229279689",
+                                "video_id": "1",
+                                "src": "http://www.youtube.com/v/Er34PbFkVGk?version=3&hl=en_US&rel=0",
+                                "width": "420",
+                                "height": "315",
+                                "type": "1",
+                                "vid": "Er34PbFkVGk"
                             }
                         },
-                        "229279690": {
-                            "item_id": "229279689",
-                            "resolved_id": "229279689",
-                            "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
-                            "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
-                            "favorite": "1",
-                            "status": "1",
-                            "resolved_title": "The Massive Ryder Cup Preview",
-                            "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
-                            "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.",
-                            "is_article": "1",
-                            "has_video": "0",
-                            "has_image": "0",
-                            "word_count": "3197"
+                        "tags": {
+                            "grantland": {
+                                "item_id": "1147652870",
+                                "tag": "grantland"
+                            },
+                            "Ryder Cup": {
+                                "item_id": "1147652870",
+                                "tag": "Ryder Cup"
+                            }
                         }
+                    },
+                    "229279690": {
+                        "item_id": "229279689",
+                        "resolved_id": "229279689",
+                        "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
+                        "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
+                        "favorite": "1",
+                        "status": "1",
+                        "time_added": "1473020899",
+                        "time_updated": "1473020899",
+                        "time_read": "0",
+                        "time_favorited": "0",
+                        "sort_id": 1,
+                        "resolved_title": "The Massive Ryder Cup Preview",
+                        "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
+                        "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.",
+                        "is_article": "1",
+                        "is_index": "0",
+                        "has_video": "0",
+                        "has_image": "0",
+                        "word_count": "3197"
                     }
                 }
-            ')),
-        ]);
-
-        $client->getEmitter()->attach($mock);
+            }
+JSON
+));
 
-        $pocketImport = $this->getPocketImport();
+        $pocketImport = $this->getPocketImport('ConsumerKey', 1);
 
         $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
             ->disableOriginalConstructor()
@@ -266,6 +200,13 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
             ->method('getRepository')
             ->willReturn($entryRepo);
 
+        $this->em
+            ->expects($this->any())
+            ->method('persist')
+            ->with($this->callback(function ($persistedEntry) {
+                return $persistedEntry->isArchived() && $persistedEntry->isStarred();
+            }));
+
         $entry = new Entry($this->user);
 
         $this->contentProxy
@@ -273,13 +214,13 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
             ->method('updateEntry')
             ->willReturn($entry);
 
-        $pocketImport->setClient($client);
+        $pocketImport->setClient($httpMockClient);
         $pocketImport->authorize('wunderbar_code');
 
         $res = $pocketImport->import();
 
         $this->assertTrue($res);
-        $this->assertEquals(['skipped' => 1, 'imported' => 1], $pocketImport->getSummary());
+        $this->assertSame(['skipped' => 1, 'imported' => 1, 'queued' => 0], $pocketImport->getSummary());
     }
 
     /**
@@ -287,48 +228,54 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
      */
     public function testImportAndMarkAllAsRead()
     {
-        $client = new Client();
-
-        $mock = new Mock([
-            new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))),
-            new Response(200, ['Content-Type' => 'application/json'], Stream::factory('
-                {
-                    "status": 1,
-                    "list": {
-                        "229279689": {
-                            "item_id": "229279689",
-                            "resolved_id": "229279689",
-                            "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
-                            "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
-                            "favorite": "1",
-                            "status": "1",
-                            "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.",
-                            "is_article": "1",
-                            "has_video": "1",
-                            "has_image": "1",
-                            "word_count": "3197"
-                        },
-                        "229279690": {
-                            "item_id": "229279689",
-                            "resolved_id": "229279689",
-                            "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview/2",
-                            "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
-                            "favorite": "1",
-                            "status": "0",
-                            "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.",
-                            "is_article": "1",
-                            "has_video": "0",
-                            "has_image": "0",
-                            "word_count": "3197"
-                        }
+        $httpMockClient = new HttpMockClient();
+        $httpMockClient->addResponse(new Response(200, ['Content-Type' => 'application/json'], json_encode(['access_token' => 'wunderbar_token'])));
+        $httpMockClient->addResponse(new Response(200, ['Content-Type' => 'application/json'], <<<'JSON'
+            {
+                "status": 1,
+                "list": {
+                    "229279689": {
+                        "item_id": "229279689",
+                        "resolved_id": "229279689",
+                        "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
+                        "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
+                        "favorite": "1",
+                        "status": "1",
+                        "time_added": "1473020899",
+                        "time_updated": "1473020899",
+                        "time_read": "0",
+                        "time_favorited": "0",
+                        "sort_id": 0,
+                        "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.",
+                        "is_article": "1",
+                        "has_video": "1",
+                        "has_image": "1",
+                        "word_count": "3197"
+                    },
+                    "229279690": {
+                        "item_id": "229279689",
+                        "resolved_id": "229279689",
+                        "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview/2",
+                        "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
+                        "favorite": "1",
+                        "status": "0",
+                        "time_added": "1473020899",
+                        "time_updated": "1473020899",
+                        "time_read": "0",
+                        "time_favorited": "0",
+                        "sort_id": 1,
+                        "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.",
+                        "is_article": "1",
+                        "has_video": "0",
+                        "has_image": "0",
+                        "word_count": "3197"
                     }
                 }
-            ')),
-        ]);
-
-        $client->getEmitter()->attach($mock);
+            }
+JSON
+));
 
-        $pocketImport = $this->getPocketImport();
+        $pocketImport = $this->getPocketImport('ConsumerKey', 2);
 
         $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
             ->disableOriginalConstructor()
@@ -358,28 +305,185 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
             ->method('updateEntry')
             ->willReturn($entry);
 
-        $pocketImport->setClient($client);
+        $pocketImport->setClient($httpMockClient);
         $pocketImport->authorize('wunderbar_code');
 
         $res = $pocketImport->setMarkAsRead(true)->import();
 
         $this->assertTrue($res);
-        $this->assertEquals(['skipped' => 0, 'imported' => 2], $pocketImport->getSummary());
+        $this->assertSame(['skipped' => 0, 'imported' => 2, 'queued' => 0], $pocketImport->getSummary());
     }
 
-    public function testImportBadResponse()
+    /**
+     * Will sample results from https://getpocket.com/developer/docs/v3/retrieve.
+     */
+    public function testImportWithRabbit()
+    {
+        $httpMockClient = new HttpMockClient();
+
+        $body = <<<'JSON'
+{
+    "item_id": "229279689",
+    "resolved_id": "229279689",
+    "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
+    "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
+    "favorite": "1",
+    "status": "1",
+    "time_added": "1473020899",
+    "time_updated": "1473020899",
+    "time_read": "0",
+    "time_favorited": "0",
+    "sort_id": 0,
+    "resolved_title": "The Massive Ryder Cup Preview",
+    "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
+    "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.",
+    "is_article": "1",
+    "has_video": "0",
+    "has_image": "0",
+    "word_count": "3197"
+}
+JSON;
+
+        $httpMockClient->addResponse(new Response(200, ['Content-Type' => 'application/json'], json_encode(['access_token' => 'wunderbar_token'])));
+        $httpMockClient->addResponse(new Response(200, ['Content-Type' => 'application/json'], <<<JSON
+            {
+                "status": 1,
+                "list": {
+                    "229279690": $body
+                }
+            }
+JSON
+        ));
+
+        $pocketImport = $this->getPocketImport();
+
+        $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $entryRepo->expects($this->never())
+            ->method('findByUrlAndUserId');
+
+        $this->em
+            ->expects($this->never())
+            ->method('getRepository');
+
+        $entry = new Entry($this->user);
+
+        $this->contentProxy
+            ->expects($this->never())
+            ->method('updateEntry');
+
+        $producer = $this->getMockBuilder('OldSound\RabbitMqBundle\RabbitMq\Producer')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $bodyAsArray = json_decode($body, true);
+        // because with just use `new User()` so it doesn't have an id
+        $bodyAsArray['userId'] = null;
+
+        $producer
+            ->expects($this->once())
+            ->method('publish')
+            ->with(json_encode($bodyAsArray));
+
+        $pocketImport->setClient($httpMockClient);
+        $pocketImport->setProducer($producer);
+        $pocketImport->authorize('wunderbar_code');
+
+        $res = $pocketImport->setMarkAsRead(true)->import();
+
+        $this->assertTrue($res);
+        $this->assertSame(['skipped' => 0, 'imported' => 0, 'queued' => 1], $pocketImport->getSummary());
+    }
+
+    /**
+     * Will sample results from https://getpocket.com/developer/docs/v3/retrieve.
+     */
+    public function testImportWithRedis()
     {
-        $client = new Client();
+        $httpMockClient = new HttpMockClient();
+
+        $body = <<<'JSON'
+{
+    "item_id": "229279689",
+    "resolved_id": "229279689",
+    "given_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
+    "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
+    "favorite": "1",
+    "status": "1",
+    "time_added": "1473020899",
+    "time_updated": "1473020899",
+    "time_read": "0",
+    "time_favorited": "0",
+    "sort_id": 0,
+    "resolved_title": "The Massive Ryder Cup Preview",
+    "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
+    "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.",
+    "is_article": "1",
+    "has_video": "0",
+    "has_image": "0",
+    "word_count": "3197"
+}
+JSON;
+
+        $httpMockClient->addResponse(new Response(200, ['Content-Type' => 'application/json'], json_encode(['access_token' => 'wunderbar_token'])));
+        $httpMockClient->addResponse(new Response(200, ['Content-Type' => 'application/json'], <<<JSON
+            {
+                "status": 1,
+                "list": {
+                    "229279690": $body
+                }
+            }
+JSON
+        ));
+
+        $pocketImport = $this->getPocketImport();
+
+        $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
+            ->disableOriginalConstructor()
+            ->getMock();
 
-        $mock = new Mock([
-            new Response(200, ['Content-Type' => 'application/json'], Stream::factory(json_encode(['access_token' => 'wunderbar_token']))),
-            new Response(403),
-        ]);
+        $entryRepo->expects($this->never())
+            ->method('findByUrlAndUserId');
 
-        $client->getEmitter()->attach($mock);
+        $this->em
+            ->expects($this->never())
+            ->method('getRepository');
+
+        $entry = new Entry($this->user);
+
+        $this->contentProxy
+            ->expects($this->never())
+            ->method('updateEntry');
+
+        $factory = new RedisMockFactory();
+        $redisMock = $factory->getAdapter('Predis\Client', true);
+
+        $queue = new RedisQueue($redisMock, 'pocket');
+        $producer = new Producer($queue);
+
+        $pocketImport->setClient($httpMockClient);
+        $pocketImport->setProducer($producer);
+        $pocketImport->authorize('wunderbar_code');
+
+        $res = $pocketImport->setMarkAsRead(true)->import();
+
+        $this->assertTrue($res);
+        $this->assertSame(['skipped' => 0, 'imported' => 0, 'queued' => 1], $pocketImport->getSummary());
+
+        $this->assertNotEmpty($redisMock->lpop('pocket'));
+    }
+
+    public function testImportBadResponse()
+    {
+        $httpMockClient = new HttpMockClient();
+
+        $httpMockClient->addResponse(new Response(200, ['Content-Type' => 'application/json'], json_encode(['access_token' => 'wunderbar_token'])));
+        $httpMockClient->addResponse(new Response(403));
 
         $pocketImport = $this->getPocketImport();
-        $pocketImport->setClient($client);
+        $pocketImport->setClient($httpMockClient);
         $pocketImport->authorize('wunderbar_code');
 
         $res = $pocketImport->import();
@@ -388,6 +492,110 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
 
         $records = $this->logHandler->getRecords();
         $this->assertContains('PocketImport: Failed to import', $records[0]['message']);
-        $this->assertEquals('ERROR', $records[0]['level_name']);
+        $this->assertSame('ERROR', $records[0]['level_name']);
+    }
+
+    public function testImportWithExceptionFromGraby()
+    {
+        $httpMockClient = new HttpMockClient();
+
+        $httpMockClient->addResponse(new Response(200, ['Content-Type' => 'application/json'], json_encode(['access_token' => 'wunderbar_token'])));
+        $httpMockClient->addResponse(new Response(200, ['Content-Type' => 'application/json'], <<<'JSON'
+            {
+                "status": 1,
+                "list": {
+                    "229279689": {
+                        "status": "1",
+                        "favorite": "1",
+                        "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview"
+                    }
+                }
+            }
+            
+JSON
+        ));
+
+        $pocketImport = $this->getPocketImport('ConsumerKey', 1);
+
+        $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $entryRepo->expects($this->once())
+            ->method('findByUrlAndUserId')
+            ->will($this->onConsecutiveCalls(false, true));
+
+        $this->em
+            ->expects($this->once())
+            ->method('getRepository')
+            ->willReturn($entryRepo);
+
+        $entry = new Entry($this->user);
+
+        $this->contentProxy
+            ->expects($this->once())
+            ->method('updateEntry')
+            ->will($this->throwException(new \Exception()));
+
+        $pocketImport->setClient($httpMockClient);
+        $pocketImport->authorize('wunderbar_code');
+
+        $res = $pocketImport->import();
+
+        $this->assertTrue($res);
+        $this->assertSame(['skipped' => 0, 'imported' => 1, 'queued' => 0], $pocketImport->getSummary());
+    }
+
+    private function getPocketImport($consumerKey = 'ConsumerKey', $dispatched = 0)
+    {
+        $this->user = new User();
+
+        $config = new Config($this->user);
+        $config->setPocketConsumerKey('xxx');
+
+        $this->user->setConfig($config);
+
+        $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->tagsAssigner = $this->getMockBuilder('Wallabag\CoreBundle\Helper\TagsAssigner')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->uow = $this->getMockBuilder('Doctrine\ORM\UnitOfWork')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->em
+            ->expects($this->any())
+            ->method('getUnitOfWork')
+            ->willReturn($this->uow);
+
+        $this->uow
+            ->expects($this->any())
+            ->method('getScheduledEntityInsertions')
+            ->willReturn([]);
+
+        $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcher')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $dispatcher
+            ->expects($this->exactly($dispatched))
+            ->method('dispatch');
+
+        $pocket = new PocketImport($this->em, $this->contentProxy, $this->tagsAssigner, $dispatcher);
+        $pocket->setUser($this->user);
+
+        $this->logHandler = new TestHandler();
+        $logger = new Logger('test', [$this->logHandler]);
+        $pocket->setLogger($logger);
+
+        return $pocket;
     }
 }