aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Wallabag/ApiBundle/Controller/DeveloperControllerTest.php (renamed from tests/Wallabag/CoreBundle/Controller/DeveloperControllerTest.php)37
-rw-r--r--tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php334
-rw-r--r--tests/Wallabag/CoreBundle/Command/InstallCommandTest.php8
-rw-r--r--tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php173
-rw-r--r--tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php130
-rw-r--r--tests/Wallabag/CoreBundle/Controller/ExportControllerTest.php43
-rw-r--r--tests/Wallabag/CoreBundle/Controller/SecurityControllerTest.php15
-rw-r--r--tests/Wallabag/CoreBundle/Controller/TagControllerTest.php70
-rw-r--r--tests/Wallabag/CoreBundle/EventListener/LocaleListenerTest.php6
-rw-r--r--tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php23
-rw-r--r--tests/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverterTest.php8
-rw-r--r--tests/Wallabag/CoreBundle/Twig/WallabagExtensionTest.php18
-rw-r--r--tests/Wallabag/CoreBundle/WallabagCoreTestCase.php13
-rw-r--r--tests/Wallabag/ImportBundle/Command/ImportCommandTest.php85
-rw-r--r--tests/Wallabag/ImportBundle/Command/RedisWorkerCommandTest.php74
-rw-r--r--tests/Wallabag/ImportBundle/Consumer/AMQPEntryConsumerTest.php225
-rw-r--r--tests/Wallabag/ImportBundle/Consumer/RedisEntryConsumerTest.php225
-rw-r--r--tests/Wallabag/ImportBundle/Controller/ChromeControllerTest.php153
-rw-r--r--tests/Wallabag/ImportBundle/Controller/FirefoxControllerTest.php166
-rw-r--r--tests/Wallabag/ImportBundle/Controller/ImportControllerTest.php2
-rw-r--r--tests/Wallabag/ImportBundle/Controller/InstapaperControllerTest.php196
-rw-r--r--tests/Wallabag/ImportBundle/Controller/PocketControllerTest.php31
-rw-r--r--tests/Wallabag/ImportBundle/Controller/ReadabilityControllerTest.php197
-rw-r--r--tests/Wallabag/ImportBundle/Controller/WallabagV1ControllerTest.php75
-rw-r--r--tests/Wallabag/ImportBundle/Controller/WallabagV2ControllerTest.php77
-rw-r--r--tests/Wallabag/ImportBundle/Import/ChromeImportTest.php233
-rw-r--r--tests/Wallabag/ImportBundle/Import/FirefoxImportTest.php233
-rw-r--r--tests/Wallabag/ImportBundle/Import/InstapaperImportTest.php233
-rw-r--r--tests/Wallabag/ImportBundle/Import/PocketImportTest.php248
-rw-r--r--tests/Wallabag/ImportBundle/Import/ReadabilityImportTest.php233
-rw-r--r--tests/Wallabag/ImportBundle/Import/WallabagV1ImportTest.php101
-rw-r--r--tests/Wallabag/ImportBundle/Import/WallabagV2ImportTest.php97
-rw-r--r--tests/Wallabag/ImportBundle/fixtures/chrome-bookmarks36
-rw-r--r--tests/Wallabag/ImportBundle/fixtures/firefox-bookmarks.json63
-rw-r--r--tests/Wallabag/ImportBundle/fixtures/instapaper-export.csv4
-rw-r--r--tests/Wallabag/ImportBundle/fixtures/readability-read.json25
-rw-r--r--tests/Wallabag/ImportBundle/fixtures/readability.json176
-rw-r--r--tests/Wallabag/ImportBundle/fixtures/wallabag-v2-read.json4
-rw-r--r--tests/Wallabag/ImportBundle/fixtures/wallabag-v2.json48
-rw-r--r--tests/Wallabag/UserBundle/Controller/ManageControllerTest.php82
-rw-r--r--tests/Wallabag/UserBundle/EventListener/CreateConfigListenerTest.php (renamed from tests/Wallabag/CoreBundle/EventListener/RegistrationConfirmedListenerTest.php)34
-rw-r--r--tests/Wallabag/UserBundle/Mailer/AuthCodeMailerTest.php2
42 files changed, 3983 insertions, 253 deletions
diff --git a/tests/Wallabag/CoreBundle/Controller/DeveloperControllerTest.php b/tests/Wallabag/ApiBundle/Controller/DeveloperControllerTest.php
index 79452ace..95befa9c 100644
--- a/tests/Wallabag/CoreBundle/Controller/DeveloperControllerTest.php
+++ b/tests/Wallabag/ApiBundle/Controller/DeveloperControllerTest.php
@@ -1,6 +1,6 @@
1<?php 1<?php
2 2
3namespace Tests\Wallabag\CoreBundle\Controller; 3namespace Tests\Wallabag\ApiBundle\Controller;
4 4
5use Tests\Wallabag\CoreBundle\WallabagCoreTestCase; 5use Tests\Wallabag\CoreBundle\WallabagCoreTestCase;
6 6
@@ -18,12 +18,45 @@ class DeveloperControllerTest extends WallabagCoreTestCase
18 18
19 $form = $crawler->filter('button[type=submit]')->form(); 19 $form = $crawler->filter('button[type=submit]')->form();
20 20
21 $client->submit($form); 21 $data = [
22 'client[name]' => 'My app',
23 ];
24
25 $crawler = $client->submit($form, $data);
22 26
23 $this->assertEquals(200, $client->getResponse()->getStatusCode()); 27 $this->assertEquals(200, $client->getResponse()->getStatusCode());
24 28
25 $newNbClients = $em->getRepository('WallabagApiBundle:Client')->findAll(); 29 $newNbClients = $em->getRepository('WallabagApiBundle:Client')->findAll();
26 $this->assertGreaterThan(count($nbClients), count($newNbClients)); 30 $this->assertGreaterThan(count($nbClients), count($newNbClients));
31
32 $this->assertGreaterThan(1, $alert = $crawler->filter('.settings ul li strong')->extract(['_text']));
33 $this->assertContains('My app', $alert[0]);
34 }
35
36 /**
37 * @depends testCreateClient
38 */
39 public function testCreateToken()
40 {
41 $client = $this->getClient();
42 $em = $client->getContainer()->get('doctrine.orm.entity_manager');
43 $apiClient = $em->getRepository('WallabagApiBundle:Client')->findOneByName('My app');
44
45 $client->request('POST', '/oauth/v2/token', [
46 'grant_type' => 'password',
47 'client_id' => $apiClient->getPublicId(),
48 'client_secret' => $apiClient->getSecret(),
49 'username' => 'admin',
50 'password' => 'mypassword',
51 ]);
52
53 $this->assertEquals(200, $client->getResponse()->getStatusCode());
54
55 $data = json_decode($client->getResponse()->getContent(), true);
56 $this->assertArrayHasKey('access_token', $data);
57 $this->assertArrayHasKey('expires_in', $data);
58 $this->assertArrayHasKey('token_type', $data);
59 $this->assertArrayHasKey('refresh_token', $data);
27 } 60 }
28 61
29 public function testListingClient() 62 public function testListingClient()
diff --git a/tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php b/tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php
index c39cc357..5dcb3e00 100644
--- a/tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php
+++ b/tests/Wallabag/ApiBundle/Controller/WallabagRestControllerTest.php
@@ -3,6 +3,7 @@
3namespace Tests\Wallabag\ApiBundle\Controller; 3namespace Tests\Wallabag\ApiBundle\Controller;
4 4
5use Tests\Wallabag\ApiBundle\WallabagApiTestCase; 5use Tests\Wallabag\ApiBundle\WallabagApiTestCase;
6use Wallabag\CoreBundle\Entity\Tag;
6 7
7class WallabagRestControllerTest extends WallabagApiTestCase 8class WallabagRestControllerTest extends WallabagApiTestCase
8{ 9{
@@ -77,9 +78,56 @@ class WallabagRestControllerTest extends WallabagApiTestCase
77 ); 78 );
78 } 79 }
79 80
81 public function testGetEntriesWithFullOptions()
82 {
83 $this->client->request('GET', '/api/entries', [
84 'archive' => 1,
85 'starred' => 1,
86 'sort' => 'updated',
87 'order' => 'asc',
88 'page' => 1,
89 'perPage' => 2,
90 'tags' => 'foo',
91 'since' => 1443274283,
92 ]);
93
94 $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
95
96 $content = json_decode($this->client->getResponse()->getContent(), true);
97
98 $this->assertGreaterThanOrEqual(1, count($content));
99 $this->assertArrayHasKey('items', $content['_embedded']);
100 $this->assertGreaterThanOrEqual(0, $content['total']);
101 $this->assertEquals(1, $content['page']);
102 $this->assertEquals(2, $content['limit']);
103 $this->assertGreaterThanOrEqual(1, $content['pages']);
104
105 $this->assertArrayHasKey('_links', $content);
106 $this->assertArrayHasKey('self', $content['_links']);
107 $this->assertArrayHasKey('first', $content['_links']);
108 $this->assertArrayHasKey('last', $content['_links']);
109
110 foreach (['self', 'first', 'last'] as $link) {
111 $this->assertArrayHasKey('href', $content['_links'][$link]);
112 $this->assertContains('archive=1', $content['_links'][$link]['href']);
113 $this->assertContains('starred=1', $content['_links'][$link]['href']);
114 $this->assertContains('sort=updated', $content['_links'][$link]['href']);
115 $this->assertContains('order=asc', $content['_links'][$link]['href']);
116 $this->assertContains('tags=foo', $content['_links'][$link]['href']);
117 $this->assertContains('since=1443274283', $content['_links'][$link]['href']);
118 }
119
120 $this->assertTrue(
121 $this->client->getResponse()->headers->contains(
122 'Content-Type',
123 'application/json'
124 )
125 );
126 }
127
80 public function testGetStarredEntries() 128 public function testGetStarredEntries()
81 { 129 {
82 $this->client->request('GET', '/api/entries', ['star' => 1, 'sort' => 'updated']); 130 $this->client->request('GET', '/api/entries', ['starred' => 1, 'sort' => 'updated']);
83 131
84 $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); 132 $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
85 133
@@ -91,6 +139,17 @@ class WallabagRestControllerTest extends WallabagApiTestCase
91 $this->assertEquals(1, $content['page']); 139 $this->assertEquals(1, $content['page']);
92 $this->assertGreaterThanOrEqual(1, $content['pages']); 140 $this->assertGreaterThanOrEqual(1, $content['pages']);
93 141
142 $this->assertArrayHasKey('_links', $content);
143 $this->assertArrayHasKey('self', $content['_links']);
144 $this->assertArrayHasKey('first', $content['_links']);
145 $this->assertArrayHasKey('last', $content['_links']);
146
147 foreach (['self', 'first', 'last'] as $link) {
148 $this->assertArrayHasKey('href', $content['_links'][$link]);
149 $this->assertContains('starred=1', $content['_links'][$link]['href']);
150 $this->assertContains('sort=updated', $content['_links'][$link]['href']);
151 }
152
94 $this->assertTrue( 153 $this->assertTrue(
95 $this->client->getResponse()->headers->contains( 154 $this->client->getResponse()->headers->contains(
96 'Content-Type', 155 'Content-Type',
@@ -113,6 +172,113 @@ class WallabagRestControllerTest extends WallabagApiTestCase
113 $this->assertEquals(1, $content['page']); 172 $this->assertEquals(1, $content['page']);
114 $this->assertGreaterThanOrEqual(1, $content['pages']); 173 $this->assertGreaterThanOrEqual(1, $content['pages']);
115 174
175 $this->assertArrayHasKey('_links', $content);
176 $this->assertArrayHasKey('self', $content['_links']);
177 $this->assertArrayHasKey('first', $content['_links']);
178 $this->assertArrayHasKey('last', $content['_links']);
179
180 foreach (['self', 'first', 'last'] as $link) {
181 $this->assertArrayHasKey('href', $content['_links'][$link]);
182 $this->assertContains('archive=1', $content['_links'][$link]['href']);
183 }
184
185 $this->assertTrue(
186 $this->client->getResponse()->headers->contains(
187 'Content-Type',
188 'application/json'
189 )
190 );
191 }
192
193 public function testGetTaggedEntries()
194 {
195 $this->client->request('GET', '/api/entries', ['tags' => 'foo,bar']);
196
197 $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
198
199 $content = json_decode($this->client->getResponse()->getContent(), true);
200
201 $this->assertGreaterThanOrEqual(1, count($content));
202 $this->assertNotEmpty($content['_embedded']['items']);
203 $this->assertGreaterThanOrEqual(1, $content['total']);
204 $this->assertEquals(1, $content['page']);
205 $this->assertGreaterThanOrEqual(1, $content['pages']);
206
207 $this->assertArrayHasKey('_links', $content);
208 $this->assertArrayHasKey('self', $content['_links']);
209 $this->assertArrayHasKey('first', $content['_links']);
210 $this->assertArrayHasKey('last', $content['_links']);
211
212 foreach (['self', 'first', 'last'] as $link) {
213 $this->assertArrayHasKey('href', $content['_links'][$link]);
214 $this->assertContains('tags='.urlencode('foo,bar'), $content['_links'][$link]['href']);
215 }
216
217 $this->assertTrue(
218 $this->client->getResponse()->headers->contains(
219 'Content-Type',
220 'application/json'
221 )
222 );
223 }
224
225 public function testGetDatedEntries()
226 {
227 $this->client->request('GET', '/api/entries', ['since' => 1443274283]);
228
229 $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
230
231 $content = json_decode($this->client->getResponse()->getContent(), true);
232
233 $this->assertGreaterThanOrEqual(1, count($content));
234 $this->assertNotEmpty($content['_embedded']['items']);
235 $this->assertGreaterThanOrEqual(1, $content['total']);
236 $this->assertEquals(1, $content['page']);
237 $this->assertGreaterThanOrEqual(1, $content['pages']);
238
239 $this->assertArrayHasKey('_links', $content);
240 $this->assertArrayHasKey('self', $content['_links']);
241 $this->assertArrayHasKey('first', $content['_links']);
242 $this->assertArrayHasKey('last', $content['_links']);
243
244 foreach (['self', 'first', 'last'] as $link) {
245 $this->assertArrayHasKey('href', $content['_links'][$link]);
246 $this->assertContains('since=1443274283', $content['_links'][$link]['href']);
247 }
248
249 $this->assertTrue(
250 $this->client->getResponse()->headers->contains(
251 'Content-Type',
252 'application/json'
253 )
254 );
255 }
256
257 public function testGetDatedSupEntries()
258 {
259 $future = new \DateTime(date('Y-m-d H:i:s'));
260 $this->client->request('GET', '/api/entries', ['since' => $future->getTimestamp() + 1000]);
261
262 $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
263
264 $content = json_decode($this->client->getResponse()->getContent(), true);
265
266 $this->assertGreaterThanOrEqual(1, count($content));
267 $this->assertEmpty($content['_embedded']['items']);
268 $this->assertEquals(0, $content['total']);
269 $this->assertEquals(1, $content['page']);
270 $this->assertEquals(1, $content['pages']);
271
272 $this->assertArrayHasKey('_links', $content);
273 $this->assertArrayHasKey('self', $content['_links']);
274 $this->assertArrayHasKey('first', $content['_links']);
275 $this->assertArrayHasKey('last', $content['_links']);
276
277 foreach (['self', 'first', 'last'] as $link) {
278 $this->assertArrayHasKey('href', $content['_links'][$link]);
279 $this->assertContains('since='.($future->getTimestamp() + 1000), $content['_links'][$link]['href']);
280 }
281
116 $this->assertTrue( 282 $this->assertTrue(
117 $this->client->getResponse()->headers->contains( 283 $this->client->getResponse()->headers->contains(
118 'Content-Type', 284 'Content-Type',
@@ -292,7 +458,7 @@ class WallabagRestControllerTest extends WallabagApiTestCase
292 $entry = $this->client->getContainer() 458 $entry = $this->client->getContainer()
293 ->get('doctrine.orm.entity_manager') 459 ->get('doctrine.orm.entity_manager')
294 ->getRepository('WallabagCoreBundle:Entry') 460 ->getRepository('WallabagCoreBundle:Entry')
295 ->findOneWithTags(1); 461 ->findOneWithTags($this->user->getId());
296 462
297 $entry = $entry[0]; 463 $entry = $entry[0];
298 464
@@ -354,7 +520,7 @@ class WallabagRestControllerTest extends WallabagApiTestCase
354 $entry = $this->client->getContainer() 520 $entry = $this->client->getContainer()
355 ->get('doctrine.orm.entity_manager') 521 ->get('doctrine.orm.entity_manager')
356 ->getRepository('WallabagCoreBundle:Entry') 522 ->getRepository('WallabagCoreBundle:Entry')
357 ->findOneWithTags(1); 523 ->findOneWithTags($this->user->getId());
358 $entry = $entry[0]; 524 $entry = $entry[0];
359 525
360 if (!$entry) { 526 if (!$entry) {
@@ -395,6 +561,8 @@ class WallabagRestControllerTest extends WallabagApiTestCase
395 */ 561 */
396 public function testDeleteUserTag($tag) 562 public function testDeleteUserTag($tag)
397 { 563 {
564 $tagName = $tag['label'];
565
398 $this->client->request('DELETE', '/api/tags/'.$tag['id'].'.json'); 566 $this->client->request('DELETE', '/api/tags/'.$tag['id'].'.json');
399 567
400 $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); 568 $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
@@ -405,12 +573,125 @@ class WallabagRestControllerTest extends WallabagApiTestCase
405 $this->assertEquals($tag['label'], $content['label']); 573 $this->assertEquals($tag['label'], $content['label']);
406 $this->assertEquals($tag['slug'], $content['slug']); 574 $this->assertEquals($tag['slug'], $content['slug']);
407 575
408 $entries = $entry = $this->client->getContainer() 576 $entries = $this->client->getContainer()
409 ->get('doctrine.orm.entity_manager') 577 ->get('doctrine.orm.entity_manager')
410 ->getRepository('WallabagCoreBundle:Entry') 578 ->getRepository('WallabagCoreBundle:Entry')
411 ->findAllByTagId($this->user->getId(), $tag['id']); 579 ->findAllByTagId($this->user->getId(), $tag['id']);
412 580
413 $this->assertCount(0, $entries); 581 $this->assertCount(0, $entries);
582
583 $tag = $this->client->getContainer()
584 ->get('doctrine.orm.entity_manager')
585 ->getRepository('WallabagCoreBundle:Tag')
586 ->findOneByLabel($tagName);
587
588 $this->assertNull($tag, $tagName.' was removed because it begun an orphan tag');
589 }
590
591 public function testDeleteTagByLabel()
592 {
593 $em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
594 $entry = $this->client->getContainer()
595 ->get('doctrine.orm.entity_manager')
596 ->getRepository('WallabagCoreBundle:Entry')
597 ->findOneWithTags($this->user->getId());
598
599 $entry = $entry[0];
600
601 $tag = new Tag();
602 $tag->setLabel('Awesome tag for test');
603 $em->persist($tag);
604
605 $entry->addTag($tag);
606
607 $em->persist($entry);
608 $em->flush();
609
610 $this->client->request('DELETE', '/api/tag/label.json', ['tag' => $tag->getLabel()]);
611
612 $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
613
614 $content = json_decode($this->client->getResponse()->getContent(), true);
615
616 $this->assertArrayHasKey('label', $content);
617 $this->assertEquals($tag->getLabel(), $content['label']);
618 $this->assertEquals($tag->getSlug(), $content['slug']);
619
620 $entries = $this->client->getContainer()
621 ->get('doctrine.orm.entity_manager')
622 ->getRepository('WallabagCoreBundle:Entry')
623 ->findAllByTagId($this->user->getId(), $tag->getId());
624
625 $this->assertCount(0, $entries);
626 }
627
628 public function testDeleteTagByLabelNotFound()
629 {
630 $this->client->request('DELETE', '/api/tag/label.json', ['tag' => 'does not exist']);
631
632 $this->assertEquals(404, $this->client->getResponse()->getStatusCode());
633 }
634
635 public function testDeleteTagsByLabel()
636 {
637 $em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
638 $entry = $this->client->getContainer()
639 ->get('doctrine.orm.entity_manager')
640 ->getRepository('WallabagCoreBundle:Entry')
641 ->findOneWithTags($this->user->getId());
642
643 $entry = $entry[0];
644
645 $tag = new Tag();
646 $tag->setLabel('Awesome tag for tagsLabel');
647 $em->persist($tag);
648
649 $tag2 = new Tag();
650 $tag2->setLabel('Awesome tag for tagsLabel 2');
651 $em->persist($tag2);
652
653 $entry->addTag($tag);
654 $entry->addTag($tag2);
655
656 $em->persist($entry);
657 $em->flush();
658
659 $this->client->request('DELETE', '/api/tags/label.json', ['tags' => $tag->getLabel().','.$tag2->getLabel()]);
660
661 $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
662
663 $content = json_decode($this->client->getResponse()->getContent(), true);
664
665 $this->assertCount(2, $content);
666
667 $this->assertArrayHasKey('label', $content[0]);
668 $this->assertEquals($tag->getLabel(), $content[0]['label']);
669 $this->assertEquals($tag->getSlug(), $content[0]['slug']);
670
671 $this->assertArrayHasKey('label', $content[1]);
672 $this->assertEquals($tag2->getLabel(), $content[1]['label']);
673 $this->assertEquals($tag2->getSlug(), $content[1]['slug']);
674
675 $entries = $this->client->getContainer()
676 ->get('doctrine.orm.entity_manager')
677 ->getRepository('WallabagCoreBundle:Entry')
678 ->findAllByTagId($this->user->getId(), $tag->getId());
679
680 $this->assertCount(0, $entries);
681
682 $entries = $this->client->getContainer()
683 ->get('doctrine.orm.entity_manager')
684 ->getRepository('WallabagCoreBundle:Entry')
685 ->findAllByTagId($this->user->getId(), $tag2->getId());
686
687 $this->assertCount(0, $entries);
688 }
689
690 public function testDeleteTagsByLabelNotFound()
691 {
692 $this->client->request('DELETE', '/api/tags/label.json', ['tags' => 'does not exist']);
693
694 $this->assertEquals(404, $this->client->getResponse()->getStatusCode());
414 } 695 }
415 696
416 public function testGetVersion() 697 public function testGetVersion()
@@ -510,4 +791,49 @@ class WallabagRestControllerTest extends WallabagApiTestCase
510 791
511 $this->assertEquals(true, $content['is_starred']); 792 $this->assertEquals(true, $content['is_starred']);
512 } 793 }
794
795 public function testGetEntriesExists()
796 {
797 $this->client->request('GET', '/api/entries/exists?url=http://0.0.0.0/entry2');
798
799 $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
800
801 $content = json_decode($this->client->getResponse()->getContent(), true);
802
803 $this->assertEquals(true, $content['exists']);
804 }
805
806 public function testGetEntriesExistsWithManyUrls()
807 {
808 $url1 = 'http://0.0.0.0/entry2';
809 $url2 = 'http://0.0.0.0/entry10';
810 $this->client->request('GET', '/api/entries/exists?urls[]='.$url1.'&urls[]='.$url2);
811
812 $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
813
814 $content = json_decode($this->client->getResponse()->getContent(), true);
815
816 $this->assertArrayHasKey($url1, $content);
817 $this->assertArrayHasKey($url2, $content);
818 $this->assertEquals(true, $content[$url1]);
819 $this->assertEquals(false, $content[$url2]);
820 }
821
822 public function testGetEntriesExistsWhichDoesNotExists()
823 {
824 $this->client->request('GET', '/api/entries/exists?url=http://google.com/entry2');
825
826 $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
827
828 $content = json_decode($this->client->getResponse()->getContent(), true);
829
830 $this->assertEquals(false, $content['exists']);
831 }
832
833 public function testGetEntriesExistsWithNoUrl()
834 {
835 $this->client->request('GET', '/api/entries/exists?url=');
836
837 $this->assertEquals(403, $this->client->getResponse()->getStatusCode());
838 }
513} 839}
diff --git a/tests/Wallabag/CoreBundle/Command/InstallCommandTest.php b/tests/Wallabag/CoreBundle/Command/InstallCommandTest.php
index 83f5bf24..1bfd41d5 100644
--- a/tests/Wallabag/CoreBundle/Command/InstallCommandTest.php
+++ b/tests/Wallabag/CoreBundle/Command/InstallCommandTest.php
@@ -33,7 +33,7 @@ class InstallCommandTest extends WallabagCoreTestCase
33 } 33 }
34 34
35 /** 35 /**
36 * Ensure next tests will have a clean database 36 * Ensure next tests will have a clean database.
37 */ 37 */
38 public static function tearDownAfterClass() 38 public static function tearDownAfterClass()
39 { 39 {
@@ -87,7 +87,6 @@ class InstallCommandTest extends WallabagCoreTestCase
87 $this->assertContains('Setting up database.', $tester->getDisplay()); 87 $this->assertContains('Setting up database.', $tester->getDisplay());
88 $this->assertContains('Administration setup.', $tester->getDisplay()); 88 $this->assertContains('Administration setup.', $tester->getDisplay());
89 $this->assertContains('Config setup.', $tester->getDisplay()); 89 $this->assertContains('Config setup.', $tester->getDisplay());
90 $this->assertContains('Installing assets.', $tester->getDisplay());
91 } 90 }
92 91
93 public function testRunInstallCommandWithReset() 92 public function testRunInstallCommandWithReset()
@@ -119,7 +118,6 @@ class InstallCommandTest extends WallabagCoreTestCase
119 $this->assertContains('Droping database, creating database and schema, clearing the cache', $tester->getDisplay()); 118 $this->assertContains('Droping database, creating database and schema, clearing the cache', $tester->getDisplay());
120 $this->assertContains('Administration setup.', $tester->getDisplay()); 119 $this->assertContains('Administration setup.', $tester->getDisplay());
121 $this->assertContains('Config setup.', $tester->getDisplay()); 120 $this->assertContains('Config setup.', $tester->getDisplay());
122 $this->assertContains('Installing assets.', $tester->getDisplay());
123 121
124 // we force to reset everything 122 // we force to reset everything
125 $this->assertContains('Droping database, creating database and schema, clearing the cache', $tester->getDisplay()); 123 $this->assertContains('Droping database, creating database and schema, clearing the cache', $tester->getDisplay());
@@ -170,7 +168,6 @@ class InstallCommandTest extends WallabagCoreTestCase
170 $this->assertContains('Setting up database.', $tester->getDisplay()); 168 $this->assertContains('Setting up database.', $tester->getDisplay());
171 $this->assertContains('Administration setup.', $tester->getDisplay()); 169 $this->assertContains('Administration setup.', $tester->getDisplay());
172 $this->assertContains('Config setup.', $tester->getDisplay()); 170 $this->assertContains('Config setup.', $tester->getDisplay());
173 $this->assertContains('Installing assets.', $tester->getDisplay());
174 171
175 // the current database doesn't already exist 172 // the current database doesn't already exist
176 $this->assertContains('Creating database and schema, clearing the cache', $tester->getDisplay()); 173 $this->assertContains('Creating database and schema, clearing the cache', $tester->getDisplay());
@@ -208,7 +205,6 @@ class InstallCommandTest extends WallabagCoreTestCase
208 $this->assertContains('Setting up database.', $tester->getDisplay()); 205 $this->assertContains('Setting up database.', $tester->getDisplay());
209 $this->assertContains('Administration setup.', $tester->getDisplay()); 206 $this->assertContains('Administration setup.', $tester->getDisplay());
210 $this->assertContains('Config setup.', $tester->getDisplay()); 207 $this->assertContains('Config setup.', $tester->getDisplay());
211 $this->assertContains('Installing assets.', $tester->getDisplay());
212 208
213 $this->assertContains('Droping schema and creating schema', $tester->getDisplay()); 209 $this->assertContains('Droping schema and creating schema', $tester->getDisplay());
214 } 210 }
@@ -263,7 +259,6 @@ class InstallCommandTest extends WallabagCoreTestCase
263 $this->assertContains('Setting up database.', $tester->getDisplay()); 259 $this->assertContains('Setting up database.', $tester->getDisplay());
264 $this->assertContains('Administration setup.', $tester->getDisplay()); 260 $this->assertContains('Administration setup.', $tester->getDisplay());
265 $this->assertContains('Config setup.', $tester->getDisplay()); 261 $this->assertContains('Config setup.', $tester->getDisplay());
266 $this->assertContains('Installing assets.', $tester->getDisplay());
267 262
268 $this->assertContains('Creating schema', $tester->getDisplay()); 263 $this->assertContains('Creating schema', $tester->getDisplay());
269 } 264 }
@@ -296,6 +291,5 @@ class InstallCommandTest extends WallabagCoreTestCase
296 $this->assertContains('Setting up database.', $tester->getDisplay()); 291 $this->assertContains('Setting up database.', $tester->getDisplay());
297 $this->assertContains('Administration setup.', $tester->getDisplay()); 292 $this->assertContains('Administration setup.', $tester->getDisplay());
298 $this->assertContains('Config setup.', $tester->getDisplay()); 293 $this->assertContains('Config setup.', $tester->getDisplay());
299 $this->assertContains('Installing assets.', $tester->getDisplay());
300 } 294 }
301} 295}
diff --git a/tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php b/tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php
index 7193f9b0..1954c654 100644
--- a/tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php
+++ b/tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php
@@ -28,7 +28,6 @@ class ConfigControllerTest extends WallabagCoreTestCase
28 $this->assertCount(1, $crawler->filter('button[id=config_save]')); 28 $this->assertCount(1, $crawler->filter('button[id=config_save]'));
29 $this->assertCount(1, $crawler->filter('button[id=change_passwd_save]')); 29 $this->assertCount(1, $crawler->filter('button[id=change_passwd_save]'));
30 $this->assertCount(1, $crawler->filter('button[id=update_user_save]')); 30 $this->assertCount(1, $crawler->filter('button[id=update_user_save]'));
31 $this->assertCount(1, $crawler->filter('button[id=new_user_save]'));
32 $this->assertCount(1, $crawler->filter('button[id=rss_config_save]')); 31 $this->assertCount(1, $crawler->filter('button[id=rss_config_save]'));
33 } 32 }
34 33
@@ -56,8 +55,7 @@ class ConfigControllerTest extends WallabagCoreTestCase
56 55
57 $crawler = $client->followRedirect(); 56 $crawler = $client->followRedirect();
58 57
59 $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text'])); 58 $this->assertContains('flashes.config.notice.config_saved', $crawler->filter('body')->extract(['_text'])[0]);
60 $this->assertContains('flashes.config.notice.config_saved', $alert[0]);
61 } 59 }
62 60
63 public function testChangeReadingSpeed() 61 public function testChangeReadingSpeed()
@@ -213,8 +211,7 @@ class ConfigControllerTest extends WallabagCoreTestCase
213 211
214 $crawler = $client->followRedirect(); 212 $crawler = $client->followRedirect();
215 213
216 $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text'])); 214 $this->assertContains('flashes.config.notice.password_updated', $crawler->filter('body')->extract(['_text'])[0]);
217 $this->assertContains('flashes.config.notice.password_updated', $alert[0]);
218 } 215 }
219 216
220 public function dataForUserFailed() 217 public function dataForUserFailed()
@@ -285,120 +282,6 @@ class ConfigControllerTest extends WallabagCoreTestCase
285 $this->assertContains('flashes.config.notice.user_updated', $alert[0]); 282 $this->assertContains('flashes.config.notice.user_updated', $alert[0]);
286 } 283 }
287 284
288 public function dataForNewUserFailed()
289 {
290 return [
291 [
292 [
293 'new_user[username]' => '',
294 'new_user[plainPassword][first]' => '',
295 'new_user[plainPassword][second]' => '',
296 'new_user[email]' => '',
297 ],
298 'fos_user.username.blank',
299 ],
300 [
301 [
302 'new_user[username]' => 'a',
303 'new_user[plainPassword][first]' => 'mypassword',
304 'new_user[plainPassword][second]' => 'mypassword',
305 'new_user[email]' => '',
306 ],
307 'fos_user.username.short',
308 ],
309 [
310 [
311 'new_user[username]' => 'wallace',
312 'new_user[plainPassword][first]' => 'mypassword',
313 'new_user[plainPassword][second]' => 'mypassword',
314 'new_user[email]' => 'test',
315 ],
316 'fos_user.email.invalid',
317 ],
318 [
319 [
320 'new_user[username]' => 'admin',
321 'new_user[plainPassword][first]' => 'wallacewallace',
322 'new_user[plainPassword][second]' => 'wallacewallace',
323 'new_user[email]' => 'wallace@wallace.me',
324 ],
325 'fos_user.username.already_used',
326 ],
327 [
328 [
329 'new_user[username]' => 'wallace',
330 'new_user[plainPassword][first]' => 'mypassword1',
331 'new_user[plainPassword][second]' => 'mypassword2',
332 'new_user[email]' => 'wallace@wallace.me',
333 ],
334 'validator.password_must_match',
335 ],
336 ];
337 }
338
339 /**
340 * @dataProvider dataForNewUserFailed
341 */
342 public function testNewUserFailed($data, $expectedMessage)
343 {
344 $this->logInAs('admin');
345 $client = $this->getClient();
346
347 $crawler = $client->request('GET', '/config');
348
349 $this->assertEquals(200, $client->getResponse()->getStatusCode());
350
351 $form = $crawler->filter('button[id=new_user_save]')->form();
352
353 $crawler = $client->submit($form, $data);
354
355 $this->assertEquals(200, $client->getResponse()->getStatusCode());
356
357 $this->assertGreaterThan(1, $alert = $crawler->filter('body')->extract(['_text']));
358 $this->assertContains($expectedMessage, $alert[0]);
359 }
360
361 public function testNewUserCreated()
362 {
363 $this->logInAs('admin');
364 $client = $this->getClient();
365
366 $crawler = $client->request('GET', '/config');
367
368 $this->assertEquals(200, $client->getResponse()->getStatusCode());
369
370 $form = $crawler->filter('button[id=new_user_save]')->form();
371
372 $data = [
373 'new_user[username]' => 'wallace',
374 'new_user[plainPassword][first]' => 'wallace1',
375 'new_user[plainPassword][second]' => 'wallace1',
376 'new_user[email]' => 'wallace@wallace.me',
377 ];
378
379 $client->submit($form, $data);
380
381 $this->assertEquals(302, $client->getResponse()->getStatusCode());
382
383 $crawler = $client->followRedirect();
384
385 $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text']));
386 $this->assertContains('flashes.config.notice.user_added', $alert[0]);
387
388 $em = $client->getContainer()->get('doctrine.orm.entity_manager');
389 $user = $em
390 ->getRepository('WallabagUserBundle:User')
391 ->findOneByUsername('wallace');
392
393 $this->assertTrue(false !== $user);
394 $this->assertTrue($user->isEnabled());
395 $this->assertEquals('material', $user->getConfig()->getTheme());
396 $this->assertEquals(12, $user->getConfig()->getItemsPerPage());
397 $this->assertEquals(50, $user->getConfig()->getRssLimit());
398 $this->assertEquals('en', $user->getConfig()->getLanguage());
399 $this->assertEquals(1, $user->getConfig()->getReadingSpeed());
400 }
401
402 public function testRssUpdateResetToken() 285 public function testRssUpdateResetToken()
403 { 286 {
404 $this->logInAs('admin'); 287 $this->logInAs('admin');
@@ -474,8 +357,7 @@ class ConfigControllerTest extends WallabagCoreTestCase
474 357
475 $crawler = $client->followRedirect(); 358 $crawler = $client->followRedirect();
476 359
477 $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text'])); 360 $this->assertContains('flashes.config.notice.rss_updated', $crawler->filter('body')->extract(['_text'])[0]);
478 $this->assertContains('flashes.config.notice.rss_updated', $alert[0]);
479 } 361 }
480 362
481 public function dataForRssFailed() 363 public function dataForRssFailed()
@@ -540,8 +422,32 @@ class ConfigControllerTest extends WallabagCoreTestCase
540 422
541 $crawler = $client->followRedirect(); 423 $crawler = $client->followRedirect();
542 424
543 $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text'])); 425 $this->assertContains('flashes.config.notice.tagging_rules_updated', $crawler->filter('body')->extract(['_text'])[0]);
544 $this->assertContains('flashes.config.notice.tagging_rules_updated', $alert[0]); 426
427 $editLink = $crawler->filter('.mode_edit')->last()->link();
428
429 $crawler = $client->click($editLink);
430 $this->assertEquals(302, $client->getResponse()->getStatusCode());
431 $this->assertContains('?tagging-rule=', $client->getResponse()->headers->get('location'));
432
433 $crawler = $client->followRedirect();
434
435 $form = $crawler->filter('button[id=tagging_rule_save]')->form();
436
437 $data = [
438 'tagging_rule[rule]' => 'readingTime <= 30',
439 'tagging_rule[tags]' => 'short reading',
440 ];
441
442 $client->submit($form, $data);
443
444 $this->assertEquals(302, $client->getResponse()->getStatusCode());
445
446 $crawler = $client->followRedirect();
447
448 $this->assertContains('flashes.config.notice.tagging_rules_updated', $crawler->filter('body')->extract(['_text'])[0]);
449
450 $this->assertContains('readingTime <= 30', $crawler->filter('body')->extract(['_text'])[0]);
545 451
546 $deleteLink = $crawler->filter('.delete')->last()->link(); 452 $deleteLink = $crawler->filter('.delete')->last()->link();
547 453
@@ -549,8 +455,7 @@ class ConfigControllerTest extends WallabagCoreTestCase
549 $this->assertEquals(302, $client->getResponse()->getStatusCode()); 455 $this->assertEquals(302, $client->getResponse()->getStatusCode());
550 456
551 $crawler = $client->followRedirect(); 457 $crawler = $client->followRedirect();
552 $this->assertGreaterThan(1, $alert = $crawler->filter('div.messages.success')->extract(['_text'])); 458 $this->assertContains('flashes.config.notice.tagging_rules_deleted', $crawler->filter('body')->extract(['_text'])[0]);
553 $this->assertContains('flashes.config.notice.tagging_rules_deleted', $alert[0]);
554 } 459 }
555 460
556 public function dataForTaggingRuleFailed() 461 public function dataForTaggingRuleFailed()
@@ -613,7 +518,23 @@ class ConfigControllerTest extends WallabagCoreTestCase
613 ->getRepository('WallabagCoreBundle:TaggingRule') 518 ->getRepository('WallabagCoreBundle:TaggingRule')
614 ->findAll()[0]; 519 ->findAll()[0];
615 520
616 $crawler = $client->request('GET', '/tagging-rule/delete/'.$rule->getId()); 521 $crawler = $client->request('GET', '/tagging-rule/edit/'.$rule->getId());
522
523 $this->assertEquals(403, $client->getResponse()->getStatusCode());
524 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
525 $this->assertContains('You can not access this tagging rule', $body[0]);
526 }
527
528 public function testEditingTaggingRuleFromAnOtherUser()
529 {
530 $this->logInAs('bob');
531 $client = $this->getClient();
532
533 $rule = $client->getContainer()->get('doctrine.orm.entity_manager')
534 ->getRepository('WallabagCoreBundle:TaggingRule')
535 ->findAll()[0];
536
537 $crawler = $client->request('GET', '/tagging-rule/edit/'.$rule->getId());
617 538
618 $this->assertEquals(403, $client->getResponse()->getStatusCode()); 539 $this->assertEquals(403, $client->getResponse()->getStatusCode());
619 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text'])); 540 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
diff --git a/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php b/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php
index 5c739c78..9b03a519 100644
--- a/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php
+++ b/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php
@@ -29,7 +29,7 @@ class EntryControllerTest extends WallabagCoreTestCase
29 29
30 $this->assertEquals(200, $client->getResponse()->getStatusCode()); 30 $this->assertEquals(200, $client->getResponse()->getStatusCode());
31 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text'])); 31 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
32 $this->assertContains('quickstart.intro.paragraph_1', $body[0]); 32 $this->assertContains('quickstart.intro.title', $body[0]);
33 33
34 // Test if quickstart is disabled when user has 1 entry 34 // Test if quickstart is disabled when user has 1 entry
35 $crawler = $client->request('GET', '/new'); 35 $crawler = $client->request('GET', '/new');
@@ -160,6 +160,50 @@ class EntryControllerTest extends WallabagCoreTestCase
160 $this->assertContains('/view/', $client->getResponse()->getTargetUrl()); 160 $this->assertContains('/view/', $client->getResponse()->getTargetUrl());
161 } 161 }
162 162
163 public function testPostNewOkUrlExistWithAccent()
164 {
165 $this->logInAs('admin');
166 $client = $this->getClient();
167
168 $url = 'http://www.aritylabs.com/post/106091708292/des-contr%C3%B4leurs-optionnels-gr%C3%A2ce-%C3%A0-constmissing';
169
170 $crawler = $client->request('GET', '/new');
171
172 $this->assertEquals(200, $client->getResponse()->getStatusCode());
173
174 $form = $crawler->filter('form[name=entry]')->form();
175
176 $data = [
177 'entry[url]' => $url,
178 ];
179
180 $client->submit($form, $data);
181
182 $crawler = $client->request('GET', '/new');
183
184 $this->assertEquals(200, $client->getResponse()->getStatusCode());
185
186 $form = $crawler->filter('form[name=entry]')->form();
187
188 $data = [
189 'entry[url]' => $url,
190 ];
191
192 $client->submit($form, $data);
193
194 $this->assertEquals(302, $client->getResponse()->getStatusCode());
195 $this->assertContains('/view/', $client->getResponse()->getTargetUrl());
196
197 $em = $client->getContainer()
198 ->get('doctrine.orm.entity_manager');
199 $entry = $em
200 ->getRepository('WallabagCoreBundle:Entry')
201 ->findOneByUrl(urldecode($url));
202
203 $em->remove($entry);
204 $em->flush();
205 }
206
163 /** 207 /**
164 * This test will require an internet connection. 208 * This test will require an internet connection.
165 */ 209 */
@@ -236,6 +280,16 @@ class EntryControllerTest extends WallabagCoreTestCase
236 $this->assertEquals(200, $client->getResponse()->getStatusCode()); 280 $this->assertEquals(200, $client->getResponse()->getStatusCode());
237 } 281 }
238 282
283 public function testUntagged()
284 {
285 $this->logInAs('admin');
286 $client = $this->getClient();
287
288 $client->request('GET', '/untagged/list');
289
290 $this->assertEquals(200, $client->getResponse()->getStatusCode());
291 }
292
239 public function testStarred() 293 public function testStarred()
240 { 294 {
241 $this->logInAs('admin'); 295 $this->logInAs('admin');
@@ -287,22 +341,23 @@ class EntryControllerTest extends WallabagCoreTestCase
287 $this->logInAs('admin'); 341 $this->logInAs('admin');
288 $client = $this->getClient(); 342 $client = $this->getClient();
289 343
290 $content = $client->getContainer() 344 $em = $client->getContainer()
291 ->get('doctrine.orm.entity_manager') 345 ->get('doctrine.orm.entity_manager');
346
347 $content = $em
292 ->getRepository('WallabagCoreBundle:Entry') 348 ->getRepository('WallabagCoreBundle:Entry')
293 ->findByUrlAndUserId($this->url, $this->getLoggedInUserId()); 349 ->findByUrlAndUserId($this->url, $this->getLoggedInUserId());
294 350
295 // empty content 351 // empty content
296 $content->setContent(''); 352 $content->setContent('');
297 $client->getContainer()->get('doctrine.orm.entity_manager')->persist($content); 353 $em->persist($content);
298 $client->getContainer()->get('doctrine.orm.entity_manager')->flush(); 354 $em->flush();
299 355
300 $client->request('GET', '/reload/'.$content->getId()); 356 $client->request('GET', '/reload/'.$content->getId());
301 357
302 $this->assertEquals(302, $client->getResponse()->getStatusCode()); 358 $this->assertEquals(302, $client->getResponse()->getStatusCode());
303 359
304 $content = $client->getContainer() 360 $content = $em
305 ->get('doctrine.orm.entity_manager')
306 ->getRepository('WallabagCoreBundle:Entry') 361 ->getRepository('WallabagCoreBundle:Entry')
307 ->findByUrlAndUserId($this->url, $this->getLoggedInUserId()); 362 ->findByUrlAndUserId($this->url, $this->getLoggedInUserId());
308 363
@@ -432,9 +487,11 @@ class EntryControllerTest extends WallabagCoreTestCase
432 $this->logInAs('admin'); 487 $this->logInAs('admin');
433 $client = $this->getClient(); 488 $client = $this->getClient();
434 489
490 $em = $client->getContainer()
491 ->get('doctrine.orm.entity_manager');
492
435 // add a new content to be removed later 493 // add a new content to be removed later
436 $user = $client->getContainer() 494 $user = $em
437 ->get('doctrine.orm.entity_manager')
438 ->getRepository('WallabagUserBundle:User') 495 ->getRepository('WallabagUserBundle:User')
439 ->findOneByUserName('admin'); 496 ->findOneByUserName('admin');
440 497
@@ -448,12 +505,8 @@ class EntryControllerTest extends WallabagCoreTestCase
448 $content->setArchived(true); 505 $content->setArchived(true);
449 $content->setLanguage('fr'); 506 $content->setLanguage('fr');
450 507
451 $client->getContainer() 508 $em->persist($content);
452 ->get('doctrine.orm.entity_manager') 509 $em->flush();
453 ->persist($content);
454 $client->getContainer()
455 ->get('doctrine.orm.entity_manager')
456 ->flush();
457 510
458 $client->request('GET', '/view/'.$content->getId()); 511 $client->request('GET', '/view/'.$content->getId());
459 $this->assertEquals(200, $client->getResponse()->getStatusCode()); 512 $this->assertEquals(200, $client->getResponse()->getStatusCode());
@@ -698,4 +751,51 @@ class EntryControllerTest extends WallabagCoreTestCase
698 $crawler = $client->submit($form, $data); 751 $crawler = $client->submit($form, $data);
699 $this->assertCount(2, $crawler->filter('div[class=entry]')); 752 $this->assertCount(2, $crawler->filter('div[class=entry]'));
700 } 753 }
754
755 public function testShareEntryPublicly()
756 {
757 $this->logInAs('admin');
758 $client = $this->getClient();
759
760 $content = $client->getContainer()
761 ->get('doctrine.orm.entity_manager')
762 ->getRepository('WallabagCoreBundle:Entry')
763 ->findOneByUser($this->getLoggedInUserId());
764
765 // no uuid
766 $client->request('GET', '/share/'.$content->getUuid());
767 $this->assertEquals(404, $client->getResponse()->getStatusCode());
768
769 // generating the uuid
770 $client->request('GET', '/share/'.$content->getId());
771 $this->assertEquals(302, $client->getResponse()->getStatusCode());
772
773 // follow link with uuid
774 $crawler = $client->followRedirect();
775 $this->assertEquals(200, $client->getResponse()->getStatusCode());
776 $this->assertContains('max-age=25200', $client->getResponse()->headers->get('cache-control'));
777 $this->assertContains('public', $client->getResponse()->headers->get('cache-control'));
778 $this->assertContains('s-maxage=25200', $client->getResponse()->headers->get('cache-control'));
779 $this->assertNotContains('no-cache', $client->getResponse()->headers->get('cache-control'));
780 $this->assertContains('og:title', $client->getResponse()->getContent());
781 $this->assertContains('og:type', $client->getResponse()->getContent());
782 $this->assertContains('og:url', $client->getResponse()->getContent());
783 $this->assertContains('og:image', $client->getResponse()->getContent());
784
785 // sharing is now disabled
786 $client->getContainer()->get('craue_config')->set('share_public', 0);
787 $client->request('GET', '/share/'.$content->getUuid());
788 $this->assertEquals(404, $client->getResponse()->getStatusCode());
789
790 $client->request('GET', '/view/'.$content->getId());
791 $this->assertContains('no-cache', $client->getResponse()->headers->get('cache-control'));
792
793 // removing the share
794 $client->request('GET', '/share/delete/'.$content->getId());
795 $this->assertEquals(302, $client->getResponse()->getStatusCode());
796
797 // share is now disable
798 $client->request('GET', '/share/'.$content->getUuid());
799 $this->assertEquals(404, $client->getResponse()->getStatusCode());
800 }
701} 801}
diff --git a/tests/Wallabag/CoreBundle/Controller/ExportControllerTest.php b/tests/Wallabag/CoreBundle/Controller/ExportControllerTest.php
index b22156c3..9ecd8bc4 100644
--- a/tests/Wallabag/CoreBundle/Controller/ExportControllerTest.php
+++ b/tests/Wallabag/CoreBundle/Controller/ExportControllerTest.php
@@ -146,7 +146,9 @@ class ExportControllerTest extends WallabagCoreTestCase
146 ->get('doctrine.orm.entity_manager') 146 ->get('doctrine.orm.entity_manager')
147 ->getRepository('WallabagCoreBundle:Entry') 147 ->getRepository('WallabagCoreBundle:Entry')
148 ->createQueryBuilder('e') 148 ->createQueryBuilder('e')
149 ->select('e, t')
149 ->leftJoin('e.user', 'u') 150 ->leftJoin('e.user', 'u')
151 ->leftJoin('e.tags', 't')
150 ->where('u.username = :username')->setParameter('username', 'admin') 152 ->where('u.username = :username')->setParameter('username', 'admin')
151 ->andWhere('e.isArchived = true') 153 ->andWhere('e.isArchived = true')
152 ->getQuery() 154 ->getQuery()
@@ -168,7 +170,19 @@ class ExportControllerTest extends WallabagCoreTestCase
168 $this->assertGreaterThan(1, $csv); 170 $this->assertGreaterThan(1, $csv);
169 // +1 for title line 171 // +1 for title line
170 $this->assertEquals(count($contentInDB) + 1, count($csv)); 172 $this->assertEquals(count($contentInDB) + 1, count($csv));
171 $this->assertEquals('Title;URL;Content;Tags;"MIME Type";Language', $csv[0]); 173 $this->assertEquals('Title;URL;Content;Tags;"MIME Type";Language;"Creation date"', $csv[0]);
174 $this->assertContains($contentInDB[0]['title'], $csv[1]);
175 $this->assertContains($contentInDB[0]['url'], $csv[1]);
176 $this->assertContains($contentInDB[0]['content'], $csv[1]);
177 $this->assertContains($contentInDB[0]['mimetype'], $csv[1]);
178 $this->assertContains($contentInDB[0]['language'], $csv[1]);
179 $this->assertContains($contentInDB[0]['createdAt']->format('d/m/Y h:i:s'), $csv[1]);
180
181 $expectedTag = [];
182 foreach ($contentInDB[0]['tags'] as $tag) {
183 $expectedTag[] = $tag['label'];
184 }
185 $this->assertContains(implode(', ', $expectedTag), $csv[1]);
172 } 186 }
173 187
174 public function testJsonExport() 188 public function testJsonExport()
@@ -176,29 +190,23 @@ class ExportControllerTest extends WallabagCoreTestCase
176 $this->logInAs('admin'); 190 $this->logInAs('admin');
177 $client = $this->getClient(); 191 $client = $this->getClient();
178 192
179 // to be sure results are the same
180 $contentInDB = $client->getContainer() 193 $contentInDB = $client->getContainer()
181 ->get('doctrine.orm.entity_manager') 194 ->get('doctrine.orm.entity_manager')
182 ->getRepository('WallabagCoreBundle:Entry') 195 ->getRepository('WallabagCoreBundle:Entry')
183 ->createQueryBuilder('e') 196 ->findByUrlAndUserId('http://0.0.0.0/entry1', $this->getLoggedInUserId());
184 ->leftJoin('e.user', 'u')
185 ->where('u.username = :username')->setParameter('username', 'admin')
186 ->getQuery()
187 ->getArrayResult();
188 197
189 ob_start(); 198 ob_start();
190 $crawler = $client->request('GET', '/export/all.json'); 199 $crawler = $client->request('GET', '/export/'.$contentInDB->getId().'.json');
191 ob_end_clean(); 200 ob_end_clean();
192 201
193 $this->assertEquals(200, $client->getResponse()->getStatusCode()); 202 $this->assertEquals(200, $client->getResponse()->getStatusCode());
194 203
195 $headers = $client->getResponse()->headers; 204 $headers = $client->getResponse()->headers;
196 $this->assertEquals('application/json', $headers->get('content-type')); 205 $this->assertEquals('application/json', $headers->get('content-type'));
197 $this->assertEquals('attachment; filename="All articles.json"', $headers->get('content-disposition')); 206 $this->assertEquals('attachment; filename="'.$contentInDB->getTitle().'.json"', $headers->get('content-disposition'));
198 $this->assertEquals('UTF-8', $headers->get('content-transfer-encoding')); 207 $this->assertEquals('UTF-8', $headers->get('content-transfer-encoding'));
199 208
200 $content = json_decode($client->getResponse()->getContent(), true); 209 $content = json_decode($client->getResponse()->getContent(), true);
201 $this->assertEquals(count($contentInDB), count($content));
202 $this->assertArrayHasKey('id', $content[0]); 210 $this->assertArrayHasKey('id', $content[0]);
203 $this->assertArrayHasKey('title', $content[0]); 211 $this->assertArrayHasKey('title', $content[0]);
204 $this->assertArrayHasKey('url', $content[0]); 212 $this->assertArrayHasKey('url', $content[0]);
@@ -210,6 +218,19 @@ class ExportControllerTest extends WallabagCoreTestCase
210 $this->assertArrayHasKey('reading_time', $content[0]); 218 $this->assertArrayHasKey('reading_time', $content[0]);
211 $this->assertArrayHasKey('domain_name', $content[0]); 219 $this->assertArrayHasKey('domain_name', $content[0]);
212 $this->assertArrayHasKey('tags', $content[0]); 220 $this->assertArrayHasKey('tags', $content[0]);
221 $this->assertArrayHasKey('created_at', $content[0]);
222 $this->assertArrayHasKey('updated_at', $content[0]);
223
224 $this->assertEquals($contentInDB->isArchived(), $content[0]['is_archived']);
225 $this->assertEquals($contentInDB->isStarred(), $content[0]['is_starred']);
226 $this->assertEquals($contentInDB->getTitle(), $content[0]['title']);
227 $this->assertEquals($contentInDB->getUrl(), $content[0]['url']);
228 $this->assertEquals([['text' => 'This is my annotation /o/', 'quote' => 'content']], $content[0]['annotations']);
229 $this->assertEquals($contentInDB->getMimetype(), $content[0]['mimetype']);
230 $this->assertEquals($contentInDB->getLanguage(), $content[0]['language']);
231 $this->assertEquals($contentInDB->getReadingtime(), $content[0]['reading_time']);
232 $this->assertEquals($contentInDB->getDomainname(), $content[0]['domain_name']);
233 $this->assertEquals(['foo', 'baz'], $content[0]['tags']);
213 } 234 }
214 235
215 public function testXmlExport() 236 public function testXmlExport()
@@ -247,5 +268,7 @@ class ExportControllerTest extends WallabagCoreTestCase
247 $this->assertNotEmpty('url', (string) $content->entry[0]->url); 268 $this->assertNotEmpty('url', (string) $content->entry[0]->url);
248 $this->assertNotEmpty('content', (string) $content->entry[0]->content); 269 $this->assertNotEmpty('content', (string) $content->entry[0]->content);
249 $this->assertNotEmpty('domain_name', (string) $content->entry[0]->domain_name); 270 $this->assertNotEmpty('domain_name', (string) $content->entry[0]->domain_name);
271 $this->assertNotEmpty('created_at', (string) $content->entry[0]->created_at);
272 $this->assertNotEmpty('updated_at', (string) $content->entry[0]->updated_at);
250 } 273 }
251} 274}
diff --git a/tests/Wallabag/CoreBundle/Controller/SecurityControllerTest.php b/tests/Wallabag/CoreBundle/Controller/SecurityControllerTest.php
index 03355f5a..08f4676e 100644
--- a/tests/Wallabag/CoreBundle/Controller/SecurityControllerTest.php
+++ b/tests/Wallabag/CoreBundle/Controller/SecurityControllerTest.php
@@ -69,4 +69,19 @@ class SecurityControllerTest extends WallabagCoreTestCase
69 $this->assertTrue($user->isTrustedComputer('ABCDEF')); 69 $this->assertTrue($user->isTrustedComputer('ABCDEF'));
70 $this->assertFalse($user->isTrustedComputer('FEDCBA')); 70 $this->assertFalse($user->isTrustedComputer('FEDCBA'));
71 } 71 }
72
73 public function testEnabledRegistration()
74 {
75 $client = $this->getClient();
76
77 if (!$client->getContainer()->getParameter('fosuser_registration')) {
78 $this->markTestSkipped('fosuser_registration is not enabled.');
79
80 return;
81 }
82
83 $client->followRedirects();
84 $crawler = $client->request('GET', '/register');
85 $this->assertContains('registration.submit', $crawler->filter('body')->extract(['_text'])[0]);
86 }
72} 87}
diff --git a/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php b/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php
index 58450e5f..769ce66e 100644
--- a/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php
+++ b/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php
@@ -3,6 +3,7 @@
3namespace Tests\Wallabag\CoreBundle\Controller; 3namespace Tests\Wallabag\CoreBundle\Controller;
4 4
5use Tests\Wallabag\CoreBundle\WallabagCoreTestCase; 5use Tests\Wallabag\CoreBundle\WallabagCoreTestCase;
6use Wallabag\CoreBundle\Entity\Tag;
6 7
7class TagControllerTest extends WallabagCoreTestCase 8class TagControllerTest extends WallabagCoreTestCase
8{ 9{
@@ -26,7 +27,7 @@ class TagControllerTest extends WallabagCoreTestCase
26 $entry = $client->getContainer() 27 $entry = $client->getContainer()
27 ->get('doctrine.orm.entity_manager') 28 ->get('doctrine.orm.entity_manager')
28 ->getRepository('WallabagCoreBundle:Entry') 29 ->getRepository('WallabagCoreBundle:Entry')
29 ->findOneByUsernameAndNotArchived('admin'); 30 ->findByUrlAndUserId('http://0.0.0.0/entry1', $this->getLoggedInUserId());
30 31
31 $crawler = $client->request('GET', '/view/'.$entry->getId()); 32 $crawler = $client->request('GET', '/view/'.$entry->getId());
32 33
@@ -43,11 +44,11 @@ class TagControllerTest extends WallabagCoreTestCase
43 $entry = $client->getContainer() 44 $entry = $client->getContainer()
44 ->get('doctrine.orm.entity_manager') 45 ->get('doctrine.orm.entity_manager')
45 ->getRepository('WallabagCoreBundle:Entry') 46 ->getRepository('WallabagCoreBundle:Entry')
46 ->findOneByUsernameAndNotArchived('admin'); 47 ->findByUrlAndUserId('http://0.0.0.0/entry1', $this->getLoggedInUserId());
47 48
48 $this->assertEquals(1, count($entry->getTags())); 49 $this->assertEquals(3, count($entry->getTags()));
49 50
50 # tag already exists and already assigned 51 // tag already exists and already assigned
51 $client->submit($form, $data); 52 $client->submit($form, $data);
52 $this->assertEquals(302, $client->getResponse()->getStatusCode()); 53 $this->assertEquals(302, $client->getResponse()->getStatusCode());
53 54
@@ -56,9 +57,9 @@ class TagControllerTest extends WallabagCoreTestCase
56 ->getRepository('WallabagCoreBundle:Entry') 57 ->getRepository('WallabagCoreBundle:Entry')
57 ->find($entry->getId()); 58 ->find($entry->getId());
58 59
59 $this->assertEquals(1, count($newEntry->getTags())); 60 $this->assertEquals(3, count($newEntry->getTags()));
60 61
61 # tag already exists but still not assigned to this entry 62 // tag already exists but still not assigned to this entry
62 $data = [ 63 $data = [
63 'tag[label]' => 'foo', 64 'tag[label]' => 'foo',
64 ]; 65 ];
@@ -71,7 +72,7 @@ class TagControllerTest extends WallabagCoreTestCase
71 ->getRepository('WallabagCoreBundle:Entry') 72 ->getRepository('WallabagCoreBundle:Entry')
72 ->find($entry->getId()); 73 ->find($entry->getId());
73 74
74 $this->assertEquals(2, count($newEntry->getTags())); 75 $this->assertEquals(3, count($newEntry->getTags()));
75 } 76 }
76 77
77 public function testAddMultipleTagToEntry() 78 public function testAddMultipleTagToEntry()
@@ -82,7 +83,7 @@ class TagControllerTest extends WallabagCoreTestCase
82 $entry = $client->getContainer() 83 $entry = $client->getContainer()
83 ->get('doctrine.orm.entity_manager') 84 ->get('doctrine.orm.entity_manager')
84 ->getRepository('WallabagCoreBundle:Entry') 85 ->getRepository('WallabagCoreBundle:Entry')
85 ->findOneByUsernameAndNotArchived('admin'); 86 ->findByUrlAndUserId('http://0.0.0.0/entry2', $this->getLoggedInUserId());
86 87
87 $crawler = $client->request('GET', '/view/'.$entry->getId()); 88 $crawler = $client->request('GET', '/view/'.$entry->getId());
88 89
@@ -101,9 +102,13 @@ class TagControllerTest extends WallabagCoreTestCase
101 ->find($entry->getId()); 102 ->find($entry->getId());
102 103
103 $tags = $newEntry->getTags()->toArray(); 104 $tags = $newEntry->getTags()->toArray();
105 foreach ($tags as $key => $tag) {
106 $tags[$key] = $tag->getLabel();
107 }
108
104 $this->assertGreaterThanOrEqual(2, count($tags)); 109 $this->assertGreaterThanOrEqual(2, count($tags));
105 $this->assertNotEquals(false, array_search('foo2', $tags), 'Tag foo2 is assigned to the entry'); 110 $this->assertNotFalse(array_search('foo2', $tags), 'Tag foo2 is assigned to the entry');
106 $this->assertNotEquals(false, array_search('bar2', $tags), 'Tag bar2 is assigned to the entry'); 111 $this->assertNotFalse(array_search('bar2', $tags), 'Tag bar2 is assigned to the entry');
107 } 112 }
108 113
109 public function testRemoveTagFromEntry() 114 public function testRemoveTagFromEntry()
@@ -114,7 +119,7 @@ class TagControllerTest extends WallabagCoreTestCase
114 $entry = $client->getContainer() 119 $entry = $client->getContainer()
115 ->get('doctrine.orm.entity_manager') 120 ->get('doctrine.orm.entity_manager')
116 ->getRepository('WallabagCoreBundle:Entry') 121 ->getRepository('WallabagCoreBundle:Entry')
117 ->findOneByUsernameAndNotArchived('admin'); 122 ->findByUrlAndUserId('http://0.0.0.0/entry1', $this->getLoggedInUserId());
118 123
119 $tag = $client->getContainer() 124 $tag = $client->getContainer()
120 ->get('doctrine.orm.entity_manager') 125 ->get('doctrine.orm.entity_manager')
@@ -130,5 +135,48 @@ class TagControllerTest extends WallabagCoreTestCase
130 $client->request('GET', '/remove-tag/'.$entry->getId().'/'.$tag->getId()); 135 $client->request('GET', '/remove-tag/'.$entry->getId().'/'.$tag->getId());
131 136
132 $this->assertEquals(404, $client->getResponse()->getStatusCode()); 137 $this->assertEquals(404, $client->getResponse()->getStatusCode());
138
139 $tag = $client->getContainer()
140 ->get('doctrine.orm.entity_manager')
141 ->getRepository('WallabagCoreBundle:Tag')
142 ->findOneByLabel($this->tagName);
143
144 $this->assertNull($tag, $this->tagName.' was removed because it begun an orphan tag');
145 }
146
147 public function testShowEntriesForTagAction()
148 {
149 $this->logInAs('admin');
150 $client = $this->getClient();
151 $em = $client->getContainer()
152 ->get('doctrine.orm.entity_manager');
153
154 $tag = new Tag();
155 $tag->setLabel($this->tagName);
156
157 $entry = $client->getContainer()
158 ->get('doctrine.orm.entity_manager')
159 ->getRepository('WallabagCoreBundle:Entry')
160 ->findByUrlAndUserId('http://0.0.0.0/entry4', $this->getLoggedInUserId());
161
162 $tag->addEntry($entry);
163
164 $em->persist($entry);
165 $em->persist($tag);
166 $em->flush();
167
168 $tag = $client->getContainer()
169 ->get('doctrine.orm.entity_manager')
170 ->getRepository('WallabagCoreBundle:Tag')
171 ->findOneByEntryAndTagLabel($entry, $this->tagName);
172
173 $crawler = $client->request('GET', '/tag/list/'.$tag->getSlug());
174
175 $this->assertEquals(200, $client->getResponse()->getStatusCode());
176 $this->assertCount(1, $crawler->filter('[id*="entry-"]'));
177
178 $entry->removeTag($tag);
179 $em->remove($tag);
180 $em->flush();
133 } 181 }
134} 182}
diff --git a/tests/Wallabag/CoreBundle/EventListener/LocaleListenerTest.php b/tests/Wallabag/CoreBundle/EventListener/LocaleListenerTest.php
index 2a7f9390..078bb69a 100644
--- a/tests/Wallabag/CoreBundle/EventListener/LocaleListenerTest.php
+++ b/tests/Wallabag/CoreBundle/EventListener/LocaleListenerTest.php
@@ -15,7 +15,11 @@ class LocaleListenerTest extends \PHPUnit_Framework_TestCase
15{ 15{
16 private function getEvent(Request $request) 16 private function getEvent(Request $request)
17 { 17 {
18 return new GetResponseEvent($this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'), $request, HttpKernelInterface::MASTER_REQUEST); 18 $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')
19 ->disableOriginalConstructor()
20 ->getMock();
21
22 return new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
19 } 23 }
20 24
21 public function testWithoutSession() 25 public function testWithoutSession()
diff --git a/tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php b/tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php
index 7abb0737..5d772602 100644
--- a/tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php
+++ b/tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php
@@ -296,6 +296,29 @@ class ContentProxyTest extends \PHPUnit_Framework_TestCase
296 $this->assertEquals('tag2', $entry->getTags()[1]->getLabel()); 296 $this->assertEquals('tag2', $entry->getTags()[1]->getLabel());
297 } 297 }
298 298
299 public function testAssignTagsNotFlushed()
300 {
301 $graby = $this->getMockBuilder('Graby\Graby')
302 ->disableOriginalConstructor()
303 ->getMock();
304
305 $tagRepo = $this->getTagRepositoryMock();
306 $tagRepo->expects($this->never())
307 ->method('__call');
308
309 $proxy = new ContentProxy($graby, $this->getTaggerMock(), $tagRepo, $this->getLogger());
310
311 $tagEntity = new Tag();
312 $tagEntity->setLabel('tag1');
313
314 $entry = new Entry(new User());
315
316 $proxy->assignTagsToEntry($entry, 'tag1', [$tagEntity]);
317
318 $this->assertCount(1, $entry->getTags());
319 $this->assertEquals('tag1', $entry->getTags()[0]->getLabel());
320 }
321
299 private function getTaggerMock() 322 private function getTaggerMock()
300 { 323 {
301 return $this->getMockBuilder('Wallabag\CoreBundle\Helper\RuleBasedTagger') 324 return $this->getMockBuilder('Wallabag\CoreBundle\Helper\RuleBasedTagger')
diff --git a/tests/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverterTest.php b/tests/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverterTest.php
index e29b58b5..2e6fccfb 100644
--- a/tests/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverterTest.php
+++ b/tests/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverterTest.php
@@ -125,16 +125,14 @@ class UsernameRssTokenConverterTest extends \PHPUnit_Framework_TestCase
125 $this->assertTrue($converter->supports($params)); 125 $this->assertTrue($converter->supports($params));
126 } 126 }
127 127
128 /**
129 * @expectedException InvalidArgumentException
130 * @expectedExceptionMessage Route attribute is missing
131 */
132 public function testApplyEmptyRequest() 128 public function testApplyEmptyRequest()
133 { 129 {
134 $params = new ParamConverter([]); 130 $params = new ParamConverter([]);
135 $converter = new UsernameRssTokenConverter(); 131 $converter = new UsernameRssTokenConverter();
136 132
137 $converter->apply(new Request(), $params); 133 $res = $converter->apply(new Request(), $params);
134
135 $this->assertFalse($res);
138 } 136 }
139 137
140 /** 138 /**
diff --git a/tests/Wallabag/CoreBundle/Twig/WallabagExtensionTest.php b/tests/Wallabag/CoreBundle/Twig/WallabagExtensionTest.php
index 8ec2a75a..b1c8c946 100644
--- a/tests/Wallabag/CoreBundle/Twig/WallabagExtensionTest.php
+++ b/tests/Wallabag/CoreBundle/Twig/WallabagExtensionTest.php
@@ -8,7 +8,23 @@ class WallabagExtensionTest extends \PHPUnit_Framework_TestCase
8{ 8{
9 public function testRemoveWww() 9 public function testRemoveWww()
10 { 10 {
11 $extension = new WallabagExtension(); 11 $entryRepository = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
12 ->disableOriginalConstructor()
13 ->getMock();
14
15 $tagRepository = $this->getMockBuilder('Wallabag\CoreBundle\Repository\TagRepository')
16 ->disableOriginalConstructor()
17 ->getMock();
18
19 $tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')
20 ->disableOriginalConstructor()
21 ->getMock();
22
23 $translator = $this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')
24 ->disableOriginalConstructor()
25 ->getMock();
26
27 $extension = new WallabagExtension($entryRepository, $tagRepository, $tokenStorage, 0, $translator);
12 28
13 $this->assertEquals('lemonde.fr', $extension->removeWww('www.lemonde.fr')); 29 $this->assertEquals('lemonde.fr', $extension->removeWww('www.lemonde.fr'));
14 $this->assertEquals('lemonde.fr', $extension->removeWww('lemonde.fr')); 30 $this->assertEquals('lemonde.fr', $extension->removeWww('lemonde.fr'));
diff --git a/tests/Wallabag/CoreBundle/WallabagCoreTestCase.php b/tests/Wallabag/CoreBundle/WallabagCoreTestCase.php
index c0055888..7bf4b43c 100644
--- a/tests/Wallabag/CoreBundle/WallabagCoreTestCase.php
+++ b/tests/Wallabag/CoreBundle/WallabagCoreTestCase.php
@@ -80,4 +80,17 @@ abstract class WallabagCoreTestCase extends WebTestCase
80 80
81 throw new \RuntimeException('No logged in User.'); 81 throw new \RuntimeException('No logged in User.');
82 } 82 }
83
84 /**
85 * Check if Redis is installed.
86 * If not, mark test as skip.
87 */
88 protected function checkRedis()
89 {
90 try {
91 $this->client->getContainer()->get('wallabag_core.redis.client')->connect();
92 } catch (\Exception $e) {
93 $this->markTestSkipped('Redis is not installed/activated');
94 }
95 }
83} 96}
diff --git a/tests/Wallabag/ImportBundle/Command/ImportCommandTest.php b/tests/Wallabag/ImportBundle/Command/ImportCommandTest.php
new file mode 100644
index 00000000..7be1eb18
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/Command/ImportCommandTest.php
@@ -0,0 +1,85 @@
1<?php
2
3namespace Tests\Wallabag\ImportBundle\Command;
4
5use Symfony\Bundle\FrameworkBundle\Console\Application;
6use Symfony\Component\Console\Tester\CommandTester;
7use Wallabag\ImportBundle\Command\ImportCommand;
8use Tests\Wallabag\CoreBundle\WallabagCoreTestCase;
9
10class ImportCommandTest extends WallabagCoreTestCase
11{
12 /**
13 * @expectedException Symfony\Component\Console\Exception\RuntimeException
14 * @expectedExceptionMessage Not enough arguments
15 */
16 public function testRunImportCommandWithoutArguments()
17 {
18 $application = new Application($this->getClient()->getKernel());
19 $application->add(new ImportCommand());
20
21 $command = $application->find('wallabag:import');
22
23 $tester = new CommandTester($command);
24 $tester->execute([
25 'command' => $command->getName(),
26 ]);
27 }
28
29 /**
30 * @expectedException Symfony\Component\Config\Definition\Exception\Exception
31 * @expectedExceptionMessage not found
32 */
33 public function testRunImportCommandWithoutFilepath()
34 {
35 $application = new Application($this->getClient()->getKernel());
36 $application->add(new ImportCommand());
37
38 $command = $application->find('wallabag:import');
39
40 $tester = new CommandTester($command);
41 $tester->execute([
42 'command' => $command->getName(),
43 'userId' => 1,
44 'filepath' => 1,
45 ]);
46 }
47
48 /**
49 * @expectedException Symfony\Component\Config\Definition\Exception\Exception
50 * @expectedExceptionMessage User with id
51 */
52 public function testRunImportCommandWithoutUserId()
53 {
54 $application = new Application($this->getClient()->getKernel());
55 $application->add(new ImportCommand());
56
57 $command = $application->find('wallabag:import');
58
59 $tester = new CommandTester($command);
60 $tester->execute([
61 'command' => $command->getName(),
62 'userId' => 0,
63 'filepath' => './',
64 ]);
65 }
66
67 public function testRunImportCommand()
68 {
69 $application = new Application($this->getClient()->getKernel());
70 $application->add(new ImportCommand());
71
72 $command = $application->find('wallabag:import');
73
74 $tester = new CommandTester($command);
75 $tester->execute([
76 'command' => $command->getName(),
77 'userId' => 1,
78 'filepath' => $application->getKernel()->getContainer()->getParameter('kernel.root_dir').'/../tests/Wallabag/ImportBundle/fixtures/wallabag-v2-read.json',
79 '--importer' => 'v2',
80 ]);
81
82 $this->assertContains('imported', $tester->getDisplay());
83 $this->assertContains('already saved', $tester->getDisplay());
84 }
85}
diff --git a/tests/Wallabag/ImportBundle/Command/RedisWorkerCommandTest.php b/tests/Wallabag/ImportBundle/Command/RedisWorkerCommandTest.php
new file mode 100644
index 00000000..74952847
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/Command/RedisWorkerCommandTest.php
@@ -0,0 +1,74 @@
1<?php
2
3namespace Tests\Wallabag\ImportBundle\Command;
4
5use Symfony\Bundle\FrameworkBundle\Console\Application;
6use Symfony\Component\Console\Tester\CommandTester;
7use Wallabag\ImportBundle\Command\RedisWorkerCommand;
8use Tests\Wallabag\CoreBundle\WallabagCoreTestCase;
9use M6Web\Component\RedisMock\RedisMockFactory;
10
11class RedisWorkerCommandTest extends WallabagCoreTestCase
12{
13 /**
14 * @expectedException Symfony\Component\Console\Exception\RuntimeException
15 * @expectedExceptionMessage Not enough arguments (missing: "serviceName")
16 */
17 public function testRunRedisWorkerCommandWithoutArguments()
18 {
19 $application = new Application($this->getClient()->getKernel());
20 $application->add(new RedisWorkerCommand());
21
22 $command = $application->find('wallabag:import:redis-worker');
23
24 $tester = new CommandTester($command);
25 $tester->execute([
26 'command' => $command->getName(),
27 ]);
28 }
29
30 /**
31 * @expectedException Symfony\Component\Config\Definition\Exception\Exception
32 * @expectedExceptionMessage No queue or consumer found for service name
33 */
34 public function testRunRedisWorkerCommandWithBadService()
35 {
36 $application = new Application($this->getClient()->getKernel());
37 $application->add(new RedisWorkerCommand());
38
39 $command = $application->find('wallabag:import:redis-worker');
40
41 $tester = new CommandTester($command);
42 $tester->execute([
43 'command' => $command->getName(),
44 'serviceName' => 'YOMONSERVICE',
45 ]);
46 }
47
48 public function testRunRedisWorkerCommand()
49 {
50 $application = new Application($this->getClient()->getKernel());
51 $application->add(new RedisWorkerCommand());
52
53 $factory = new RedisMockFactory();
54 $redisMock = $factory->getAdapter('Predis\Client', true);
55
56 $application->getKernel()->getContainer()->set('wallabag_core.redis.client', $redisMock);
57
58 // put a fake message in the queue so the worker will stop after reading that message
59 // instead of waiting for others
60 $redisMock->lpush('wallabag.import.readability', '{}');
61
62 $command = $application->find('wallabag:import:redis-worker');
63
64 $tester = new CommandTester($command);
65 $tester->execute([
66 'command' => $command->getName(),
67 'serviceName' => 'readability',
68 '--maxIterations' => 1,
69 ]);
70
71 $this->assertContains('Worker started at', $tester->getDisplay());
72 $this->assertContains('Waiting for message', $tester->getDisplay());
73 }
74}
diff --git a/tests/Wallabag/ImportBundle/Consumer/AMQPEntryConsumerTest.php b/tests/Wallabag/ImportBundle/Consumer/AMQPEntryConsumerTest.php
new file mode 100644
index 00000000..a3263771
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/Consumer/AMQPEntryConsumerTest.php
@@ -0,0 +1,225 @@
1<?php
2
3namespace Tests\Wallabag\ImportBundle\Consumer\AMQP;
4
5use Wallabag\ImportBundle\Consumer\AMQPEntryConsumer;
6use PhpAmqpLib\Message\AMQPMessage;
7use Wallabag\UserBundle\Entity\User;
8use Wallabag\CoreBundle\Entity\Entry;
9
10class AMQPEntryConsumerTest extends \PHPUnit_Framework_TestCase
11{
12 public function testMessageOk()
13 {
14 $em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
15 ->disableOriginalConstructor()
16 ->getMock();
17
18 $em
19 ->expects($this->once())
20 ->method('flush');
21
22 $em
23 ->expects($this->exactly(2))
24 ->method('clear');
25
26 $body = <<<'JSON'
27{
28 "item_id": "1402935436",
29 "resolved_id": "1402935436",
30 "given_url": "http://mashable.com/2016/09/04/leslie-jones-back-on-twitter-after-hack/?utm_campaign=Mash-Prod-RSS-Feedburner-All-Partial&utm_cid=Mash-Prod-RSS-Feedburner-All-Partial",
31 "given_title": "Leslie Jones is back on Twitter and her comeback tweet rules",
32 "favorite": "0",
33 "status": "0",
34 "time_added": "1473020899",
35 "time_updated": "1473020899",
36 "time_read": "0",
37 "time_favorited": "0",
38 "sort_id": 0,
39 "resolved_title": "Leslie Jones is back on Twitter and her comeback tweet rules",
40 "resolved_url": "http://mashable.com/2016/09/04/leslie-jones-back-on-twitter-after-hack/?utm_campaign=Mash-Prod-RSS-Feedburner-All-Partial&utm_cid=Mash-Prod-RSS-Feedburner-All-Partial",
41 "excerpt": "Leslie Jones is back to communicating with her adoring public on Twitter after cowardly hacker-trolls drove her away, probably to compensate for their own failings. It all started with a mic drop ...",
42 "is_article": "1",
43 "is_index": "0",
44 "has_video": "0",
45 "has_image": "1",
46 "word_count": "200",
47 "tags": {
48 "ifttt": {
49 "item_id": "1402935436",
50 "tag": "ifttt"
51 },
52 "mashable": {
53 "item_id": "1402935436",
54 "tag": "mashable"
55 }
56 },
57 "authors": {
58 "2484273": {
59 "item_id": "1402935436",
60 "author_id": "2484273",
61 "name": "Adam Rosenberg",
62 "url": "http://mashable.com/author/adam-rosenberg/"
63 }
64 },
65 "image": {
66 "item_id": "1402935436",
67 "src": "http://i.amz.mshcdn.com/i-V5cS6_sDqFABaVR0hVSBJqG_w=/950x534/https%3A%2F%2Fblueprint-api-production.s3.amazonaws.com%2Fuploads%2Fcard%2Fimage%2F199899%2Fleslie_jones_war_dogs.jpg",
68 "width": "0",
69 "height": "0"
70 },
71 "images": {
72 "1": {
73 "item_id": "1402935436",
74 "image_id": "1",
75 "src": "http://i.amz.mshcdn.com/i-V5cS6_sDqFABaVR0hVSBJqG_w=/950x534/https%3A%2F%2Fblueprint-api-production.s3.amazonaws.com%2Fuploads%2Fcard%2Fimage%2F199899%2Fleslie_jones_war_dogs.jpg",
76 "width": "0",
77 "height": "0",
78 "credit": "Image: Steve Eichner/NameFace/Sipa USA",
79 "caption": ""
80 }
81 },
82 "userId": 1
83}
84JSON;
85
86 $user = new User();
87 $entry = new Entry($user);
88
89 $userRepository = $this->getMockBuilder('Wallabag\UserBundle\Repository\UserRepository')
90 ->disableOriginalConstructor()
91 ->getMock();
92
93 $userRepository
94 ->expects($this->once())
95 ->method('find')
96 // userId from the body json above
97 ->with(1)
98 ->willReturn($user);
99
100 $import = $this->getMockBuilder('Wallabag\ImportBundle\Import\AbstractImport')
101 ->disableOriginalConstructor()
102 ->getMock();
103
104 $import
105 ->expects($this->once())
106 ->method('setUser')
107 ->with($user);
108
109 $import
110 ->expects($this->once())
111 ->method('parseEntry')
112 ->with(json_decode($body, true))
113 ->willReturn($entry);
114
115 $consumer = new AMQPEntryConsumer(
116 $em,
117 $userRepository,
118 $import
119 );
120
121 $message = new AMQPMessage($body);
122
123 $consumer->execute($message);
124 }
125
126 public function testMessageWithBadUser()
127 {
128 $em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
129 ->disableOriginalConstructor()
130 ->getMock();
131
132 $em
133 ->expects($this->never())
134 ->method('flush');
135
136 $em
137 ->expects($this->never())
138 ->method('clear');
139
140 $body = '{ "userId": 123 }';
141
142 $user = new User();
143 $entry = new Entry($user);
144
145 $userRepository = $this->getMockBuilder('Wallabag\UserBundle\Repository\UserRepository')
146 ->disableOriginalConstructor()
147 ->getMock();
148
149 $userRepository
150 ->expects($this->once())
151 ->method('find')
152 // userId from the body json above
153 ->with(123)
154 ->willReturn(null);
155
156 $import = $this->getMockBuilder('Wallabag\ImportBundle\Import\AbstractImport')
157 ->disableOriginalConstructor()
158 ->getMock();
159
160 $consumer = new AMQPEntryConsumer(
161 $em,
162 $userRepository,
163 $import
164 );
165
166 $message = new AMQPMessage($body);
167
168 $consumer->execute($message);
169 }
170
171 public function testMessageWithEntryProcessed()
172 {
173 $em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
174 ->disableOriginalConstructor()
175 ->getMock();
176
177 $em
178 ->expects($this->never())
179 ->method('flush');
180
181 $em
182 ->expects($this->never())
183 ->method('clear');
184
185 $body = '{ "userId": 123 }';
186
187 $user = new User();
188
189 $userRepository = $this->getMockBuilder('Wallabag\UserBundle\Repository\UserRepository')
190 ->disableOriginalConstructor()
191 ->getMock();
192
193 $userRepository
194 ->expects($this->once())
195 ->method('find')
196 // userId from the body json above
197 ->with(123)
198 ->willReturn($user);
199
200 $import = $this->getMockBuilder('Wallabag\ImportBundle\Import\AbstractImport')
201 ->disableOriginalConstructor()
202 ->getMock();
203
204 $import
205 ->expects($this->once())
206 ->method('setUser')
207 ->with($user);
208
209 $import
210 ->expects($this->once())
211 ->method('parseEntry')
212 ->with(json_decode($body, true))
213 ->willReturn(null);
214
215 $consumer = new AMQPEntryConsumer(
216 $em,
217 $userRepository,
218 $import
219 );
220
221 $message = new AMQPMessage($body);
222
223 $consumer->execute($message);
224 }
225}
diff --git a/tests/Wallabag/ImportBundle/Consumer/RedisEntryConsumerTest.php b/tests/Wallabag/ImportBundle/Consumer/RedisEntryConsumerTest.php
new file mode 100644
index 00000000..5e8ee41d
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/Consumer/RedisEntryConsumerTest.php
@@ -0,0 +1,225 @@
1<?php
2
3namespace Tests\Wallabag\ImportBundle\Consumer\AMQP;
4
5use Wallabag\ImportBundle\Consumer\RedisEntryConsumer;
6use Wallabag\UserBundle\Entity\User;
7use Wallabag\CoreBundle\Entity\Entry;
8
9class RedisEntryConsumerTest extends \PHPUnit_Framework_TestCase
10{
11 public function testMessageOk()
12 {
13 $em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
14 ->disableOriginalConstructor()
15 ->getMock();
16
17 $em
18 ->expects($this->once())
19 ->method('flush');
20
21 $em
22 ->expects($this->exactly(2))
23 ->method('clear');
24
25 $body = <<<'JSON'
26{
27 "item_id": "1402935436",
28 "resolved_id": "1402935436",
29 "given_url": "http://mashable.com/2016/09/04/leslie-jones-back-on-twitter-after-hack/?utm_campaign=Mash-Prod-RSS-Feedburner-All-Partial&utm_cid=Mash-Prod-RSS-Feedburner-All-Partial",
30 "given_title": "Leslie Jones is back on Twitter and her comeback tweet rules",
31 "favorite": "0",
32 "status": "0",
33 "time_added": "1473020899",
34 "time_updated": "1473020899",
35 "time_read": "0",
36 "time_favorited": "0",
37 "sort_id": 0,
38 "resolved_title": "Leslie Jones is back on Twitter and her comeback tweet rules",
39 "resolved_url": "http://mashable.com/2016/09/04/leslie-jones-back-on-twitter-after-hack/?utm_campaign=Mash-Prod-RSS-Feedburner-All-Partial&utm_cid=Mash-Prod-RSS-Feedburner-All-Partial",
40 "excerpt": "Leslie Jones is back to communicating with her adoring public on Twitter after cowardly hacker-trolls drove her away, probably to compensate for their own failings. It all started with a mic drop ...",
41 "is_article": "1",
42 "is_index": "0",
43 "has_video": "0",
44 "has_image": "1",
45 "word_count": "200",
46 "tags": {
47 "ifttt": {
48 "item_id": "1402935436",
49 "tag": "ifttt"
50 },
51 "mashable": {
52 "item_id": "1402935436",
53 "tag": "mashable"
54 }
55 },
56 "authors": {
57 "2484273": {
58 "item_id": "1402935436",
59 "author_id": "2484273",
60 "name": "Adam Rosenberg",
61 "url": "http://mashable.com/author/adam-rosenberg/"
62 }
63 },
64 "image": {
65 "item_id": "1402935436",
66 "src": "http://i.amz.mshcdn.com/i-V5cS6_sDqFABaVR0hVSBJqG_w=/950x534/https%3A%2F%2Fblueprint-api-production.s3.amazonaws.com%2Fuploads%2Fcard%2Fimage%2F199899%2Fleslie_jones_war_dogs.jpg",
67 "width": "0",
68 "height": "0"
69 },
70 "images": {
71 "1": {
72 "item_id": "1402935436",
73 "image_id": "1",
74 "src": "http://i.amz.mshcdn.com/i-V5cS6_sDqFABaVR0hVSBJqG_w=/950x534/https%3A%2F%2Fblueprint-api-production.s3.amazonaws.com%2Fuploads%2Fcard%2Fimage%2F199899%2Fleslie_jones_war_dogs.jpg",
75 "width": "0",
76 "height": "0",
77 "credit": "Image: Steve Eichner/NameFace/Sipa USA",
78 "caption": ""
79 }
80 },
81 "userId": 1
82}
83JSON;
84
85 $user = new User();
86 $entry = new Entry($user);
87
88 $userRepository = $this->getMockBuilder('Wallabag\UserBundle\Repository\UserRepository')
89 ->disableOriginalConstructor()
90 ->getMock();
91
92 $userRepository
93 ->expects($this->once())
94 ->method('find')
95 // userId from the body json above
96 ->with(1)
97 ->willReturn($user);
98
99 $import = $this->getMockBuilder('Wallabag\ImportBundle\Import\AbstractImport')
100 ->disableOriginalConstructor()
101 ->getMock();
102
103 $import
104 ->expects($this->once())
105 ->method('setUser')
106 ->with($user);
107
108 $import
109 ->expects($this->once())
110 ->method('parseEntry')
111 ->with(json_decode($body, true))
112 ->willReturn($entry);
113
114 $consumer = new RedisEntryConsumer(
115 $em,
116 $userRepository,
117 $import
118 );
119
120 $res = $consumer->manage($body);
121
122 $this->assertTrue($res);
123 }
124
125 public function testMessageWithBadUser()
126 {
127 $em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
128 ->disableOriginalConstructor()
129 ->getMock();
130
131 $em
132 ->expects($this->never())
133 ->method('flush');
134
135 $em
136 ->expects($this->never())
137 ->method('clear');
138
139 $body = '{ "userId": 123 }';
140
141 $user = new User();
142 $entry = new Entry($user);
143
144 $userRepository = $this->getMockBuilder('Wallabag\UserBundle\Repository\UserRepository')
145 ->disableOriginalConstructor()
146 ->getMock();
147
148 $userRepository
149 ->expects($this->once())
150 ->method('find')
151 // userId from the body json above
152 ->with(123)
153 ->willReturn(null);
154
155 $import = $this->getMockBuilder('Wallabag\ImportBundle\Import\AbstractImport')
156 ->disableOriginalConstructor()
157 ->getMock();
158
159 $consumer = new RedisEntryConsumer(
160 $em,
161 $userRepository,
162 $import
163 );
164
165 $res = $consumer->manage($body);
166
167 $this->assertFalse($res);
168 }
169
170 public function testMessageWithEntryProcessed()
171 {
172 $em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
173 ->disableOriginalConstructor()
174 ->getMock();
175
176 $em
177 ->expects($this->never())
178 ->method('flush');
179
180 $em
181 ->expects($this->never())
182 ->method('clear');
183
184 $body = '{ "userId": 123 }';
185
186 $user = new User();
187
188 $userRepository = $this->getMockBuilder('Wallabag\UserBundle\Repository\UserRepository')
189 ->disableOriginalConstructor()
190 ->getMock();
191
192 $userRepository
193 ->expects($this->once())
194 ->method('find')
195 // userId from the body json above
196 ->with(123)
197 ->willReturn($user);
198
199 $import = $this->getMockBuilder('Wallabag\ImportBundle\Import\AbstractImport')
200 ->disableOriginalConstructor()
201 ->getMock();
202
203 $import
204 ->expects($this->once())
205 ->method('setUser')
206 ->with($user);
207
208 $import
209 ->expects($this->once())
210 ->method('parseEntry')
211 ->with(json_decode($body, true))
212 ->willReturn(null);
213
214 $consumer = new RedisEntryConsumer(
215 $em,
216 $userRepository,
217 $import
218 );
219
220 $res = $consumer->manage($body);
221
222 $this->assertFalse($res);
223 $this->assertFalse($consumer->isStopJob($body));
224 }
225}
diff --git a/tests/Wallabag/ImportBundle/Controller/ChromeControllerTest.php b/tests/Wallabag/ImportBundle/Controller/ChromeControllerTest.php
new file mode 100644
index 00000000..c0417bbe
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/Controller/ChromeControllerTest.php
@@ -0,0 +1,153 @@
1<?php
2
3namespace Tests\Wallabag\ImportBundle\Controller;
4
5use Tests\Wallabag\CoreBundle\WallabagCoreTestCase;
6use Symfony\Component\HttpFoundation\File\UploadedFile;
7
8class ChromeControllerTest extends WallabagCoreTestCase
9{
10 public function testImportChrome()
11 {
12 $this->logInAs('admin');
13 $client = $this->getClient();
14
15 $crawler = $client->request('GET', '/import/chrome');
16
17 $this->assertEquals(200, $client->getResponse()->getStatusCode());
18 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
19 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
20 }
21
22 public function testImportChromeWithRabbitEnabled()
23 {
24 $this->logInAs('admin');
25 $client = $this->getClient();
26
27 $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 1);
28
29 $crawler = $client->request('GET', '/import/chrome');
30
31 $this->assertEquals(200, $client->getResponse()->getStatusCode());
32 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
33 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
34
35 $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 0);
36 }
37
38 public function testImportChromeBadFile()
39 {
40 $this->logInAs('admin');
41 $client = $this->getClient();
42
43 $crawler = $client->request('GET', '/import/chrome');
44 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
45
46 $data = [
47 'upload_import_file[file]' => '',
48 ];
49
50 $client->submit($form, $data);
51
52 $this->assertEquals(200, $client->getResponse()->getStatusCode());
53 }
54
55 public function testImportChromeWithRedisEnabled()
56 {
57 $this->checkRedis();
58 $this->logInAs('admin');
59 $client = $this->getClient();
60 $client->getContainer()->get('craue_config')->set('import_with_redis', 1);
61
62 $crawler = $client->request('GET', '/import/chrome');
63
64 $this->assertEquals(200, $client->getResponse()->getStatusCode());
65 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
66 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
67
68 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
69
70 $file = new UploadedFile(__DIR__.'/../fixtures/chrome-bookmarks', 'Bookmarks');
71
72 $data = [
73 'upload_import_file[file]' => $file,
74 ];
75
76 $client->submit($form, $data);
77
78 $this->assertEquals(302, $client->getResponse()->getStatusCode());
79
80 $crawler = $client->followRedirect();
81
82 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
83 $this->assertContains('flashes.import.notice.summary', $body[0]);
84
85 $this->assertNotEmpty($client->getContainer()->get('wallabag_core.redis.client')->lpop('wallabag.import.chrome'));
86
87 $client->getContainer()->get('craue_config')->set('import_with_redis', 0);
88 }
89
90 public function testImportWallabagWithChromeFile()
91 {
92 $this->logInAs('admin');
93 $client = $this->getClient();
94
95 $crawler = $client->request('GET', '/import/chrome');
96 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
97
98 $file = new UploadedFile(__DIR__.'/../fixtures/chrome-bookmarks', 'Bookmarks');
99
100 $data = [
101 'upload_import_file[file]' => $file,
102 ];
103
104 $client->submit($form, $data);
105
106 $this->assertEquals(302, $client->getResponse()->getStatusCode());
107
108 $crawler = $client->followRedirect();
109
110 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
111 $this->assertContains('flashes.import.notice.summary', $body[0]);
112
113 $content = $client->getContainer()
114 ->get('doctrine.orm.entity_manager')
115 ->getRepository('WallabagCoreBundle:Entry')
116 ->findByUrlAndUserId(
117 'http://www.usinenouvelle.com/article/la-multiplication-des-chefs-de-projet-est-une-catastrophe-manageriale-majeure-affirme-le-sociologue-francois-dupuy.N307730',
118 $this->getLoggedInUserId()
119 );
120
121 $this->assertNotEmpty($content->getPreviewPicture());
122 $this->assertNotEmpty($content->getLanguage());
123 $this->assertEquals(0, count($content->getTags()));
124
125 $createdAt = $content->getCreatedAt();
126 $this->assertEquals('2011', $createdAt->format('Y'));
127 $this->assertEquals('07', $createdAt->format('m'));
128 }
129
130 public function testImportWallabagWithEmptyFile()
131 {
132 $this->logInAs('admin');
133 $client = $this->getClient();
134
135 $crawler = $client->request('GET', '/import/chrome');
136 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
137
138 $file = new UploadedFile(__DIR__.'/../fixtures/test.txt', 'test.txt');
139
140 $data = [
141 'upload_import_file[file]' => $file,
142 ];
143
144 $client->submit($form, $data);
145
146 $this->assertEquals(302, $client->getResponse()->getStatusCode());
147
148 $crawler = $client->followRedirect();
149
150 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
151 $this->assertContains('flashes.import.notice.failed', $body[0]);
152 }
153}
diff --git a/tests/Wallabag/ImportBundle/Controller/FirefoxControllerTest.php b/tests/Wallabag/ImportBundle/Controller/FirefoxControllerTest.php
new file mode 100644
index 00000000..6154ae8d
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/Controller/FirefoxControllerTest.php
@@ -0,0 +1,166 @@
1<?php
2
3namespace Tests\Wallabag\ImportBundle\Controller;
4
5use Tests\Wallabag\CoreBundle\WallabagCoreTestCase;
6use Symfony\Component\HttpFoundation\File\UploadedFile;
7
8class FirefoxControllerTest extends WallabagCoreTestCase
9{
10 public function testImportFirefox()
11 {
12 $this->logInAs('admin');
13 $client = $this->getClient();
14
15 $crawler = $client->request('GET', '/import/firefox');
16
17 $this->assertEquals(200, $client->getResponse()->getStatusCode());
18 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
19 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
20 }
21
22 public function testImportFirefoxWithRabbitEnabled()
23 {
24 $this->logInAs('admin');
25 $client = $this->getClient();
26
27 $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 1);
28
29 $crawler = $client->request('GET', '/import/firefox');
30
31 $this->assertEquals(200, $client->getResponse()->getStatusCode());
32 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
33 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
34
35 $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 0);
36 }
37
38 public function testImportFirefoxBadFile()
39 {
40 $this->logInAs('admin');
41 $client = $this->getClient();
42
43 $crawler = $client->request('GET', '/import/firefox');
44 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
45
46 $data = [
47 'upload_import_file[file]' => '',
48 ];
49
50 $client->submit($form, $data);
51
52 $this->assertEquals(200, $client->getResponse()->getStatusCode());
53 }
54
55 public function testImportFirefoxWithRedisEnabled()
56 {
57 $this->checkRedis();
58 $this->logInAs('admin');
59 $client = $this->getClient();
60 $client->getContainer()->get('craue_config')->set('import_with_redis', 1);
61
62 $crawler = $client->request('GET', '/import/firefox');
63
64 $this->assertEquals(200, $client->getResponse()->getStatusCode());
65 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
66 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
67
68 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
69
70 $file = new UploadedFile(__DIR__.'/../fixtures/firefox-bookmarks.json', 'Bookmarks');
71
72 $data = [
73 'upload_import_file[file]' => $file,
74 ];
75
76 $client->submit($form, $data);
77
78 $this->assertEquals(302, $client->getResponse()->getStatusCode());
79
80 $crawler = $client->followRedirect();
81
82 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
83 $this->assertContains('flashes.import.notice.summary', $body[0]);
84
85 $this->assertNotEmpty($client->getContainer()->get('wallabag_core.redis.client')->lpop('wallabag.import.firefox'));
86
87 $client->getContainer()->get('craue_config')->set('import_with_redis', 0);
88 }
89
90 public function testImportWallabagWithFirefoxFile()
91 {
92 $this->logInAs('admin');
93 $client = $this->getClient();
94
95 $crawler = $client->request('GET', '/import/firefox');
96 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
97
98 $file = new UploadedFile(__DIR__.'/../fixtures/firefox-bookmarks.json', 'Bookmarks');
99
100 $data = [
101 'upload_import_file[file]' => $file,
102 ];
103
104 $client->submit($form, $data);
105
106 $this->assertEquals(302, $client->getResponse()->getStatusCode());
107
108 $crawler = $client->followRedirect();
109
110 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
111 $this->assertContains('flashes.import.notice.summary', $body[0]);
112
113 $content = $client->getContainer()
114 ->get('doctrine.orm.entity_manager')
115 ->getRepository('WallabagCoreBundle:Entry')
116 ->findByUrlAndUserId(
117 'http://lexpansion.lexpress.fr/high-tech/orange-offre-un-meilleur-reseau-mobile-que-bouygues-et-sfr-free-derriere_1811554.html',
118 $this->getLoggedInUserId()
119 );
120
121 $this->assertNotEmpty($content->getMimetype());
122 $this->assertNotEmpty($content->getPreviewPicture());
123 $this->assertNotEmpty($content->getLanguage());
124 $this->assertEquals(2, count($content->getTags()));
125
126 $content = $client->getContainer()
127 ->get('doctrine.orm.entity_manager')
128 ->getRepository('WallabagCoreBundle:Entry')
129 ->findByUrlAndUserId(
130 'http://stackoverflow.com/questions/15017163/parser-for-exported-bookmarks-html-file-of-google-chrome-and-mozilla-in-java',
131 $this->getLoggedInUserId()
132 );
133
134 $this->assertNotEmpty($content->getMimetype());
135 $this->assertNotEmpty($content->getPreviewPicture());
136 $this->assertEmpty($content->getLanguage());
137
138 $createdAt = $content->getCreatedAt();
139 $this->assertEquals('2013', $createdAt->format('Y'));
140 $this->assertEquals('12', $createdAt->format('m'));
141 }
142
143 public function testImportWallabagWithEmptyFile()
144 {
145 $this->logInAs('admin');
146 $client = $this->getClient();
147
148 $crawler = $client->request('GET', '/import/firefox');
149 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
150
151 $file = new UploadedFile(__DIR__.'/../fixtures/test.txt', 'test.txt');
152
153 $data = [
154 'upload_import_file[file]' => $file,
155 ];
156
157 $client->submit($form, $data);
158
159 $this->assertEquals(302, $client->getResponse()->getStatusCode());
160
161 $crawler = $client->followRedirect();
162
163 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
164 $this->assertContains('flashes.import.notice.failed', $body[0]);
165 }
166}
diff --git a/tests/Wallabag/ImportBundle/Controller/ImportControllerTest.php b/tests/Wallabag/ImportBundle/Controller/ImportControllerTest.php
index 96b5300b..0bc40bdd 100644
--- a/tests/Wallabag/ImportBundle/Controller/ImportControllerTest.php
+++ b/tests/Wallabag/ImportBundle/Controller/ImportControllerTest.php
@@ -24,6 +24,6 @@ class ImportControllerTest extends WallabagCoreTestCase
24 $crawler = $client->request('GET', '/import/'); 24 $crawler = $client->request('GET', '/import/');
25 25
26 $this->assertEquals(200, $client->getResponse()->getStatusCode()); 26 $this->assertEquals(200, $client->getResponse()->getStatusCode());
27 $this->assertEquals(3, $crawler->filter('blockquote')->count()); 27 $this->assertEquals(7, $crawler->filter('blockquote')->count());
28 } 28 }
29} 29}
diff --git a/tests/Wallabag/ImportBundle/Controller/InstapaperControllerTest.php b/tests/Wallabag/ImportBundle/Controller/InstapaperControllerTest.php
new file mode 100644
index 00000000..9df08e75
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/Controller/InstapaperControllerTest.php
@@ -0,0 +1,196 @@
1<?php
2
3namespace Tests\Wallabag\ImportBundle\Controller;
4
5use Tests\Wallabag\CoreBundle\WallabagCoreTestCase;
6use Symfony\Component\HttpFoundation\File\UploadedFile;
7
8class InstapaperControllerTest extends WallabagCoreTestCase
9{
10 public function testImportInstapaper()
11 {
12 $this->logInAs('admin');
13 $client = $this->getClient();
14
15 $crawler = $client->request('GET', '/import/instapaper');
16
17 $this->assertEquals(200, $client->getResponse()->getStatusCode());
18 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
19 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
20 }
21
22 public function testImportInstapaperWithRabbitEnabled()
23 {
24 $this->logInAs('admin');
25 $client = $this->getClient();
26
27 $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 1);
28
29 $crawler = $client->request('GET', '/import/instapaper');
30
31 $this->assertEquals(200, $client->getResponse()->getStatusCode());
32 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
33 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
34
35 $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 0);
36 }
37
38 public function testImportInstapaperBadFile()
39 {
40 $this->logInAs('admin');
41 $client = $this->getClient();
42
43 $crawler = $client->request('GET', '/import/instapaper');
44 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
45
46 $data = [
47 'upload_import_file[file]' => '',
48 ];
49
50 $client->submit($form, $data);
51
52 $this->assertEquals(200, $client->getResponse()->getStatusCode());
53 }
54
55 public function testImportInstapaperWithRedisEnabled()
56 {
57 $this->checkRedis();
58 $this->logInAs('admin');
59 $client = $this->getClient();
60 $client->getContainer()->get('craue_config')->set('import_with_redis', 1);
61
62 $crawler = $client->request('GET', '/import/instapaper');
63
64 $this->assertEquals(200, $client->getResponse()->getStatusCode());
65 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
66 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
67
68 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
69
70 $file = new UploadedFile(__DIR__.'/../fixtures/instapaper-export.csv', 'instapaper.csv');
71
72 $data = [
73 'upload_import_file[file]' => $file,
74 ];
75
76 $client->submit($form, $data);
77
78 $this->assertEquals(302, $client->getResponse()->getStatusCode());
79
80 $crawler = $client->followRedirect();
81
82 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
83 $this->assertContains('flashes.import.notice.summary', $body[0]);
84
85 $this->assertNotEmpty($client->getContainer()->get('wallabag_core.redis.client')->lpop('wallabag.import.instapaper'));
86
87 $client->getContainer()->get('craue_config')->set('import_with_redis', 0);
88 }
89
90 public function testImportInstapaperWithFile()
91 {
92 $this->logInAs('admin');
93 $client = $this->getClient();
94
95 $crawler = $client->request('GET', '/import/instapaper');
96 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
97
98 $file = new UploadedFile(__DIR__.'/../fixtures/instapaper-export.csv', 'instapaper.csv');
99
100 $data = [
101 'upload_import_file[file]' => $file,
102 ];
103
104 $client->submit($form, $data);
105
106 $this->assertEquals(302, $client->getResponse()->getStatusCode());
107
108 $crawler = $client->followRedirect();
109
110 $content = $client->getContainer()
111 ->get('doctrine.orm.entity_manager')
112 ->getRepository('WallabagCoreBundle:Entry')
113 ->findByUrlAndUserId(
114 'http://www.liberation.fr/societe/2012/12/06/baumettes-un-tour-en-cellule_865551',
115 $this->getLoggedInUserId()
116 );
117
118 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
119 $this->assertContains('flashes.import.notice.summary', $body[0]);
120
121 $this->assertNotEmpty($content->getMimetype());
122 $this->assertNotEmpty($content->getPreviewPicture());
123 $this->assertNotEmpty($content->getLanguage());
124 $this->assertEquals(0, count($content->getTags()));
125 $this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
126 }
127
128 public function testImportInstapaperWithFileAndMarkAllAsRead()
129 {
130 $this->logInAs('admin');
131 $client = $this->getClient();
132
133 $crawler = $client->request('GET', '/import/instapaper');
134 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
135
136 $file = new UploadedFile(__DIR__.'/../fixtures/instapaper-export.csv', 'instapaper-read.csv');
137
138 $data = [
139 'upload_import_file[file]' => $file,
140 'upload_import_file[mark_as_read]' => 1,
141 ];
142
143 $client->submit($form, $data);
144
145 $this->assertEquals(302, $client->getResponse()->getStatusCode());
146
147 $crawler = $client->followRedirect();
148
149 $content1 = $client->getContainer()
150 ->get('doctrine.orm.entity_manager')
151 ->getRepository('WallabagCoreBundle:Entry')
152 ->findByUrlAndUserId(
153 'https://redditblog.com/2016/09/20/amp-and-reactredux/',
154 $this->getLoggedInUserId()
155 );
156
157 $this->assertTrue($content1->isArchived());
158
159 $content2 = $client->getContainer()
160 ->get('doctrine.orm.entity_manager')
161 ->getRepository('WallabagCoreBundle:Entry')
162 ->findByUrlAndUserId(
163 'https://medium.com/@the_minh/why-foursquare-swarm-is-still-my-favourite-social-network-e38228493e6c',
164 $this->getLoggedInUserId()
165 );
166
167 $this->assertTrue($content2->isArchived());
168
169 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
170 $this->assertContains('flashes.import.notice.summary', $body[0]);
171 }
172
173 public function testImportInstapaperWithEmptyFile()
174 {
175 $this->logInAs('admin');
176 $client = $this->getClient();
177
178 $crawler = $client->request('GET', '/import/instapaper');
179 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
180
181 $file = new UploadedFile(__DIR__.'/../fixtures/test.txt', 'test.txt');
182
183 $data = [
184 'upload_import_file[file]' => $file,
185 ];
186
187 $client->submit($form, $data);
188
189 $this->assertEquals(302, $client->getResponse()->getStatusCode());
190
191 $crawler = $client->followRedirect();
192
193 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
194 $this->assertContains('flashes.import.notice.failed', $body[0]);
195 }
196}
diff --git a/tests/Wallabag/ImportBundle/Controller/PocketControllerTest.php b/tests/Wallabag/ImportBundle/Controller/PocketControllerTest.php
index e0e61df8..7d6a300f 100644
--- a/tests/Wallabag/ImportBundle/Controller/PocketControllerTest.php
+++ b/tests/Wallabag/ImportBundle/Controller/PocketControllerTest.php
@@ -17,6 +17,37 @@ class PocketControllerTest extends WallabagCoreTestCase
17 $this->assertEquals(1, $crawler->filter('button[type=submit]')->count()); 17 $this->assertEquals(1, $crawler->filter('button[type=submit]')->count());
18 } 18 }
19 19
20 public function testImportPocketWithRabbitEnabled()
21 {
22 $this->logInAs('admin');
23 $client = $this->getClient();
24
25 $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 1);
26
27 $crawler = $client->request('GET', '/import/pocket');
28
29 $this->assertEquals(200, $client->getResponse()->getStatusCode());
30 $this->assertEquals(1, $crawler->filter('button[type=submit]')->count());
31
32 $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 0);
33 }
34
35 public function testImportPocketWithRedisEnabled()
36 {
37 $this->checkRedis();
38 $this->logInAs('admin');
39 $client = $this->getClient();
40
41 $client->getContainer()->get('craue_config')->set('import_with_redis', 1);
42
43 $crawler = $client->request('GET', '/import/pocket');
44
45 $this->assertEquals(200, $client->getResponse()->getStatusCode());
46 $this->assertEquals(1, $crawler->filter('button[type=submit]')->count());
47
48 $client->getContainer()->get('craue_config')->set('import_with_redis', 0);
49 }
50
20 public function testImportPocketAuthBadToken() 51 public function testImportPocketAuthBadToken()
21 { 52 {
22 $this->logInAs('admin'); 53 $this->logInAs('admin');
diff --git a/tests/Wallabag/ImportBundle/Controller/ReadabilityControllerTest.php b/tests/Wallabag/ImportBundle/Controller/ReadabilityControllerTest.php
new file mode 100644
index 00000000..916dd297
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/Controller/ReadabilityControllerTest.php
@@ -0,0 +1,197 @@
1<?php
2
3namespace Tests\Wallabag\ImportBundle\Controller;
4
5use Tests\Wallabag\CoreBundle\WallabagCoreTestCase;
6use Symfony\Component\HttpFoundation\File\UploadedFile;
7
8class ReadabilityControllerTest extends WallabagCoreTestCase
9{
10 public function testImportReadability()
11 {
12 $this->logInAs('admin');
13 $client = $this->getClient();
14
15 $crawler = $client->request('GET', '/import/readability');
16
17 $this->assertEquals(200, $client->getResponse()->getStatusCode());
18 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
19 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
20 }
21
22 public function testImportReadabilityWithRabbitEnabled()
23 {
24 $this->logInAs('admin');
25 $client = $this->getClient();
26
27 $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 1);
28
29 $crawler = $client->request('GET', '/import/readability');
30
31 $this->assertEquals(200, $client->getResponse()->getStatusCode());
32 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
33 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
34
35 $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 0);
36 }
37
38 public function testImportReadabilityBadFile()
39 {
40 $this->logInAs('admin');
41 $client = $this->getClient();
42
43 $crawler = $client->request('GET', '/import/readability');
44 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
45
46 $data = [
47 'upload_import_file[file]' => '',
48 ];
49
50 $client->submit($form, $data);
51
52 $this->assertEquals(200, $client->getResponse()->getStatusCode());
53 }
54
55 public function testImportReadabilityWithRedisEnabled()
56 {
57 $this->checkRedis();
58 $this->logInAs('admin');
59 $client = $this->getClient();
60 $client->getContainer()->get('craue_config')->set('import_with_redis', 1);
61
62 $crawler = $client->request('GET', '/import/readability');
63
64 $this->assertEquals(200, $client->getResponse()->getStatusCode());
65 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
66 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
67
68 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
69
70 $file = new UploadedFile(__DIR__.'/../fixtures/readability.json', 'readability.json');
71
72 $data = [
73 'upload_import_file[file]' => $file,
74 ];
75
76 $client->submit($form, $data);
77
78 $this->assertEquals(302, $client->getResponse()->getStatusCode());
79
80 $crawler = $client->followRedirect();
81
82 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
83 $this->assertContains('flashes.import.notice.summary', $body[0]);
84
85 $this->assertNotEmpty($client->getContainer()->get('wallabag_core.redis.client')->lpop('wallabag.import.readability'));
86
87 $client->getContainer()->get('craue_config')->set('import_with_redis', 0);
88 }
89
90 public function testImportReadabilityWithFile()
91 {
92 $this->logInAs('admin');
93 $client = $this->getClient();
94
95 $crawler = $client->request('GET', '/import/readability');
96 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
97
98 $file = new UploadedFile(__DIR__.'/../fixtures/readability.json', 'readability.json');
99
100 $data = [
101 'upload_import_file[file]' => $file,
102 ];
103
104 $client->submit($form, $data);
105
106 $this->assertEquals(302, $client->getResponse()->getStatusCode());
107
108 $crawler = $client->followRedirect();
109
110 $content = $client->getContainer()
111 ->get('doctrine.orm.entity_manager')
112 ->getRepository('WallabagCoreBundle:Entry')
113 ->findByUrlAndUserId(
114 'https://venngage.com/blog/hashtags-are-worthless/',
115 $this->getLoggedInUserId()
116 );
117
118 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
119 $this->assertContains('flashes.import.notice.summary', $body[0]);
120
121 $this->assertNotEmpty($content->getMimetype());
122 $this->assertNotEmpty($content->getPreviewPicture());
123 $this->assertNotEmpty($content->getLanguage());
124 $this->assertEquals(0, count($content->getTags()));
125 $this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
126 $this->assertEquals('2016-08-25', $content->getCreatedAt()->format('Y-m-d'));
127 }
128
129 public function testImportReadabilityWithFileAndMarkAllAsRead()
130 {
131 $this->logInAs('admin');
132 $client = $this->getClient();
133
134 $crawler = $client->request('GET', '/import/readability');
135 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
136
137 $file = new UploadedFile(__DIR__.'/../fixtures/readability-read.json', 'readability-read.json');
138
139 $data = [
140 'upload_import_file[file]' => $file,
141 'upload_import_file[mark_as_read]' => 1,
142 ];
143
144 $client->submit($form, $data);
145
146 $this->assertEquals(302, $client->getResponse()->getStatusCode());
147
148 $crawler = $client->followRedirect();
149
150 $content1 = $client->getContainer()
151 ->get('doctrine.orm.entity_manager')
152 ->getRepository('WallabagCoreBundle:Entry')
153 ->findByUrlAndUserId(
154 'https://blog.travis-ci.com/2016-07-28-what-we-learned-from-analyzing-2-million-travis-builds/',
155 $this->getLoggedInUserId()
156 );
157
158 $this->assertTrue($content1->isArchived());
159
160 $content2 = $client->getContainer()
161 ->get('doctrine.orm.entity_manager')
162 ->getRepository('WallabagCoreBundle:Entry')
163 ->findByUrlAndUserId(
164 'https://facebook.github.io/graphql/',
165 $this->getLoggedInUserId()
166 );
167
168 $this->assertTrue($content2->isArchived());
169
170 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
171 $this->assertContains('flashes.import.notice.summary', $body[0]);
172 }
173
174 public function testImportReadabilityWithEmptyFile()
175 {
176 $this->logInAs('admin');
177 $client = $this->getClient();
178
179 $crawler = $client->request('GET', '/import/readability');
180 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
181
182 $file = new UploadedFile(__DIR__.'/../fixtures/test.txt', 'test.txt');
183
184 $data = [
185 'upload_import_file[file]' => $file,
186 ];
187
188 $client->submit($form, $data);
189
190 $this->assertEquals(302, $client->getResponse()->getStatusCode());
191
192 $crawler = $client->followRedirect();
193
194 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
195 $this->assertContains('flashes.import.notice.failed', $body[0]);
196 }
197}
diff --git a/tests/Wallabag/ImportBundle/Controller/WallabagV1ControllerTest.php b/tests/Wallabag/ImportBundle/Controller/WallabagV1ControllerTest.php
index c1025b41..3497c4b8 100644
--- a/tests/Wallabag/ImportBundle/Controller/WallabagV1ControllerTest.php
+++ b/tests/Wallabag/ImportBundle/Controller/WallabagV1ControllerTest.php
@@ -19,6 +19,75 @@ class WallabagV1ControllerTest extends WallabagCoreTestCase
19 $this->assertEquals(1, $crawler->filter('input[type=file]')->count()); 19 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
20 } 20 }
21 21
22 public function testImportWallabagWithRabbitEnabled()
23 {
24 $this->logInAs('admin');
25 $client = $this->getClient();
26
27 $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 1);
28
29 $crawler = $client->request('GET', '/import/wallabag-v1');
30
31 $this->assertEquals(200, $client->getResponse()->getStatusCode());
32 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
33 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
34
35 $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 0);
36 }
37
38 public function testImportWallabagBadFile()
39 {
40 $this->logInAs('admin');
41 $client = $this->getClient();
42
43 $crawler = $client->request('GET', '/import/wallabag-v1');
44 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
45
46 $data = [
47 'upload_import_file[file]' => '',
48 ];
49
50 $client->submit($form, $data);
51
52 $this->assertEquals(200, $client->getResponse()->getStatusCode());
53 }
54
55 public function testImportWallabagWithRedisEnabled()
56 {
57 $this->checkRedis();
58 $this->logInAs('admin');
59 $client = $this->getClient();
60
61 $client->getContainer()->get('craue_config')->set('import_with_redis', 1);
62
63 $crawler = $client->request('GET', '/import/wallabag-v1');
64
65 $this->assertEquals(200, $client->getResponse()->getStatusCode());
66 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
67 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
68
69 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
70
71 $file = new UploadedFile(__DIR__.'/../fixtures/wallabag-v1.json', 'wallabag-v1.json');
72
73 $data = [
74 'upload_import_file[file]' => $file,
75 ];
76
77 $client->submit($form, $data);
78
79 $this->assertEquals(302, $client->getResponse()->getStatusCode());
80
81 $crawler = $client->followRedirect();
82
83 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
84 $this->assertContains('flashes.import.notice.summary', $body[0]);
85
86 $this->assertNotEmpty($client->getContainer()->get('wallabag_core.redis.client')->lpop('wallabag.import.wallabag_v1'));
87
88 $client->getContainer()->get('craue_config')->set('import_with_redis', 0);
89 }
90
22 public function testImportWallabagWithFile() 91 public function testImportWallabagWithFile()
23 { 92 {
24 $this->logInAs('admin'); 93 $this->logInAs('admin');
@@ -56,6 +125,12 @@ class WallabagV1ControllerTest extends WallabagCoreTestCase
56 125
57 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text'])); 126 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
58 $this->assertContains('flashes.import.notice.summary', $body[0]); 127 $this->assertContains('flashes.import.notice.summary', $body[0]);
128
129 $this->assertEmpty($content->getMimetype());
130 $this->assertEmpty($content->getPreviewPicture());
131 $this->assertEmpty($content->getLanguage());
132 $this->assertEquals(1, count($content->getTags()));
133 $this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
59 } 134 }
60 135
61 public function testImportWallabagWithFileAndMarkAllAsRead() 136 public function testImportWallabagWithFileAndMarkAllAsRead()
diff --git a/tests/Wallabag/ImportBundle/Controller/WallabagV2ControllerTest.php b/tests/Wallabag/ImportBundle/Controller/WallabagV2ControllerTest.php
index d8d2c8bf..27d2d52b 100644
--- a/tests/Wallabag/ImportBundle/Controller/WallabagV2ControllerTest.php
+++ b/tests/Wallabag/ImportBundle/Controller/WallabagV2ControllerTest.php
@@ -19,6 +19,75 @@ class WallabagV2ControllerTest extends WallabagCoreTestCase
19 $this->assertEquals(1, $crawler->filter('input[type=file]')->count()); 19 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
20 } 20 }
21 21
22 public function testImportWallabagWithRabbitEnabled()
23 {
24 $this->logInAs('admin');
25 $client = $this->getClient();
26
27 $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 1);
28
29 $crawler = $client->request('GET', '/import/wallabag-v2');
30
31 $this->assertEquals(200, $client->getResponse()->getStatusCode());
32 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
33 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
34
35 $client->getContainer()->get('craue_config')->set('import_with_rabbitmq', 0);
36 }
37
38 public function testImportWallabagBadFile()
39 {
40 $this->logInAs('admin');
41 $client = $this->getClient();
42
43 $crawler = $client->request('GET', '/import/wallabag-v2');
44 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
45
46 $data = [
47 'upload_import_file[file]' => '',
48 ];
49
50 $client->submit($form, $data);
51
52 $this->assertEquals(200, $client->getResponse()->getStatusCode());
53 }
54
55 public function testImportWallabagWithRedisEnabled()
56 {
57 $this->checkRedis();
58 $this->logInAs('admin');
59 $client = $this->getClient();
60
61 $client->getContainer()->get('craue_config')->set('import_with_redis', 1);
62
63 $crawler = $client->request('GET', '/import/wallabag-v2');
64
65 $this->assertEquals(200, $client->getResponse()->getStatusCode());
66 $this->assertEquals(1, $crawler->filter('form[name=upload_import_file] > button[type=submit]')->count());
67 $this->assertEquals(1, $crawler->filter('input[type=file]')->count());
68
69 $form = $crawler->filter('form[name=upload_import_file] > button[type=submit]')->form();
70
71 $file = new UploadedFile(__DIR__.'/../fixtures/wallabag-v2.json', 'wallabag-v2.json');
72
73 $data = [
74 'upload_import_file[file]' => $file,
75 ];
76
77 $client->submit($form, $data);
78
79 $this->assertEquals(302, $client->getResponse()->getStatusCode());
80
81 $crawler = $client->followRedirect();
82
83 $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text']));
84 $this->assertContains('flashes.import.notice.summary', $body[0]);
85
86 $this->assertNotEmpty($client->getContainer()->get('wallabag_core.redis.client')->lpop('wallabag.import.wallabag_v2'));
87
88 $client->getContainer()->get('craue_config')->set('import_with_redis', 0);
89 }
90
22 public function testImportWallabagWithFile() 91 public function testImportWallabagWithFile()
23 { 92 {
24 $this->logInAs('admin'); 93 $this->logInAs('admin');
@@ -50,9 +119,9 @@ class WallabagV2ControllerTest extends WallabagCoreTestCase
50 $this->getLoggedInUserId() 119 $this->getLoggedInUserId()
51 ); 120 );
52 121
53 $this->assertEmpty($content->getMimetype()); 122 $this->assertNotEmpty($content->getMimetype());
54 $this->assertEmpty($content->getPreviewPicture()); 123 $this->assertNotEmpty($content->getPreviewPicture());
55 $this->assertEmpty($content->getLanguage()); 124 $this->assertNotEmpty($content->getLanguage());
56 $this->assertEquals(0, count($content->getTags())); 125 $this->assertEquals(0, count($content->getTags()));
57 126
58 $content = $client->getContainer() 127 $content = $client->getContainer()
@@ -67,6 +136,8 @@ class WallabagV2ControllerTest extends WallabagCoreTestCase
67 $this->assertNotEmpty($content->getPreviewPicture()); 136 $this->assertNotEmpty($content->getPreviewPicture());
68 $this->assertNotEmpty($content->getLanguage()); 137 $this->assertNotEmpty($content->getLanguage());
69 $this->assertEquals(2, count($content->getTags())); 138 $this->assertEquals(2, count($content->getTags()));
139 $this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
140 $this->assertEquals('2016-09-08', $content->getCreatedAt()->format('Y-m-d'));
70 } 141 }
71 142
72 public function testImportWallabagWithEmptyFile() 143 public function testImportWallabagWithEmptyFile()
diff --git a/tests/Wallabag/ImportBundle/Import/ChromeImportTest.php b/tests/Wallabag/ImportBundle/Import/ChromeImportTest.php
new file mode 100644
index 00000000..1e52615c
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/Import/ChromeImportTest.php
@@ -0,0 +1,233 @@
1<?php
2
3namespace Tests\Wallabag\ImportBundle\Import;
4
5use Wallabag\ImportBundle\Import\ChromeImport;
6use Wallabag\UserBundle\Entity\User;
7use Wallabag\CoreBundle\Entity\Entry;
8use Wallabag\ImportBundle\Redis\Producer;
9use Monolog\Logger;
10use Monolog\Handler\TestHandler;
11use Simpleue\Queue\RedisQueue;
12use M6Web\Component\RedisMock\RedisMockFactory;
13
14class ChromeImportTest extends \PHPUnit_Framework_TestCase
15{
16 protected $user;
17 protected $em;
18 protected $logHandler;
19 protected $contentProxy;
20
21 private function getChromeImport($unsetUser = false)
22 {
23 $this->user = new User();
24
25 $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
26 ->disableOriginalConstructor()
27 ->getMock();
28
29 $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy')
30 ->disableOriginalConstructor()
31 ->getMock();
32
33 $wallabag = new ChromeImport($this->em, $this->contentProxy);
34
35 $this->logHandler = new TestHandler();
36 $logger = new Logger('test', [$this->logHandler]);
37 $wallabag->setLogger($logger);
38
39 if (false === $unsetUser) {
40 $wallabag->setUser($this->user);
41 }
42
43 return $wallabag;
44 }
45
46 public function testInit()
47 {
48 $chromeImport = $this->getChromeImport();
49
50 $this->assertEquals('Chrome', $chromeImport->getName());
51 $this->assertNotEmpty($chromeImport->getUrl());
52 $this->assertEquals('import.chrome.description', $chromeImport->getDescription());
53 }
54
55 public function testImport()
56 {
57 $chromeImport = $this->getChromeImport();
58 $chromeImport->setFilepath(__DIR__.'/../fixtures/chrome-bookmarks');
59
60 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
61 ->disableOriginalConstructor()
62 ->getMock();
63
64 $entryRepo->expects($this->exactly(1))
65 ->method('findByUrlAndUserId')
66 ->willReturn(false);
67
68 $this->em
69 ->expects($this->any())
70 ->method('getRepository')
71 ->willReturn($entryRepo);
72
73 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
74 ->disableOriginalConstructor()
75 ->getMock();
76
77 $this->contentProxy
78 ->expects($this->exactly(1))
79 ->method('updateEntry')
80 ->willReturn($entry);
81
82 $res = $chromeImport->import();
83
84 $this->assertTrue($res);
85 $this->assertEquals(['skipped' => 0, 'imported' => 1, 'queued' => 0], $chromeImport->getSummary());
86 }
87
88 public function testImportAndMarkAllAsRead()
89 {
90 $chromeImport = $this->getChromeImport();
91 $chromeImport->setFilepath(__DIR__.'/../fixtures/chrome-bookmarks');
92
93 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
94 ->disableOriginalConstructor()
95 ->getMock();
96
97 $entryRepo->expects($this->exactly(1))
98 ->method('findByUrlAndUserId')
99 ->will($this->onConsecutiveCalls(false, true));
100
101 $this->em
102 ->expects($this->any())
103 ->method('getRepository')
104 ->willReturn($entryRepo);
105
106 $this->contentProxy
107 ->expects($this->exactly(1))
108 ->method('updateEntry')
109 ->willReturn(new Entry($this->user));
110
111 // check that every entry persisted are archived
112 $this->em
113 ->expects($this->any())
114 ->method('persist')
115 ->with($this->callback(function ($persistedEntry) {
116 return $persistedEntry->isArchived();
117 }));
118
119 $res = $chromeImport->setMarkAsRead(true)->import();
120
121 $this->assertTrue($res);
122
123 $this->assertEquals(['skipped' => 0, 'imported' => 1, 'queued' => 0], $chromeImport->getSummary());
124 }
125
126 public function testImportWithRabbit()
127 {
128 $chromeImport = $this->getChromeImport();
129 $chromeImport->setFilepath(__DIR__.'/../fixtures/chrome-bookmarks');
130
131 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
132 ->disableOriginalConstructor()
133 ->getMock();
134
135 $entryRepo->expects($this->never())
136 ->method('findByUrlAndUserId');
137
138 $this->em
139 ->expects($this->never())
140 ->method('getRepository');
141
142 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
143 ->disableOriginalConstructor()
144 ->getMock();
145
146 $this->contentProxy
147 ->expects($this->never())
148 ->method('updateEntry');
149
150 $producer = $this->getMockBuilder('OldSound\RabbitMqBundle\RabbitMq\Producer')
151 ->disableOriginalConstructor()
152 ->getMock();
153
154 $producer
155 ->expects($this->exactly(1))
156 ->method('publish');
157
158 $chromeImport->setProducer($producer);
159
160 $res = $chromeImport->setMarkAsRead(true)->import();
161
162 $this->assertTrue($res);
163 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 1], $chromeImport->getSummary());
164 }
165
166 public function testImportWithRedis()
167 {
168 $chromeImport = $this->getChromeImport();
169 $chromeImport->setFilepath(__DIR__.'/../fixtures/chrome-bookmarks');
170
171 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
172 ->disableOriginalConstructor()
173 ->getMock();
174
175 $entryRepo->expects($this->never())
176 ->method('findByUrlAndUserId');
177
178 $this->em
179 ->expects($this->never())
180 ->method('getRepository');
181
182 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
183 ->disableOriginalConstructor()
184 ->getMock();
185
186 $this->contentProxy
187 ->expects($this->never())
188 ->method('updateEntry');
189
190 $factory = new RedisMockFactory();
191 $redisMock = $factory->getAdapter('Predis\Client', true);
192
193 $queue = new RedisQueue($redisMock, 'chrome');
194 $producer = new Producer($queue);
195
196 $chromeImport->setProducer($producer);
197
198 $res = $chromeImport->setMarkAsRead(true)->import();
199
200 $this->assertTrue($res);
201 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 1], $chromeImport->getSummary());
202
203 $this->assertNotEmpty($redisMock->lpop('chrome'));
204 }
205
206 public function testImportBadFile()
207 {
208 $chromeImport = $this->getChromeImport();
209 $chromeImport->setFilepath(__DIR__.'/../fixtures/wallabag-v1.jsonx');
210
211 $res = $chromeImport->import();
212
213 $this->assertFalse($res);
214
215 $records = $this->logHandler->getRecords();
216 $this->assertContains('Wallabag Browser Import: unable to read file', $records[0]['message']);
217 $this->assertEquals('ERROR', $records[0]['level_name']);
218 }
219
220 public function testImportUserNotDefined()
221 {
222 $chromeImport = $this->getChromeImport(true);
223 $chromeImport->setFilepath(__DIR__.'/../fixtures/chrome-bookmarks');
224
225 $res = $chromeImport->import();
226
227 $this->assertFalse($res);
228
229 $records = $this->logHandler->getRecords();
230 $this->assertContains('Wallabag Browser Import: user is not defined', $records[0]['message']);
231 $this->assertEquals('ERROR', $records[0]['level_name']);
232 }
233}
diff --git a/tests/Wallabag/ImportBundle/Import/FirefoxImportTest.php b/tests/Wallabag/ImportBundle/Import/FirefoxImportTest.php
new file mode 100644
index 00000000..007dda6a
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/Import/FirefoxImportTest.php
@@ -0,0 +1,233 @@
1<?php
2
3namespace Tests\Wallabag\ImportBundle\Import;
4
5use Wallabag\ImportBundle\Import\FirefoxImport;
6use Wallabag\UserBundle\Entity\User;
7use Wallabag\CoreBundle\Entity\Entry;
8use Wallabag\ImportBundle\Redis\Producer;
9use Monolog\Logger;
10use Monolog\Handler\TestHandler;
11use Simpleue\Queue\RedisQueue;
12use M6Web\Component\RedisMock\RedisMockFactory;
13
14class FirefoxImportTest extends \PHPUnit_Framework_TestCase
15{
16 protected $user;
17 protected $em;
18 protected $logHandler;
19 protected $contentProxy;
20
21 private function getFirefoxImport($unsetUser = false)
22 {
23 $this->user = new User();
24
25 $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
26 ->disableOriginalConstructor()
27 ->getMock();
28
29 $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy')
30 ->disableOriginalConstructor()
31 ->getMock();
32
33 $wallabag = new FirefoxImport($this->em, $this->contentProxy);
34
35 $this->logHandler = new TestHandler();
36 $logger = new Logger('test', [$this->logHandler]);
37 $wallabag->setLogger($logger);
38
39 if (false === $unsetUser) {
40 $wallabag->setUser($this->user);
41 }
42
43 return $wallabag;
44 }
45
46 public function testInit()
47 {
48 $firefoxImport = $this->getFirefoxImport();
49
50 $this->assertEquals('Firefox', $firefoxImport->getName());
51 $this->assertNotEmpty($firefoxImport->getUrl());
52 $this->assertEquals('import.firefox.description', $firefoxImport->getDescription());
53 }
54
55 public function testImport()
56 {
57 $firefoxImport = $this->getFirefoxImport();
58 $firefoxImport->setFilepath(__DIR__.'/../fixtures/firefox-bookmarks.json');
59
60 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
61 ->disableOriginalConstructor()
62 ->getMock();
63
64 $entryRepo->expects($this->exactly(2))
65 ->method('findByUrlAndUserId')
66 ->willReturn(false);
67
68 $this->em
69 ->expects($this->any())
70 ->method('getRepository')
71 ->willReturn($entryRepo);
72
73 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
74 ->disableOriginalConstructor()
75 ->getMock();
76
77 $this->contentProxy
78 ->expects($this->exactly(2))
79 ->method('updateEntry')
80 ->willReturn($entry);
81
82 $res = $firefoxImport->import();
83
84 $this->assertTrue($res);
85 $this->assertEquals(['skipped' => 0, 'imported' => 2, 'queued' => 0], $firefoxImport->getSummary());
86 }
87
88 public function testImportAndMarkAllAsRead()
89 {
90 $firefoxImport = $this->getFirefoxImport();
91 $firefoxImport->setFilepath(__DIR__.'/../fixtures/firefox-bookmarks.json');
92
93 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
94 ->disableOriginalConstructor()
95 ->getMock();
96
97 $entryRepo->expects($this->exactly(2))
98 ->method('findByUrlAndUserId')
99 ->will($this->onConsecutiveCalls(false, true));
100
101 $this->em
102 ->expects($this->any())
103 ->method('getRepository')
104 ->willReturn($entryRepo);
105
106 $this->contentProxy
107 ->expects($this->exactly(1))
108 ->method('updateEntry')
109 ->willReturn(new Entry($this->user));
110
111 // check that every entry persisted are archived
112 $this->em
113 ->expects($this->any())
114 ->method('persist')
115 ->with($this->callback(function ($persistedEntry) {
116 return $persistedEntry->isArchived();
117 }));
118
119 $res = $firefoxImport->setMarkAsRead(true)->import();
120
121 $this->assertTrue($res);
122
123 $this->assertEquals(['skipped' => 1, 'imported' => 1, 'queued' => 0], $firefoxImport->getSummary());
124 }
125
126 public function testImportWithRabbit()
127 {
128 $firefoxImport = $this->getFirefoxImport();
129 $firefoxImport->setFilepath(__DIR__.'/../fixtures/firefox-bookmarks.json');
130
131 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
132 ->disableOriginalConstructor()
133 ->getMock();
134
135 $entryRepo->expects($this->never())
136 ->method('findByUrlAndUserId');
137
138 $this->em
139 ->expects($this->never())
140 ->method('getRepository');
141
142 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
143 ->disableOriginalConstructor()
144 ->getMock();
145
146 $this->contentProxy
147 ->expects($this->never())
148 ->method('updateEntry');
149
150 $producer = $this->getMockBuilder('OldSound\RabbitMqBundle\RabbitMq\Producer')
151 ->disableOriginalConstructor()
152 ->getMock();
153
154 $producer
155 ->expects($this->exactly(1))
156 ->method('publish');
157
158 $firefoxImport->setProducer($producer);
159
160 $res = $firefoxImport->setMarkAsRead(true)->import();
161
162 $this->assertTrue($res);
163 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 1], $firefoxImport->getSummary());
164 }
165
166 public function testImportWithRedis()
167 {
168 $firefoxImport = $this->getFirefoxImport();
169 $firefoxImport->setFilepath(__DIR__.'/../fixtures/firefox-bookmarks.json');
170
171 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
172 ->disableOriginalConstructor()
173 ->getMock();
174
175 $entryRepo->expects($this->never())
176 ->method('findByUrlAndUserId');
177
178 $this->em
179 ->expects($this->never())
180 ->method('getRepository');
181
182 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
183 ->disableOriginalConstructor()
184 ->getMock();
185
186 $this->contentProxy
187 ->expects($this->never())
188 ->method('updateEntry');
189
190 $factory = new RedisMockFactory();
191 $redisMock = $factory->getAdapter('Predis\Client', true);
192
193 $queue = new RedisQueue($redisMock, 'firefox');
194 $producer = new Producer($queue);
195
196 $firefoxImport->setProducer($producer);
197
198 $res = $firefoxImport->setMarkAsRead(true)->import();
199
200 $this->assertTrue($res);
201 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 1], $firefoxImport->getSummary());
202
203 $this->assertNotEmpty($redisMock->lpop('firefox'));
204 }
205
206 public function testImportBadFile()
207 {
208 $firefoxImport = $this->getFirefoxImport();
209 $firefoxImport->setFilepath(__DIR__.'/../fixtures/wallabag-v1.jsonx');
210
211 $res = $firefoxImport->import();
212
213 $this->assertFalse($res);
214
215 $records = $this->logHandler->getRecords();
216 $this->assertContains('Wallabag Browser Import: unable to read file', $records[0]['message']);
217 $this->assertEquals('ERROR', $records[0]['level_name']);
218 }
219
220 public function testImportUserNotDefined()
221 {
222 $firefoxImport = $this->getFirefoxImport(true);
223 $firefoxImport->setFilepath(__DIR__.'/../fixtures/firefox-bookmarks.json');
224
225 $res = $firefoxImport->import();
226
227 $this->assertFalse($res);
228
229 $records = $this->logHandler->getRecords();
230 $this->assertContains('Wallabag Browser Import: user is not defined', $records[0]['message']);
231 $this->assertEquals('ERROR', $records[0]['level_name']);
232 }
233}
diff --git a/tests/Wallabag/ImportBundle/Import/InstapaperImportTest.php b/tests/Wallabag/ImportBundle/Import/InstapaperImportTest.php
new file mode 100644
index 00000000..75900bd7
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/Import/InstapaperImportTest.php
@@ -0,0 +1,233 @@
1<?php
2
3namespace Tests\Wallabag\ImportBundle\Import;
4
5use Wallabag\ImportBundle\Import\InstapaperImport;
6use Wallabag\UserBundle\Entity\User;
7use Wallabag\CoreBundle\Entity\Entry;
8use Wallabag\ImportBundle\Redis\Producer;
9use Monolog\Logger;
10use Monolog\Handler\TestHandler;
11use Simpleue\Queue\RedisQueue;
12use M6Web\Component\RedisMock\RedisMockFactory;
13
14class InstapaperImportTest extends \PHPUnit_Framework_TestCase
15{
16 protected $user;
17 protected $em;
18 protected $logHandler;
19 protected $contentProxy;
20
21 private function getInstapaperImport($unsetUser = false)
22 {
23 $this->user = new User();
24
25 $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
26 ->disableOriginalConstructor()
27 ->getMock();
28
29 $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy')
30 ->disableOriginalConstructor()
31 ->getMock();
32
33 $import = new InstapaperImport($this->em, $this->contentProxy);
34
35 $this->logHandler = new TestHandler();
36 $logger = new Logger('test', [$this->logHandler]);
37 $import->setLogger($logger);
38
39 if (false === $unsetUser) {
40 $import->setUser($this->user);
41 }
42
43 return $import;
44 }
45
46 public function testInit()
47 {
48 $instapaperImport = $this->getInstapaperImport();
49
50 $this->assertEquals('Instapaper', $instapaperImport->getName());
51 $this->assertNotEmpty($instapaperImport->getUrl());
52 $this->assertEquals('import.instapaper.description', $instapaperImport->getDescription());
53 }
54
55 public function testImport()
56 {
57 $instapaperImport = $this->getInstapaperImport();
58 $instapaperImport->setFilepath(__DIR__.'/../fixtures/instapaper-export.csv');
59
60 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
61 ->disableOriginalConstructor()
62 ->getMock();
63
64 $entryRepo->expects($this->exactly(3))
65 ->method('findByUrlAndUserId')
66 ->willReturn(false);
67
68 $this->em
69 ->expects($this->any())
70 ->method('getRepository')
71 ->willReturn($entryRepo);
72
73 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
74 ->disableOriginalConstructor()
75 ->getMock();
76
77 $this->contentProxy
78 ->expects($this->exactly(3))
79 ->method('updateEntry')
80 ->willReturn($entry);
81
82 $res = $instapaperImport->import();
83
84 $this->assertTrue($res);
85 $this->assertEquals(['skipped' => 0, 'imported' => 3, 'queued' => 0], $instapaperImport->getSummary());
86 }
87
88 public function testImportAndMarkAllAsRead()
89 {
90 $instapaperImport = $this->getInstapaperImport();
91 $instapaperImport->setFilepath(__DIR__.'/../fixtures/instapaper-export.csv');
92
93 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
94 ->disableOriginalConstructor()
95 ->getMock();
96
97 $entryRepo->expects($this->exactly(3))
98 ->method('findByUrlAndUserId')
99 ->will($this->onConsecutiveCalls(false, true, true));
100
101 $this->em
102 ->expects($this->any())
103 ->method('getRepository')
104 ->willReturn($entryRepo);
105
106 $this->contentProxy
107 ->expects($this->once())
108 ->method('updateEntry')
109 ->willReturn(new Entry($this->user));
110
111 // check that every entry persisted are archived
112 $this->em
113 ->expects($this->once())
114 ->method('persist')
115 ->with($this->callback(function ($persistedEntry) {
116 return $persistedEntry->isArchived();
117 }));
118
119 $res = $instapaperImport->setMarkAsRead(true)->import();
120
121 $this->assertTrue($res);
122
123 $this->assertEquals(['skipped' => 2, 'imported' => 1, 'queued' => 0], $instapaperImport->getSummary());
124 }
125
126 public function testImportWithRabbit()
127 {
128 $instapaperImport = $this->getInstapaperImport();
129 $instapaperImport->setFilepath(__DIR__.'/../fixtures/instapaper-export.csv');
130
131 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
132 ->disableOriginalConstructor()
133 ->getMock();
134
135 $entryRepo->expects($this->never())
136 ->method('findByUrlAndUserId');
137
138 $this->em
139 ->expects($this->never())
140 ->method('getRepository');
141
142 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
143 ->disableOriginalConstructor()
144 ->getMock();
145
146 $this->contentProxy
147 ->expects($this->never())
148 ->method('updateEntry');
149
150 $producer = $this->getMockBuilder('OldSound\RabbitMqBundle\RabbitMq\Producer')
151 ->disableOriginalConstructor()
152 ->getMock();
153
154 $producer
155 ->expects($this->exactly(3))
156 ->method('publish');
157
158 $instapaperImport->setProducer($producer);
159
160 $res = $instapaperImport->setMarkAsRead(true)->import();
161
162 $this->assertTrue($res);
163 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 3], $instapaperImport->getSummary());
164 }
165
166 public function testImportWithRedis()
167 {
168 $instapaperImport = $this->getInstapaperImport();
169 $instapaperImport->setFilepath(__DIR__.'/../fixtures/instapaper-export.csv');
170
171 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
172 ->disableOriginalConstructor()
173 ->getMock();
174
175 $entryRepo->expects($this->never())
176 ->method('findByUrlAndUserId');
177
178 $this->em
179 ->expects($this->never())
180 ->method('getRepository');
181
182 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
183 ->disableOriginalConstructor()
184 ->getMock();
185
186 $this->contentProxy
187 ->expects($this->never())
188 ->method('updateEntry');
189
190 $factory = new RedisMockFactory();
191 $redisMock = $factory->getAdapter('Predis\Client', true);
192
193 $queue = new RedisQueue($redisMock, 'instapaper');
194 $producer = new Producer($queue);
195
196 $instapaperImport->setProducer($producer);
197
198 $res = $instapaperImport->setMarkAsRead(true)->import();
199
200 $this->assertTrue($res);
201 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 3], $instapaperImport->getSummary());
202
203 $this->assertNotEmpty($redisMock->lpop('instapaper'));
204 }
205
206 public function testImportBadFile()
207 {
208 $instapaperImport = $this->getInstapaperImport();
209 $instapaperImport->setFilepath(__DIR__.'/../fixtures/wallabag-v1.jsonx');
210
211 $res = $instapaperImport->import();
212
213 $this->assertFalse($res);
214
215 $records = $this->logHandler->getRecords();
216 $this->assertContains('InstapaperImport: unable to read file', $records[0]['message']);
217 $this->assertEquals('ERROR', $records[0]['level_name']);
218 }
219
220 public function testImportUserNotDefined()
221 {
222 $instapaperImport = $this->getInstapaperImport(true);
223 $instapaperImport->setFilepath(__DIR__.'/../fixtures/instapaper-export.csv');
224
225 $res = $instapaperImport->import();
226
227 $this->assertFalse($res);
228
229 $records = $this->logHandler->getRecords();
230 $this->assertContains('InstapaperImport: user is not defined', $records[0]['message']);
231 $this->assertEquals('ERROR', $records[0]['level_name']);
232 }
233}
diff --git a/tests/Wallabag/ImportBundle/Import/PocketImportTest.php b/tests/Wallabag/ImportBundle/Import/PocketImportTest.php
index 8534e1c8..9ec7935c 100644
--- a/tests/Wallabag/ImportBundle/Import/PocketImportTest.php
+++ b/tests/Wallabag/ImportBundle/Import/PocketImportTest.php
@@ -4,21 +4,17 @@ namespace Tests\Wallabag\ImportBundle\Import;
4 4
5use Wallabag\UserBundle\Entity\User; 5use Wallabag\UserBundle\Entity\User;
6use Wallabag\CoreBundle\Entity\Entry; 6use Wallabag\CoreBundle\Entity\Entry;
7use Wallabag\CoreBundle\Entity\Config;
7use Wallabag\ImportBundle\Import\PocketImport; 8use Wallabag\ImportBundle\Import\PocketImport;
8use GuzzleHttp\Client; 9use GuzzleHttp\Client;
9use GuzzleHttp\Subscriber\Mock; 10use GuzzleHttp\Subscriber\Mock;
10use GuzzleHttp\Message\Response; 11use GuzzleHttp\Message\Response;
11use GuzzleHttp\Stream\Stream; 12use GuzzleHttp\Stream\Stream;
13use Wallabag\ImportBundle\Redis\Producer;
12use Monolog\Logger; 14use Monolog\Logger;
13use Monolog\Handler\TestHandler; 15use Monolog\Handler\TestHandler;
14 16use Simpleue\Queue\RedisQueue;
15class PocketImportMock extends PocketImport 17use M6Web\Component\RedisMock\RedisMockFactory;
16{
17 public function getAccessToken()
18 {
19 return $this->accessToken;
20 }
21}
22 18
23class PocketImportTest extends \PHPUnit_Framework_TestCase 19class PocketImportTest extends \PHPUnit_Framework_TestCase
24{ 20{
@@ -32,45 +28,38 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
32 { 28 {
33 $this->user = new User(); 29 $this->user = new User();
34 30
35 $this->tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface') 31 $config = new Config($this->user);
36 ->disableOriginalConstructor() 32 $config->setPocketConsumerKey('xxx');
37 ->getMock();
38 33
39 $token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface') 34 $this->user->setConfig($config);
40 ->disableOriginalConstructor()
41 ->getMock();
42 35
43 $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy') 36 $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy')
44 ->disableOriginalConstructor() 37 ->disableOriginalConstructor()
45 ->getMock(); 38 ->getMock();
46 39
47 $token->expects($this->once())
48 ->method('getUser')
49 ->willReturn($this->user);
50
51 $this->tokenStorage->expects($this->once())
52 ->method('getToken')
53 ->willReturn($token);
54
55 $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager') 40 $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
56 ->disableOriginalConstructor() 41 ->disableOriginalConstructor()
57 ->getMock(); 42 ->getMock();
58 43
59 $config = $this->getMockBuilder('Craue\ConfigBundle\Util\Config') 44 $this->uow = $this->getMockBuilder('Doctrine\ORM\UnitOfWork')
60 ->disableOriginalConstructor() 45 ->disableOriginalConstructor()
61 ->getMock(); 46 ->getMock();
62 47
63 $config->expects($this->any()) 48 $this->em
64 ->method('get') 49 ->expects($this->any())
65 ->with('pocket_consumer_key') 50 ->method('getUnitOfWork')
66 ->willReturn($consumerKey); 51 ->willReturn($this->uow);
52
53 $this->uow
54 ->expects($this->any())
55 ->method('getScheduledEntityInsertions')
56 ->willReturn([]);
67 57
68 $pocket = new PocketImportMock( 58 $pocket = new PocketImport(
69 $this->tokenStorage,
70 $this->em, 59 $this->em,
71 $this->contentProxy, 60 $this->contentProxy
72 $config
73 ); 61 );
62 $pocket->setUser($this->user);
74 63
75 $this->logHandler = new TestHandler(); 64 $this->logHandler = new TestHandler();
76 $logger = new Logger('test', [$this->logHandler]); 65 $logger = new Logger('test', [$this->logHandler]);
@@ -189,10 +178,16 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
189 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland", 178 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
190 "favorite": "1", 179 "favorite": "1",
191 "status": "1", 180 "status": "1",
181 "time_added": "1473020899",
182 "time_updated": "1473020899",
183 "time_read": "0",
184 "time_favorited": "0",
185 "sort_id": 0,
192 "resolved_title": "The Massive Ryder Cup Preview", 186 "resolved_title": "The Massive Ryder Cup Preview",
193 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview", 187 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview",
194 "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.", 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.",
195 "is_article": "1", 189 "is_article": "1",
190 "is_index": "0",
196 "has_video": "1", 191 "has_video": "1",
197 "has_image": "1", 192 "has_image": "1",
198 "word_count": "3197", 193 "word_count": "3197",
@@ -236,10 +231,16 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
236 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland", 231 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
237 "favorite": "1", 232 "favorite": "1",
238 "status": "1", 233 "status": "1",
234 "time_added": "1473020899",
235 "time_updated": "1473020899",
236 "time_read": "0",
237 "time_favorited": "0",
238 "sort_id": 1,
239 "resolved_title": "The Massive Ryder Cup Preview", 239 "resolved_title": "The Massive Ryder Cup Preview",
240 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/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.", 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", 242 "is_article": "1",
243 "is_index": "0",
243 "has_video": "0", 244 "has_video": "0",
244 "has_image": "0", 245 "has_image": "0",
245 "word_count": "3197" 246 "word_count": "3197"
@@ -279,7 +280,7 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
279 $res = $pocketImport->import(); 280 $res = $pocketImport->import();
280 281
281 $this->assertTrue($res); 282 $this->assertTrue($res);
282 $this->assertEquals(['skipped' => 1, 'imported' => 1], $pocketImport->getSummary()); 283 $this->assertEquals(['skipped' => 1, 'imported' => 1, 'queued' => 0], $pocketImport->getSummary());
283 } 284 }
284 285
285 /** 286 /**
@@ -302,6 +303,11 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
302 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland", 303 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
303 "favorite": "1", 304 "favorite": "1",
304 "status": "1", 305 "status": "1",
306 "time_added": "1473020899",
307 "time_updated": "1473020899",
308 "time_read": "0",
309 "time_favorited": "0",
310 "sort_id": 0,
305 "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.", 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.",
306 "is_article": "1", 312 "is_article": "1",
307 "has_video": "1", 313 "has_video": "1",
@@ -315,6 +321,11 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
315 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland", 321 "given_title": "The Massive Ryder Cup Preview - The Triangle Blog - Grantland",
316 "favorite": "1", 322 "favorite": "1",
317 "status": "0", 323 "status": "0",
324 "time_added": "1473020899",
325 "time_updated": "1473020899",
326 "time_read": "0",
327 "time_favorited": "0",
328 "sort_id": 1,
318 "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.", 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.",
319 "is_article": "1", 330 "is_article": "1",
320 "has_video": "0", 331 "has_video": "0",
@@ -364,7 +375,174 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
364 $res = $pocketImport->setMarkAsRead(true)->import(); 375 $res = $pocketImport->setMarkAsRead(true)->import();
365 376
366 $this->assertTrue($res); 377 $this->assertTrue($res);
367 $this->assertEquals(['skipped' => 0, 'imported' => 2], $pocketImport->getSummary()); 378 $this->assertEquals(['skipped' => 0, 'imported' => 2, 'queued' => 0], $pocketImport->getSummary());
379 }
380
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",
396 "time_added": "1473020899",
397 "time_updated": "1473020899",
398 "time_read": "0",
399 "time_favorited": "0",
400 "sort_id": 0,
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);
458 $pocketImport->setProducer($producer);
459 $pocketImport->authorize('wunderbar_code');
460
461 $res = $pocketImport->setMarkAsRead(true)->import();
462
463 $this->assertTrue($res);
464 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 1], $pocketImport->getSummary());
465 }
466
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);
543 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 1], $pocketImport->getSummary());
544
545 $this->assertNotEmpty($redisMock->lpop('pocket'));
368 } 546 }
369 547
370 public function testImportBadResponse() 548 public function testImportBadResponse()
@@ -402,6 +580,8 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
402 "status": 1, 580 "status": 1,
403 "list": { 581 "list": {
404 "229279689": { 582 "229279689": {
583 "status": "1",
584 "favorite": "1",
405 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview" 585 "resolved_url": "http://www.grantland.com/blog/the-triangle/post/_/id/38347/ryder-cup-preview"
406 } 586 }
407 } 587 }
@@ -439,6 +619,6 @@ class PocketImportTest extends \PHPUnit_Framework_TestCase
439 $res = $pocketImport->import(); 619 $res = $pocketImport->import();
440 620
441 $this->assertTrue($res); 621 $this->assertTrue($res);
442 $this->assertEquals(['skipped' => 1, 'imported' => 0], $pocketImport->getSummary()); 622 $this->assertEquals(['skipped' => 0, 'imported' => 1, 'queued' => 0], $pocketImport->getSummary());
443 } 623 }
444} 624}
diff --git a/tests/Wallabag/ImportBundle/Import/ReadabilityImportTest.php b/tests/Wallabag/ImportBundle/Import/ReadabilityImportTest.php
new file mode 100644
index 00000000..d98cd486
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/Import/ReadabilityImportTest.php
@@ -0,0 +1,233 @@
1<?php
2
3namespace Tests\Wallabag\ImportBundle\Import;
4
5use Wallabag\ImportBundle\Import\ReadabilityImport;
6use Wallabag\UserBundle\Entity\User;
7use Wallabag\CoreBundle\Entity\Entry;
8use Wallabag\ImportBundle\Redis\Producer;
9use Monolog\Logger;
10use Monolog\Handler\TestHandler;
11use Simpleue\Queue\RedisQueue;
12use M6Web\Component\RedisMock\RedisMockFactory;
13
14class ReadabilityImportTest extends \PHPUnit_Framework_TestCase
15{
16 protected $user;
17 protected $em;
18 protected $logHandler;
19 protected $contentProxy;
20
21 private function getReadabilityImport($unsetUser = false)
22 {
23 $this->user = new User();
24
25 $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
26 ->disableOriginalConstructor()
27 ->getMock();
28
29 $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy')
30 ->disableOriginalConstructor()
31 ->getMock();
32
33 $wallabag = new ReadabilityImport($this->em, $this->contentProxy);
34
35 $this->logHandler = new TestHandler();
36 $logger = new Logger('test', [$this->logHandler]);
37 $wallabag->setLogger($logger);
38
39 if (false === $unsetUser) {
40 $wallabag->setUser($this->user);
41 }
42
43 return $wallabag;
44 }
45
46 public function testInit()
47 {
48 $readabilityImport = $this->getReadabilityImport();
49
50 $this->assertEquals('Readability', $readabilityImport->getName());
51 $this->assertNotEmpty($readabilityImport->getUrl());
52 $this->assertEquals('import.readability.description', $readabilityImport->getDescription());
53 }
54
55 public function testImport()
56 {
57 $readabilityImport = $this->getReadabilityImport();
58 $readabilityImport->setFilepath(__DIR__.'/../fixtures/readability.json');
59
60 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
61 ->disableOriginalConstructor()
62 ->getMock();
63
64 $entryRepo->expects($this->exactly(24))
65 ->method('findByUrlAndUserId')
66 ->willReturn(false);
67
68 $this->em
69 ->expects($this->any())
70 ->method('getRepository')
71 ->willReturn($entryRepo);
72
73 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
74 ->disableOriginalConstructor()
75 ->getMock();
76
77 $this->contentProxy
78 ->expects($this->exactly(24))
79 ->method('updateEntry')
80 ->willReturn($entry);
81
82 $res = $readabilityImport->import();
83
84 $this->assertTrue($res);
85 $this->assertEquals(['skipped' => 0, 'imported' => 24, 'queued' => 0], $readabilityImport->getSummary());
86 }
87
88 public function testImportAndMarkAllAsRead()
89 {
90 $readabilityImport = $this->getReadabilityImport();
91 $readabilityImport->setFilepath(__DIR__.'/../fixtures/readability-read.json');
92
93 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
94 ->disableOriginalConstructor()
95 ->getMock();
96
97 $entryRepo->expects($this->exactly(2))
98 ->method('findByUrlAndUserId')
99 ->will($this->onConsecutiveCalls(false, true));
100
101 $this->em
102 ->expects($this->any())
103 ->method('getRepository')
104 ->willReturn($entryRepo);
105
106 $this->contentProxy
107 ->expects($this->exactly(1))
108 ->method('updateEntry')
109 ->willReturn(new Entry($this->user));
110
111 // check that every entry persisted are archived
112 $this->em
113 ->expects($this->any())
114 ->method('persist')
115 ->with($this->callback(function ($persistedEntry) {
116 return $persistedEntry->isArchived();
117 }));
118
119 $res = $readabilityImport->setMarkAsRead(true)->import();
120
121 $this->assertTrue($res);
122
123 $this->assertEquals(['skipped' => 1, 'imported' => 1, 'queued' => 0], $readabilityImport->getSummary());
124 }
125
126 public function testImportWithRabbit()
127 {
128 $readabilityImport = $this->getReadabilityImport();
129 $readabilityImport->setFilepath(__DIR__.'/../fixtures/readability.json');
130
131 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
132 ->disableOriginalConstructor()
133 ->getMock();
134
135 $entryRepo->expects($this->never())
136 ->method('findByUrlAndUserId');
137
138 $this->em
139 ->expects($this->never())
140 ->method('getRepository');
141
142 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
143 ->disableOriginalConstructor()
144 ->getMock();
145
146 $this->contentProxy
147 ->expects($this->never())
148 ->method('updateEntry');
149
150 $producer = $this->getMockBuilder('OldSound\RabbitMqBundle\RabbitMq\Producer')
151 ->disableOriginalConstructor()
152 ->getMock();
153
154 $producer
155 ->expects($this->exactly(24))
156 ->method('publish');
157
158 $readabilityImport->setProducer($producer);
159
160 $res = $readabilityImport->setMarkAsRead(true)->import();
161
162 $this->assertTrue($res);
163 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 24], $readabilityImport->getSummary());
164 }
165
166 public function testImportWithRedis()
167 {
168 $readabilityImport = $this->getReadabilityImport();
169 $readabilityImport->setFilepath(__DIR__.'/../fixtures/readability.json');
170
171 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
172 ->disableOriginalConstructor()
173 ->getMock();
174
175 $entryRepo->expects($this->never())
176 ->method('findByUrlAndUserId');
177
178 $this->em
179 ->expects($this->never())
180 ->method('getRepository');
181
182 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
183 ->disableOriginalConstructor()
184 ->getMock();
185
186 $this->contentProxy
187 ->expects($this->never())
188 ->method('updateEntry');
189
190 $factory = new RedisMockFactory();
191 $redisMock = $factory->getAdapter('Predis\Client', true);
192
193 $queue = new RedisQueue($redisMock, 'readability');
194 $producer = new Producer($queue);
195
196 $readabilityImport->setProducer($producer);
197
198 $res = $readabilityImport->setMarkAsRead(true)->import();
199
200 $this->assertTrue($res);
201 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 24], $readabilityImport->getSummary());
202
203 $this->assertNotEmpty($redisMock->lpop('readability'));
204 }
205
206 public function testImportBadFile()
207 {
208 $readabilityImport = $this->getReadabilityImport();
209 $readabilityImport->setFilepath(__DIR__.'/../fixtures/wallabag-v1.jsonx');
210
211 $res = $readabilityImport->import();
212
213 $this->assertFalse($res);
214
215 $records = $this->logHandler->getRecords();
216 $this->assertContains('ReadabilityImport: unable to read file', $records[0]['message']);
217 $this->assertEquals('ERROR', $records[0]['level_name']);
218 }
219
220 public function testImportUserNotDefined()
221 {
222 $readabilityImport = $this->getReadabilityImport(true);
223 $readabilityImport->setFilepath(__DIR__.'/../fixtures/readability.json');
224
225 $res = $readabilityImport->import();
226
227 $this->assertFalse($res);
228
229 $records = $this->logHandler->getRecords();
230 $this->assertContains('ReadabilityImport: user is not defined', $records[0]['message']);
231 $this->assertEquals('ERROR', $records[0]['level_name']);
232 }
233}
diff --git a/tests/Wallabag/ImportBundle/Import/WallabagV1ImportTest.php b/tests/Wallabag/ImportBundle/Import/WallabagV1ImportTest.php
index bdc47dac..82dc4c7e 100644
--- a/tests/Wallabag/ImportBundle/Import/WallabagV1ImportTest.php
+++ b/tests/Wallabag/ImportBundle/Import/WallabagV1ImportTest.php
@@ -5,8 +5,11 @@ namespace Tests\Wallabag\ImportBundle\Import;
5use Wallabag\ImportBundle\Import\WallabagV1Import; 5use Wallabag\ImportBundle\Import\WallabagV1Import;
6use Wallabag\UserBundle\Entity\User; 6use Wallabag\UserBundle\Entity\User;
7use Wallabag\CoreBundle\Entity\Entry; 7use Wallabag\CoreBundle\Entity\Entry;
8use Wallabag\ImportBundle\Redis\Producer;
8use Monolog\Logger; 9use Monolog\Logger;
9use Monolog\Handler\TestHandler; 10use Monolog\Handler\TestHandler;
11use Simpleue\Queue\RedisQueue;
12use M6Web\Component\RedisMock\RedisMockFactory;
10 13
11class WallabagV1ImportTest extends \PHPUnit_Framework_TestCase 14class WallabagV1ImportTest extends \PHPUnit_Framework_TestCase
12{ 15{
@@ -23,6 +26,20 @@ class WallabagV1ImportTest extends \PHPUnit_Framework_TestCase
23 ->disableOriginalConstructor() 26 ->disableOriginalConstructor()
24 ->getMock(); 27 ->getMock();
25 28
29 $this->uow = $this->getMockBuilder('Doctrine\ORM\UnitOfWork')
30 ->disableOriginalConstructor()
31 ->getMock();
32
33 $this->em
34 ->expects($this->any())
35 ->method('getUnitOfWork')
36 ->willReturn($this->uow);
37
38 $this->uow
39 ->expects($this->any())
40 ->method('getScheduledEntityInsertions')
41 ->willReturn([]);
42
26 $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy') 43 $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy')
27 ->disableOriginalConstructor() 44 ->disableOriginalConstructor()
28 ->getMock(); 45 ->getMock();
@@ -79,7 +96,7 @@ class WallabagV1ImportTest extends \PHPUnit_Framework_TestCase
79 $res = $wallabagV1Import->import(); 96 $res = $wallabagV1Import->import();
80 97
81 $this->assertTrue($res); 98 $this->assertTrue($res);
82 $this->assertEquals(['skipped' => 1, 'imported' => 3], $wallabagV1Import->getSummary()); 99 $this->assertEquals(['skipped' => 1, 'imported' => 3, 'queued' => 0], $wallabagV1Import->getSummary());
83 } 100 }
84 101
85 public function testImportAndMarkAllAsRead() 102 public function testImportAndMarkAllAsRead()
@@ -117,7 +134,87 @@ class WallabagV1ImportTest extends \PHPUnit_Framework_TestCase
117 134
118 $this->assertTrue($res); 135 $this->assertTrue($res);
119 136
120 $this->assertEquals(['skipped' => 0, 'imported' => 3], $wallabagV1Import->getSummary()); 137 $this->assertEquals(['skipped' => 0, 'imported' => 3, 'queued' => 0], $wallabagV1Import->getSummary());
138 }
139
140 public function testImportWithRabbit()
141 {
142 $wallabagV1Import = $this->getWallabagV1Import();
143 $wallabagV1Import->setFilepath(__DIR__.'/../fixtures/wallabag-v1.json');
144
145 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
146 ->disableOriginalConstructor()
147 ->getMock();
148
149 $entryRepo->expects($this->never())
150 ->method('findByUrlAndUserId');
151
152 $this->em
153 ->expects($this->never())
154 ->method('getRepository');
155
156 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
157 ->disableOriginalConstructor()
158 ->getMock();
159
160 $this->contentProxy
161 ->expects($this->never())
162 ->method('updateEntry');
163
164 $producer = $this->getMockBuilder('OldSound\RabbitMqBundle\RabbitMq\Producer')
165 ->disableOriginalConstructor()
166 ->getMock();
167
168 $producer
169 ->expects($this->exactly(4))
170 ->method('publish');
171
172 $wallabagV1Import->setProducer($producer);
173
174 $res = $wallabagV1Import->setMarkAsRead(true)->import();
175
176 $this->assertTrue($res);
177 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 4], $wallabagV1Import->getSummary());
178 }
179
180 public function testImportWithRedis()
181 {
182 $wallabagV1Import = $this->getWallabagV1Import();
183 $wallabagV1Import->setFilepath(__DIR__.'/../fixtures/wallabag-v1.json');
184
185 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
186 ->disableOriginalConstructor()
187 ->getMock();
188
189 $entryRepo->expects($this->never())
190 ->method('findByUrlAndUserId');
191
192 $this->em
193 ->expects($this->never())
194 ->method('getRepository');
195
196 $entry = $this->getMockBuilder('Wallabag\CoreBundle\Entity\Entry')
197 ->disableOriginalConstructor()
198 ->getMock();
199
200 $this->contentProxy
201 ->expects($this->never())
202 ->method('updateEntry');
203
204 $factory = new RedisMockFactory();
205 $redisMock = $factory->getAdapter('Predis\Client', true);
206
207 $queue = new RedisQueue($redisMock, 'wallabag_v1');
208 $producer = new Producer($queue);
209
210 $wallabagV1Import->setProducer($producer);
211
212 $res = $wallabagV1Import->setMarkAsRead(true)->import();
213
214 $this->assertTrue($res);
215 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 4], $wallabagV1Import->getSummary());
216
217 $this->assertNotEmpty($redisMock->lpop('wallabag_v1'));
121 } 218 }
122 219
123 public function testImportBadFile() 220 public function testImportBadFile()
diff --git a/tests/Wallabag/ImportBundle/Import/WallabagV2ImportTest.php b/tests/Wallabag/ImportBundle/Import/WallabagV2ImportTest.php
index 4a45e0f0..bea89efb 100644
--- a/tests/Wallabag/ImportBundle/Import/WallabagV2ImportTest.php
+++ b/tests/Wallabag/ImportBundle/Import/WallabagV2ImportTest.php
@@ -5,8 +5,11 @@ namespace Tests\Wallabag\ImportBundle\Import;
5use Wallabag\ImportBundle\Import\WallabagV2Import; 5use Wallabag\ImportBundle\Import\WallabagV2Import;
6use Wallabag\UserBundle\Entity\User; 6use Wallabag\UserBundle\Entity\User;
7use Wallabag\CoreBundle\Entity\Entry; 7use Wallabag\CoreBundle\Entity\Entry;
8use Wallabag\ImportBundle\Redis\Producer;
8use Monolog\Logger; 9use Monolog\Logger;
9use Monolog\Handler\TestHandler; 10use Monolog\Handler\TestHandler;
11use Simpleue\Queue\RedisQueue;
12use M6Web\Component\RedisMock\RedisMockFactory;
10 13
11class WallabagV2ImportTest extends \PHPUnit_Framework_TestCase 14class WallabagV2ImportTest extends \PHPUnit_Framework_TestCase
12{ 15{
@@ -23,6 +26,20 @@ class WallabagV2ImportTest extends \PHPUnit_Framework_TestCase
23 ->disableOriginalConstructor() 26 ->disableOriginalConstructor()
24 ->getMock(); 27 ->getMock();
25 28
29 $this->uow = $this->getMockBuilder('Doctrine\ORM\UnitOfWork')
30 ->disableOriginalConstructor()
31 ->getMock();
32
33 $this->em
34 ->expects($this->any())
35 ->method('getUnitOfWork')
36 ->willReturn($this->uow);
37
38 $this->uow
39 ->expects($this->any())
40 ->method('getScheduledEntityInsertions')
41 ->willReturn([]);
42
26 $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy') 43 $this->contentProxy = $this->getMockBuilder('Wallabag\CoreBundle\Helper\ContentProxy')
27 ->disableOriginalConstructor() 44 ->disableOriginalConstructor()
28 ->getMock(); 45 ->getMock();
@@ -75,7 +92,7 @@ class WallabagV2ImportTest extends \PHPUnit_Framework_TestCase
75 $res = $wallabagV2Import->import(); 92 $res = $wallabagV2Import->import();
76 93
77 $this->assertTrue($res); 94 $this->assertTrue($res);
78 $this->assertEquals(['skipped' => 22, 'imported' => 2], $wallabagV2Import->getSummary()); 95 $this->assertEquals(['skipped' => 22, 'imported' => 2, 'queued' => 0], $wallabagV2Import->getSummary());
79 } 96 }
80 97
81 public function testImportAndMarkAllAsRead() 98 public function testImportAndMarkAllAsRead()
@@ -113,7 +130,79 @@ class WallabagV2ImportTest extends \PHPUnit_Framework_TestCase
113 130
114 $this->assertTrue($res); 131 $this->assertTrue($res);
115 132
116 $this->assertEquals(['skipped' => 0, 'imported' => 2], $wallabagV2Import->getSummary()); 133 $this->assertEquals(['skipped' => 0, 'imported' => 2, 'queued' => 0], $wallabagV2Import->getSummary());
134 }
135
136 public function testImportWithRabbit()
137 {
138 $wallabagV2Import = $this->getWallabagV2Import();
139 $wallabagV2Import->setFilepath(__DIR__.'/../fixtures/wallabag-v2.json');
140
141 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
142 ->disableOriginalConstructor()
143 ->getMock();
144
145 $entryRepo->expects($this->never())
146 ->method('findByUrlAndUserId');
147
148 $this->em
149 ->expects($this->never())
150 ->method('getRepository');
151
152 $this->contentProxy
153 ->expects($this->never())
154 ->method('updateEntry');
155
156 $producer = $this->getMockBuilder('OldSound\RabbitMqBundle\RabbitMq\Producer')
157 ->disableOriginalConstructor()
158 ->getMock();
159
160 $producer
161 ->expects($this->exactly(24))
162 ->method('publish');
163
164 $wallabagV2Import->setProducer($producer);
165
166 $res = $wallabagV2Import->setMarkAsRead(true)->import();
167
168 $this->assertTrue($res);
169 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 24], $wallabagV2Import->getSummary());
170 }
171
172 public function testImportWithRedis()
173 {
174 $wallabagV2Import = $this->getWallabagV2Import();
175 $wallabagV2Import->setFilepath(__DIR__.'/../fixtures/wallabag-v2.json');
176
177 $entryRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\EntryRepository')
178 ->disableOriginalConstructor()
179 ->getMock();
180
181 $entryRepo->expects($this->never())
182 ->method('findByUrlAndUserId');
183
184 $this->em
185 ->expects($this->never())
186 ->method('getRepository');
187
188 $this->contentProxy
189 ->expects($this->never())
190 ->method('updateEntry');
191
192 $factory = new RedisMockFactory();
193 $redisMock = $factory->getAdapter('Predis\Client', true);
194
195 $queue = new RedisQueue($redisMock, 'wallabag_v2');
196 $producer = new Producer($queue);
197
198 $wallabagV2Import->setProducer($producer);
199
200 $res = $wallabagV2Import->setMarkAsRead(true)->import();
201
202 $this->assertTrue($res);
203 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 24], $wallabagV2Import->getSummary());
204
205 $this->assertNotEmpty($redisMock->lpop('wallabag_v2'));
117 } 206 }
118 207
119 public function testImportBadFile() 208 public function testImportBadFile()
@@ -152,7 +241,7 @@ class WallabagV2ImportTest extends \PHPUnit_Framework_TestCase
152 $res = $wallabagV2Import->import(); 241 $res = $wallabagV2Import->import();
153 242
154 $this->assertFalse($res); 243 $this->assertFalse($res);
155 $this->assertEquals(['skipped' => 0, 'imported' => 0], $wallabagV2Import->getSummary()); 244 $this->assertEquals(['skipped' => 0, 'imported' => 0, 'queued' => 0], $wallabagV2Import->getSummary());
156 } 245 }
157 246
158 public function testImportWithExceptionFromGraby() 247 public function testImportWithExceptionFromGraby()
@@ -181,6 +270,6 @@ class WallabagV2ImportTest extends \PHPUnit_Framework_TestCase
181 $res = $wallabagV2Import->import(); 270 $res = $wallabagV2Import->import();
182 271
183 $this->assertTrue($res); 272 $this->assertTrue($res);
184 $this->assertEquals(['skipped' => 24, 'imported' => 0], $wallabagV2Import->getSummary()); 273 $this->assertEquals(['skipped' => 22, 'imported' => 2, 'queued' => 0], $wallabagV2Import->getSummary());
185 } 274 }
186} 275}
diff --git a/tests/Wallabag/ImportBundle/fixtures/chrome-bookmarks b/tests/Wallabag/ImportBundle/fixtures/chrome-bookmarks
new file mode 100644
index 00000000..0478eb41
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/fixtures/chrome-bookmarks
@@ -0,0 +1,36 @@
1{
2 "checksum": "f3aa0e9c0edad632a246f7e98ec64918",
3 "roots": {
4 "bookmark_bar": {
5 "children": [ {
6 "date_added": "13118850929335823",
7 "id": "6",
8 "name": "\"La multiplication des chefs de projet est une catastrophe managériale majeure\", affirme le sociologue François Dupuy - Ressources humaines",
9 "type": "url",
10 "url": "http://www.usinenouvelle.com/article/la-multiplication-des-chefs-de-projet-est-une-catastrophe-manageriale-majeure-affirme-le-sociologue-francois-dupuy.N307730"
11 } ],
12 "date_added": "13118829474385693",
13 "date_modified": "13118850929335823",
14 "id": "1",
15 "name": "Barre de favoris",
16 "type": "folder"
17 },
18 "other": {
19 "children": [ ],
20 "date_added": "13118829474385701",
21 "date_modified": "0",
22 "id": "2",
23 "name": "Autres favoris",
24 "type": "folder"
25 },
26 "synced": {
27 "children": [ ],
28 "date_added": "13118829474385702",
29 "date_modified": "0",
30 "id": "3",
31 "name": "Favoris sur mobile",
32 "type": "folder"
33 }
34 },
35 "version": 1
36}
diff --git a/tests/Wallabag/ImportBundle/fixtures/firefox-bookmarks.json b/tests/Wallabag/ImportBundle/fixtures/firefox-bookmarks.json
new file mode 100644
index 00000000..406b5697
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/fixtures/firefox-bookmarks.json
@@ -0,0 +1,63 @@
1{
2 "guid": "root________",
3 "title": "",
4 "index": 0,
5 "dateAdded": 1388166091504000,
6 "lastModified": 1472897622350000,
7 "id": 1,
8 "type": "text/x-moz-place-container",
9 "root": "placesRoot",
10 "children": [
11 {
12 "guid": "toolbar_____",
13 "title": "Barre personnelle",
14 "index": 1,
15 "dateAdded": 1388166091504000,
16 "lastModified": 1472897622263000,
17 "id": 3,
18 "annos": [
19 {
20 "name": "bookmarkProperties/description",
21 "flags": 0,
22 "expires": 4,
23 "value": "Ajoutez des marque-pages dans ce dossier pour les voir apparaître sur votre barre personnelle"
24 }
25 ],
26 "type": "text/x-moz-place-container",
27 "root": "toolbarFolder",
28 "children": [
29 {
30 "guid": "tard77lzbC5H",
31 "title": "Orange offre un meilleur réseau mobile que Bouygues et SFR, Free derrière - L'Express L'Expansion",
32 "index": 1,
33 "dateAdded": 1388166091644000,
34 "lastModified": 1388166091644000,
35 "tags":"test,tag",
36 "id": 4,
37 "type": "text/x-moz-place",
38 "uri": "http://lexpansion.lexpress.fr/high-tech/orange-offre-un-meilleur-reseau-mobile-que-bouygues-et-sfr-free-derriere_1811554.html"
39 },
40 {
41 "guid": "E385l9vZ_LVn",
42 "title": "Parser for Exported Bookmarks HTML file of Google Chrome and Mozilla in Java",
43 "index": 1,
44 "dateAdded": 1388166091544000,
45 "lastModified": 1388166091545000,
46 "id": 5,
47 "type": "text/x-moz-place",
48 "uri": "http://stackoverflow.com/questions/15017163/parser-for-exported-bookmarks-html-file-of-google-chrome-and-mozilla-in-java"
49 }
50 ]
51 },
52 {
53 "guid": "unfiled_____",
54 "title": "Autres marque-pages",
55 "index": 3,
56 "dateAdded": 1388166091504000,
57 "lastModified": 1388166091542000,
58 "id": 6,
59 "type": "text/x-moz-place-container",
60 "root": "unfiledBookmarksFolder"
61 }
62 ]
63}
diff --git a/tests/Wallabag/ImportBundle/fixtures/instapaper-export.csv b/tests/Wallabag/ImportBundle/fixtures/instapaper-export.csv
new file mode 100644
index 00000000..28a4c8e6
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/fixtures/instapaper-export.csv
@@ -0,0 +1,4 @@
1URL,Title,Selection,Folder
2http://www.liberation.fr/societe/2012/12/06/baumettes-un-tour-en-cellule_865551,Baumettes : un tour en cellule,,Unread
3https://redditblog.com/2016/09/20/amp-and-reactredux/,AMP and React+Redux: Why Not?,,Archive
4https://medium.com/@the_minh/why-foursquare-swarm-is-still-my-favourite-social-network-e38228493e6c,Why Foursquare / Swarm is still my favourite social network,,Starred
diff --git a/tests/Wallabag/ImportBundle/fixtures/readability-read.json b/tests/Wallabag/ImportBundle/fixtures/readability-read.json
new file mode 100644
index 00000000..c60767dc
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/fixtures/readability-read.json
@@ -0,0 +1,25 @@
1{
2 "bookmarks": [
3 {
4 "article__excerpt": "This is a guest post from Moritz Beller from the Delft University of Technology in The Netherlands. His team produced amazing research on several million Travis CI builds, creating invaluable&hellip;",
5 "favorite": false,
6 "date_archived": "2016-08-02T06:49:30",
7 "article__url": "https://blog.travis-ci.com/2016-07-28-what-we-learned-from-analyzing-2-million-travis-builds/",
8 "date_added": "2016-08-01T05:24:16",
9 "date_favorited": null,
10 "article__title": "Travis",
11 "archive": true
12 },
13 {
14 "article__excerpt": "The GraphQL Type system describes the capabilities of a GraphQL server and is used to determine if a query is valid. The type system also describes the input types of query variables to determine if&hellip;",
15 "favorite": false,
16 "date_archived": "2016-07-19T06:48:31",
17 "article__url": "https://facebook.github.io/graphql/",
18 "date_added": "2016-06-24T17:50:16",
19 "date_favorited": null,
20 "article__title": "GraphQL",
21 "archive": true
22 }
23 ],
24 "recommendations": []
25}
diff --git a/tests/Wallabag/ImportBundle/fixtures/readability.json b/tests/Wallabag/ImportBundle/fixtures/readability.json
new file mode 100644
index 00000000..32f6fa53
--- /dev/null
+++ b/tests/Wallabag/ImportBundle/fixtures/readability.json
@@ -0,0 +1,176 @@
1{
2 "bookmarks": [
3 {
4 "article__excerpt": "When Twitter started it had so much promise to change the way we communicate. But now it has been ruined by the amount of garbage and hate we have to wade through. It&#x2019;s like that polluted&hellip;",
5 "favorite": false,
6 "date_archived": null,
7 "article__url": "https://venngage.com/blog/hashtags-are-worthless/",
8 "date_added": "2016-08-25T12:05:00",
9 "date_favorited": null,
10 "article__title": "We Looked At 167,943 Tweets & Found Out Hashtags Are Worthless",
11 "archive": false
12 },
13 {
14 "article__title": "Réfugiés: l'UE va créer 100 000 places d'accueil dans les Balkans",
15 "article__url": "http://www.liberation.fr/planete/2015/10/26/refugies-l-ue-va-creer-100-000-places-d-accueil-dans-les-balkans_1408867",
16 "archive": false,
17 "date_added": "2016-09-08T11:55:58+0200",
18 "favorite": false
19 },
20 {
21 "article__title": "No title found",
22 "article__url": "http://news.nationalgeographic.com/2016/02/160211-albatrosses-mothers-babies-animals-science/&sf20739758=1",
23 "archive": false,
24 "date_added": "2016-09-08T11:55:58+0200",
25 "favorite": true
26 },
27 {
28 "archive": 0,
29 "date_added": "2016-09-08T11:55:58+0200",
30 "favorite": 0,
31 "article__title": "Échecs",
32 "article__url": "https://fr.wikipedia.org/wiki/Échecs"
33 },
34 {
35 "archive": 0,
36 "date_added": "2016-09-08T11:55:58+0200",
37 "favorite": 0,
38 "article__title": "90% des dossiers médicaux des Coréens du sud vendus à des entreprises privées - ZATAZ",
39 "article__url": "http://www.zataz.com/90-des-dossiers-medicaux-des-coreens-du-sud-vendus-a-des-entreprises-privees/"
40 },
41 {
42 "archive": 0,
43 "date_added": "2016-09-08T11:55:58+0200",
44 "favorite": 0,
45 "article__title": "Mass Surveillance As Art",
46 "article__url": "https://www.nationaljournal.com/s/73311/mass-surveillance-art"
47 },
48 {
49 "archive": 0,
50 "date_added": "2016-09-08T11:55:58+0200",
51 "favorite": 0,
52 "article__title": "What David Cameron did to the pig, his party is now doing to the country",
53 "article__url": "http://www.newstatesman.com/2015/09/what-david-cameron-did-pig-his-party-now-doing-country"
54 },
55 {
56 "archive": 1,
57 "date_added": "2016-09-08T11:55:58+0200",
58 "favorite": 0,
59 "article__title": "CLICK HERE to support 2016 CES Winner, Revolutionary Auto-Tracking Robot",
60 "article__url": "https://www.indiegogo.com/projects/2016-ces-winner-revolutionary-auto-tracking-robot"
61 },
62 {
63 "archive": 0,
64 "date_added": "2016-09-08T11:55:58+0200",
65 "favorite": 1,
66 "article__title": "No title found",
67 "article__url": "http://carnetdevol.shost.ca/wordpress/aide-memoire-sur-les-commandes-associees-a-systemd/"
68 },
69 {
70 "archive": 1,
71 "date_added": "2016-09-08T11:55:58+0200",
72 "favorite": 0,
73 "article__title": "Présentation d'Arduino - Tuto Arduino - Le blog d'Eskimon",
74 "article__url": "http://eskimon.fr/73-arduino-101-presentation"
75 },
76 {
77 "archive": 1,
78 "date_added": "2016-09-08T11:55:58+0200",
79 "favorite": 0,
80 "article__title": "Lenovo ThinkPad X1 Carbon Ultrabook Review",
81 "article__url": "http://www.notebookcheck.net/Lenovo-ThinkPad-X1-Carbon-Ultrabook-Review.138033.0.html"
82 },
83 {
84 "archive": 0,
85 "date_added": "2016-09-08T11:55:58+0200",
86 "favorite": 0,
87 "article__title": "Visitons le Château de Landsberg !",
88 "article__url": "http://autour-du-mont-sainte-odile.overblog.com/2016/01/visitons-le-chateau-de-landsberg.html"
89 },
90 {
91 "archive": 1,
92 "date_added": "2016-09-08T11:55:58+0200",
93 "favorite": 0,
94 "article__title": "Contrer les stéréotypes par les livres : “C'est dès l'enfance qu'ils se construisent”",
95 "article__url": "https://www.actualitte.com/article/monde-edition/contrer-les-stereotypes-par-les-livres-c-est-des-l-enfance-qu-ils-se-construisent/64058"
96 },
97 {
98 "archive": 1,
99 "date_added": "2016-09-08T11:55:58+0200",
100 "favorite": 0,
101 "article__title": "[ROM][6.0.1][Layers][N5] TipsyOS official builds {UBER TCs}",
102 "article__url": "http://forum.xda-developers.com/google-nexus-5/development/rom-tipsyos-official-builds-uber-tcs-t3325989"
103 },
104 {
105 "archive": 0,
106 "date_added": "2016-09-08T11:55:58+0200",
107 "favorite": 0,
108 "article__title": "Top 15 Podcasts All Web Developers Should Follow - Envato Tuts+ Code Article",
109 "article__url": "http://code.tutsplus.com/articles/top-15-podcasts-all-web-developers-should-follow--net-14461"
110 },
111 {
112 "archive": 1,
113 "date_added": "2016-09-08T11:55:58+0200",
114 "favorite": 0,
115 "article__title": "University of Mississippi",
116 "article__url": "http://olemiss.edu"
117 },
118 {
119 "archive": 1,
120 "date_added": "2016-09-08T11:55:58+0200",
121 "favorite": 0,
122 "article__title": "FinnChristiansen.de Jetzt Dank Let’s Encrypt Per HTTPS Erreichbar",
123 "article__url": "https://www.finnchristiansen.de/2015/12/06/finnchristiansen-de-jetzt-dank-lets-encrypt-per-https-erreichbar/"
124 },
125 {
126 "archive": 1,
127 "date_added": "2016-09-08T11:55:58+0200",
128 "favorite": 0,
129 "article__title": "Le développeur et l'ingénierie logicielle",
130 "article__url": "http://wemucs.com/le-developpeur-et-lingenierie-logicielle/"
131 },
132 {
133 "archive": 1,
134 "date_added": "2016-09-08T11:55:58+0200",
135 "favorite": 0,
136 "article__title": "The Role of Methylation in Gene Expression",
137 "article__url": "http://www.nature.com/scitable/topicpage/the-role-of-methylation-in-gene-expression-1070"
138 },
139 {
140 "archive": 1,
141 "date_added": "2016-09-08T11:55:58+0200",
142 "favorite": 0,
143 "article__title": "E-Mail-Adresse kostenlos, FreeMail, De-Mail & Nachrichten",
144 "article__url": "http://web.de"
145 },
146 {
147 "archive": 1,
148 "date_added": "2016-09-08T11:55:58+0200",
149 "favorite": 0,
150 "article__title": "OpenSSH Server on Arch Linux | DominicM test",
151 "article__url": "http://dominicm.com/openssh-server-arch-linux/"
152 },
153 {
154 "archive": 1,
155 "date_added": "2016-09-08T11:55:58+0200",
156 "favorite": 0,
157 "article__title": "Site Moved | Site Help",
158 "article__url": "http://g1.com/help/sitemoved.asp"
159 },
160 {
161 "archive": 1,
162 "date_added": "2016-09-08T11:55:58+0200",
163 "favorite": 0,
164 "article__title": "#Maroc : le stylo anti-pédophiles EAGLE d’AMESYS est moins bien configuré que les faux-lowers Twitter du roi Mohammed VI",
165 "article__url": "https://reflets.info/maroc-le-stylo-anti-pedophiles-eagle-damesys-est-moins-bien-configure-que-les-faux-lowers-twitter-du-roi-mohammed-vi/"
166 },
167 {
168 "archive": 1,
169 "date_added": "2016-09-08T11:55:58+0200",
170 "favorite": 0,
171 "article__title": "Simple Cloud Infrastructure for Developers",
172 "article__url": "https://www.digitalocean.com/"
173 }
174 ],
175 "recommendations": []
176}
diff --git a/tests/Wallabag/ImportBundle/fixtures/wallabag-v2-read.json b/tests/Wallabag/ImportBundle/fixtures/wallabag-v2-read.json
index 3fa0bddf..d8609280 100644
--- a/tests/Wallabag/ImportBundle/fixtures/wallabag-v2-read.json
+++ b/tests/Wallabag/ImportBundle/fixtures/wallabag-v2-read.json
@@ -4,6 +4,8 @@
4 "title": "Wikimedia Foundation removes The Diary of Anne Frank due to copyright law requirements « Wikimedia blog", 4 "title": "Wikimedia Foundation removes The Diary of Anne Frank due to copyright law requirements « Wikimedia blog",
5 "url": "https://blog.wikimedia.org/2016/02/10/anne-frank-diary-removal/", 5 "url": "https://blog.wikimedia.org/2016/02/10/anne-frank-diary-removal/",
6 "is_archived": true, 6 "is_archived": true,
7 "created_at": "2016-09-08T11:55:58+0200",
8 "updated_at": "2016-09-08T11:57:16+0200",
7 "is_starred": false, 9 "is_starred": false,
8 "content": "<p><a href=\"https://commons.wikimedia.org/wiki/File:AnneFrankSchoolPhoto.jpg\" rel=\"attachment wp-att-45105\"><img class=\"alignnone size-full wp-image-45105\" src=\"https://wikimediablog.files.wordpress.com/2016/02/annefrankschoolphoto.jpg?w=316&amp;h=520\" alt=\"AnneFrankSchoolPhoto\" width=\"316\" height=\"520\"/></a><br/><small><i>Anne Frank in 1940. <a href=\"https://commons.wikimedia.org/wiki/File:AnneFrankSchoolPhoto.jpg\">Photo</a> by Collectie Anne Frank Stichting Amsterdam, public domain.</i></small></p>\n<p>Today, in an unfortunate example of the overreach of the United States’ current copyright law, the Wikimedia Foundation removed the Dutch-language text of <a href=\"https://en.wikipedia.org/wiki/The_Diary_of_a_Young_Girl\"><em>The Diary of a Young Girl</em></a>—more commonly known in English as the <em>Diary of Anne Frank—</em>from Wikisource.<sup id=\"one\"><a href=\"https://blog.wikimedia.org/2016/02/10/anne-frank-diary-removal/#cite1\">[1]</a></sup></p>\n<p>We took this action to comply with the United States’ <a href=\"https://en.wikipedia.org/wiki/Digital_Millennium_Copyright_Act\">Digital Millennium Copyright Act</a> (DMCA), as we believe the diary is still under US copyright protection under the law as it is currently written. Nevertheless, our removal serves as an excellent example of why the law should be changed to prevent repeated extensions of copyright terms, an issue that has plagued our communities <a href=\"https://en.wikipedia.org/wiki/Wikipedia:Wikipedia_Signpost/2014-02-26/News_and_notes\">for years</a>.</p>\n<h3>What prompted us to remove the diary?</h3>\n<p>The deletion was required because the Foundation is under the jurisdiction of US law and is therefore subject to the DMCA, specifically <a href=\"https://www.law.cornell.edu/uscode/text/17/512\" target=\"_blank\">title 17, chapter 5, section 512 of the United States Code</a>. As we <a href=\"https://meta.wikimedia.org/wiki/Legal/URAA_Statement\" target=\"_blank\">noted</a> in 2013, “The location of the servers, incorporation, and headquarters are just three of many factors that establish US jurisdiction … if infringing content is linked to or embedded in Wikimedia projects, then  the Foundation may still be subject to liability for such use—either as a direct or contributory infringer.</p>\n<p>Based on email discussions sent to the Wikimedia Foundation at legal[at]wikimedia.org, we determined that the Wikimedia Foundation had either “actual knowledge” (i in the statute quoted below) or what is commonly called “red flag knowledge” (ii in the statute quoted below) that the Anne Frank text was hosted on Wikisource and was under copyright. The statute section states that a service provider is only protected by the DMCA when it:</p>\n<p><strong>(i) </strong>does not have actual knowledge that the material or an activity using the material on the system or network is infringing;</p>\n<p><strong>(ii) </strong>in the absence of such actual knowledge, is not aware of facts or circumstances from which infringing activity is apparent; or</p>\n<p>(The rest applies when we get a proper DMCA takedown notice.)</p>\n<p>Of particular concern, the US’ <a href=\"https://en.wikipedia.org/wiki/United_States_Court_of_Appeals_for_the_Ninth_Circuit\">9th Circuit Court of Appeals</a> stated in their ruling for <a href=\"http://law.justia.com/cases/federal/appellate-courts/ca9/09-55902/09-55902-2013-03-14.html\"><em>UMG Recordings, Inc. v. Shelter Capital Partners LLC</em></a> that in circumstances where a hosting provider (like the Wikimedia Foundation) is informed by a third party (like an unrelated user) about infringing copyrighted content, that would likely constitute either actual or red flag knowledge under the DMCA.</p>\n<p>We believe, based on the detail and specificity contained in the emails, that we received that we had actual knowledge sufficient for the DMCA to require us to perform a takedown even in the absence of a demand letter.</p>\n<h3>How is the diary still copyrighted?</h3>\n<p>You may wonder why or how the Anne Frank text is copyrighted at all, as <a href=\"https://en.wikipedia.org/wiki/Anne_Frank\">Anne Frank</a> died in February 1945. With 70 years having passed since her death, the text may have passed into public domain in the Netherlands on January 1, 2016, where it was first published, although <a href=\"http://www.npr.org/sections/thetwo-way/2015/12/31/461606275/mein-kampf-enters-public-domain-arguably-anne-franks-diary-may-too\">there is still some dispute about this</a>.</p>\n<p>However, in the United States, the Anne Frank original text will be under copyright until 2042. This is the result of several factors coming together, and the English-language Wikipedia has actually covered this issue with a multi-part test on its <a href=\"https://en.wikipedia.org/wiki/Wikipedia:Non-U.S._copyrights\">non-US copyrights content guideline.</a></p>\n<p>In short, there are three major laws that together make the diary still copyrighted:</p>\n<ol><li>In general, the U.S. copyright for works published before 1978 is 95 years from date of publication. This came about because copyrights in the U.S. were originally for 28 years, with the ability to then extend that for a second 28 years (making a total of 56). Starting with the <a href=\"https://en.wikipedia.org/wiki/Copyright_Act_of_1976\">1976 Copyright Act</a> and extending to several more acts, the renewal became automatic and was extended. Today, the total term of works published before 1978 is 95 years from date of publication.</li>\n<li>Foreign works of countries that are treaty partners to the United States are covered as if they were US works.</li>\n<li>Even if a country was not a treaty partner under copyright law at the time of a publication, the <a href=\"https://en.wikipedia.org/wiki/Uruguay_Round_Agreements_Act\">1994 Uruguay Round Agreements Act</a> (URAA) restored copyright to works that:\n<ul><li>had been published in a foreign country</li>\n<li>were still under copyright in that country in 1996</li>\n<li>and would have had U.S. copyright but for the fact they were published abroad.</li>\n</ul></li>\n</ol>\n<p>Court challenges to the URAA have all failed, with the most notable (<a href=\"https://en.wikipedia.org/wiki/Golan_v._Holder\"><em>Golan v. Holder</em></a>) resulting in a Supreme Court ruling that upheld the URAA.</p>\n<p>What that means for Anne Frank’s diary is unfortunately simple: no matter how it wound up in the United States and regardless of what formal copyright notices they used, the US grants it copyright until the year 2042, or 95 years after its original publication in 1947.</p>\n<p>Under current copyright law, this remains true regardless of its copyright status anywhere else in the world and regardless of whether it may have been in the public domain in the United States in the past.</p>\n<p><a href=\"https://wikimediafoundation.org/wiki/User:Jrogers_(WMF)\"><em>Jacob Rogers</em></a><em>, Legal Counsel*<br/>Wikimedia Foundation</em></p>\n<p><em>*Special thanks to </em><a href=\"https://wikimediafoundation.org/wiki/User:AMangalick_(WMF)\"><em>Anisha Mangalick</em></a><em>, Legal Fellow, for her assistance in this matter.</em></p>\n<p><a href=\"https://blog.wikimedia.org/2016/02/10/anne-frank-diary-removal/#one\">[1]</a> The diary text was originally located at <a href=\"https://nl.wikisource.org/wiki/Het_Achterhuis_(Anne_Frank)\" rel=\"nofollow\">https://nl.wikisource.org/wiki/Het_Achterhuis_(Anne_Frank)</a>.</p>\n<p><em>This article was edited to clarify that it is not just the location of the Wikimedia Foundation’s servers that determine whether we fall in US jurisdiction.</em></p>\n\t\t\t\t\t\t\t\t\t\t\t", 10 "content": "<p><a href=\"https://commons.wikimedia.org/wiki/File:AnneFrankSchoolPhoto.jpg\" rel=\"attachment wp-att-45105\"><img class=\"alignnone size-full wp-image-45105\" src=\"https://wikimediablog.files.wordpress.com/2016/02/annefrankschoolphoto.jpg?w=316&amp;h=520\" alt=\"AnneFrankSchoolPhoto\" width=\"316\" height=\"520\"/></a><br/><small><i>Anne Frank in 1940. <a href=\"https://commons.wikimedia.org/wiki/File:AnneFrankSchoolPhoto.jpg\">Photo</a> by Collectie Anne Frank Stichting Amsterdam, public domain.</i></small></p>\n<p>Today, in an unfortunate example of the overreach of the United States’ current copyright law, the Wikimedia Foundation removed the Dutch-language text of <a href=\"https://en.wikipedia.org/wiki/The_Diary_of_a_Young_Girl\"><em>The Diary of a Young Girl</em></a>—more commonly known in English as the <em>Diary of Anne Frank—</em>from Wikisource.<sup id=\"one\"><a href=\"https://blog.wikimedia.org/2016/02/10/anne-frank-diary-removal/#cite1\">[1]</a></sup></p>\n<p>We took this action to comply with the United States’ <a href=\"https://en.wikipedia.org/wiki/Digital_Millennium_Copyright_Act\">Digital Millennium Copyright Act</a> (DMCA), as we believe the diary is still under US copyright protection under the law as it is currently written. Nevertheless, our removal serves as an excellent example of why the law should be changed to prevent repeated extensions of copyright terms, an issue that has plagued our communities <a href=\"https://en.wikipedia.org/wiki/Wikipedia:Wikipedia_Signpost/2014-02-26/News_and_notes\">for years</a>.</p>\n<h3>What prompted us to remove the diary?</h3>\n<p>The deletion was required because the Foundation is under the jurisdiction of US law and is therefore subject to the DMCA, specifically <a href=\"https://www.law.cornell.edu/uscode/text/17/512\" target=\"_blank\">title 17, chapter 5, section 512 of the United States Code</a>. As we <a href=\"https://meta.wikimedia.org/wiki/Legal/URAA_Statement\" target=\"_blank\">noted</a> in 2013, “The location of the servers, incorporation, and headquarters are just three of many factors that establish US jurisdiction … if infringing content is linked to or embedded in Wikimedia projects, then  the Foundation may still be subject to liability for such use—either as a direct or contributory infringer.</p>\n<p>Based on email discussions sent to the Wikimedia Foundation at legal[at]wikimedia.org, we determined that the Wikimedia Foundation had either “actual knowledge” (i in the statute quoted below) or what is commonly called “red flag knowledge” (ii in the statute quoted below) that the Anne Frank text was hosted on Wikisource and was under copyright. The statute section states that a service provider is only protected by the DMCA when it:</p>\n<p><strong>(i) </strong>does not have actual knowledge that the material or an activity using the material on the system or network is infringing;</p>\n<p><strong>(ii) </strong>in the absence of such actual knowledge, is not aware of facts or circumstances from which infringing activity is apparent; or</p>\n<p>(The rest applies when we get a proper DMCA takedown notice.)</p>\n<p>Of particular concern, the US’ <a href=\"https://en.wikipedia.org/wiki/United_States_Court_of_Appeals_for_the_Ninth_Circuit\">9th Circuit Court of Appeals</a> stated in their ruling for <a href=\"http://law.justia.com/cases/federal/appellate-courts/ca9/09-55902/09-55902-2013-03-14.html\"><em>UMG Recordings, Inc. v. Shelter Capital Partners LLC</em></a> that in circumstances where a hosting provider (like the Wikimedia Foundation) is informed by a third party (like an unrelated user) about infringing copyrighted content, that would likely constitute either actual or red flag knowledge under the DMCA.</p>\n<p>We believe, based on the detail and specificity contained in the emails, that we received that we had actual knowledge sufficient for the DMCA to require us to perform a takedown even in the absence of a demand letter.</p>\n<h3>How is the diary still copyrighted?</h3>\n<p>You may wonder why or how the Anne Frank text is copyrighted at all, as <a href=\"https://en.wikipedia.org/wiki/Anne_Frank\">Anne Frank</a> died in February 1945. With 70 years having passed since her death, the text may have passed into public domain in the Netherlands on January 1, 2016, where it was first published, although <a href=\"http://www.npr.org/sections/thetwo-way/2015/12/31/461606275/mein-kampf-enters-public-domain-arguably-anne-franks-diary-may-too\">there is still some dispute about this</a>.</p>\n<p>However, in the United States, the Anne Frank original text will be under copyright until 2042. This is the result of several factors coming together, and the English-language Wikipedia has actually covered this issue with a multi-part test on its <a href=\"https://en.wikipedia.org/wiki/Wikipedia:Non-U.S._copyrights\">non-US copyrights content guideline.</a></p>\n<p>In short, there are three major laws that together make the diary still copyrighted:</p>\n<ol><li>In general, the U.S. copyright for works published before 1978 is 95 years from date of publication. This came about because copyrights in the U.S. were originally for 28 years, with the ability to then extend that for a second 28 years (making a total of 56). Starting with the <a href=\"https://en.wikipedia.org/wiki/Copyright_Act_of_1976\">1976 Copyright Act</a> and extending to several more acts, the renewal became automatic and was extended. Today, the total term of works published before 1978 is 95 years from date of publication.</li>\n<li>Foreign works of countries that are treaty partners to the United States are covered as if they were US works.</li>\n<li>Even if a country was not a treaty partner under copyright law at the time of a publication, the <a href=\"https://en.wikipedia.org/wiki/Uruguay_Round_Agreements_Act\">1994 Uruguay Round Agreements Act</a> (URAA) restored copyright to works that:\n<ul><li>had been published in a foreign country</li>\n<li>were still under copyright in that country in 1996</li>\n<li>and would have had U.S. copyright but for the fact they were published abroad.</li>\n</ul></li>\n</ol>\n<p>Court challenges to the URAA have all failed, with the most notable (<a href=\"https://en.wikipedia.org/wiki/Golan_v._Holder\"><em>Golan v. Holder</em></a>) resulting in a Supreme Court ruling that upheld the URAA.</p>\n<p>What that means for Anne Frank’s diary is unfortunately simple: no matter how it wound up in the United States and regardless of what formal copyright notices they used, the US grants it copyright until the year 2042, or 95 years after its original publication in 1947.</p>\n<p>Under current copyright law, this remains true regardless of its copyright status anywhere else in the world and regardless of whether it may have been in the public domain in the United States in the past.</p>\n<p><a href=\"https://wikimediafoundation.org/wiki/User:Jrogers_(WMF)\"><em>Jacob Rogers</em></a><em>, Legal Counsel*<br/>Wikimedia Foundation</em></p>\n<p><em>*Special thanks to </em><a href=\"https://wikimediafoundation.org/wiki/User:AMangalick_(WMF)\"><em>Anisha Mangalick</em></a><em>, Legal Fellow, for her assistance in this matter.</em></p>\n<p><a href=\"https://blog.wikimedia.org/2016/02/10/anne-frank-diary-removal/#one\">[1]</a> The diary text was originally located at <a href=\"https://nl.wikisource.org/wiki/Het_Achterhuis_(Anne_Frank)\" rel=\"nofollow\">https://nl.wikisource.org/wiki/Het_Achterhuis_(Anne_Frank)</a>.</p>\n<p><em>This article was edited to clarify that it is not just the location of the Wikimedia Foundation’s servers that determine whether we fall in US jurisdiction.</em></p>\n\t\t\t\t\t\t\t\t\t\t\t",
9 "mimetype": "text/html", 11 "mimetype": "text/html",
@@ -17,6 +19,8 @@
17 "title": "Tails - Tails 2.0.1 is out", 19 "title": "Tails - Tails 2.0.1 is out",
18 "url": "https://tails.boum.org/news/version_2.0.1/index.en.html", 20 "url": "https://tails.boum.org/news/version_2.0.1/index.en.html",
19 "is_archived": false, 21 "is_archived": false,
22 "created_at": "2016-09-08T11:55:58+0200",
23 "updated_at": "2016-09-08T11:57:16+0200",
20 "is_starred": false, 24 "is_starred": false,
21 "content": "<div id=\"pagebody\" readability=\"39\">\n<p>This release fixes <a href=\"https://tails.boum.org/security/Numerous_security_holes_in_2.0/index.en.html\">numerous security issues</a>. All users must upgrade as soon as possible.</p>\n<div class=\"toc\">\n<ol><li class=\"L1\"><a href=\"https://tails.boum.org/news/version_2.0.1/index.en.html#index1h1\">Changes</a></li>\n<li class=\"L1\"><a href=\"https://tails.boum.org/news/version_2.0.1/index.en.html#index2h1\">Known issues</a></li>\n<li class=\"L1\"><a href=\"https://tails.boum.org/news/version_2.0.1/index.en.html#index3h1\">Download or upgrade</a></li>\n<li class=\"L1\"><a href=\"https://tails.boum.org/news/version_2.0.1/index.en.html#index4h1\">What's coming up?</a></li>\n</ol></div>\n<h2>New features</h2>\n<ul><li readability=\"11\">\n<p>Tails now uses the GNOME Shell desktop environment, in its Classic mode. GNOME Shell provides a modern, simple, and actively developed desktop environment. The Classic mode keeps the traditional Applications, Places menu, and windows list. Accessibility and non-Latin input sources are also better integrated.</p>\n<p>To find your way around, <a href=\"https://tails.boum.org/doc/first_steps/introduction_to_gnome_and_the_tails_desktop/index.en.html\">read our introduction to GNOME and the Tails desktop.</a></p>\n<table class=\"img\"><caption>The desktop and Applications menu</caption>\n<tr><td><img alt=\"Tails 2.0 desktop with applications menu unfolded\" class=\"img\" height=\"384\" src=\"https://tails.boum.org/inc/release_notes/2.0/applications_menu.png\" width=\"512\"/></td>\n</tr></table><table class=\"img\"><caption>The activities overview</caption>\n<tr><td><img alt=\"Tails 2.0 activities overview\" class=\"img\" height=\"384\" src=\"https://tails.boum.org/inc/release_notes/2.0/activities_overview.png\" width=\"512\"/></td>\n</tr></table></li>\n</ul><h2>Upgrades and changes</h2>\n<ul><li readability=\"2\">\n<p>Debian 8 upgrades most included software, for example:</p>\n<ul><li>Many core GNOME utilities from 3.4 to 3.14: Files, Disks, Videos, etc.</li>\n<li>LibreOffice from 3.5 to 4.3</li>\n<li>PiTiVi from 0.15 to 0.93</li>\n<li>Git from 1.7.10 to 2.1.4</li>\n<li>Poedit from 1.5.4 to 1.6.10</li>\n<li>Liferea from 1.8.6 to 1.10</li>\n</ul></li>\n<li readability=\"1\">\n<p>Update Tor Browser to 5.5 (based on Firefox 38.6.0 ESR):</p>\n<ul><li>Add Japanese support.</li>\n</ul></li>\n<li readability=\"2\">\n<p>Remove the Windows camouflage which is currently broken in GNOME Shell. We started working on <a href=\"https://labs.riseup.net/code/issues/10830\">adding it back</a> but <a href=\"https://tails.boum.org/news/windows_camouflage_jessie/index.en.html\">your help is needed</a>!</p>\n</li>\n<li readability=\"1\">\n<p>Change to <code>systemd</code> as init system and use it to:</p>\n<ul><li>Sandbox many services using Linux namespaces and make them harder to exploit.</li>\n<li>Make the launching of Tor and the memory wipe on shutdown more robust.</li>\n<li>Sanitize our code base by replacing many custom scripts.</li>\n</ul></li>\n<li readability=\"1\">\n<p>Update most firmware packages which might improve hardware compatibility.</p>\n</li>\n<li readability=\"1\">\n<p>Notify the user if Tails is running from a non-free virtualization software.</p>\n</li>\n<li readability=\"3\">\n<p>Remove Claws Mail, replaced by <a href=\"https://tails.boum.org/doc/anonymous_internet/icedove/index.en.html\">Icedove</a>, a rebranded version of Mozilla Thunderbird.</p>\n</li>\n</ul><h2>Fixed problems</h2>\n<ul><li readability=\"1\">\n<p>HiDPI displays are better supported. (<a href=\"https://labs.riseup.net/code/issues/8659\">#8659</a>)</p>\n</li>\n<li readability=\"3\">\n<p>Remove the option to open a download with an external application in Tor Browser as this is usually impossible due to the AppArmor confinement. (<a href=\"https://labs.riseup.net/code/issues/9285\">#9285</a>)</p>\n</li>\n<li readability=\"1\">\n<p>Close Vidalia before restarting Tor.</p>\n</li>\n<li readability=\"2\">\n<p>Allow Videos to access the DVD drive. (<a href=\"https://labs.riseup.net/code/issues/10455\">#10455</a>, <a href=\"https://labs.riseup.net/code/issues/9990\">#9990</a>)</p>\n</li>\n<li readability=\"1\">\n<p>Allow configuring printers without administration password. (<a href=\"https://labs.riseup.net/code/issues/8443\">#8443</a>)</p>\n</li>\n</ul>\n<p>See the current list of <a href=\"https://tails.boum.org/support/known_issues/index.en.html\">known issues</a>.</p>\n<p>Go to the <a href=\"https://tails.boum.org/download/index.en.html\">download</a> or <a href=\"https://tails.boum.org/doc/first_steps/upgrade/index.en.html\">upgrade</a> page.</p>\n<p>If your Tails does not boot after an automatic upgrade, please <a href=\"https://tails.boum.org/doc/first_steps/upgrade/index.en.html#manual\">upgrade your Tails manually</a>.</p>\n<p>The next Tails release is <a href=\"https://tails.boum.org/contribute/calendar/\">scheduled</a> for March 08.</p>\n<p>Have a look at our <a href=\"https://labs.riseup.net/code/projects/tails/roadmap\">roadmap</a> to see where we are heading to.</p>\n<p>We need your help and there are many ways to <a href=\"https://tails.boum.org/contribute/index.en.html\">contribute to Tails</a> (<a href=\"https://tails.boum.org/contribute/how/donate/index.en.html\">donating</a> is only one of them). Come <a href=\"https://tails.boum.org/contribute/talk/\">talk to us</a>!</p>\n</div><div id=\"footer\" class=\"pagefooter\" role=\"contentinfo\" readability=\"15\">\n<p>Tags: <a href=\"https://tails.boum.org/tags/announce/\" rel=\"tag\">announce</a></p>\n<p>Pages linking to this one: <a href=\"https://tails.boum.org/inc/stable_i386_release_notes/index.en.html\">inc/stable i386 release notes</a> <a href=\"https://tails.boum.org/security/Numerous_security_holes_in_2.0/index.en.html\">security/Numerous security holes in 2.0</a></p>\n<p>Last edited Sat 13 Feb 2016 02:23:58 PM CET </p>\n</div>", 25 "content": "<div id=\"pagebody\" readability=\"39\">\n<p>This release fixes <a href=\"https://tails.boum.org/security/Numerous_security_holes_in_2.0/index.en.html\">numerous security issues</a>. All users must upgrade as soon as possible.</p>\n<div class=\"toc\">\n<ol><li class=\"L1\"><a href=\"https://tails.boum.org/news/version_2.0.1/index.en.html#index1h1\">Changes</a></li>\n<li class=\"L1\"><a href=\"https://tails.boum.org/news/version_2.0.1/index.en.html#index2h1\">Known issues</a></li>\n<li class=\"L1\"><a href=\"https://tails.boum.org/news/version_2.0.1/index.en.html#index3h1\">Download or upgrade</a></li>\n<li class=\"L1\"><a href=\"https://tails.boum.org/news/version_2.0.1/index.en.html#index4h1\">What's coming up?</a></li>\n</ol></div>\n<h2>New features</h2>\n<ul><li readability=\"11\">\n<p>Tails now uses the GNOME Shell desktop environment, in its Classic mode. GNOME Shell provides a modern, simple, and actively developed desktop environment. The Classic mode keeps the traditional Applications, Places menu, and windows list. Accessibility and non-Latin input sources are also better integrated.</p>\n<p>To find your way around, <a href=\"https://tails.boum.org/doc/first_steps/introduction_to_gnome_and_the_tails_desktop/index.en.html\">read our introduction to GNOME and the Tails desktop.</a></p>\n<table class=\"img\"><caption>The desktop and Applications menu</caption>\n<tr><td><img alt=\"Tails 2.0 desktop with applications menu unfolded\" class=\"img\" height=\"384\" src=\"https://tails.boum.org/inc/release_notes/2.0/applications_menu.png\" width=\"512\"/></td>\n</tr></table><table class=\"img\"><caption>The activities overview</caption>\n<tr><td><img alt=\"Tails 2.0 activities overview\" class=\"img\" height=\"384\" src=\"https://tails.boum.org/inc/release_notes/2.0/activities_overview.png\" width=\"512\"/></td>\n</tr></table></li>\n</ul><h2>Upgrades and changes</h2>\n<ul><li readability=\"2\">\n<p>Debian 8 upgrades most included software, for example:</p>\n<ul><li>Many core GNOME utilities from 3.4 to 3.14: Files, Disks, Videos, etc.</li>\n<li>LibreOffice from 3.5 to 4.3</li>\n<li>PiTiVi from 0.15 to 0.93</li>\n<li>Git from 1.7.10 to 2.1.4</li>\n<li>Poedit from 1.5.4 to 1.6.10</li>\n<li>Liferea from 1.8.6 to 1.10</li>\n</ul></li>\n<li readability=\"1\">\n<p>Update Tor Browser to 5.5 (based on Firefox 38.6.0 ESR):</p>\n<ul><li>Add Japanese support.</li>\n</ul></li>\n<li readability=\"2\">\n<p>Remove the Windows camouflage which is currently broken in GNOME Shell. We started working on <a href=\"https://labs.riseup.net/code/issues/10830\">adding it back</a> but <a href=\"https://tails.boum.org/news/windows_camouflage_jessie/index.en.html\">your help is needed</a>!</p>\n</li>\n<li readability=\"1\">\n<p>Change to <code>systemd</code> as init system and use it to:</p>\n<ul><li>Sandbox many services using Linux namespaces and make them harder to exploit.</li>\n<li>Make the launching of Tor and the memory wipe on shutdown more robust.</li>\n<li>Sanitize our code base by replacing many custom scripts.</li>\n</ul></li>\n<li readability=\"1\">\n<p>Update most firmware packages which might improve hardware compatibility.</p>\n</li>\n<li readability=\"1\">\n<p>Notify the user if Tails is running from a non-free virtualization software.</p>\n</li>\n<li readability=\"3\">\n<p>Remove Claws Mail, replaced by <a href=\"https://tails.boum.org/doc/anonymous_internet/icedove/index.en.html\">Icedove</a>, a rebranded version of Mozilla Thunderbird.</p>\n</li>\n</ul><h2>Fixed problems</h2>\n<ul><li readability=\"1\">\n<p>HiDPI displays are better supported. (<a href=\"https://labs.riseup.net/code/issues/8659\">#8659</a>)</p>\n</li>\n<li readability=\"3\">\n<p>Remove the option to open a download with an external application in Tor Browser as this is usually impossible due to the AppArmor confinement. (<a href=\"https://labs.riseup.net/code/issues/9285\">#9285</a>)</p>\n</li>\n<li readability=\"1\">\n<p>Close Vidalia before restarting Tor.</p>\n</li>\n<li readability=\"2\">\n<p>Allow Videos to access the DVD drive. (<a href=\"https://labs.riseup.net/code/issues/10455\">#10455</a>, <a href=\"https://labs.riseup.net/code/issues/9990\">#9990</a>)</p>\n</li>\n<li readability=\"1\">\n<p>Allow configuring printers without administration password. (<a href=\"https://labs.riseup.net/code/issues/8443\">#8443</a>)</p>\n</li>\n</ul>\n<p>See the current list of <a href=\"https://tails.boum.org/support/known_issues/index.en.html\">known issues</a>.</p>\n<p>Go to the <a href=\"https://tails.boum.org/download/index.en.html\">download</a> or <a href=\"https://tails.boum.org/doc/first_steps/upgrade/index.en.html\">upgrade</a> page.</p>\n<p>If your Tails does not boot after an automatic upgrade, please <a href=\"https://tails.boum.org/doc/first_steps/upgrade/index.en.html#manual\">upgrade your Tails manually</a>.</p>\n<p>The next Tails release is <a href=\"https://tails.boum.org/contribute/calendar/\">scheduled</a> for March 08.</p>\n<p>Have a look at our <a href=\"https://labs.riseup.net/code/projects/tails/roadmap\">roadmap</a> to see where we are heading to.</p>\n<p>We need your help and there are many ways to <a href=\"https://tails.boum.org/contribute/index.en.html\">contribute to Tails</a> (<a href=\"https://tails.boum.org/contribute/how/donate/index.en.html\">donating</a> is only one of them). Come <a href=\"https://tails.boum.org/contribute/talk/\">talk to us</a>!</p>\n</div><div id=\"footer\" class=\"pagefooter\" role=\"contentinfo\" readability=\"15\">\n<p>Tags: <a href=\"https://tails.boum.org/tags/announce/\" rel=\"tag\">announce</a></p>\n<p>Pages linking to this one: <a href=\"https://tails.boum.org/inc/stable_i386_release_notes/index.en.html\">inc/stable i386 release notes</a> <a href=\"https://tails.boum.org/security/Numerous_security_holes_in_2.0/index.en.html\">security/Numerous security holes in 2.0</a></p>\n<p>Last edited Sat 13 Feb 2016 02:23:58 PM CET </p>\n</div>",
22 "mimetype": "text/html", 26 "mimetype": "text/html",
diff --git a/tests/Wallabag/ImportBundle/fixtures/wallabag-v2.json b/tests/Wallabag/ImportBundle/fixtures/wallabag-v2.json
index 37c59668..efa8faf2 100644
--- a/tests/Wallabag/ImportBundle/fixtures/wallabag-v2.json
+++ b/tests/Wallabag/ImportBundle/fixtures/wallabag-v2.json
@@ -4,6 +4,8 @@
4 "title": "Site d'information français d'actualités indépendant et participatif en ligne | Mediapart", 4 "title": "Site d'information français d'actualités indépendant et participatif en ligne | Mediapart",
5 "url": "https://www.mediapart.fr/", 5 "url": "https://www.mediapart.fr/",
6 "is_archived": false, 6 "is_archived": false,
7 "created_at": "2016-09-08T11:55:58+0200",
8 "updated_at": "2016-09-08T11:57:16+0200",
7 "is_starred": false, 9 "is_starred": false,
8 "content": "<div alt=\"li\">Édition <a href=\"https://blogs.mediapart.fr/edition/camedia-0\">CAMédia</a>\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/edition/camedia/article/180116/deux-nouvelles-editions-pour-debattre-dans-le-club-sur-la-laicite-et-sur-la-democratie\">Deux nouvelles éditions pour débattre dans le club sur la laïcité et sur la démocratie</a></h3>\n<p>18 janv. 2016 | Par </p>\n<p>CAMédia après un échange sur « l'éthique du débat » a lancé deux discussions , l'une sur le thème de la laïcité, l'autre ( encore en cours) sur celui de la démocratie. Nous sommes heureux de pouvoir signaler la création de deux nouvelles éditions participatives sur ces thèmes. Nous vous invitons à les lire et à participer à leurs débats.</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/lucile-longre/blog/170116/de-limportance-de-rever-eloge-du-merveilleux\">De l'importance de rêver, éloge du merveilleux</a></h3>\n<p>17 janv. 2016 | Par </p>\n<p>Je parlerai ici des rêves comme moteur de vie, de ces rêves qui vous rattachent et vous font espérer à ce qu’il y a de plus humain dans l’homme, même au milieu de la plus noire des détresses.</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/barbara-romagnan/blog/180116/fins-dune-toute-puissance\">Fin(s) d'une toute-puissance</a></h3>\n<p>18 janv. 2016 | Par </p>\n<p>En ce début d’année, je recommande la lecture du dernier ouvrage de Guillaume Duval, La France ne sera jamais plus une grande puissance ? Tant mieux !</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/jean-pierre-thibaudat/blog/170116/l-allier-departement-de-destruction-massive-du-tissu-culturel\">L’Allier, département de destruction massive du tissu culturel</a></h3>\n<p>18 janv. 2016 | Par </p>\n<p>Les temps sont durs pour les petites structures, les associations culturelles qui, de bourgades en villages, travaillent au cœur des régions. Leurs subventions sont souvent revues à la baisse. Le département de l’Allier les a carrément supprimées. Pour favoriser « l’événementiel ».</p>\n</div><div alt=\"li\">Édition <a href=\"https://blogs.mediapart.fr/edition/les-invites-de-mediapart\">Les invités de Mediapart</a>\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/edition/les-invites-de-mediapart/article/180116/la-democratie-deja-attaquee-par-la-cooperation-reglementaire-transatlantiqu\">La démocratie déjà attaquée par la coopération réglementaire transatlantique</a></h3>\n<p>18 janv. 2016 | Par </p>\n<p>Lora Verheecke et David Lundy travaillent pour Corporate Europe Observatory, une ONG basée à Bruxelles qui enquête sur le pouvoir des lobbies des grandes entreprises sur la politique de l’Union européenne. Ils révèlent que depuis 25 ans le projet de « coopération réglementaire » mené par l’Union européenne et les États-Unis a été dominé par les grandes entreprises. ET que le TTIP cherche à entériner ce projet.</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/jacqueline-derens/blog/180116/2016-une-annee-test-pour-jacob-zuma-et-son-gouvernement\">2016, une année test pour Jacob Zuma et son gouvernement</a></h3>\n<p>18 janv. 2016 | Par </p>\n<p>Les turbulences de l’an passé ont toutes les chances de continuer à troubler le climat politique et social de l’Afrique du Sud en 2016. La situation exige des changements profonds dans la conduite des affaires du pays. Jacob Zuma tout en admettant la nécessité de ces changements, est-il l’homme de la situation ? Son gouvernement répondra-t-il aux attentes des citoyens sud-africains ?</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/marie-cosnay/blog/140116/un-mal-fou-janvier-2016\">Un mal fou (janvier 2016)</a></h3>\n<p>14 janv. 2016 | Par </p>\n<p>J’ai une fringale d’aventure, d’aventures à venir. J’ai la fringale de la fringale des aventures et soudain, rupture. Je n’y arrive plus, tout est bloqué, tout empêché. Faut dire que depuis un an environ, tout est devenu plus compliqué. Ecrire va de moins en moins de soi.</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/jean-pierre-veran/blog/170116/redoublement-le-changement-bas-bruit\">Redoublement : le changement à bas bruit ?</a></h3>\n<p>17 janv. 2016 | Par </p>\n<p>S’il est une caractéristique de la forme scolaire française bien établie dans la culture des personnels, des élèves et des parents, c’est bien le redoublement, censé sanctionner des résultats insuffisants pour envisager le passage dans la classe supérieure. Or, en ce domaine, l’évolution est nette.</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/michel-de-pracontal/blog/160116/samedi-sciences-196-des-chasseurs-de-mammouths-en-arctique-il-y-45-000-ans\">Samedi-sciences (196): des chasseurs de mammouths en Arctique il y a 45 000 ans</a></h3>\n<p>16 janv. 2016 | Par <a href=\"https://blogs.mediapart.fr/michel-de-pracontal\" class=\"journalist\">Michel de Pracontal</a></p>\n<p>Les restes d’un mammouth retrouvés en Arctique sibérien, datés de 45 000 ans, portent les traces de blessures infligées par des chasseurs humains. Les scientifiques pensaient jusqu’ici que notre espèce ne s’était pas aventurée dans cette région glaciale il y a plus de 30 000 ou 35 0000 ans. En réalité, des hommes ont réussi à survivre en Arctique au moins 10 000 ans plus tôt que l’on croyait.</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/alain-zolty/blog/140116/de-la-democratie-du-citoyen-et-de-lethique\">De la démocratie, du citoyen et de l'éthique</a></h3>\n<p>14 janv. 2016 | Par </p>\n<p>Trois ouvrages sont parus au Seuil, qui font état de la nécessité d’intégrer le citoyen dans la gouvernance de la nation. Non pas à titre consultatif mais doté d’un pouvoir délibératif pour constituer une contre-force face aux clans politico-financiers qui dominent la vie publique.</p>\n</div>", 10 "content": "<div alt=\"li\">Édition <a href=\"https://blogs.mediapart.fr/edition/camedia-0\">CAMédia</a>\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/edition/camedia/article/180116/deux-nouvelles-editions-pour-debattre-dans-le-club-sur-la-laicite-et-sur-la-democratie\">Deux nouvelles éditions pour débattre dans le club sur la laïcité et sur la démocratie</a></h3>\n<p>18 janv. 2016 | Par </p>\n<p>CAMédia après un échange sur « l'éthique du débat » a lancé deux discussions , l'une sur le thème de la laïcité, l'autre ( encore en cours) sur celui de la démocratie. Nous sommes heureux de pouvoir signaler la création de deux nouvelles éditions participatives sur ces thèmes. Nous vous invitons à les lire et à participer à leurs débats.</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/lucile-longre/blog/170116/de-limportance-de-rever-eloge-du-merveilleux\">De l'importance de rêver, éloge du merveilleux</a></h3>\n<p>17 janv. 2016 | Par </p>\n<p>Je parlerai ici des rêves comme moteur de vie, de ces rêves qui vous rattachent et vous font espérer à ce qu’il y a de plus humain dans l’homme, même au milieu de la plus noire des détresses.</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/barbara-romagnan/blog/180116/fins-dune-toute-puissance\">Fin(s) d'une toute-puissance</a></h3>\n<p>18 janv. 2016 | Par </p>\n<p>En ce début d’année, je recommande la lecture du dernier ouvrage de Guillaume Duval, La France ne sera jamais plus une grande puissance ? Tant mieux !</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/jean-pierre-thibaudat/blog/170116/l-allier-departement-de-destruction-massive-du-tissu-culturel\">L’Allier, département de destruction massive du tissu culturel</a></h3>\n<p>18 janv. 2016 | Par </p>\n<p>Les temps sont durs pour les petites structures, les associations culturelles qui, de bourgades en villages, travaillent au cœur des régions. Leurs subventions sont souvent revues à la baisse. Le département de l’Allier les a carrément supprimées. Pour favoriser « l’événementiel ».</p>\n</div><div alt=\"li\">Édition <a href=\"https://blogs.mediapart.fr/edition/les-invites-de-mediapart\">Les invités de Mediapart</a>\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/edition/les-invites-de-mediapart/article/180116/la-democratie-deja-attaquee-par-la-cooperation-reglementaire-transatlantiqu\">La démocratie déjà attaquée par la coopération réglementaire transatlantique</a></h3>\n<p>18 janv. 2016 | Par </p>\n<p>Lora Verheecke et David Lundy travaillent pour Corporate Europe Observatory, une ONG basée à Bruxelles qui enquête sur le pouvoir des lobbies des grandes entreprises sur la politique de l’Union européenne. Ils révèlent que depuis 25 ans le projet de « coopération réglementaire » mené par l’Union européenne et les États-Unis a été dominé par les grandes entreprises. ET que le TTIP cherche à entériner ce projet.</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/jacqueline-derens/blog/180116/2016-une-annee-test-pour-jacob-zuma-et-son-gouvernement\">2016, une année test pour Jacob Zuma et son gouvernement</a></h3>\n<p>18 janv. 2016 | Par </p>\n<p>Les turbulences de l’an passé ont toutes les chances de continuer à troubler le climat politique et social de l’Afrique du Sud en 2016. La situation exige des changements profonds dans la conduite des affaires du pays. Jacob Zuma tout en admettant la nécessité de ces changements, est-il l’homme de la situation ? Son gouvernement répondra-t-il aux attentes des citoyens sud-africains ?</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/marie-cosnay/blog/140116/un-mal-fou-janvier-2016\">Un mal fou (janvier 2016)</a></h3>\n<p>14 janv. 2016 | Par </p>\n<p>J’ai une fringale d’aventure, d’aventures à venir. J’ai la fringale de la fringale des aventures et soudain, rupture. Je n’y arrive plus, tout est bloqué, tout empêché. Faut dire que depuis un an environ, tout est devenu plus compliqué. Ecrire va de moins en moins de soi.</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/jean-pierre-veran/blog/170116/redoublement-le-changement-bas-bruit\">Redoublement : le changement à bas bruit ?</a></h3>\n<p>17 janv. 2016 | Par </p>\n<p>S’il est une caractéristique de la forme scolaire française bien établie dans la culture des personnels, des élèves et des parents, c’est bien le redoublement, censé sanctionner des résultats insuffisants pour envisager le passage dans la classe supérieure. Or, en ce domaine, l’évolution est nette.</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/michel-de-pracontal/blog/160116/samedi-sciences-196-des-chasseurs-de-mammouths-en-arctique-il-y-45-000-ans\">Samedi-sciences (196): des chasseurs de mammouths en Arctique il y a 45 000 ans</a></h3>\n<p>16 janv. 2016 | Par <a href=\"https://blogs.mediapart.fr/michel-de-pracontal\" class=\"journalist\">Michel de Pracontal</a></p>\n<p>Les restes d’un mammouth retrouvés en Arctique sibérien, datés de 45 000 ans, portent les traces de blessures infligées par des chasseurs humains. Les scientifiques pensaient jusqu’ici que notre espèce ne s’était pas aventurée dans cette région glaciale il y a plus de 30 000 ou 35 0000 ans. En réalité, des hommes ont réussi à survivre en Arctique au moins 10 000 ans plus tôt que l’on croyait.</p>\n</div><div alt=\"li\">\n<h3 class=\"title\"><a href=\"https://blogs.mediapart.fr/alain-zolty/blog/140116/de-la-democratie-du-citoyen-et-de-lethique\">De la démocratie, du citoyen et de l'éthique</a></h3>\n<p>14 janv. 2016 | Par </p>\n<p>Trois ouvrages sont parus au Seuil, qui font état de la nécessité d’intégrer le citoyen dans la gouvernance de la nation. Non pas à titre consultatif mais doté d’un pouvoir délibératif pour constituer une contre-force face aux clans politico-financiers qui dominent la vie publique.</p>\n</div>",
9 "mimetype": "text/html", 11 "mimetype": "text/html",
@@ -21,6 +23,8 @@
21 "title": "Réfugiés: l'UE va créer 100 000 places d'accueil dans les Balkans", 23 "title": "Réfugiés: l'UE va créer 100 000 places d'accueil dans les Balkans",
22 "url": "http://www.liberation.fr/planete/2015/10/26/refugies-l-ue-va-creer-100-000-places-d-accueil-dans-les-balkans_1408867", 24 "url": "http://www.liberation.fr/planete/2015/10/26/refugies-l-ue-va-creer-100-000-places-d-accueil-dans-les-balkans_1408867",
23 "is_archived": false, 25 "is_archived": false,
26 "created_at": "2016-09-08T11:55:58+0200",
27 "updated_at": "2016-09-08T11:57:16+0200",
24 "is_starred": false, 28 "is_starred": false,
25 "content": "<p>Pour un sommet sur les réfugiés qui devait se concentrer sur des <em>«mesures opérationnelles immédiates»</em> dans les Balkans, la réunion, dimanche à Bruxelles, de 11 chefs d’Etat et de gouvernement, dont 8 Européens, a été agitée. Dès leur arrivée, Viktor Orbán (Hongrie) et Aléxis Tsípras (Grèce) se sont jeté des anathèmes. Le Premier ministre grec a dénoncé l’attitude <em>«not in my backyard»</em> (pas de ça chez moi) de certains Etats européens, alors que son pays est montré du doigt par d’autres dirigeants, dont Orbán : ils reprochent à la Grèce de ne pas suffisamment contrôler ses frontières avec la Turquie et ne pas montrer assez de zèle dans l’enregistrement des demandeurs d’asile.</p>\n<p>Le sommet, convoqué par la Commission européenne, sur suggestion de l’Allemagne, aura au moins permis à ces 11 Etats – Autriche, Bulgarie, Croatie, Allemagne, Grèce, Hongrie, Roumanie, Slovénie côté européen, et 3 pays «non UE», Albanie, Macédoine et Serbie – de discuter ensemble.</p>\n<h3>400 policiers européens en Slovénie</h3>\n<p>L’objectif, rappelé par Angela Merkel, était de trouver une <em>«réponse coordonnée»</em> à la crise des réfugiés. Quelques mesures ont été annoncées : 100 000 places d’accueil seront créées, dont 50 000 en Grèce, et le reste le long de la route des Balkans. 400 officiers de police de pays européens partiront en Slovénie, actuellement submergée, pour aider au contrôle des frontières. Frontex, l’agence européenne de surveillance des frontières, s’impliquera aux frontières gréco-macédonienne et gréco-albanaise pour des contrôles et identifications.</p>\n<p>Ce sommet est intervenu dans un contexte de fortes tensions, marqué par des fermetures de frontières bloquant les réfugiés dans des zones tampon. Ces obstacles ont été partiellement levés ces derniers jours, les autorités tentant d’organiser un «corridor» informel vers l’Allemagne, qui pourtant durcit sa politique d’accueil et souhaite désormais ralentir le flux. Mais la situation des réfugiés est catastrophique. L’ONG Human Rights Watch craint que des réfugiés ne meurent dans les Balkans. Des groupes de centaines, voire de milliers de personnes, bloqués près des postes-frontières, se retrouvent dans des conditions humanitaires intenables.</p>\n<p>Depuis mi-septembre, 250 000 personnes ont traversé les Balkans. En une semaine, la Slovénie a vu 60 000 réfugiés fouler le sol de son territoire. Dimanche, 15 000 personnes ont transité en Slovénie.</p>\n<h3>Des zones tampon</h3>\n<p>L’enjeu principal du sommet, aux yeux de nombreux Etats de l’Union européenne, était aussi que les pays des Balkans <em>«prennent leur part»</em> face à la crise : qu’ils accueillent et enregistrent davantage de réfugiés. Ces Etats craignent que l’Autriche ou l’Allemagne ne ferment leurs frontières et fassent de leurs pays des <em>«zones tampon»</em>, comme s’en inquiétait Boyko Borissov, Premier ministre bulgare.</p>\n<p><em>« Aujourd’hui, plusieurs Etats du nord de l’Europe veulent que l’on enregistre les migrants puis que l’on détermine leur éligibilité au statut de réfugié,</em> explique Marc Pierini, du think tank Carnegie Europe. <em>La difficulté, c’est que les gens sont en mouvement. Pour le faire, il faut se poser quelque part. La crainte des pays intermédiaires, donc ceux des Balkans, est qu’on enregistre ces personnes sur leur territoire et qu’ils soient contraints de rester sur leur sol. Donc les pays des Balkans ne sont pas désireux d’accueillir ces réfugiés et ces derniers veulent avancer.»</em></p>\n<p>Le sommet a élaboré quelques principes. L’idée générale est de rendre effective la «logique de hotspot» : un enregistrement des demandeurs d’asile à leur point d’entrée dans l’Union européenne, suivi de l’expulsion de ceux qui ne correspondraient pas aux critères de la Convention de Genève, et la répartition des autres, via le mécanisme de relocalisation.</p>\n<p>Dans ce cadre, l’enregistrement des demandeurs d’asile est un élément clé. <em>«Pas d’enregistrement, pas de droit»</em>, a prévenu le président de la Commission européenne, Jean-Claude Juncker, dimanche soir. Les Etats ont tenu à rappeler que les migrants qui refusent de demander l’asile à la frontière peuvent se voir refuser l’entrée dans un pays.</p>\n<p>Et les Etats <em>«décourageront les mouvements de réfugiés»</em> de frontière en frontière. La politique consistant à laisser passer les migrants vers un autre pays est officiellement jugée <em>«inacceptable»</em>.</p>\n<h3>Se jeter dans la gueule du loup</h3>\n<p>Voilà pour la théorie. En pratique, la relocalisation ne devrait concerner que 160 000 réfugiés en deux ans, alors que près de 700 000 personnes sont arrivées en Europe depuis le début de l’année. De plus, les Etats ne jouent pas le jeu. La semaine passée, seules 854 places de relocalisation avaient été proposées.</p>\n<p>Dans ce contexte, il est probable que les Etats des Balkans ne s’impliqueront pas outre mesure dans les solutions proposées, craignant de devoir «garder» les réfugiés alors que l’Union européenne tarde à mettre en œuvre leur répartition.</p>\n<p>Quant aux réfugiés, ils préfèrent traverser les frontières par eux-mêmes, plutôt que de se jeter dans ces «hotspots», considérés comme la gueule du loup.</p>\n<a itemprop=\"name\" href=\"http://www.liberation.fr/auteur/15743-cedric-vallet\">Cédric Vallet</a>", 29 "content": "<p>Pour un sommet sur les réfugiés qui devait se concentrer sur des <em>«mesures opérationnelles immédiates»</em> dans les Balkans, la réunion, dimanche à Bruxelles, de 11 chefs d’Etat et de gouvernement, dont 8 Européens, a été agitée. Dès leur arrivée, Viktor Orbán (Hongrie) et Aléxis Tsípras (Grèce) se sont jeté des anathèmes. Le Premier ministre grec a dénoncé l’attitude <em>«not in my backyard»</em> (pas de ça chez moi) de certains Etats européens, alors que son pays est montré du doigt par d’autres dirigeants, dont Orbán : ils reprochent à la Grèce de ne pas suffisamment contrôler ses frontières avec la Turquie et ne pas montrer assez de zèle dans l’enregistrement des demandeurs d’asile.</p>\n<p>Le sommet, convoqué par la Commission européenne, sur suggestion de l’Allemagne, aura au moins permis à ces 11 Etats – Autriche, Bulgarie, Croatie, Allemagne, Grèce, Hongrie, Roumanie, Slovénie côté européen, et 3 pays «non UE», Albanie, Macédoine et Serbie – de discuter ensemble.</p>\n<h3>400 policiers européens en Slovénie</h3>\n<p>L’objectif, rappelé par Angela Merkel, était de trouver une <em>«réponse coordonnée»</em> à la crise des réfugiés. Quelques mesures ont été annoncées : 100 000 places d’accueil seront créées, dont 50 000 en Grèce, et le reste le long de la route des Balkans. 400 officiers de police de pays européens partiront en Slovénie, actuellement submergée, pour aider au contrôle des frontières. Frontex, l’agence européenne de surveillance des frontières, s’impliquera aux frontières gréco-macédonienne et gréco-albanaise pour des contrôles et identifications.</p>\n<p>Ce sommet est intervenu dans un contexte de fortes tensions, marqué par des fermetures de frontières bloquant les réfugiés dans des zones tampon. Ces obstacles ont été partiellement levés ces derniers jours, les autorités tentant d’organiser un «corridor» informel vers l’Allemagne, qui pourtant durcit sa politique d’accueil et souhaite désormais ralentir le flux. Mais la situation des réfugiés est catastrophique. L’ONG Human Rights Watch craint que des réfugiés ne meurent dans les Balkans. Des groupes de centaines, voire de milliers de personnes, bloqués près des postes-frontières, se retrouvent dans des conditions humanitaires intenables.</p>\n<p>Depuis mi-septembre, 250 000 personnes ont traversé les Balkans. En une semaine, la Slovénie a vu 60 000 réfugiés fouler le sol de son territoire. Dimanche, 15 000 personnes ont transité en Slovénie.</p>\n<h3>Des zones tampon</h3>\n<p>L’enjeu principal du sommet, aux yeux de nombreux Etats de l’Union européenne, était aussi que les pays des Balkans <em>«prennent leur part»</em> face à la crise : qu’ils accueillent et enregistrent davantage de réfugiés. Ces Etats craignent que l’Autriche ou l’Allemagne ne ferment leurs frontières et fassent de leurs pays des <em>«zones tampon»</em>, comme s’en inquiétait Boyko Borissov, Premier ministre bulgare.</p>\n<p><em>« Aujourd’hui, plusieurs Etats du nord de l’Europe veulent que l’on enregistre les migrants puis que l’on détermine leur éligibilité au statut de réfugié,</em> explique Marc Pierini, du think tank Carnegie Europe. <em>La difficulté, c’est que les gens sont en mouvement. Pour le faire, il faut se poser quelque part. La crainte des pays intermédiaires, donc ceux des Balkans, est qu’on enregistre ces personnes sur leur territoire et qu’ils soient contraints de rester sur leur sol. Donc les pays des Balkans ne sont pas désireux d’accueillir ces réfugiés et ces derniers veulent avancer.»</em></p>\n<p>Le sommet a élaboré quelques principes. L’idée générale est de rendre effective la «logique de hotspot» : un enregistrement des demandeurs d’asile à leur point d’entrée dans l’Union européenne, suivi de l’expulsion de ceux qui ne correspondraient pas aux critères de la Convention de Genève, et la répartition des autres, via le mécanisme de relocalisation.</p>\n<p>Dans ce cadre, l’enregistrement des demandeurs d’asile est un élément clé. <em>«Pas d’enregistrement, pas de droit»</em>, a prévenu le président de la Commission européenne, Jean-Claude Juncker, dimanche soir. Les Etats ont tenu à rappeler que les migrants qui refusent de demander l’asile à la frontière peuvent se voir refuser l’entrée dans un pays.</p>\n<p>Et les Etats <em>«décourageront les mouvements de réfugiés»</em> de frontière en frontière. La politique consistant à laisser passer les migrants vers un autre pays est officiellement jugée <em>«inacceptable»</em>.</p>\n<h3>Se jeter dans la gueule du loup</h3>\n<p>Voilà pour la théorie. En pratique, la relocalisation ne devrait concerner que 160 000 réfugiés en deux ans, alors que près de 700 000 personnes sont arrivées en Europe depuis le début de l’année. De plus, les Etats ne jouent pas le jeu. La semaine passée, seules 854 places de relocalisation avaient été proposées.</p>\n<p>Dans ce contexte, il est probable que les Etats des Balkans ne s’impliqueront pas outre mesure dans les solutions proposées, craignant de devoir «garder» les réfugiés alors que l’Union européenne tarde à mettre en œuvre leur répartition.</p>\n<p>Quant aux réfugiés, ils préfèrent traverser les frontières par eux-mêmes, plutôt que de se jeter dans ces «hotspots», considérés comme la gueule du loup.</p>\n<a itemprop=\"name\" href=\"http://www.liberation.fr/auteur/15743-cedric-vallet\">Cédric Vallet</a>",
26 "mimetype": "", 30 "mimetype": "",
@@ -34,6 +38,8 @@
34 "title": "No title found", 38 "title": "No title found",
35 "url": "http://news.nationalgeographic.com/2016/02/160211-albatrosses-mothers-babies-animals-science/&sf20739758=1", 39 "url": "http://news.nationalgeographic.com/2016/02/160211-albatrosses-mothers-babies-animals-science/&sf20739758=1",
36 "is_archived": false, 40 "is_archived": false,
41 "created_at": "2016-09-08T11:55:58+0200",
42 "updated_at": "2016-09-08T11:57:16+0200",
37 "is_starred": true, 43 "is_starred": true,
38 "content": "Oh, what a shame, no content", 44 "content": "Oh, what a shame, no content",
39 "mimetype": "", 45 "mimetype": "",
@@ -44,6 +50,8 @@
44 }, 50 },
45 { 51 {
46 "is_archived": 0, 52 "is_archived": 0,
53 "created_at": "2016-09-08T11:55:58+0200",
54 "updated_at": "2016-09-08T11:57:16+0200",
47 "is_starred": 0, 55 "is_starred": 0,
48 "id": 612, 56 "id": 612,
49 "title": "Échecs", 57 "title": "Échecs",
@@ -58,6 +66,8 @@
58 }, 66 },
59 { 67 {
60 "is_archived": 0, 68 "is_archived": 0,
69 "created_at": "2016-09-08T11:55:58+0200",
70 "updated_at": "2016-09-08T11:57:16+0200",
61 "is_starred": 0, 71 "is_starred": 0,
62 "id": 608, 72 "id": 608,
63 "title": "90% des dossiers médicaux des Coréens du sud vendus à des entreprises privées - ZATAZ", 73 "title": "90% des dossiers médicaux des Coréens du sud vendus à des entreprises privées - ZATAZ",
@@ -73,6 +83,8 @@
73 }, 83 },
74 { 84 {
75 "is_archived": 0, 85 "is_archived": 0,
86 "created_at": "2016-09-08T11:55:58+0200",
87 "updated_at": "2016-09-08T11:57:16+0200",
76 "is_starred": 0, 88 "is_starred": 0,
77 "id": 606, 89 "id": 606,
78 "title": "Mass Surveillance As Art", 90 "title": "Mass Surveillance As Art",
@@ -87,6 +99,8 @@
87 }, 99 },
88 { 100 {
89 "is_archived": 0, 101 "is_archived": 0,
102 "created_at": "2016-09-08T11:55:58+0200",
103 "updated_at": "2016-09-08T11:57:16+0200",
90 "is_starred": 0, 104 "is_starred": 0,
91 "id": 605, 105 "id": 605,
92 "title": "What David Cameron did to the pig, his party is now doing to the country", 106 "title": "What David Cameron did to the pig, his party is now doing to the country",
@@ -102,6 +116,8 @@
102 }, 116 },
103 { 117 {
104 "is_archived": 1, 118 "is_archived": 1,
119 "created_at": "2016-09-08T11:55:58+0200",
120 "updated_at": "2016-09-08T11:57:16+0200",
105 "is_starred": 0, 121 "is_starred": 0,
106 "id": 604, 122 "id": 604,
107 "title": "CLICK HERE to support 2016 CES Winner, Revolutionary Auto-Tracking Robot", 123 "title": "CLICK HERE to support 2016 CES Winner, Revolutionary Auto-Tracking Robot",
@@ -116,6 +132,8 @@
116 }, 132 },
117 { 133 {
118 "is_archived": 0, 134 "is_archived": 0,
135 "created_at": "2016-09-08T11:55:58+0200",
136 "updated_at": "2016-09-08T11:57:16+0200",
119 "is_starred": 1, 137 "is_starred": 1,
120 "id": 603, 138 "id": 603,
121 "title": "No title found", 139 "title": "No title found",
@@ -129,6 +147,8 @@
129 }, 147 },
130 { 148 {
131 "is_archived": 1, 149 "is_archived": 1,
150 "created_at": "2016-09-08T11:55:58+0200",
151 "updated_at": "2016-09-08T11:57:16+0200",
132 "is_starred": 0, 152 "is_starred": 0,
133 "id": 602, 153 "id": 602,
134 "title": "Présentation d'Arduino - Tuto Arduino - Le blog d'Eskimon", 154 "title": "Présentation d'Arduino - Tuto Arduino - Le blog d'Eskimon",
@@ -144,6 +164,8 @@
144 }, 164 },
145 { 165 {
146 "is_archived": 1, 166 "is_archived": 1,
167 "created_at": "2016-09-08T11:55:58+0200",
168 "updated_at": "2016-09-08T11:57:16+0200",
147 "is_starred": 0, 169 "is_starred": 0,
148 "id": 543, 170 "id": 543,
149 "title": "Lenovo ThinkPad X1 Carbon Ultrabook Review", 171 "title": "Lenovo ThinkPad X1 Carbon Ultrabook Review",
@@ -159,6 +181,8 @@
159 }, 181 },
160 { 182 {
161 "is_archived": 0, 183 "is_archived": 0,
184 "created_at": "2016-09-08T11:55:58+0200",
185 "updated_at": "2016-09-08T11:57:16+0200",
162 "is_starred": 0, 186 "is_starred": 0,
163 "id": 541, 187 "id": 541,
164 "title": "Visitons le Château de Landsberg !", 188 "title": "Visitons le Château de Landsberg !",
@@ -174,6 +198,8 @@
174 }, 198 },
175 { 199 {
176 "is_archived": 1, 200 "is_archived": 1,
201 "created_at": "2016-09-08T11:55:58+0200",
202 "updated_at": "2016-09-08T11:57:16+0200",
177 "is_starred": 0, 203 "is_starred": 0,
178 "id": 454, 204 "id": 454,
179 "title": "Contrer les stéréotypes par les livres : “C'est dès l'enfance qu'ils se construisent”", 205 "title": "Contrer les stéréotypes par les livres : “C'est dès l'enfance qu'ils se construisent”",
@@ -189,6 +215,8 @@
189 }, 215 },
190 { 216 {
191 "is_archived": 1, 217 "is_archived": 1,
218 "created_at": "2016-09-08T11:55:58+0200",
219 "updated_at": "2016-09-08T11:57:16+0200",
192 "is_starred": 0, 220 "is_starred": 0,
193 "id": 99, 221 "id": 99,
194 "title": "[ROM][6.0.1][Layers][N5] TipsyOS official builds {UBER TCs}", 222 "title": "[ROM][6.0.1][Layers][N5] TipsyOS official builds {UBER TCs}",
@@ -204,6 +232,8 @@
204 }, 232 },
205 { 233 {
206 "is_archived": 0, 234 "is_archived": 0,
235 "created_at": "2016-09-08T11:55:58+0200",
236 "updated_at": "2016-09-08T11:57:16+0200",
207 "is_starred": 0, 237 "is_starred": 0,
208 "id": 98, 238 "id": 98,
209 "title": "Top 15 Podcasts All Web Developers Should Follow - Envato Tuts+ Code Article", 239 "title": "Top 15 Podcasts All Web Developers Should Follow - Envato Tuts+ Code Article",
@@ -218,6 +248,8 @@
218 }, 248 },
219 { 249 {
220 "is_archived": 1, 250 "is_archived": 1,
251 "created_at": "2016-09-08T11:55:58+0200",
252 "updated_at": "2016-09-08T11:57:16+0200",
221 "is_starred": 0, 253 "is_starred": 0,
222 "id": 97, 254 "id": 97,
223 "title": "University of Mississippi", 255 "title": "University of Mississippi",
@@ -232,6 +264,8 @@
232 }, 264 },
233 { 265 {
234 "is_archived": 1, 266 "is_archived": 1,
267 "created_at": "2016-09-08T11:55:58+0200",
268 "updated_at": "2016-09-08T11:57:16+0200",
235 "is_starred": 0, 269 "is_starred": 0,
236 "id": 96, 270 "id": 96,
237 "title": "FinnChristiansen.de Jetzt Dank Let’s Encrypt Per HTTPS Erreichbar", 271 "title": "FinnChristiansen.de Jetzt Dank Let’s Encrypt Per HTTPS Erreichbar",
@@ -246,6 +280,8 @@
246 }, 280 },
247 { 281 {
248 "is_archived": 1, 282 "is_archived": 1,
283 "created_at": "2016-09-08T11:55:58+0200",
284 "updated_at": "2016-09-08T11:57:16+0200",
249 "is_starred": 0, 285 "is_starred": 0,
250 "id": 82, 286 "id": 82,
251 "title": "Le développeur et l'ingénierie logicielle", 287 "title": "Le développeur et l'ingénierie logicielle",
@@ -259,6 +295,8 @@
259 }, 295 },
260 { 296 {
261 "is_archived": 1, 297 "is_archived": 1,
298 "created_at": "2016-09-08T11:55:58+0200",
299 "updated_at": "2016-09-08T11:57:16+0200",
262 "is_starred": 0, 300 "is_starred": 0,
263 "id": 78, 301 "id": 78,
264 "title": "The Role of Methylation in Gene Expression", 302 "title": "The Role of Methylation in Gene Expression",
@@ -273,6 +311,8 @@
273 }, 311 },
274 { 312 {
275 "is_archived": 1, 313 "is_archived": 1,
314 "created_at": "2016-09-08T11:55:58+0200",
315 "updated_at": "2016-09-08T11:57:16+0200",
276 "is_starred": 0, 316 "is_starred": 0,
277 "id": 53, 317 "id": 53,
278 "title": "E-Mail-Adresse kostenlos, FreeMail, De-Mail & Nachrichten", 318 "title": "E-Mail-Adresse kostenlos, FreeMail, De-Mail & Nachrichten",
@@ -287,6 +327,8 @@
287 }, 327 },
288 { 328 {
289 "is_archived": 1, 329 "is_archived": 1,
330 "created_at": "2016-09-08T11:55:58+0200",
331 "updated_at": "2016-09-08T11:57:16+0200",
290 "is_starred": 0, 332 "is_starred": 0,
291 "id": 48, 333 "id": 48,
292 "title": "OpenSSH Server on Arch Linux | DominicM test", 334 "title": "OpenSSH Server on Arch Linux | DominicM test",
@@ -302,6 +344,8 @@
302 }, 344 },
303 { 345 {
304 "is_archived": 1, 346 "is_archived": 1,
347 "created_at": "2016-09-08T11:55:58+0200",
348 "updated_at": "2016-09-08T11:57:16+0200",
305 "is_starred": 0, 349 "is_starred": 0,
306 "id": 39, 350 "id": 39,
307 "title": "Site Moved | Site Help", 351 "title": "Site Moved | Site Help",
@@ -316,6 +360,8 @@
316 }, 360 },
317 { 361 {
318 "is_archived": 1, 362 "is_archived": 1,
363 "created_at": "2016-09-08T11:55:58+0200",
364 "updated_at": "2016-09-08T11:57:16+0200",
319 "is_starred": 0, 365 "is_starred": 0,
320 "id": 38, 366 "id": 38,
321 "title": "#Maroc : le stylo anti-pédophiles EAGLE d’AMESYS est moins bien configuré que les faux-lowers Twitter du roi Mohammed VI", 367 "title": "#Maroc : le stylo anti-pédophiles EAGLE d’AMESYS est moins bien configuré que les faux-lowers Twitter du roi Mohammed VI",
@@ -331,6 +377,8 @@
331 }, 377 },
332 { 378 {
333 "is_archived": 1, 379 "is_archived": 1,
380 "created_at": "2016-09-08T11:55:58+0200",
381 "updated_at": "2016-09-08T11:57:16+0200",
334 "is_starred": 0, 382 "is_starred": 0,
335 "id": 3, 383 "id": 3,
336 "title": "Simple Cloud Infrastructure for Developers", 384 "title": "Simple Cloud Infrastructure for Developers",
diff --git a/tests/Wallabag/UserBundle/Controller/ManageControllerTest.php b/tests/Wallabag/UserBundle/Controller/ManageControllerTest.php
new file mode 100644
index 00000000..243a4459
--- /dev/null
+++ b/tests/Wallabag/UserBundle/Controller/ManageControllerTest.php
@@ -0,0 +1,82 @@
1<?php
2
3namespace Wallabag\UserBundle\Tests\Controller;
4
5use Tests\Wallabag\CoreBundle\WallabagCoreTestCase;
6
7class ManageControllerTest extends WallabagCoreTestCase
8{
9 public function testLogin()
10 {
11 $client = $this->getClient();
12
13 $client->request('GET', '/users/');
14
15 $this->assertEquals(302, $client->getResponse()->getStatusCode());
16 $this->assertContains('login', $client->getResponse()->headers->get('location'));
17 }
18
19 public function testCompleteScenario()
20 {
21 $this->logInAs('admin');
22 $client = $this->getClient();
23
24 // Create a new user in the database
25 $crawler = $client->request('GET', '/users/');
26 $this->assertEquals(200, $client->getResponse()->getStatusCode(), 'Unexpected HTTP status code for GET /users/');
27 $crawler = $client->click($crawler->selectLink('user.list.create_new_one')->link());
28
29 // Fill in the form and submit it
30 $form = $crawler->selectButton('user.form.save')->form(array(
31 'new_user[username]' => 'test_user',
32 'new_user[email]' => 'test@test.io',
33 'new_user[plainPassword][first]' => 'test',
34 'new_user[plainPassword][second]' => 'test',
35 ));
36
37 $client->submit($form);
38 $client->followRedirect();
39 $crawler = $client->request('GET', '/users/');
40
41 // Check data in the show view
42 $this->assertGreaterThan(0, $crawler->filter('td:contains("test_user")')->count(), 'Missing element td:contains("test_user")');
43
44 // Edit the user
45 $crawler = $client->click($crawler->selectLink('user.list.edit_action')->last()->link());
46
47 $form = $crawler->selectButton('user.form.save')->form(array(
48 'user[name]' => 'Foo User',
49 'user[username]' => 'test_user',
50 'user[email]' => 'test@test.io',
51 'user[enabled]' => true,
52 'user[locked]' => false,
53 ));
54
55 $client->submit($form);
56 $crawler = $client->followRedirect();
57
58 // Check the element contains an attribute with value equals "Foo User"
59 $this->assertGreaterThan(0, $crawler->filter('[value="Foo User"]')->count(), 'Missing element [value="Foo User"]');
60
61 $crawler = $client->request('GET', '/users/');
62 $crawler = $client->click($crawler->selectLink('user.list.edit_action')->last()->link());
63
64 // Delete the user
65 $client->submit($crawler->selectButton('user.form.delete')->form());
66 $crawler = $client->followRedirect();
67
68 // Check the user has been delete on the list
69 $this->assertNotRegExp('/Foo User/', $client->getResponse()->getContent());
70 }
71
72 public function testDeleteDisabledForLoggedUser()
73 {
74 $this->logInAs('admin');
75 $client = $this->getClient();
76
77 $crawler = $client->request('GET', '/users/'.$this->getLoggedInUserId().'/edit');
78 $disabled = $crawler->selectButton('user.form.delete')->extract('disabled');
79
80 $this->assertEquals('disabled', $disabled[0]);
81 }
82}
diff --git a/tests/Wallabag/CoreBundle/EventListener/RegistrationConfirmedListenerTest.php b/tests/Wallabag/UserBundle/EventListener/CreateConfigListenerTest.php
index e45722fa..a78b77bc 100644
--- a/tests/Wallabag/CoreBundle/EventListener/RegistrationConfirmedListenerTest.php
+++ b/tests/Wallabag/UserBundle/EventListener/CreateConfigListenerTest.php
@@ -1,6 +1,6 @@
1<?php 1<?php
2 2
3namespace Tests\Wallabag\CoreBundle\EventListener; 3namespace Tests\Wallabag\UserBundle\EventListener;
4 4
5use FOS\UserBundle\Event\FilterUserResponseEvent; 5use FOS\UserBundle\Event\FilterUserResponseEvent;
6use FOS\UserBundle\FOSUserEvents; 6use FOS\UserBundle\FOSUserEvents;
@@ -8,10 +8,10 @@ use Symfony\Component\EventDispatcher\EventDispatcher;
8use Symfony\Component\HttpFoundation\Request; 8use Symfony\Component\HttpFoundation\Request;
9use Symfony\Component\HttpFoundation\Response; 9use Symfony\Component\HttpFoundation\Response;
10use Wallabag\CoreBundle\Entity\Config; 10use Wallabag\CoreBundle\Entity\Config;
11use Wallabag\CoreBundle\EventListener\RegistrationConfirmedListener; 11use Wallabag\UserBundle\EventListener\CreateConfigListener;
12use Wallabag\UserBundle\Entity\User; 12use Wallabag\UserBundle\Entity\User;
13 13
14class RegistrationConfirmedListenerTest extends \PHPUnit_Framework_TestCase 14class CreateConfigListenerTest extends \PHPUnit_Framework_TestCase
15{ 15{
16 private $em; 16 private $em;
17 private $listener; 17 private $listener;
@@ -25,12 +25,13 @@ class RegistrationConfirmedListenerTest extends \PHPUnit_Framework_TestCase
25 ->disableOriginalConstructor() 25 ->disableOriginalConstructor()
26 ->getMock(); 26 ->getMock();
27 27
28 $this->listener = new RegistrationConfirmedListener( 28 $this->listener = new CreateConfigListener(
29 $this->em, 29 $this->em,
30 'baggy', 30 'baggy',
31 20, 31 20,
32 50, 32 50,
33 'fr' 33 'fr',
34 1
34 ); 35 );
35 36
36 $this->dispatcher = new EventDispatcher(); 37 $this->dispatcher = new EventDispatcher();
@@ -40,26 +41,6 @@ class RegistrationConfirmedListenerTest extends \PHPUnit_Framework_TestCase
40 $this->response = Response::create(); 41 $this->response = Response::create();
41 } 42 }
42 43
43 public function testWithInvalidUser()
44 {
45 $user = new User();
46 $user->setEnabled(false);
47
48 $event = new FilterUserResponseEvent(
49 $user,
50 $this->request,
51 $this->response
52 );
53
54 $this->em->expects($this->never())->method('persist');
55 $this->em->expects($this->never())->method('flush');
56
57 $this->dispatcher->dispatch(
58 FOSUserEvents::REGISTRATION_CONFIRMED,
59 $event
60 );
61 }
62
63 public function testWithValidUser() 44 public function testWithValidUser()
64 { 45 {
65 $user = new User(); 46 $user = new User();
@@ -76,6 +57,7 @@ class RegistrationConfirmedListenerTest extends \PHPUnit_Framework_TestCase
76 $config->setItemsPerPage(20); 57 $config->setItemsPerPage(20);
77 $config->setRssLimit(50); 58 $config->setRssLimit(50);
78 $config->setLanguage('fr'); 59 $config->setLanguage('fr');
60 $config->setReadingSpeed(1);
79 61
80 $this->em->expects($this->once()) 62 $this->em->expects($this->once())
81 ->method('persist') 63 ->method('persist')
@@ -84,7 +66,7 @@ class RegistrationConfirmedListenerTest extends \PHPUnit_Framework_TestCase
84 ->method('flush'); 66 ->method('flush');
85 67
86 $this->dispatcher->dispatch( 68 $this->dispatcher->dispatch(
87 FOSUserEvents::REGISTRATION_CONFIRMED, 69 FOSUserEvents::REGISTRATION_COMPLETED,
88 $event 70 $event
89 ); 71 );
90 } 72 }
diff --git a/tests/Wallabag/UserBundle/Mailer/AuthCodeMailerTest.php b/tests/Wallabag/UserBundle/Mailer/AuthCodeMailerTest.php
index f670c925..441d6519 100644
--- a/tests/Wallabag/UserBundle/Mailer/AuthCodeMailerTest.php
+++ b/tests/Wallabag/UserBundle/Mailer/AuthCodeMailerTest.php
@@ -37,7 +37,7 @@ class AuthCodeMailerTest extends \PHPUnit_Framework_TestCase
37 ); 37 );
38 $this->mailer = new \Swift_Mailer($transport); 38 $this->mailer = new \Swift_Mailer($transport);
39 39
40 $twigTemplate = <<<TWIG 40 $twigTemplate = <<<'TWIG'
41{% block subject %}subject{% endblock %} 41{% block subject %}subject{% endblock %}
42{% block body_html %}html body {{ code }}{% endblock %} 42{% block body_html %}html body {{ code }}{% endblock %}
43{% block body_text %}text body {{ support_url }}{% endblock %} 43{% block body_text %}text body {{ support_url }}{% endblock %}