Skip to content

Commit 3118266

Browse files
#6 Improve test coverage for FlockMutex
1 parent 33db073 commit 3118266

12 files changed

+69
-27
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace malkusch\lock\exception;
4+
5+
class DeadlineException extends \Exception
6+
{
7+
8+
}

classes/exception/TimeoutException.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,12 @@
1111
*/
1212
class TimeoutException extends LockAcquireException
1313
{
14-
14+
/**
15+
* @param int $timeout
16+
* @return TimeoutException
17+
*/
18+
public static function create($timeout)
19+
{
20+
return new self(sprintf("Timeout of %d seconds exceeded.", $timeout));
21+
}
1522
}

classes/mutex/FlockMutex.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace malkusch\lock\mutex;
44

5+
use malkusch\lock\exception\DeadlineException;
56
use malkusch\lock\exception\ExecutionOutsideLockException;
67
use malkusch\lock\exception\LockAcquireException;
78
use malkusch\lock\exception\LockReleaseException;
@@ -99,9 +100,15 @@ private function lockPcntl()
99100
{
100101
$timebox = new PcntlTimeout($this->timeout);
101102

102-
$timebox->timeBoxed(function () {
103-
$this->lockBlocking();
104-
});
103+
try {
104+
$timebox->timeBoxed(
105+
function () {
106+
$this->lockBlocking();
107+
}
108+
);
109+
} catch (DeadlineException $e) {
110+
throw TimeoutException::create($this->timeout);
111+
}
105112
}
106113

107114
/**

classes/mutex/MySQLMutex.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public function lock()
6262
throw new LockAcquireException("An error occurred while acquiring the lock");
6363
}
6464

65-
throw new TimeoutException("Timeout when acquiring lock.");
65+
throw TimeoutException::create($this->timeout);
6666
}
6767

6868
public function unlock()

classes/mutex/PgAdvisoryLockMutex.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22

33
namespace malkusch\lock\mutex;
44

5-
use malkusch\lock\exception\LockAcquireException;
6-
use malkusch\lock\exception\TimeoutException;
7-
85
class PgAdvisoryLockMutex extends LockMutex
96
{
107
/**

classes/util/Loop.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ public function execute(callable $code)
6969
{
7070
$this->looping = true;
7171
$minWait = 100; // microseconds
72-
$timeout = microtime(true) + $this->timeout; // At this time, the lock will time out.
72+
$deadline = microtime(true) + $this->timeout; // At this time, the lock will time out.
7373
$result = null;
7474

75-
for ($i = 0; $this->looping && microtime(true) < $timeout; $i++) {
75+
for ($i = 0; $this->looping && microtime(true) < $deadline; $i++) {
7676
$result = call_user_func($code);
7777
if (!$this->looping) {
7878
break;
@@ -84,22 +84,22 @@ public function execute(callable $code)
8484
/*
8585
* Calculate max time remaining, don't sleep any longer than that.
8686
*/
87-
$usecRemaining = \intval(($timeout - microtime(true)) * 1e6);
87+
$usecRemaining = \intval(($deadline - microtime(true)) * 1e6);
8888

8989
if ($usecRemaining <= 0) {
9090
/*
9191
* We've ran out of time.
9292
*/
93-
throw new TimeoutException("Timeout of $this->timeout seconds exceeded.");
93+
throw TimeoutException::create($this->timeout);
9494
}
9595

9696
$usleep = \min($usecRemaining, \random_int($min, $max));
9797

9898
usleep($usleep);
9999
}
100100

