From fd1ddad98df45bc3c18be7980c1cbe68ce6b219c Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 26 Sep 2020 14:18:01 +0200 Subject: Add mutex on datastore I/O operations To make sure that there is no concurrent operation on the datastore file. Fixes #1132 --- tests/bookmark/BookmarkFileServiceTest.php | 44 +++++++++++++++++------------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'tests/bookmark/BookmarkFileServiceTest.php') diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php index c399822b..6c56dfaa 100644 --- a/tests/bookmark/BookmarkFileServiceTest.php +++ b/tests/bookmark/BookmarkFileServiceTest.php @@ -6,6 +6,7 @@ namespace Shaarli\Bookmark; use DateTime; +use malkusch\lock\mutex\NoMutex; use ReferenceLinkDB; use ReflectionClass; use Shaarli; @@ -52,6 +53,9 @@ class BookmarkFileServiceTest extends TestCase */ protected $privateLinkDB = null; + /** @var NoMutex */ + protected $mutex; + /** * Instantiates public and private LinkDBs with test data * @@ -68,6 +72,8 @@ class BookmarkFileServiceTest extends TestCase */ protected function setUp(): void { + $this->mutex = new NoMutex(); + if (file_exists(self::$testDatastore)) { unlink(self::$testDatastore); } @@ -87,8 +93,8 @@ class BookmarkFileServiceTest extends TestCase $this->refDB = new \ReferenceLinkDB(); $this->refDB->write(self::$testDatastore); $this->history = new History('sandbox/history.php'); - $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, false); - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false); + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); } /** @@ -105,7 +111,7 @@ class BookmarkFileServiceTest extends TestCase $db = self::getMethod('migrate'); $db->invokeArgs($this->privateLinkDB, []); - $db = new \FakeBookmarkService($this->conf, $this->history, true); + $db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, true); $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks()); $this->assertEquals($this->refDB->countLinks(), $db->count()); } @@ -174,7 +180,7 @@ class BookmarkFileServiceTest extends TestCase $this->assertEquals($updated, $bookmark->getUpdated()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); $bookmark = $this->privateLinkDB->get(43); $this->assertEquals(43, $bookmark->getId()); @@ -212,7 +218,7 @@ class BookmarkFileServiceTest extends TestCase $this->assertNull($bookmark->getUpdated()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); $bookmark = $this->privateLinkDB->get(43); $this->assertEquals(43, $bookmark->getId()); @@ -242,7 +248,7 @@ class BookmarkFileServiceTest extends TestCase $this->assertEquals(43, $bookmark->getId()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); $this->privateLinkDB->get(43); } @@ -314,7 +320,7 @@ class BookmarkFileServiceTest extends TestCase $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); $bookmark = $this->privateLinkDB->get(42); $this->assertEquals(42, $bookmark->getId()); @@ -355,7 +361,7 @@ class BookmarkFileServiceTest extends TestCase $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); $bookmark = $this->privateLinkDB->get(42); $this->assertEquals(42, $bookmark->getId()); @@ -388,7 +394,7 @@ class BookmarkFileServiceTest extends TestCase $this->assertEquals($title, $bookmark->getTitle()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); $bookmark = $this->privateLinkDB->get(42); $this->assertEquals(42, $bookmark->getId()); @@ -452,7 +458,7 @@ class BookmarkFileServiceTest extends TestCase $this->assertEquals(43, $bookmark->getId()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); $bookmark = $this->privateLinkDB->get(43); $this->assertEquals(43, $bookmark->getId()); @@ -472,7 +478,7 @@ class BookmarkFileServiceTest extends TestCase $this->assertEquals($title, $bookmark->getTitle()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); $bookmark = $this->privateLinkDB->get(42); $this->assertEquals(42, $bookmark->getId()); @@ -515,7 +521,7 @@ class BookmarkFileServiceTest extends TestCase $this->assertEquals($title, $bookmark->getTitle()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); $bookmark = $this->privateLinkDB->get(42); $this->assertEquals(42, $bookmark->getId()); @@ -541,7 +547,7 @@ class BookmarkFileServiceTest extends TestCase $this->assertInstanceOf(BookmarkNotFoundException::class, $exception); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); $this->privateLinkDB->get(42); } @@ -645,7 +651,7 @@ class BookmarkFileServiceTest extends TestCase $conf = new ConfigManager('tests/utils/config/configJson'); $conf->set('resource.datastore', 'null/store.db'); - new BookmarkFileService($conf, $this->history, true); + new BookmarkFileService($conf, $this->history, $this->mutex, true); } /** @@ -655,7 +661,7 @@ class BookmarkFileServiceTest extends TestCase { unlink(self::$testDatastore); $this->assertFileNotExists(self::$testDatastore); - new BookmarkFileService($this->conf, $this->history, true); + new BookmarkFileService($this->conf, $this->history, $this->mutex, true); $this->assertFileExists(self::$testDatastore); // ensure the correct data has been written @@ -669,7 +675,7 @@ class BookmarkFileServiceTest extends TestCase { unlink(self::$testDatastore); $this->assertFileNotExists(self::$testDatastore); - $db = new \FakeBookmarkService($this->conf, $this->history, false); + $db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, false); $this->assertFileNotExists(self::$testDatastore); $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks()); $this->assertCount(0, $db->getBookmarks()); @@ -702,13 +708,13 @@ class BookmarkFileServiceTest extends TestCase */ public function testSave() { - $testDB = new BookmarkFileService($this->conf, $this->history, true); + $testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); $dbSize = $testDB->count(); $bookmark = new Bookmark(); $testDB->add($bookmark); - $testDB = new BookmarkFileService($this->conf, $this->history, true); + $testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); $this->assertEquals($dbSize + 1, $testDB->count()); } @@ -718,7 +724,7 @@ class BookmarkFileServiceTest extends TestCase public function testCountHiddenPublic() { $this->conf->set('privacy.hide_public_links', true); - $linkDB = new BookmarkFileService($this->conf, $this->history, false); + $linkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false); $this->assertEquals(0, $linkDB->count()); } -- cgit v1.2.3 From efb7d21b52eb033530e80e5e49d175e6e3b031f4 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Fri, 2 Oct 2020 17:50:59 +0200 Subject: Add strict types for bookmarks management Parameters typing and using strict types overall increase the codebase quality by enforcing the a given parameter will have the expected type. It also removes the need to unnecessary unit tests checking methods behavior with invalid input. --- tests/bookmark/BookmarkFileServiceTest.php | 44 ------------------------------ 1 file changed, 44 deletions(-) (limited to 'tests/bookmark/BookmarkFileServiceTest.php') diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php index 6c56dfaa..59c0608c 100644 --- a/tests/bookmark/BookmarkFileServiceTest.php +++ b/tests/bookmark/BookmarkFileServiceTest.php @@ -264,17 +264,6 @@ class BookmarkFileServiceTest extends TestCase $this->publicLinkDB->add(new Bookmark()); } - /** - * Test add() method with an entry which is not a bookmark instance - */ - public function testAddNotABookmark() - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Provided data is invalid'); - - $this->privateLinkDB->add(['title' => 'hi!']); - } - /** * Test add() method with a Bookmark already containing an ID */ @@ -412,17 +401,6 @@ class BookmarkFileServiceTest extends TestCase $this->publicLinkDB->set(new Bookmark()); } - /** - * Test set() method with an entry which is not a bookmark instance - */ - public function testSetNotABookmark() - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Provided data is invalid'); - - $this->privateLinkDB->set(['title' => 'hi!']); - } - /** * Test set() method with a Bookmark without an ID defined. */ @@ -496,17 +474,6 @@ class BookmarkFileServiceTest extends TestCase $this->publicLinkDB->addOrSet(new Bookmark()); } - /** - * Test addOrSet() method with an entry which is not a bookmark instance - */ - public function testAddOrSetNotABookmark() - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Provided data is invalid'); - - $this->privateLinkDB->addOrSet(['title' => 'hi!']); - } - /** * Test addOrSet() method for a bookmark without any field set and without writing the data store */ @@ -564,17 +531,6 @@ class BookmarkFileServiceTest extends TestCase $this->publicLinkDB->remove($bookmark); } - /** - * Test remove() method with an entry which is not a bookmark instance - */ - public function testRemoveNotABookmark() - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Provided data is invalid'); - - $this->privateLinkDB->remove(['title' => 'hi!']); - } - /** * Test remove() method with a Bookmark with an unknown ID */ -- cgit v1.2.3 From 4b3aca66238f4ec31ab67c990fd388738e959289 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Fri, 16 Oct 2020 12:04:46 +0200 Subject: Strict types: fix an issue in daily where the date could be an int --- tests/bookmark/BookmarkFileServiceTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests/bookmark/BookmarkFileServiceTest.php') diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php index 59c0608c..42485c99 100644 --- a/tests/bookmark/BookmarkFileServiceTest.php +++ b/tests/bookmark/BookmarkFileServiceTest.php @@ -690,12 +690,12 @@ class BookmarkFileServiceTest extends TestCase */ public function testDays() { - $this->assertEquals( + $this->assertSame( ['20100309', '20100310', '20121206', '20121207', '20130614', '20150310'], $this->publicLinkDB->days() ); - $this->assertEquals( + $this->assertSame( ['20100309', '20100310', '20121206', '20121207', '20130614', '20141125', '20150310'], $this->privateLinkDB->days() ); -- cgit v1.2.3 From f1a148ab92c061ac129b5b2976de02d45b6a71e7 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Mon, 12 Oct 2020 12:23:57 +0200 Subject: add search highlight unit tests --- tests/bookmark/BookmarkFileServiceTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'tests/bookmark/BookmarkFileServiceTest.php') diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php index 42485c99..daafd250 100644 --- a/tests/bookmark/BookmarkFileServiceTest.php +++ b/tests/bookmark/BookmarkFileServiceTest.php @@ -748,6 +748,10 @@ class BookmarkFileServiceTest extends TestCase // They need to be grouped with the first case found - order by date DESC: `sTuff`. 'sTuff' => 2, 'ut' => 1, + 'assurance' => 1, + 'coding-style' => 1, + 'quality' => 1, + 'standards' => 1, ], $this->publicLinkDB->bookmarksCountPerTag() ); @@ -776,6 +780,10 @@ class BookmarkFileServiceTest extends TestCase 'tag3' => 1, 'tag4' => 1, 'ut' => 1, + 'assurance' => 1, + 'coding-style' => 1, + 'quality' => 1, + 'standards' => 1, ], $this->privateLinkDB->bookmarksCountPerTag() ); @@ -918,6 +926,10 @@ class BookmarkFileServiceTest extends TestCase 'tag4' => 1, 'ut' => 1, 'w3c' => 1, + 'assurance' => 1, + 'coding-style' => 1, + 'quality' => 1, + 'standards' => 1, ]; $tags = $this->privateLinkDB->bookmarksCountPerTag(); @@ -1016,6 +1028,10 @@ class BookmarkFileServiceTest extends TestCase 'stallman' => 1, 'ut' => 1, 'w3c' => 1, + 'assurance' => 1, + 'coding-style' => 1, + 'quality' => 1, + 'standards' => 1, ]; $bookmark = new Bookmark(); $bookmark->setTags(['newTagToCount', BookmarkMarkdownFormatter::NO_MD_TAG]); -- cgit v1.2.3 From 9c04921a8c28c18ef757f2d43ba35e7e2a7f1a4b Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Fri, 16 Oct 2020 20:17:08 +0200 Subject: Feature: Share private bookmarks using a URL containing a private key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add a share link next to « Permalink » in linklist (using share icon from fork awesome) - This link generates a private key associated to the bookmark - Accessing the bookmark while logged out with the proper key will display it Fixes #475 --- tests/bookmark/BookmarkFileServiceTest.php | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'tests/bookmark/BookmarkFileServiceTest.php') diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php index daafd250..47970117 100644 --- a/tests/bookmark/BookmarkFileServiceTest.php +++ b/tests/bookmark/BookmarkFileServiceTest.php @@ -897,6 +897,37 @@ class BookmarkFileServiceTest extends TestCase $this->publicLinkDB->findByHash(''); } + /** + * Test filterHash() on a private bookmark while logged out. + */ + public function testFilterHashPrivateWhileLoggedOut() + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Not authorized'); + + $hash = smallHash('20141125_084734' . 6); + + $this->publicLinkDB->findByHash($hash); + } + + /** + * Test filterHash() with private key. + */ + public function testFilterHashWithPrivateKey() + { + $hash = smallHash('20141125_084734' . 6); + $privateKey = 'this is usually auto generated'; + + $bookmark = $this->privateLinkDB->findByHash($hash); + $bookmark->addAdditionalContentEntry('private_key', $privateKey); + $this->privateLinkDB->save(); + + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false); + $bookmark = $this->privateLinkDB->findByHash($hash, $privateKey); + + static::assertSame(6, $bookmark->getId()); + } + /** * Test linksCountPerTag all tags without filter. * Equal occurrences should be sorted alphabetically. -- cgit v1.2.3 From 36e6d88dbfd753665224664d5214f39ccfbbf6a5 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Fri, 16 Oct 2020 11:50:53 +0200 Subject: Feature: add weekly and monthly view/RSS feed for daily page - Heavy refactoring of DailyController - Add a banner like in tag cloud to display monthly and weekly links - Translations: t() now supports variables with optional first letter uppercase Fixes #160 --- tests/bookmark/BookmarkFileServiceTest.php | 124 +++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 34 deletions(-) (limited to 'tests/bookmark/BookmarkFileServiceTest.php') diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php index 47970117..8e0ff8dd 100644 --- a/tests/bookmark/BookmarkFileServiceTest.php +++ b/tests/bookmark/BookmarkFileServiceTest.php @@ -685,22 +685,6 @@ class BookmarkFileServiceTest extends TestCase $this->assertEquals(0, $linkDB->count()); } - /** - * List the days for which bookmarks have been posted - */ - public function testDays() - { - $this->assertSame( - ['20100309', '20100310', '20121206', '20121207', '20130614', '20150310'], - $this->publicLinkDB->days() - ); - - $this->assertSame( - ['20100309', '20100310', '20121206', '20121207', '20130614', '20141125', '20150310'], - $this->privateLinkDB->days() - ); - } - /** * The URL corresponds to an existing entry in the DB */ @@ -1074,33 +1058,105 @@ class BookmarkFileServiceTest extends TestCase } /** - * Test filterDay while logged in + * Test find by dates in the middle of the datastore (sorted by dates) with a single bookmark as a result. */ - public function testFilterDayLoggedIn(): void + public function testFilterByDateMidTimePeriodSingleBookmark(): void { - $bookmarks = $this->privateLinkDB->filterDay('20121206'); - $expectedIds = [4, 9, 1, 0]; + $bookmarks = $this->privateLinkDB->findByDate( + DateTime::createFromFormat('Ymd_His', '20121206_150000'), + DateTime::createFromFormat('Ymd_His', '20121206_160000'), + $before, + $after + ); - static::assertCount(4, $bookmarks); - foreach ($bookmarks as $bookmark) { - $i = ($i ?? -1) + 1; - static::assertSame($expectedIds[$i], $bookmark->getId()); - } + static::assertCount(1, $bookmarks); + + static::assertSame(9, $bookmarks[0]->getId()); + static::assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_142300'), $before); + static::assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_172539'), $after); } /** - * Test filterDay while logged out + * Test find by dates in the middle of the datastore (sorted by dates) with a multiple bookmarks as a result. */ - public function testFilterDayLoggedOut(): void + public function testFilterByDateMidTimePeriodMultipleBookmarks(): void { - $bookmarks = $this->publicLinkDB->filterDay('20121206'); - $expectedIds = [4, 9, 1]; + $bookmarks = $this->privateLinkDB->findByDate( + DateTime::createFromFormat('Ymd_His', '20121206_150000'), + DateTime::createFromFormat('Ymd_His', '20121206_180000'), + $before, + $after + ); - static::assertCount(3, $bookmarks); - foreach ($bookmarks as $bookmark) { - $i = ($i ?? -1) + 1; - static::assertSame($expectedIds[$i], $bookmark->getId()); - } + static::assertCount(2, $bookmarks); + + static::assertSame(1, $bookmarks[0]->getId()); + static::assertSame(9, $bookmarks[1]->getId()); + static::assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_142300'), $before); + static::assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_182539'), $after); + } + + /** + * Test find by dates at the end of the datastore (sorted by dates). + */ + public function testFilterByDateLastTimePeriod(): void + { + $after = new DateTime(); + $bookmarks = $this->privateLinkDB->findByDate( + DateTime::createFromFormat('Ymd_His', '20150310_114640'), + DateTime::createFromFormat('Ymd_His', '20450101_010101'), + $before, + $after + ); + + static::assertCount(1, $bookmarks); + + static::assertSame(41, $bookmarks[0]->getId()); + static::assertEquals(DateTime::createFromFormat('Ymd_His', '20150310_114633'), $before); + static::assertNull($after); + } + + /** + * Test find by dates at the beginning of the datastore (sorted by dates). + */ + public function testFilterByDateFirstTimePeriod(): void + { + $before = new DateTime(); + $bookmarks = $this->privateLinkDB->findByDate( + DateTime::createFromFormat('Ymd_His', '20000101_101010'), + DateTime::createFromFormat('Ymd_His', '20100309_110000'), + $before, + $after + ); + + static::assertCount(1, $bookmarks); + + static::assertSame(11, $bookmarks[0]->getId()); + static::assertNull($before); + static::assertEquals(DateTime::createFromFormat('Ymd_His', '20100310_101010'), $after); + } + + /** + * Test getLatest with a sticky bookmark: it should be ignored and return the latest by creation date instead. + */ + public function testGetLatestWithSticky(): void + { + $bookmark = $this->publicLinkDB->getLatest(); + + static::assertSame(41, $bookmark->getId()); + } + + /** + * Test getLatest with a sticky bookmark: it should be ignored and return the latest by creation date instead. + */ + public function testGetLatestEmptyDatastore(): void + { + unlink($this->conf->get('resource.datastore')); + $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false); + + $bookmark = $this->publicLinkDB->getLatest(); + + static::assertNull($bookmark); } /** -- cgit v1.2.3 From 156061d445fd23d033a52f84954484a3349c988a Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Wed, 28 Oct 2020 12:54:52 +0100 Subject: Raise 404 error instead of 500 if permalink access is denied --- tests/bookmark/BookmarkFileServiceTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests/bookmark/BookmarkFileServiceTest.php') diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php index 8e0ff8dd..f619aff3 100644 --- a/tests/bookmark/BookmarkFileServiceTest.php +++ b/tests/bookmark/BookmarkFileServiceTest.php @@ -886,8 +886,8 @@ class BookmarkFileServiceTest extends TestCase */ public function testFilterHashPrivateWhileLoggedOut() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Not authorized'); + $this->expectException(BookmarkNotFoundException::class); + $this->expectExceptionMessage('The link you are trying to reach does not exist or has been deleted'); $hash = smallHash('20141125_084734' . 6); -- cgit v1.2.3