xref: /dokuwiki/_test/tests/Search/Index/LockTest.php (revision ede4646658cf51245060332d97a319a39c788ea1)
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