101-
if (microtime(true) >= $timeout) {
102-
throw new TimeoutException("Timeout of $this->timeout seconds exceeded.");
101+
if (microtime(true) >= $deadline) {
102+
throw TimeoutException::create($this->timeout);
103103
}
104104

105105
return $result;

classes/util/PcntlTimeout.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace malkusch\lock\util;
44

5+
use malkusch\lock\exception\DeadlineException;
56
use malkusch\lock\exception\TimeoutException;
67
use malkusch\lock\exception\LockAcquireException;
78

@@ -34,7 +35,7 @@ public function __construct($timeout)
3435
throw new \RuntimeException("PCNTL module not enabled");
3536
}
3637
if ($timeout <= 0) {
37-
throw new \InvalidArgumentException("Timeout must be positiv and non zero");
38+
throw new \InvalidArgumentException("Timeout must be positive and non zero");
3839
}
3940
$this->timeout = $timeout;
4041
}
@@ -52,13 +53,13 @@ public function __construct($timeout)
5253
* @param callable $code Executed code block
5354
* @return mixed Return value of the executed block
5455
*
55-
* @throws TimeoutException Running the code timed out
56+
* @throws DeadlineException Running the code hit the deadline
5657
* @throws LockAcquireException Installing the timeout failed
5758
*/
5859
public function timeBoxed(callable $code)
5960
{
6061
$signal = pcntl_signal(SIGALRM, function () {
61-
throw new TimeoutException("Timed out");
62+
throw new DeadlineException(sprintf("Timebox hit deadline of %d seconds", $this->timeout));
6263
});
6364
if (!$signal) {
6465
throw new LockAcquireException("Could not install signal");

tests/mutex/FlockMutexTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace malkusch\lock\mutex;
44

55
use Eloquent\Liberator\Liberator;
6+
use malkusch\lock\util\PcntlTimeout;
67

78
/**
89
* @author Willem Stuursma-Ruwen <[email protected]>
@@ -52,6 +53,7 @@ public function testCodeExecutedOutsideLockIsNotThrown($strategy)
5253

5354
/**
5455
* @expectedException \malkusch\lock\exception\TimeoutException
56+
* @expectedExceptionMessage Timeout of 1 seconds exceeded.
5557
* @dataProvider dpTimeoutableStrategies
5658
*/
5759
public function testTimeoutOccurs($strategy)
@@ -79,4 +81,22 @@ public function dpTimeoutableStrategies()
7981
[FlockMutex::STRATEGY_BUSY],
8082
];
8183
}
84+
85+
/**
86+
* @expectedException \malkusch\lock\exception\DeadlineException
87+
*/
88+
public function testNoTimeoutWaitsForever()
89+
{
90+
$another_resource = fopen($this->file, "r");
91+
flock($another_resource, LOCK_EX);
92+
93+
$this->mutex->strategy = FlockMutex::STRATEGY_BLOCK;
94+
95+
$timebox = new PcntlTimeout(1);
96+
$timebox->timeBoxed(function() {
97+
$this->mutex->synchronized(function() {
98+
$this->fail("Did not expect code execution.");
99+
});
100+
});
101+
}
82102
}

tests/mutex/RedisMutexTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ function () use (&$i, $available) {
125125
*
126126
* @test
127127
* @expectedException \malkusch\lock\exception\TimeoutException
128+
* @expectedExceptionMessage Timeout of 1 seconds exceeded.
128129
* @dataProvider provideMinority
129130
*/
130131
public function testAcquireTooFewKeys($count, $available)

tests/mutex/SpinlockMutexTest.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,15 @@ public function testFailAcquireLock()
5252
/**
5353
* Tests failing to acquire the lock due to a timeout.
5454
*
55-
* @test
56-
* @expectedException malkusch\lock\exception\TimeoutException
55+
* @expectedException \malkusch\lock\exception\TimeoutException
56+
* @expectedExceptionMessage Timeout of 3 seconds exceeded.
5757
*/
5858
public function testAcquireTimesOut()
5959
{
6060
$mutex = $this->getMockForAbstractClass(SpinlockMutex::class, ["test"]);
61-
$mutex->expects($this->any())->method("acquire")->willReturn(false);
61+
$mutex->expects($this->atLeastOnce())
62+
->method("acquire")
63+
->willReturn(false);
6264

6365
$mutex->synchronized(function () {
6466
$this->fail("execution is not expected");

0 commit comments

Comments
 (0)