1*ede46466SAndreas Gohr<?php 2*ede46466SAndreas Gohr 3*ede46466SAndreas Gohrnamespace dokuwiki\test\Search\Index; 4*ede46466SAndreas Gohr 5*ede46466SAndreas Gohruse dokuwiki\Search\Exception\IndexLockException; 6*ede46466SAndreas Gohruse dokuwiki\Search\Index\Lock; 7*ede46466SAndreas Gohr 8*ede46466SAndreas Gohrclass LockTest extends \DokuWikiTest 9*ede46466SAndreas Gohr{ 10*ede46466SAndreas Gohr protected function tearDown(): void 11*ede46466SAndreas Gohr { 12*ede46466SAndreas Gohr Lock::releaseAll(); 13*ede46466SAndreas Gohr parent::tearDown(); 14*ede46466SAndreas Gohr } 15*ede46466SAndreas Gohr 16*ede46466SAndreas Gohr public function testAcquireAndRelease() 17*ede46466SAndreas Gohr { 18*ede46466SAndreas Gohr Lock::acquire('test_lock'); 19*ede46466SAndreas Gohr 20*ede46466SAndreas Gohr // lock directory should exist 21*ede46466SAndreas Gohr global $conf; 22*ede46466SAndreas Gohr $this->assertDirectoryExists($conf['lockdir'] . 'test_lock.index'); 23*ede46466SAndreas Gohr 24*ede46466SAndreas Gohr Lock::release('test_lock'); 25*ede46466SAndreas Gohr 26*ede46466SAndreas Gohr // lock directory should be removed 27*ede46466SAndreas Gohr $this->assertDirectoryDoesNotExist($conf['lockdir'] . 'test_lock.index'); 28*ede46466SAndreas Gohr } 29*ede46466SAndreas Gohr 30*ede46466SAndreas Gohr public function testReferenceCounting() 31*ede46466SAndreas Gohr { 32*ede46466SAndreas Gohr global $conf; 33*ede46466SAndreas Gohr $dir = $conf['lockdir'] . 'refcount.index'; 34*ede46466SAndreas Gohr 35*ede46466SAndreas Gohr Lock::acquire('refcount'); 36*ede46466SAndreas Gohr Lock::acquire('refcount'); 37*ede46466SAndreas Gohr $this->assertDirectoryExists($dir); 38*ede46466SAndreas Gohr 39*ede46466SAndreas Gohr // first release only decrements, lock stays 40*ede46466SAndreas Gohr Lock::release('refcount'); 41*ede46466SAndreas Gohr $this->assertDirectoryExists($dir); 42*ede46466SAndreas Gohr 43*ede46466SAndreas Gohr // second release removes the lock 44*ede46466SAndreas Gohr Lock::release('refcount'); 45*ede46466SAndreas Gohr $this->assertDirectoryDoesNotExist($dir); 46*ede46466SAndreas Gohr } 47*ede46466SAndreas Gohr 48*ede46466SAndreas Gohr public function testReleaseUnheldLockIsNoop() 49*ede46466SAndreas Gohr { 50*ede46466SAndreas Gohr // should not throw or error 51*ede46466SAndreas Gohr Lock::release('never_acquired'); 52*ede46466SAndreas Gohr $this->assertTrue(true); 53*ede46466SAndreas Gohr } 54*ede46466SAndreas Gohr 55*ede46466SAndreas Gohr public function testAcquireFailsWhenAlreadyLockedByAnotherProcess() 56*ede46466SAndreas Gohr { 57*ede46466SAndreas Gohr global $conf; 58*ede46466SAndreas Gohr $dir = $conf['lockdir'] . 'foreign.index'; 59*ede46466SAndreas Gohr 60*ede46466SAndreas Gohr // simulate a foreign lock by creating the directory directly 61*ede46466SAndreas Gohr mkdir($dir); 62*ede46466SAndreas Gohr // set mtime to now so it's not stale 63*ede46466SAndreas Gohr touch($dir); 64*ede46466SAndreas Gohr 65*ede46466SAndreas Gohr $this->expectException(IndexLockException::class); 66*ede46466SAndreas Gohr Lock::acquire('foreign'); 67*ede46466SAndreas Gohr } 68*ede46466SAndreas Gohr 69*ede46466SAndreas Gohr public function testStaleLockIsOverridden() 70*ede46466SAndreas Gohr { 71*ede46466SAndreas Gohr global $conf; 72*ede46466SAndreas Gohr $dir = $conf['lockdir'] . 'stale.index'; 73*ede46466SAndreas Gohr 74*ede46466SAndreas Gohr // simulate a stale lock (older than 5 minutes) 75*ede46466SAndreas Gohr mkdir($dir); 76*ede46466SAndreas Gohr touch($dir, time() - 400); 77*ede46466SAndreas Gohr 78*ede46466SAndreas Gohr // should succeed by removing the stale lock 79*ede46466SAndreas Gohr Lock::acquire('stale'); 80*ede46466SAndreas Gohr $this->assertDirectoryExists($dir); 81*ede46466SAndreas Gohr 82*ede46466SAndreas Gohr Lock::release('stale'); 83*ede46466SAndreas Gohr } 84*ede46466SAndreas Gohr 85*ede46466SAndreas Gohr public function testReleaseAll() 86*ede46466SAndreas Gohr { 87*ede46466SAndreas Gohr global $conf; 88*ede46466SAndreas Gohr 89*ede46466SAndreas Gohr Lock::acquire('all_a'); 90*ede46466SAndreas Gohr Lock::acquire('all_b'); 91*ede46466SAndreas Gohr Lock::acquire('all_a'); // refcount 2 92*ede46466SAndreas Gohr 93*ede46466SAndreas Gohr Lock::releaseAll(); 94*ede46466SAndreas Gohr 95*ede46466SAndreas Gohr $this->assertDirectoryDoesNotExist($conf['lockdir'] . 'all_a.index'); 96*ede46466SAndreas Gohr $this->assertDirectoryDoesNotExist($conf['lockdir'] . 'all_b.index'); 97*ede46466SAndreas Gohr 98*ede46466SAndreas Gohr // releasing after releaseAll should be safe 99*ede46466SAndreas Gohr Lock::release('all_a'); 100*ede46466SAndreas Gohr } 101*ede46466SAndreas Gohr 102*ede46466SAndreas Gohr public function testMultipleIndependentLocks() 103*ede46466SAndreas Gohr { 104*ede46466SAndreas Gohr global $conf; 105*ede46466SAndreas Gohr 106*ede46466SAndreas Gohr Lock::acquire('ind_a'); 107*ede46466SAndreas Gohr Lock::acquire('ind_b'); 108*ede46466SAndreas Gohr 109*ede46466SAndreas Gohr $this->assertDirectoryExists($conf['lockdir'] . 'ind_a.index'); 110*ede46466SAndreas Gohr $this->assertDirectoryExists($conf['lockdir'] . 'ind_b.index'); 111*ede46466SAndreas Gohr 112*ede46466SAndreas Gohr Lock::release('ind_a'); 113*ede46466SAndreas Gohr $this->assertDirectoryDoesNotExist($conf['lockdir'] . 'ind_a.index'); 114*ede46466SAndreas Gohr $this->assertDirectoryExists($conf['lockdir'] . 'ind_b.index'); 115*ede46466SAndreas Gohr 116*ede46466SAndreas Gohr Lock::release('ind_b'); 117*ede46466SAndreas Gohr $this->assertDirectoryDoesNotExist($conf['lockdir'] . 'ind_b.index'); 118*ede46466SAndreas Gohr } 119*ede46466SAndreas Gohr} 120