PHP - PHPUnit - Test Ability to Secure a Filelock
Frage
I am working on updating unit tests for my core library, and came across a scenario regarding filelocks (flock), and wanted to see how others implemented these types of unit tests.
Basically I have a utlity File class which will write contents to a file:
class CoreLib_Api_File_Package
{
public static function write(array $options)
{
...
if (!$file->flock(LOCK_EX)) {
throw new CoreLib_Api_Exception('Unable to obtain lock on file');
}
...
}
}
And my unit test looks like:
public function testWriteException_UnableToSecureLock()
{
$this->touchFile($this->destFileUri);
$file = new SplFileObject($this->destFileUri, CoreLib_Api_File::MODE_WRITE);
$file->flock(LOCK_EX);
CoreLib_Api_File_Package::write(array('fileUri' => $this->destFileUri, 'content' => $this->testContent, 'mode' => CoreLib_Api_File::MODE_WRITE));
}
As you can see from the test code I am putting an explicit lock on $this->destFileUri
before I make the API call to the write()
method. What I would expect is that the exception throw new CoreLib_Api_Exception('Unable to obtain lock on file');
to be thrown. Instead, my unit test just hangs indefinitely.
What would be the proper way to test whether a file has a lock?
Thanks in advance.
Lösung
You should check this comment on the flock
docs page.
Essentially, flock
will pause execution until it is able to obtain the lock. Take the following code, which is similar to your situation above:
$file = 'file.txt';
$first = fopen($file, "w");
flock($first, LOCK_EX);
$second = fopen($file, "w");
# Your script will pause on the next line until timeout
# due to the inability to obtain a lock.
flock($second, LOCK_EX);
However, you can obtain non-blocking locks like this:
flock($file, LOCK_EX | LOCK_NB);
I am not sure if there are negative implications to locking files this way. Also, while the docs say LOCK_NB
does not work on Windows, I just tested it and it worked on my machine. So, you could do something like this in your CoreLib_Api_File_Package::write
method:
class CoreLib_Api_File_Package
{
public static function write(array $options)
{
if ( ! $file->flock(LOCK_EX | LOCK_NB))
{
throw new CoreLib_Api_Exception('Unable to obtain lock on file');
}
}
}
Your current test should pass as-written. Other than that, I can't think of anything.
Edit: They should pass as long as you are telling PHPUnit
to expect the CoreLib_Api_Exception
exception (just pointing it out because you didn't have it in your example).