aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorArthurHoaro <arthur@hoa.ro>2020-09-26 14:18:01 +0200
committerArthurHoaro <arthur@hoa.ro>2020-10-13 12:38:19 +0200
commitfd1ddad98df45bc3c18be7980c1cbe68ce6b219c (patch)
treee4017d3c979604f40e78cdc305f0ab191aedd4b9
parent458b6b9918ec27154dd45416947bb93bedb97109 (diff)
downloadShaarli-fd1ddad98df45bc3c18be7980c1cbe68ce6b219c.tar.gz
Shaarli-fd1ddad98df45bc3c18be7980c1cbe68ce6b219c.tar.zst
Shaarli-fd1ddad98df45bc3c18be7980c1cbe68ce6b219c.zip
Add mutex on datastore I/O operations
To make sure that there is no concurrent operation on the datastore file. Fixes #1132
-rw-r--r--application/api/ApiMiddleware.php2
-rw-r--r--application/bookmark/BookmarkFileService.php9
-rw-r--r--application/bookmark/BookmarkIO.php35
-rw-r--r--application/bookmark/BookmarkServiceInterface.php11
-rw-r--r--application/container/ContainerBuilder.php2
-rw-r--r--composer.json1
-rw-r--r--composer.lock87
-rw-r--r--init.php1
-rw-r--r--tests/api/controllers/info/InfoTest.php4
-rw-r--r--tests/api/controllers/links/DeleteLinkTest.php9
-rw-r--r--tests/api/controllers/links/GetLinkIdTest.php4
-rw-r--r--tests/api/controllers/links/GetLinksTest.php4
-rw-r--r--tests/api/controllers/links/PostLinkTest.php4
-rw-r--r--tests/api/controllers/links/PutLinkTest.php4
-rw-r--r--tests/api/controllers/tags/DeleteTagTest.php11
-rw-r--r--tests/api/controllers/tags/GetTagNameTest.php4
-rw-r--r--tests/api/controllers/tags/GetTagsTest.php4
-rw-r--r--tests/api/controllers/tags/PutTagTest.php4
-rw-r--r--tests/bookmark/BookmarkFileServiceTest.php44
-rw-r--r--tests/bookmark/BookmarkFilterTest.php4
-rw-r--r--tests/bookmark/BookmarkInitializerTest.php13
-rw-r--r--tests/bootstrap.php4
-rw-r--r--tests/feed/FeedBuilderTest.php4
-rw-r--r--tests/netscape/BookmarkExportTest.php4
-rw-r--r--tests/netscape/BookmarkImportTest.php4
-rw-r--r--tests/updater/UpdaterTest.php4
26 files changed, 218 insertions, 63 deletions
diff --git a/application/api/ApiMiddleware.php b/application/api/ApiMiddleware.php
index f5b53b01..adc8b266 100644
--- a/application/api/ApiMiddleware.php
+++ b/application/api/ApiMiddleware.php
@@ -1,6 +1,7 @@
1<?php 1<?php
2namespace Shaarli\Api; 2namespace Shaarli\Api;
3 3
4use malkusch\lock\mutex\FlockMutex;
4use Shaarli\Api\Exceptions\ApiAuthorizationException; 5use Shaarli\Api\Exceptions\ApiAuthorizationException;
5use Shaarli\Api\Exceptions\ApiException; 6use Shaarli\Api\Exceptions\ApiException;
6use Shaarli\Bookmark\BookmarkFileService; 7use Shaarli\Bookmark\BookmarkFileService;
@@ -143,6 +144,7 @@ class ApiMiddleware
143 $linkDb = new BookmarkFileService( 144 $linkDb = new BookmarkFileService(
144 $conf, 145 $conf,
145 $this->container->get('history'), 146 $this->container->get('history'),
147 new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2),
146 true 148 true
147 ); 149 );
148 $this->container['db'] = $linkDb; 150 $this->container['db'] = $linkDb;
diff --git a/application/bookmark/BookmarkFileService.php b/application/bookmark/BookmarkFileService.php
index c9ec2609..1ba00712 100644
--- a/application/bookmark/BookmarkFileService.php
+++ b/application/bookmark/BookmarkFileService.php
@@ -5,6 +5,7 @@ namespace Shaarli\Bookmark;
5 5
6 6
7use Exception; 7use Exception;
8use malkusch\lock\mutex\Mutex;
8use Shaarli\Bookmark\Exception\BookmarkNotFoundException; 9use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
9use Shaarli\Bookmark\Exception\DatastoreNotInitializedException; 10use Shaarli\Bookmark\Exception\DatastoreNotInitializedException;
10use Shaarli\Bookmark\Exception\EmptyDataStoreException; 11use Shaarli\Bookmark\Exception\EmptyDataStoreException;
@@ -47,15 +48,19 @@ class BookmarkFileService implements BookmarkServiceInterface
47 /** @var bool true for logged in users. Default value to retrieve private bookmarks. */ 48 /** @var bool true for logged in users. Default value to retrieve private bookmarks. */
48 protected $isLoggedIn; 49 protected $isLoggedIn;
49 50
51 /** @var Mutex */
52 protected $mutex;
53
50 /** 54 /**
51 * @inheritDoc 55 * @inheritDoc
52 */ 56 */
53 public function __construct(ConfigManager $conf, History $history, $isLoggedIn) 57 public function __construct(ConfigManager $conf, History $history, Mutex $mutex, $isLoggedIn)
54 { 58 {
55 $this->conf = $conf; 59 $this->conf = $conf;
56 $this->history = $history; 60 $this->history = $history;
61 $this->mutex = $mutex;
57 $this->pageCacheManager = new PageCacheManager($this->conf->get('resource.page_cache'), $isLoggedIn); 62 $this->pageCacheManager = new PageCacheManager($this->conf->get('resource.page_cache'), $isLoggedIn);
58 $this->bookmarksIO = new BookmarkIO($this->conf); 63 $this->bookmarksIO = new BookmarkIO($this->conf, $this->mutex);
59 $this->isLoggedIn = $isLoggedIn; 64 $this->isLoggedIn = $isLoggedIn;
60 65
61 if (!$this->isLoggedIn && $this->conf->get('privacy.hide_public_links', false)) { 66 if (!$this->isLoggedIn && $this->conf->get('privacy.hide_public_links', false)) {
diff --git a/application/bookmark/BookmarkIO.php b/application/bookmark/BookmarkIO.php
index 6bf7f365..099653b0 100644
--- a/application/bookmark/BookmarkIO.php
+++ b/application/bookmark/BookmarkIO.php
@@ -2,6 +2,8 @@
2 2
3namespace Shaarli\Bookmark; 3namespace Shaarli\Bookmark;
4 4
5use malkusch\lock\mutex\Mutex;
6use malkusch\lock\mutex\NoMutex;
5use Shaarli\Bookmark\Exception\DatastoreNotInitializedException; 7use Shaarli\Bookmark\Exception\DatastoreNotInitializedException;
6use Shaarli\Bookmark\Exception\EmptyDataStoreException; 8use Shaarli\Bookmark\Exception\EmptyDataStoreException;
7use Shaarli\Bookmark\Exception\NotWritableDataStoreException; 9use Shaarli\Bookmark\Exception\NotWritableDataStoreException;
@@ -27,11 +29,14 @@ class BookmarkIO
27 */ 29 */
28 protected $conf; 30 protected $conf;
29 31
32
33 /** @var Mutex */
34 protected $mutex;
35
30 /** 36 /**
31 * string Datastore PHP prefix 37 * string Datastore PHP prefix
32 */ 38 */
33 protected static $phpPrefix = '<?php /* '; 39 protected static $phpPrefix = '<?php /* ';
34
35 /** 40 /**
36 * string Datastore PHP suffix 41 * string Datastore PHP suffix
37 */ 42 */
@@ -42,10 +47,15 @@ class BookmarkIO
42 * 47 *
43 * @param ConfigManager $conf instance 48 * @param ConfigManager $conf instance
44 */ 49 */
45 public function __construct($conf) 50 public function __construct(ConfigManager $conf, Mutex $mutex = null)
46 { 51 {
52 if ($mutex === null) {
53 // This should only happen with legacy classes
54 $mutex = new NoMutex();
55 }
47 $this->conf = $conf; 56 $this->conf = $conf;
48 $this->datastore = $conf->get('resource.datastore'); 57 $this->datastore = $conf->get('resource.datastore');
58 $this->mutex = $mutex;
49 } 59 }
50 60
51 /** 61 /**
@@ -67,11 +77,16 @@ class BookmarkIO
67 throw new NotWritableDataStoreException($this->datastore); 77 throw new NotWritableDataStoreException($this->datastore);
68 } 78 }
69 79
80 $content = null;
81 $this->mutex->synchronized(function () use (&$content) {
82 $content = file_get_contents($this->datastore);
83 });
84
70 // Note that gzinflate is faster than gzuncompress. 85 // Note that gzinflate is faster than gzuncompress.
71 // See: http://www.php.net/manual/en/function.gzdeflate.php#96439 86 // See: http://www.php.net/manual/en/function.gzdeflate.php#96439
72 $links = unserialize(gzinflate(base64_decode( 87 $links = unserialize(gzinflate(base64_decode(
73 substr(file_get_contents($this->datastore), 88 substr($content, strlen(self::$phpPrefix), -strlen(self::$phpSuffix))
74 strlen(self::$phpPrefix), -strlen(self::$phpSuffix))))); 89 )));
75 90
76 if (empty($links)) { 91 if (empty($links)) {
77 if (filesize($this->datastore) > 100) { 92 if (filesize($this->datastore) > 100) {
@@ -100,9 +115,13 @@ class BookmarkIO
100 throw new NotWritableDataStoreException(dirname($this->datastore)); 115 throw new NotWritableDataStoreException(dirname($this->datastore));
101 } 116 }
102 117
103 file_put_contents( 118 $data = self::$phpPrefix.base64_encode(gzdeflate(serialize($links))).self::$phpSuffix;
104 $this->datastore, 119
105 self::$phpPrefix.base64_encode(gzdeflate(serialize($links))).self::$phpSuffix 120 $this->mutex->synchronized(function () use ($data) {
106 ); 121 file_put_contents(
122 $this->datastore,
123 $data
124 );
125 });
107 } 126 }
108} 127}
diff --git a/application/bookmark/BookmarkServiceInterface.php b/application/bookmark/BookmarkServiceInterface.php
index b9b483eb..638cfa5f 100644
--- a/application/bookmark/BookmarkServiceInterface.php
+++ b/application/bookmark/BookmarkServiceInterface.php
@@ -5,8 +5,6 @@ namespace Shaarli\Bookmark;
5 5
6use Shaarli\Bookmark\Exception\BookmarkNotFoundException; 6use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
7use Shaarli\Bookmark\Exception\NotWritableDataStoreException; 7use Shaarli\Bookmark\Exception\NotWritableDataStoreException;
8use Shaarli\Config\ConfigManager;
9use Shaarli\History;
10 8
11/** 9/**
12 * Class BookmarksService 10 * Class BookmarksService
@@ -16,15 +14,6 @@ use Shaarli\History;
16interface BookmarkServiceInterface 14interface BookmarkServiceInterface
17{ 15{
18 /** 16 /**
19 * BookmarksService constructor.
20 *
21 * @param ConfigManager $conf instance
22 * @param History $history instance
23 * @param bool $isLoggedIn true if the current user is logged in
24 */
25 public function __construct(ConfigManager $conf, History $history, $isLoggedIn);
26
27 /**
28 * Find a bookmark by hash 17 * Find a bookmark by hash
29 * 18 *
30 * @param string $hash 19 * @param string $hash
diff --git a/application/container/ContainerBuilder.php b/application/container/ContainerBuilder.php
index 55bb51b5..c21d58dd 100644
--- a/application/container/ContainerBuilder.php
+++ b/application/container/ContainerBuilder.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
4 4
5namespace Shaarli\Container; 5namespace Shaarli\Container;
6 6
7use malkusch\lock\mutex\FlockMutex;
7use Shaarli\Bookmark\BookmarkFileService; 8use Shaarli\Bookmark\BookmarkFileService;
8use Shaarli\Bookmark\BookmarkServiceInterface; 9use Shaarli\Bookmark\BookmarkServiceInterface;
9use Shaarli\Config\ConfigManager; 10use Shaarli\Config\ConfigManager;
@@ -84,6 +85,7 @@ class ContainerBuilder
84 return new BookmarkFileService( 85 return new BookmarkFileService(
85 $container->conf, 86 $container->conf,
86 $container->history, 87 $container->history,
88 new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2),
87 $container->loginManager->isLoggedIn() 89 $container->loginManager->isLoggedIn()
88 ); 90 );
89 }; 91 };
diff --git a/composer.json b/composer.json
index 7e675623..c0855e47 100644
--- a/composer.json
+++ b/composer.json
@@ -23,6 +23,7 @@
23 "erusev/parsedown": "^1.6", 23 "erusev/parsedown": "^1.6",
24 "erusev/parsedown-extra": "^0.8.1", 24 "erusev/parsedown-extra": "^0.8.1",
25 "gettext/gettext": "^4.4", 25 "gettext/gettext": "^4.4",
26 "malkusch/lock": "^2.1",
26 "pubsubhubbub/publisher": "dev-master", 27 "pubsubhubbub/publisher": "dev-master",
27 "shaarli/netscape-bookmark-parser": "^2.1", 28 "shaarli/netscape-bookmark-parser": "^2.1",
28 "slim/slim": "^3.0" 29 "slim/slim": "^3.0"
diff --git a/composer.lock b/composer.lock
index e02491ff..c379d8e7 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
4 "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 4 "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 "This file is @generated automatically" 5 "This file is @generated automatically"
6 ], 6 ],
7 "content-hash": "f84918821b0dceb0cd569875c0418bb8", 7 "content-hash": "932b191006135ff8be495aa0b4ba7e09",
8 "packages": [ 8 "packages": [
9 { 9 {
10 "name": "arthurhoaro/web-thumbnailer", 10 "name": "arthurhoaro/web-thumbnailer",
@@ -345,6 +345,91 @@
345 "time": "2016-11-07T19:29:14+00:00" 345 "time": "2016-11-07T19:29:14+00:00"
346 }, 346 },
347 { 347 {
348 "name": "malkusch/lock",
349 "version": "v2.1",
350 "source": {
351 "type": "git",
352 "url": "https://github.com/php-lock/lock.git",
353 "reference": "093f389ec2f38fc8686d2f70e23378182fce7714"
354 },
355 "dist": {
356 "type": "zip",
357 "url": "https://api.github.com/repos/php-lock/lock/zipball/093f389ec2f38fc8686d2f70e23378182fce7714",
358 "reference": "093f389ec2f38fc8686d2f70e23378182fce7714",
359 "shasum": ""
360 },
361 "require": {
362 "php": ">=7.1",
363 "psr/log": "^1"
364 },
365 "require-dev": {
366 "eloquent/liberator": "^2.0",
367 "ext-memcached": "*",
368 "ext-pcntl": "*",
369 "ext-pdo_mysql": "*",
370 "ext-pdo_sqlite": "*",
371 "ext-redis": "*",
372 "ext-sysvsem": "*",
373 "johnkary/phpunit-speedtrap": "^3.0",
374 "kriswallsmith/spork": "^0.3",
375 "mikey179/vfsstream": "^1.6",
376 "php-mock/php-mock-phpunit": "^2.1",
377 "phpunit/phpunit": "^7.4",
378 "predis/predis": "^1.1",
379 "squizlabs/php_codesniffer": "^3.3"
380 },
381 "suggest": {
382 "ext-pnctl": "Enables locking with flock without busy waiting in CLI scripts.",
383 "ext-redis": "To use this library with the PHP Redis extension.",
384 "ext-sysvsem": "Enables locking using semaphores.",
385 "predis/predis": "To use this library with predis."
386 },
387 "type": "library",
388 "autoload": {
389 "psr-4": {
390 "malkusch\\lock\\": "classes/"
391 }
392 },
393 "notification-url": "https://packagist.org/downloads/",
394 "license": [
395 "WTFPL"
396 ],
397 "authors": [
398 {
399 "name": "Markus Malkusch",
400 "email": "markus@malkusch.de",
401 "homepage": "http://markus.malkusch.de",
402 "role": "Developer"
403 },
404 {
405 "name": "Willem Stuursma-Ruwen",
406 "email": "willem@stuursma.name",
407 "role": "Developer"
408 }
409 ],
410 "description": "Mutex library for exclusive code execution.",
411 "homepage": "https://github.com/malkusch/lock",
412 "keywords": [
413 "advisory-locks",
414 "cas",
415 "flock",
416 "lock",
417 "locking",
418 "memcache",
419 "mutex",
420 "mysql",
421 "postgresql",
422 "redis",
423 "redlock",
424 "semaphore"
425 ],
426 "support": {
427 "issues": "https://github.com/php-lock/lock/issues",
428 "source": "https://github.com/php-lock/lock/tree/v2.1"
429 },
430 "time": "2018-12-12T19:53:29+00:00"
431 },
432 {
348 "name": "nikic/fast-route", 433 "name": "nikic/fast-route",
349 "version": "v1.3.0", 434 "version": "v1.3.0",
350 "source": { 435 "source": {
diff --git a/init.php b/init.php
index f0b84368..ab0e4ea7 100644
--- a/init.php
+++ b/init.php
@@ -60,6 +60,7 @@ ini_set('session.use_only_cookies', 1);
60ini_set('session.use_trans_sid', false); 60ini_set('session.use_trans_sid', false);
61 61
62define('SHAARLI_VERSION', ApplicationUtils::getVersion(__DIR__ .'/'. ApplicationUtils::$VERSION_FILE)); 62define('SHAARLI_VERSION', ApplicationUtils::getVersion(__DIR__ .'/'. ApplicationUtils::$VERSION_FILE));
63define('SHAARLI_MUTEX_FILE', __FILE__);
63 64
64session_name('shaarli'); 65session_name('shaarli');
65// Start session if needed (Some server auto-start sessions). 66// Start session if needed (Some server auto-start sessions).
diff --git a/tests/api/controllers/info/InfoTest.php b/tests/api/controllers/info/InfoTest.php
index 1598e1e8..10b29ab2 100644
--- a/tests/api/controllers/info/InfoTest.php
+++ b/tests/api/controllers/info/InfoTest.php
@@ -1,6 +1,7 @@
1<?php 1<?php
2namespace Shaarli\Api\Controllers; 2namespace Shaarli\Api\Controllers;
3 3
4use malkusch\lock\mutex\NoMutex;
4use Shaarli\Bookmark\BookmarkFileService; 5use Shaarli\Bookmark\BookmarkFileService;
5use Shaarli\Config\ConfigManager; 6use Shaarli\Config\ConfigManager;
6use Shaarli\History; 7use Shaarli\History;
@@ -49,6 +50,7 @@ class InfoTest extends TestCase
49 */ 50 */
50 protected function setUp(): void 51 protected function setUp(): void
51 { 52 {
53 $mutex = new NoMutex();
52 $this->conf = new ConfigManager('tests/utils/config/configJson'); 54 $this->conf = new ConfigManager('tests/utils/config/configJson');
53 $this->conf->set('resource.datastore', self::$testDatastore); 55 $this->conf->set('resource.datastore', self::$testDatastore);
54 $this->refDB = new \ReferenceLinkDB(); 56 $this->refDB = new \ReferenceLinkDB();
@@ -58,7 +60,7 @@ class InfoTest extends TestCase
58 60
59 $this->container = new Container(); 61 $this->container = new Container();
60 $this->container['conf'] = $this->conf; 62 $this->container['conf'] = $this->conf;
61 $this->container['db'] = new BookmarkFileService($this->conf, $history, true); 63 $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
62 $this->container['history'] = null; 64 $this->container['history'] = null;
63 65
64 $this->controller = new Info($this->container); 66 $this->controller = new Info($this->container);
diff --git a/tests/api/controllers/links/DeleteLinkTest.php b/tests/api/controllers/links/DeleteLinkTest.php
index cf9464f0..805c9be3 100644
--- a/tests/api/controllers/links/DeleteLinkTest.php
+++ b/tests/api/controllers/links/DeleteLinkTest.php
@@ -3,6 +3,7 @@
3 3
4namespace Shaarli\Api\Controllers; 4namespace Shaarli\Api\Controllers;
5 5
6use malkusch\lock\mutex\NoMutex;
6use Shaarli\Bookmark\BookmarkFileService; 7use Shaarli\Bookmark\BookmarkFileService;
7use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
8use Shaarli\History; 9use Shaarli\History;
@@ -53,11 +54,15 @@ class DeleteLinkTest extends \Shaarli\TestCase
53 */ 54 */
54 protected $controller; 55 protected $controller;
55 56
57 /** @var NoMutex */
58 protected $mutex;
59
56 /** 60 /**
57 * Before each test, instantiate a new Api with its config, plugins and bookmarks. 61 * Before each test, instantiate a new Api with its config, plugins and bookmarks.
58 */ 62 */
59 protected function setUp(): void 63 protected function setUp(): void
60 { 64 {
65 $this->mutex = new NoMutex();
61 $this->conf = new ConfigManager('tests/utils/config/configJson'); 66 $this->conf = new ConfigManager('tests/utils/config/configJson');
62 $this->conf->set('resource.datastore', self::$testDatastore); 67 $this->conf->set('resource.datastore', self::$testDatastore);
63 $this->refDB = new \ReferenceLinkDB(); 68 $this->refDB = new \ReferenceLinkDB();
@@ -65,7 +70,7 @@ class DeleteLinkTest extends \Shaarli\TestCase
65 $refHistory = new \ReferenceHistory(); 70 $refHistory = new \ReferenceHistory();
66 $refHistory->write(self::$testHistory); 71 $refHistory->write(self::$testHistory);
67 $this->history = new History(self::$testHistory); 72 $this->history = new History(self::$testHistory);
68 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 73 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
69 74
70 $this->container = new Container(); 75 $this->container = new Container();
71 $this->container['conf'] = $this->conf; 76 $this->container['conf'] = $this->conf;
@@ -100,7 +105,7 @@ class DeleteLinkTest extends \Shaarli\TestCase
100 $this->assertEquals(204, $response->getStatusCode()); 105 $this->assertEquals(204, $response->getStatusCode());
101 $this->assertEmpty((string) $response->getBody()); 106 $this->assertEmpty((string) $response->getBody());
102 107
103 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 108 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
104 $this->assertFalse($this->bookmarkService->exists($id)); 109 $this->assertFalse($this->bookmarkService->exists($id));
105 110
106 $historyEntry = $this->history->getHistory()[0]; 111 $historyEntry = $this->history->getHistory()[0];
diff --git a/tests/api/controllers/links/GetLinkIdTest.php b/tests/api/controllers/links/GetLinkIdTest.php
index 99dc606f..1ec56ef3 100644
--- a/tests/api/controllers/links/GetLinkIdTest.php
+++ b/tests/api/controllers/links/GetLinkIdTest.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Api\Controllers; 3namespace Shaarli\Api\Controllers;
4 4
5use malkusch\lock\mutex\NoMutex;
5use Shaarli\Bookmark\Bookmark; 6use Shaarli\Bookmark\Bookmark;
6use Shaarli\Bookmark\BookmarkFileService; 7use Shaarli\Bookmark\BookmarkFileService;
7use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
@@ -57,6 +58,7 @@ class GetLinkIdTest extends \Shaarli\TestCase
57 */ 58 */
58 protected function setUp(): void 59 protected function setUp(): void
59 { 60 {
61 $mutex = new NoMutex();
60 $this->conf = new ConfigManager('tests/utils/config/configJson'); 62 $this->conf = new ConfigManager('tests/utils/config/configJson');
61 $this->conf->set('resource.datastore', self::$testDatastore); 63 $this->conf->set('resource.datastore', self::$testDatastore);
62 $this->refDB = new \ReferenceLinkDB(); 64 $this->refDB = new \ReferenceLinkDB();
@@ -65,7 +67,7 @@ class GetLinkIdTest extends \Shaarli\TestCase
65 67
66 $this->container = new Container(); 68 $this->container = new Container();
67 $this->container['conf'] = $this->conf; 69 $this->container['conf'] = $this->conf;
68 $this->container['db'] = new BookmarkFileService($this->conf, $history, true); 70 $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
69 $this->container['history'] = null; 71 $this->container['history'] = null;
70 72
71 $this->controller = new Links($this->container); 73 $this->controller = new Links($this->container);
diff --git a/tests/api/controllers/links/GetLinksTest.php b/tests/api/controllers/links/GetLinksTest.php
index ca1bfc63..0f5073b4 100644
--- a/tests/api/controllers/links/GetLinksTest.php
+++ b/tests/api/controllers/links/GetLinksTest.php
@@ -1,6 +1,7 @@
1<?php 1<?php
2namespace Shaarli\Api\Controllers; 2namespace Shaarli\Api\Controllers;
3 3
4use malkusch\lock\mutex\NoMutex;
4use Shaarli\Bookmark\Bookmark; 5use Shaarli\Bookmark\Bookmark;
5use Shaarli\Bookmark\BookmarkFileService; 6use Shaarli\Bookmark\BookmarkFileService;
6use Shaarli\Bookmark\LinkDB; 7use Shaarli\Bookmark\LinkDB;
@@ -57,6 +58,7 @@ class GetLinksTest extends \Shaarli\TestCase
57 */ 58 */
58 protected function setUp(): void 59 protected function setUp(): void
59 { 60 {
61 $mutex = new NoMutex();
60 $this->conf = new ConfigManager('tests/utils/config/configJson'); 62 $this->conf = new ConfigManager('tests/utils/config/configJson');
61 $this->conf->set('resource.datastore', self::$testDatastore); 63 $this->conf->set('resource.datastore', self::$testDatastore);
62 $this->refDB = new \ReferenceLinkDB(); 64 $this->refDB = new \ReferenceLinkDB();
@@ -65,7 +67,7 @@ class GetLinksTest extends \Shaarli\TestCase
65 67
66 $this->container = new Container(); 68 $this->container = new Container();
67 $this->container['conf'] = $this->conf; 69 $this->container['conf'] = $this->conf;
68 $this->container['db'] = new BookmarkFileService($this->conf, $history, true); 70 $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
69 $this->container['history'] = null; 71 $this->container['history'] = null;
70 72
71 $this->controller = new Links($this->container); 73 $this->controller = new Links($this->container);
diff --git a/tests/api/controllers/links/PostLinkTest.php b/tests/api/controllers/links/PostLinkTest.php
index 20694571..7ff92f5c 100644
--- a/tests/api/controllers/links/PostLinkTest.php
+++ b/tests/api/controllers/links/PostLinkTest.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Api\Controllers; 3namespace Shaarli\Api\Controllers;
4 4
5use malkusch\lock\mutex\NoMutex;
5use Shaarli\Bookmark\Bookmark; 6use Shaarli\Bookmark\Bookmark;
6use Shaarli\Bookmark\BookmarkFileService; 7use Shaarli\Bookmark\BookmarkFileService;
7use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
@@ -72,6 +73,7 @@ class PostLinkTest extends TestCase
72 */ 73 */
73 protected function setUp(): void 74 protected function setUp(): void
74 { 75 {
76 $mutex = new NoMutex();
75 $this->conf = new ConfigManager('tests/utils/config/configJson'); 77 $this->conf = new ConfigManager('tests/utils/config/configJson');
76 $this->conf->set('resource.datastore', self::$testDatastore); 78 $this->conf->set('resource.datastore', self::$testDatastore);
77 $this->refDB = new \ReferenceLinkDB(); 79 $this->refDB = new \ReferenceLinkDB();
@@ -79,7 +81,7 @@ class PostLinkTest extends TestCase
79 $refHistory = new \ReferenceHistory(); 81 $refHistory = new \ReferenceHistory();
80 $refHistory->write(self::$testHistory); 82 $refHistory->write(self::$testHistory);
81 $this->history = new History(self::$testHistory); 83 $this->history = new History(self::$testHistory);
82 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 84 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
83 85
84 $this->container = new Container(); 86 $this->container = new Container();
85 $this->container['conf'] = $this->conf; 87 $this->container['conf'] = $this->conf;
diff --git a/tests/api/controllers/links/PutLinkTest.php b/tests/api/controllers/links/PutLinkTest.php
index a2e87c59..240ee323 100644
--- a/tests/api/controllers/links/PutLinkTest.php
+++ b/tests/api/controllers/links/PutLinkTest.php
@@ -3,6 +3,7 @@
3 3
4namespace Shaarli\Api\Controllers; 4namespace Shaarli\Api\Controllers;
5 5
6use malkusch\lock\mutex\NoMutex;
6use Shaarli\Bookmark\Bookmark; 7use Shaarli\Bookmark\Bookmark;
7use Shaarli\Bookmark\BookmarkFileService; 8use Shaarli\Bookmark\BookmarkFileService;
8use Shaarli\Config\ConfigManager; 9use Shaarli\Config\ConfigManager;
@@ -64,6 +65,7 @@ class PutLinkTest extends \Shaarli\TestCase
64 */ 65 */
65 protected function setUp(): void 66 protected function setUp(): void
66 { 67 {
68 $mutex = new NoMutex();
67 $this->conf = new ConfigManager('tests/utils/config/configJson'); 69 $this->conf = new ConfigManager('tests/utils/config/configJson');
68 $this->conf->set('resource.datastore', self::$testDatastore); 70 $this->conf->set('resource.datastore', self::$testDatastore);
69 $this->refDB = new \ReferenceLinkDB(); 71 $this->refDB = new \ReferenceLinkDB();
@@ -71,7 +73,7 @@ class PutLinkTest extends \Shaarli\TestCase
71 $refHistory = new \ReferenceHistory(); 73 $refHistory = new \ReferenceHistory();
72 $refHistory->write(self::$testHistory); 74 $refHistory->write(self::$testHistory);
73 $this->history = new History(self::$testHistory); 75 $this->history = new History(self::$testHistory);
74 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 76 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
75 77
76 $this->container = new Container(); 78 $this->container = new Container();
77 $this->container['conf'] = $this->conf; 79 $this->container['conf'] = $this->conf;
diff --git a/tests/api/controllers/tags/DeleteTagTest.php b/tests/api/controllers/tags/DeleteTagTest.php
index 1326eb47..37f07229 100644
--- a/tests/api/controllers/tags/DeleteTagTest.php
+++ b/tests/api/controllers/tags/DeleteTagTest.php
@@ -3,6 +3,7 @@
3 3
4namespace Shaarli\Api\Controllers; 4namespace Shaarli\Api\Controllers;
5 5
6use malkusch\lock\mutex\NoMutex;
6use Shaarli\Bookmark\BookmarkFileService; 7use Shaarli\Bookmark\BookmarkFileService;
7use Shaarli\Bookmark\LinkDB; 8use Shaarli\Bookmark\LinkDB;
8use Shaarli\Config\ConfigManager; 9use Shaarli\Config\ConfigManager;
@@ -54,11 +55,15 @@ class DeleteTagTest extends \Shaarli\TestCase
54 */ 55 */
55 protected $controller; 56 protected $controller;
56 57
58 /** @var NoMutex */
59 protected $mutex;
60
57 /** 61 /**
58 * Before each test, instantiate a new Api with its config, plugins and bookmarks. 62 * Before each test, instantiate a new Api with its config, plugins and bookmarks.
59 */ 63 */
60 protected function setUp(): void 64 protected function setUp(): void
61 { 65 {
66 $this->mutex = new NoMutex();
62 $this->conf = new ConfigManager('tests/utils/config/configJson'); 67 $this->conf = new ConfigManager('tests/utils/config/configJson');
63 $this->conf->set('resource.datastore', self::$testDatastore); 68 $this->conf->set('resource.datastore', self::$testDatastore);
64 $this->refDB = new \ReferenceLinkDB(); 69 $this->refDB = new \ReferenceLinkDB();
@@ -66,7 +71,7 @@ class DeleteTagTest extends \Shaarli\TestCase
66 $refHistory = new \ReferenceHistory(); 71 $refHistory = new \ReferenceHistory();
67 $refHistory->write(self::$testHistory); 72 $refHistory->write(self::$testHistory);
68 $this->history = new History(self::$testHistory); 73 $this->history = new History(self::$testHistory);
69 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 74 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
70 75
71 $this->container = new Container(); 76 $this->container = new Container();
72 $this->container['conf'] = $this->conf; 77 $this->container['conf'] = $this->conf;
@@ -102,7 +107,7 @@ class DeleteTagTest extends \Shaarli\TestCase
102 $this->assertEquals(204, $response->getStatusCode()); 107 $this->assertEquals(204, $response->getStatusCode());
103 $this->assertEmpty((string) $response->getBody()); 108 $this->assertEmpty((string) $response->getBody());
104 109
105 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 110 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
106 $tags = $this->bookmarkService->bookmarksCountPerTag(); 111 $tags = $this->bookmarkService->bookmarksCountPerTag();
107 $this->assertFalse(isset($tags[$tagName])); 112 $this->assertFalse(isset($tags[$tagName]));
108 113
@@ -136,7 +141,7 @@ class DeleteTagTest extends \Shaarli\TestCase
136 $this->assertEquals(204, $response->getStatusCode()); 141 $this->assertEquals(204, $response->getStatusCode());
137 $this->assertEmpty((string) $response->getBody()); 142 $this->assertEmpty((string) $response->getBody());
138 143
139 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 144 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
140 $tags = $this->bookmarkService->bookmarksCountPerTag(); 145 $tags = $this->bookmarkService->bookmarksCountPerTag();
141 $this->assertFalse(isset($tags[$tagName])); 146 $this->assertFalse(isset($tags[$tagName]));
142 $this->assertTrue($tags[strtolower($tagName)] > 0); 147 $this->assertTrue($tags[strtolower($tagName)] > 0);
diff --git a/tests/api/controllers/tags/GetTagNameTest.php b/tests/api/controllers/tags/GetTagNameTest.php
index 9c05954b..878de5a4 100644
--- a/tests/api/controllers/tags/GetTagNameTest.php
+++ b/tests/api/controllers/tags/GetTagNameTest.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Api\Controllers; 3namespace Shaarli\Api\Controllers;
4 4
5use malkusch\lock\mutex\NoMutex;
5use Shaarli\Bookmark\BookmarkFileService; 6use Shaarli\Bookmark\BookmarkFileService;
6use Shaarli\Bookmark\LinkDB; 7use Shaarli\Bookmark\LinkDB;
7use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
@@ -55,6 +56,7 @@ class GetTagNameTest extends \Shaarli\TestCase
55 */ 56 */
56 protected function setUp(): void 57 protected function setUp(): void
57 { 58 {
59 $mutex = new NoMutex();
58 $this->conf = new ConfigManager('tests/utils/config/configJson'); 60 $this->conf = new ConfigManager('tests/utils/config/configJson');
59 $this->conf->set('resource.datastore', self::$testDatastore); 61 $this->conf->set('resource.datastore', self::$testDatastore);
60 $this->refDB = new \ReferenceLinkDB(); 62 $this->refDB = new \ReferenceLinkDB();
@@ -63,7 +65,7 @@ class GetTagNameTest extends \Shaarli\TestCase
63 65
64 $this->container = new Container(); 66 $this->container = new Container();
65 $this->container['conf'] = $this->conf; 67 $this->container['conf'] = $this->conf;
66 $this->container['db'] = new BookmarkFileService($this->conf, $history, true); 68 $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
67 $this->container['history'] = null; 69 $this->container['history'] = null;
68 70
69 $this->controller = new Tags($this->container); 71 $this->controller = new Tags($this->container);
diff --git a/tests/api/controllers/tags/GetTagsTest.php b/tests/api/controllers/tags/GetTagsTest.php
index 3459fdfa..b565a8c4 100644
--- a/tests/api/controllers/tags/GetTagsTest.php
+++ b/tests/api/controllers/tags/GetTagsTest.php
@@ -1,6 +1,7 @@
1<?php 1<?php
2namespace Shaarli\Api\Controllers; 2namespace Shaarli\Api\Controllers;
3 3
4use malkusch\lock\mutex\NoMutex;
4use Shaarli\Bookmark\BookmarkFileService; 5use Shaarli\Bookmark\BookmarkFileService;
5use Shaarli\Bookmark\LinkDB; 6use Shaarli\Bookmark\LinkDB;
6use Shaarli\Config\ConfigManager; 7use Shaarli\Config\ConfigManager;
@@ -59,13 +60,14 @@ class GetTagsTest extends \Shaarli\TestCase
59 */ 60 */
60 protected function setUp(): void 61 protected function setUp(): void
61 { 62 {
63 $mutex = new NoMutex();
62 $this->conf = new ConfigManager('tests/utils/config/configJson'); 64 $this->conf = new ConfigManager('tests/utils/config/configJson');
63 $this->conf->set('resource.datastore', self::$testDatastore); 65 $this->conf->set('resource.datastore', self::$testDatastore);
64 $this->refDB = new \ReferenceLinkDB(); 66 $this->refDB = new \ReferenceLinkDB();
65 $this->refDB->write(self::$testDatastore); 67 $this->refDB->write(self::$testDatastore);
66 $history = new History('sandbox/history.php'); 68 $history = new History('sandbox/history.php');
67 69
68 $this->bookmarkService = new BookmarkFileService($this->conf, $history, true); 70 $this->bookmarkService = new BookmarkFileService($this->conf, $history, $mutex, true);
69 71
70 $this->container = new Container(); 72 $this->container = new Container();
71 $this->container['conf'] = $this->conf; 73 $this->container['conf'] = $this->conf;
diff --git a/tests/api/controllers/tags/PutTagTest.php b/tests/api/controllers/tags/PutTagTest.php
index 74edde78..c73f6d3b 100644
--- a/tests/api/controllers/tags/PutTagTest.php
+++ b/tests/api/controllers/tags/PutTagTest.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Api\Controllers; 3namespace Shaarli\Api\Controllers;
4 4
5use malkusch\lock\mutex\NoMutex;
5use Shaarli\Api\Exceptions\ApiBadParametersException; 6use Shaarli\Api\Exceptions\ApiBadParametersException;
6use Shaarli\Bookmark\BookmarkFileService; 7use Shaarli\Bookmark\BookmarkFileService;
7use Shaarli\Bookmark\LinkDB; 8use Shaarli\Bookmark\LinkDB;
@@ -64,6 +65,7 @@ class PutTagTest extends \Shaarli\TestCase
64 */ 65 */
65 protected function setUp(): void 66 protected function setUp(): void
66 { 67 {
68 $mutex = new NoMutex();
67 $this->conf = new ConfigManager('tests/utils/config/configJson'); 69 $this->conf = new ConfigManager('tests/utils/config/configJson');
68 $this->conf->set('resource.datastore', self::$testDatastore); 70 $this->conf->set('resource.datastore', self::$testDatastore);
69 $this->refDB = new \ReferenceLinkDB(); 71 $this->refDB = new \ReferenceLinkDB();
@@ -71,7 +73,7 @@ class PutTagTest extends \Shaarli\TestCase
71 $refHistory = new \ReferenceHistory(); 73 $refHistory = new \ReferenceHistory();
72 $refHistory->write(self::$testHistory); 74 $refHistory->write(self::$testHistory);
73 $this->history = new History(self::$testHistory); 75 $this->history = new History(self::$testHistory);
74 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 76 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
75 77
76 $this->container = new Container(); 78 $this->container = new Container();
77 $this->container['conf'] = $this->conf; 79 $this->container['conf'] = $this->conf;
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 @@
6namespace Shaarli\Bookmark; 6namespace Shaarli\Bookmark;
7 7
8use DateTime; 8use DateTime;
9use malkusch\lock\mutex\NoMutex;
9use ReferenceLinkDB; 10use ReferenceLinkDB;
10use ReflectionClass; 11use ReflectionClass;
11use Shaarli; 12use Shaarli;
@@ -52,6 +53,9 @@ class BookmarkFileServiceTest extends TestCase
52 */ 53 */
53 protected $privateLinkDB = null; 54 protected $privateLinkDB = null;
54 55
56 /** @var NoMutex */
57 protected $mutex;
58
55 /** 59 /**
56 * Instantiates public and private LinkDBs with test data 60 * Instantiates public and private LinkDBs with test data
57 * 61 *
@@ -68,6 +72,8 @@ class BookmarkFileServiceTest extends TestCase
68 */ 72 */
69 protected function setUp(): void 73 protected function setUp(): void
70 { 74 {
75 $this->mutex = new NoMutex();
76
71 if (file_exists(self::$testDatastore)) { 77 if (file_exists(self::$testDatastore)) {
72 unlink(self::$testDatastore); 78 unlink(self::$testDatastore);
73 } 79 }
@@ -87,8 +93,8 @@ class BookmarkFileServiceTest extends TestCase
87 $this->refDB = new \ReferenceLinkDB(); 93 $this->refDB = new \ReferenceLinkDB();
88 $this->refDB->write(self::$testDatastore); 94 $this->refDB->write(self::$testDatastore);
89 $this->history = new History('sandbox/history.php'); 95 $this->history = new History('sandbox/history.php');
90 $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, false); 96 $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
91 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 97 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
92 } 98 }
93 99
94 /** 100 /**
@@ -105,7 +111,7 @@ class BookmarkFileServiceTest extends TestCase
105 $db = self::getMethod('migrate'); 111 $db = self::getMethod('migrate');
106 $db->invokeArgs($this->privateLinkDB, []); 112 $db->invokeArgs($this->privateLinkDB, []);
107 113
108 $db = new \FakeBookmarkService($this->conf, $this->history, true); 114 $db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, true);
109 $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks()); 115 $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks());
110 $this->assertEquals($this->refDB->countLinks(), $db->count()); 116 $this->assertEquals($this->refDB->countLinks(), $db->count());
111 } 117 }
@@ -174,7 +180,7 @@ class BookmarkFileServiceTest extends TestCase
174 $this->assertEquals($updated, $bookmark->getUpdated()); 180 $this->assertEquals($updated, $bookmark->getUpdated());
175 181
176 // reload from file 182 // reload from file
177 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 183 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
178 184
179 $bookmark = $this->privateLinkDB->get(43); 185 $bookmark = $this->privateLinkDB->get(43);
180 $this->assertEquals(43, $bookmark->getId()); 186 $this->assertEquals(43, $bookmark->getId());
@@ -212,7 +218,7 @@ class BookmarkFileServiceTest extends TestCase
212 $this->assertNull($bookmark->getUpdated()); 218 $this->assertNull($bookmark->getUpdated());
213 219
214 // reload from file 220 // reload from file
215 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 221 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
216 222
217 $bookmark = $this->privateLinkDB->get(43); 223 $bookmark = $this->privateLinkDB->get(43);
218 $this->assertEquals(43, $bookmark->getId()); 224 $this->assertEquals(43, $bookmark->getId());
@@ -242,7 +248,7 @@ class BookmarkFileServiceTest extends TestCase
242 $this->assertEquals(43, $bookmark->getId()); 248 $this->assertEquals(43, $bookmark->getId());
243 249
244 // reload from file 250 // reload from file
245 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 251 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
246 252
247 $this->privateLinkDB->get(43); 253 $this->privateLinkDB->get(43);
248 } 254 }
@@ -314,7 +320,7 @@ class BookmarkFileServiceTest extends TestCase
314 $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated()); 320 $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated());
315 321
316 // reload from file 322 // reload from file
317 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 323 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
318 324
319 $bookmark = $this->privateLinkDB->get(42); 325 $bookmark = $this->privateLinkDB->get(42);
320 $this->assertEquals(42, $bookmark->getId()); 326 $this->assertEquals(42, $bookmark->getId());
@@ -355,7 +361,7 @@ class BookmarkFileServiceTest extends TestCase
355 $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated()); 361 $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated());
356 362
357 // reload from file 363 // reload from file
358 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 364 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
359 365
360 $bookmark = $this->privateLinkDB->get(42); 366 $bookmark = $this->privateLinkDB->get(42);
361 $this->assertEquals(42, $bookmark->getId()); 367 $this->assertEquals(42, $bookmark->getId());
@@ -388,7 +394,7 @@ class BookmarkFileServiceTest extends TestCase
388 $this->assertEquals($title, $bookmark->getTitle()); 394 $this->assertEquals($title, $bookmark->getTitle());
389 395
390 // reload from file 396 // reload from file
391 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 397 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
392 398
393 $bookmark = $this->privateLinkDB->get(42); 399 $bookmark = $this->privateLinkDB->get(42);
394 $this->assertEquals(42, $bookmark->getId()); 400 $this->assertEquals(42, $bookmark->getId());
@@ -452,7 +458,7 @@ class BookmarkFileServiceTest extends TestCase
452 $this->assertEquals(43, $bookmark->getId()); 458 $this->assertEquals(43, $bookmark->getId());
453 459
454 // reload from file 460 // reload from file
455 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 461 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
456 462
457 $bookmark = $this->privateLinkDB->get(43); 463 $bookmark = $this->privateLinkDB->get(43);
458 $this->assertEquals(43, $bookmark->getId()); 464 $this->assertEquals(43, $bookmark->getId());
@@ -472,7 +478,7 @@ class BookmarkFileServiceTest extends TestCase
472 $this->assertEquals($title, $bookmark->getTitle()); 478 $this->assertEquals($title, $bookmark->getTitle());
473 479
474 // reload from file 480 // reload from file
475 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 481 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
476 482
477 $bookmark = $this->privateLinkDB->get(42); 483 $bookmark = $this->privateLinkDB->get(42);
478 $this->assertEquals(42, $bookmark->getId()); 484 $this->assertEquals(42, $bookmark->getId());
@@ -515,7 +521,7 @@ class BookmarkFileServiceTest extends TestCase
515 $this->assertEquals($title, $bookmark->getTitle()); 521 $this->assertEquals($title, $bookmark->getTitle());
516 522
517 // reload from file 523 // reload from file
518 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 524 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
519 525
520 $bookmark = $this->privateLinkDB->get(42); 526 $bookmark = $this->privateLinkDB->get(42);
521 $this->assertEquals(42, $bookmark->getId()); 527 $this->assertEquals(42, $bookmark->getId());
@@ -541,7 +547,7 @@ class BookmarkFileServiceTest extends TestCase
541 $this->assertInstanceOf(BookmarkNotFoundException::class, $exception); 547 $this->assertInstanceOf(BookmarkNotFoundException::class, $exception);
542 548
543 // reload from file 549 // reload from file
544 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 550 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
545 551
546 $this->privateLinkDB->get(42); 552 $this->privateLinkDB->get(42);
547 } 553 }
@@ -645,7 +651,7 @@ class BookmarkFileServiceTest extends TestCase
645 651
646 $conf = new ConfigManager('tests/utils/config/configJson'); 652 $conf = new ConfigManager('tests/utils/config/configJson');
647 $conf->set('resource.datastore', 'null/store.db'); 653 $conf->set('resource.datastore', 'null/store.db');
648 new BookmarkFileService($conf, $this->history, true); 654 new BookmarkFileService($conf, $this->history, $this->mutex, true);
649 } 655 }
650 656
651 /** 657 /**
@@ -655,7 +661,7 @@ class BookmarkFileServiceTest extends TestCase
655 { 661 {
656 unlink(self::$testDatastore); 662 unlink(self::$testDatastore);
657 $this->assertFileNotExists(self::$testDatastore); 663 $this->assertFileNotExists(self::$testDatastore);
658 new BookmarkFileService($this->conf, $this->history, true); 664 new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
659 $this->assertFileExists(self::$testDatastore); 665 $this->assertFileExists(self::$testDatastore);
660 666
661 // ensure the correct data has been written 667 // ensure the correct data has been written
@@ -669,7 +675,7 @@ class BookmarkFileServiceTest extends TestCase
669 { 675 {
670 unlink(self::$testDatastore); 676 unlink(self::$testDatastore);
671 $this->assertFileNotExists(self::$testDatastore); 677 $this->assertFileNotExists(self::$testDatastore);
672 $db = new \FakeBookmarkService($this->conf, $this->history, false); 678 $db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, false);
673 $this->assertFileNotExists(self::$testDatastore); 679 $this->assertFileNotExists(self::$testDatastore);
674 $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks()); 680 $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks());
675 $this->assertCount(0, $db->getBookmarks()); 681 $this->assertCount(0, $db->getBookmarks());
@@ -702,13 +708,13 @@ class BookmarkFileServiceTest extends TestCase
702 */ 708 */
703 public function testSave() 709 public function testSave()
704 { 710 {
705 $testDB = new BookmarkFileService($this->conf, $this->history, true); 711 $testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
706 $dbSize = $testDB->count(); 712 $dbSize = $testDB->count();
707 713
708 $bookmark = new Bookmark(); 714 $bookmark = new Bookmark();
709 $testDB->add($bookmark); 715 $testDB->add($bookmark);
710 716
711 $testDB = new BookmarkFileService($this->conf, $this->history, true); 717 $testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
712 $this->assertEquals($dbSize + 1, $testDB->count()); 718 $this->assertEquals($dbSize + 1, $testDB->count());
713 } 719 }
714 720
@@ -718,7 +724,7 @@ class BookmarkFileServiceTest extends TestCase
718 public function testCountHiddenPublic() 724 public function testCountHiddenPublic()
719 { 725 {
720 $this->conf->set('privacy.hide_public_links', true); 726 $this->conf->set('privacy.hide_public_links', true);
721 $linkDB = new BookmarkFileService($this->conf, $this->history, false); 727 $linkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
722 728
723 $this->assertEquals(0, $linkDB->count()); 729 $this->assertEquals(0, $linkDB->count());
724 } 730 }
diff --git a/tests/bookmark/BookmarkFilterTest.php b/tests/bookmark/BookmarkFilterTest.php
index 48c7f824..644abbc8 100644
--- a/tests/bookmark/BookmarkFilterTest.php
+++ b/tests/bookmark/BookmarkFilterTest.php
@@ -3,6 +3,7 @@
3namespace Shaarli\Bookmark; 3namespace Shaarli\Bookmark;
4 4
5use Exception; 5use Exception;
6use malkusch\lock\mutex\NoMutex;
6use ReferenceLinkDB; 7use ReferenceLinkDB;
7use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
8use Shaarli\History; 9use Shaarli\History;
@@ -37,12 +38,13 @@ class BookmarkFilterTest extends TestCase
37 */ 38 */
38 public static function setUpBeforeClass(): void 39 public static function setUpBeforeClass(): void
39 { 40 {
41 $mutex = new NoMutex();
40 $conf = new ConfigManager('tests/utils/config/configJson'); 42 $conf = new ConfigManager('tests/utils/config/configJson');
41 $conf->set('resource.datastore', self::$testDatastore); 43 $conf->set('resource.datastore', self::$testDatastore);
42 self::$refDB = new \ReferenceLinkDB(); 44 self::$refDB = new \ReferenceLinkDB();
43 self::$refDB->write(self::$testDatastore); 45 self::$refDB->write(self::$testDatastore);
44 $history = new History('sandbox/history.php'); 46 $history = new History('sandbox/history.php');
45 self::$bookmarkService = new \FakeBookmarkService($conf, $history, true); 47 self::$bookmarkService = new \FakeBookmarkService($conf, $history, $mutex, true);
46 self::$linkFilter = new BookmarkFilter(self::$bookmarkService->getBookmarks()); 48 self::$linkFilter = new BookmarkFilter(self::$bookmarkService->getBookmarks());
47 } 49 }
48 50
diff --git a/tests/bookmark/BookmarkInitializerTest.php b/tests/bookmark/BookmarkInitializerTest.php
index 25704004..0c8420ce 100644
--- a/tests/bookmark/BookmarkInitializerTest.php
+++ b/tests/bookmark/BookmarkInitializerTest.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Bookmark; 3namespace Shaarli\Bookmark;
4 4
5use malkusch\lock\mutex\NoMutex;
5use Shaarli\Config\ConfigManager; 6use Shaarli\Config\ConfigManager;
6use Shaarli\History; 7use Shaarli\History;
7use Shaarli\TestCase; 8use Shaarli\TestCase;
@@ -34,11 +35,15 @@ class BookmarkInitializerTest extends TestCase
34 /** @var BookmarkInitializer instance */ 35 /** @var BookmarkInitializer instance */
35 protected $initializer; 36 protected $initializer;
36 37
38 /** @var NoMutex */
39 protected $mutex;
40
37 /** 41 /**
38 * Initialize an empty BookmarkFileService 42 * Initialize an empty BookmarkFileService
39 */ 43 */
40 public function setUp(): void 44 public function setUp(): void
41 { 45 {
46 $this->mutex = new NoMutex();
42 if (file_exists(self::$testDatastore)) { 47 if (file_exists(self::$testDatastore)) {
43 unlink(self::$testDatastore); 48 unlink(self::$testDatastore);
44 } 49 }
@@ -47,7 +52,7 @@ class BookmarkInitializerTest extends TestCase
47 $this->conf = new ConfigManager(self::$testConf); 52 $this->conf = new ConfigManager(self::$testConf);
48 $this->conf->set('resource.datastore', self::$testDatastore); 53 $this->conf->set('resource.datastore', self::$testDatastore);
49 $this->history = new History('sandbox/history.php'); 54 $this->history = new History('sandbox/history.php');
50 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 55 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
51 56
52 $this->initializer = new BookmarkInitializer($this->bookmarkService); 57 $this->initializer = new BookmarkInitializer($this->bookmarkService);
53 } 58 }
@@ -59,7 +64,7 @@ class BookmarkInitializerTest extends TestCase
59 { 64 {
60 $refDB = new \ReferenceLinkDB(); 65 $refDB = new \ReferenceLinkDB();
61 $refDB->write(self::$testDatastore); 66 $refDB->write(self::$testDatastore);
62 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 67 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
63 $this->initializer = new BookmarkInitializer($this->bookmarkService); 68 $this->initializer = new BookmarkInitializer($this->bookmarkService);
64 69
65 $this->initializer->initialize(); 70 $this->initializer->initialize();
@@ -90,7 +95,7 @@ class BookmarkInitializerTest extends TestCase
90 $this->bookmarkService->save(); 95 $this->bookmarkService->save();
91 96
92 // Reload from file 97 // Reload from file
93 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 98 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
94 $this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count()); 99 $this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count());
95 100
96 $bookmark = $this->bookmarkService->get(43); 101 $bookmark = $this->bookmarkService->get(43);
@@ -121,7 +126,7 @@ class BookmarkInitializerTest extends TestCase
121 public function testInitializeNonExistentDataStore(): void 126 public function testInitializeNonExistentDataStore(): void
122 { 127 {
123 $this->conf->set('resource.datastore', static::$testDatastore . '_empty'); 128 $this->conf->set('resource.datastore', static::$testDatastore . '_empty');
124 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 129 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
125 130
126 $this->initializer->initialize(); 131 $this->initializer->initialize();
127 132
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index 2d675c9a..3508a7b1 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -30,3 +30,7 @@ require_once 'tests/utils/ReferenceLinkDB.php';
30require_once 'tests/utils/ReferenceSessionIdHashes.php'; 30require_once 'tests/utils/ReferenceSessionIdHashes.php';
31 31
32\ReferenceSessionIdHashes::genAllHashes(); 32\ReferenceSessionIdHashes::genAllHashes();
33
34if (!defined('SHAARLI_MUTEX_FILE')) {
35 define('SHAARLI_MUTEX_FILE', __FILE__);
36}
diff --git a/tests/feed/FeedBuilderTest.php b/tests/feed/FeedBuilderTest.php
index c29e8ef3..6b9204eb 100644
--- a/tests/feed/FeedBuilderTest.php
+++ b/tests/feed/FeedBuilderTest.php
@@ -3,6 +3,7 @@
3namespace Shaarli\Feed; 3namespace Shaarli\Feed;
4 4
5use DateTime; 5use DateTime;
6use malkusch\lock\mutex\NoMutex;
6use ReferenceLinkDB; 7use ReferenceLinkDB;
7use Shaarli\Bookmark\Bookmark; 8use Shaarli\Bookmark\Bookmark;
8use Shaarli\Bookmark\BookmarkFileService; 9use Shaarli\Bookmark\BookmarkFileService;
@@ -47,6 +48,7 @@ class FeedBuilderTest extends TestCase
47 */ 48 */
48 public static function setUpBeforeClass(): void 49 public static function setUpBeforeClass(): void
49 { 50 {
51 $mutex = new NoMutex();
50 $conf = new ConfigManager('tests/utils/config/configJson'); 52 $conf = new ConfigManager('tests/utils/config/configJson');
51 $conf->set('resource.datastore', self::$testDatastore); 53 $conf->set('resource.datastore', self::$testDatastore);
52 $refLinkDB = new \ReferenceLinkDB(); 54 $refLinkDB = new \ReferenceLinkDB();
@@ -54,7 +56,7 @@ class FeedBuilderTest extends TestCase
54 $history = new History('sandbox/history.php'); 56 $history = new History('sandbox/history.php');
55 $factory = new FormatterFactory($conf, true); 57 $factory = new FormatterFactory($conf, true);
56 self::$formatter = $factory->getFormatter(); 58 self::$formatter = $factory->getFormatter();
57 self::$bookmarkService = new BookmarkFileService($conf, $history, true); 59 self::$bookmarkService = new BookmarkFileService($conf, $history, $mutex, true);
58 60
59 self::$serverInfo = array( 61 self::$serverInfo = array(
60 'HTTPS' => 'Off', 62 'HTTPS' => 'Off',
diff --git a/tests/netscape/BookmarkExportTest.php b/tests/netscape/BookmarkExportTest.php
index 9b95ccc9..ad288f78 100644
--- a/tests/netscape/BookmarkExportTest.php
+++ b/tests/netscape/BookmarkExportTest.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Netscape; 3namespace Shaarli\Netscape;
4 4
5use malkusch\lock\mutex\NoMutex;
5use Shaarli\Bookmark\BookmarkFileService; 6use Shaarli\Bookmark\BookmarkFileService;
6use Shaarli\Config\ConfigManager; 7use Shaarli\Config\ConfigManager;
7use Shaarli\Formatter\BookmarkFormatter; 8use Shaarli\Formatter\BookmarkFormatter;
@@ -56,12 +57,13 @@ class BookmarkExportTest extends TestCase
56 */ 57 */
57 public static function setUpBeforeClass(): void 58 public static function setUpBeforeClass(): void
58 { 59 {
60 $mutex = new NoMutex();
59 static::$conf = new ConfigManager('tests/utils/config/configJson'); 61 static::$conf = new ConfigManager('tests/utils/config/configJson');
60 static::$conf->set('resource.datastore', static::$testDatastore); 62 static::$conf->set('resource.datastore', static::$testDatastore);
61 static::$refDb = new \ReferenceLinkDB(); 63 static::$refDb = new \ReferenceLinkDB();
62 static::$refDb->write(static::$testDatastore); 64 static::$refDb->write(static::$testDatastore);
63 static::$history = new History('sandbox/history.php'); 65 static::$history = new History('sandbox/history.php');
64 static::$bookmarkService = new BookmarkFileService(static::$conf, static::$history, true); 66 static::$bookmarkService = new BookmarkFileService(static::$conf, static::$history, $mutex, true);
65 $factory = new FormatterFactory(static::$conf, true); 67 $factory = new FormatterFactory(static::$conf, true);
66 static::$formatter = $factory->getFormatter('raw'); 68 static::$formatter = $factory->getFormatter('raw');
67 } 69 }
diff --git a/tests/netscape/BookmarkImportTest.php b/tests/netscape/BookmarkImportTest.php
index c1e49b5f..c526d5c8 100644
--- a/tests/netscape/BookmarkImportTest.php
+++ b/tests/netscape/BookmarkImportTest.php
@@ -3,6 +3,7 @@
3namespace Shaarli\Netscape; 3namespace Shaarli\Netscape;
4 4
5use DateTime; 5use DateTime;
6use malkusch\lock\mutex\NoMutex;
6use Psr\Http\Message\UploadedFileInterface; 7use Psr\Http\Message\UploadedFileInterface;
7use Shaarli\Bookmark\Bookmark; 8use Shaarli\Bookmark\Bookmark;
8use Shaarli\Bookmark\BookmarkFileService; 9use Shaarli\Bookmark\BookmarkFileService;
@@ -87,6 +88,7 @@ class BookmarkImportTest extends TestCase
87 */ 88 */
88 protected function setUp(): void 89 protected function setUp(): void
89 { 90 {
91 $mutex = new NoMutex();
90 if (file_exists(self::$testDatastore)) { 92 if (file_exists(self::$testDatastore)) {
91 unlink(self::$testDatastore); 93 unlink(self::$testDatastore);
92 } 94 }
@@ -97,7 +99,7 @@ class BookmarkImportTest extends TestCase
97 $this->conf->set('resource.page_cache', $this->pagecache); 99 $this->conf->set('resource.page_cache', $this->pagecache);
98 $this->conf->set('resource.datastore', self::$testDatastore); 100 $this->conf->set('resource.datastore', self::$testDatastore);
99 $this->history = new History(self::$historyFilePath); 101 $this->history = new History(self::$historyFilePath);
100 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 102 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
101 $this->netscapeBookmarkUtils = new NetscapeBookmarkUtils($this->bookmarkService, $this->conf, $this->history); 103 $this->netscapeBookmarkUtils = new NetscapeBookmarkUtils($this->bookmarkService, $this->conf, $this->history);
102 } 104 }
103 105
diff --git a/tests/updater/UpdaterTest.php b/tests/updater/UpdaterTest.php
index a6280b8c..47332544 100644
--- a/tests/updater/UpdaterTest.php
+++ b/tests/updater/UpdaterTest.php
@@ -2,6 +2,7 @@
2namespace Shaarli\Updater; 2namespace Shaarli\Updater;
3 3
4use Exception; 4use Exception;
5use malkusch\lock\mutex\NoMutex;
5use Shaarli\Bookmark\BookmarkFileService; 6use Shaarli\Bookmark\BookmarkFileService;
6use Shaarli\Bookmark\BookmarkServiceInterface; 7use Shaarli\Bookmark\BookmarkServiceInterface;
7use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
@@ -44,12 +45,13 @@ class UpdaterTest extends TestCase
44 */ 45 */
45 protected function setUp(): void 46 protected function setUp(): void
46 { 47 {
48 $mutex = new NoMutex();
47 $this->refDB = new \ReferenceLinkDB(); 49 $this->refDB = new \ReferenceLinkDB();
48 $this->refDB->write(self::$testDatastore); 50 $this->refDB->write(self::$testDatastore);
49 51
50 copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php'); 52 copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php');
51 $this->conf = new ConfigManager(self::$configFile); 53 $this->conf = new ConfigManager(self::$configFile);
52 $this->bookmarkService = new BookmarkFileService($this->conf, $this->createMock(History::class), true); 54 $this->bookmarkService = new BookmarkFileService($this->conf, $this->createMock(History::class), $mutex, true);
53 $this->updater = new Updater([], $this->bookmarkService, $this->conf, true); 55 $this->updater = new Updater([], $this->bookmarkService, $this->conf, true);
54 } 56 }
55 57