Skip to content

Commit

Permalink
Mock fopen failure, closes #155
Browse files Browse the repository at this point in the history
Feature to test fopen() error cases, to simulate race conditions on
fopen() that is when a readable file becomes unreadable on fopen()
instantly, for example to simulate a file-system failure.
  • Loading branch information
ktomk committed Jul 12, 2017
1 parent 03c1427 commit 272b712
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 3 deletions.
28 changes: 28 additions & 0 deletions src/main/php/org/bovigo/vfs/vfsStreamFile.php
Expand Up @@ -35,6 +35,10 @@ class vfsStreamFile extends vfsStreamAbstractContent
* @type bool[string]
*/
protected $sharedLock = array();
/**
* @var null|string
*/
private $openError;

/**
* constructor
Expand Down Expand Up @@ -391,4 +395,28 @@ public function hasExclusiveLock($resource = null)

return null !== $this->exclusiveLock;
}

/**
* Setter to set (string w/ content) or remove (null) triggering an error
* on a vfs-stream-wrapped fopen() call.
*
* @param string|null $error string (non-zero length) to raise an error on fopen, null to unset (default)
* @since 1.6.5
* @see https://github.com/mikey179/vfsStream/issues/155
*/
public function setOpenError($error = null)
{
$this->openError = $error;
}

/**
* @see setOpenError
* @return null|string
* @since 1.6.5
* @see https://github.com/mikey179/vfsStream/issues/155
*/
public function getOpenError()
{
return $this->openError;
}
}
14 changes: 11 additions & 3 deletions src/main/php/org/bovigo/vfs/vfsStreamWrapper.php
Expand Up @@ -278,10 +278,12 @@ protected function resolvePath($path)
*/
public function stream_open($path, $mode, $options, $opened_path)
{
$triggerErrors = ($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS;

$extended = ((strstr($mode, '+') !== false) ? (true) : (false));
$mode = str_replace(array('t', 'b', '+'), '', $mode);
if (in_array($mode, array('r', 'w', 'a', 'x', 'c')) === false) {
if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) {
if ($triggerErrors) {
trigger_error('Illegal mode ' . $mode . ', use r, w, a, x or c, flavoured with t, b and/or +', E_USER_WARNING);
}

Expand All @@ -293,7 +295,7 @@ public function stream_open($path, $mode, $options, $opened_path)
$this->content = $this->getContentOfType($path, vfsStreamContent::TYPE_FILE);
if (null !== $this->content) {
if (self::WRITE === $mode) {
if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) {
if ($triggerErrors) {
trigger_error('File ' . $path . ' already exists, can not open with mode x', E_USER_WARNING);
}

Expand All @@ -313,11 +315,17 @@ public function stream_open($path, $mode, $options, $opened_path)
$this->content->openForAppend();
} else {
if (!$this->content->isReadable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup())) {
if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) {
if ($triggerErrors) {
trigger_error('Permission denied', E_USER_WARNING);
}
return false;
}
if ($error = $this->content->getOpenError()) {
if ($triggerErrors) {
trigger_error($error, E_USER_WARNING);
}
return false;
}
$this->content->open();
}

Expand Down
22 changes: 22 additions & 0 deletions src/test/php/org/bovigo/vfs/vfsStreamWrapperFileTestCase.php
Expand Up @@ -454,4 +454,26 @@ public function cannotReadFileFromNonReadableDir()
$this->bar->chmod(0);
$this->assertFalse(@file_get_contents($this->baz1URL));
}

/**
* @test
* @see https://github.com/mikey179/vfsStream/issues/155
* @since 1.6.5
*/
public function errorOnOpen()
{
$file = $this->baz1;
$path = $file->url();
$this->assertNotFalse(@fopen($path, 'r'), 'precondition');

$file->setOpenError("fopen() gives error");
$this->assertFalse(@fopen($path, 'r'), 'fopen fails now');

$file->setOpenError(null);
$this->assertNotFalse(@fopen($path, 'r'), 'fopen works again');

// test for error
$context = stream_context_create();
stream_context_set_option($context, 'vfs', 'trigger_errors', true);
}
}

0 comments on commit 272b712

Please sign in to comment.