vfsStream icon indicating copy to clipboard operation
vfsStream copied to clipboard

is_dir() randomly failing for vfsStreamDirectory

Open rask opened this issue 5 years ago • 1 comments

I have a test suite where I create a directory with vfsStream, which is meant to simulate a write-blocked directory for my SUT. In my code the logic checks both is_dir() and is_writable() for a directory to give granural errors to the user.

Now, in my test case I have to use __construct() as the directory is fetched in the test case via data providers, which are run before setUp. The constructor creates the directory as follows:

    public function __construct(?string $name = null, array $data = [], $dataName = '')
    {
        parent::__construct($name, $data, $dataName);

        vfsStream::setup();

        $tmpdir_name = md5((string) time());
        $tmpdir = new vfsStreamDirectory($tmpdir_name);
        $tmpdir->chmod(0444);
        vfsStreamWrapper::getRoot()->addChild($tmpdir);

        assert(vfsStreamWrapper::getRoot()->hasChild($tmpdir_name));

        $this->unwritable_tmp_directory = vfsStreamWrapper::getRoot()->getChild($tmpdir_name)->url();
    }

Here is the test case code I'm running:

    public function badTemporaryDirectories() : array
    {
        return [
            ['/missing/directory', '/missing/i'],
            [$this->unwritable_tmp_directory, '/unwritable/i'],
        ];
    }

    /**
     * @dataProvider badTemporaryDirectories
     */
    public function test_it_requires_proper_tmpdir(string $directory, string $expected_message) : void
    {
        $this->expectException(\InvalidArgumentException::class);
        $this->expectExceptionMessageMatches($expected_message);

        $_ = new Thingy($directory);
    }

And the code inside Thingy which I am testing looks as follows:

    public function __construct(?string $tmp_dir = null)
    {
        if ($tmp_dir === null) {
            $tmp_dir = \sys_get_temp_dir();
        }

        /** @var string $tmp_dir */

        if (\is_dir($tmp_dir) === false) { // <-- this here randomly fails for existing directory
            throw new \InvalidArgumentException('Invalid tempdir: missing');
        }

        if (\is_writable($tmp_dir) === false) {
            throw new \InvalidArgumentException('Invalid tempdir: unwritable');
        }

        $this->tmpdir = $tmp_dir;
    }

Now, the is_dir() call is randomly failing, even with the assert() in my test case constructor passing all runs properly. It seems like I get 50% success rate, where I can either get no exception from the SUT constructor, or then I land into the "unwritable error branch" as mandated by a test case.

PHP version is 7.4. PHPUnit version is 9.3.8, and vfsStream is at 1.6.8.

rask avatar Sep 02 '20 23:09 rask

This problem seemingly went away after a co-worker removed the data provider and split the target test method into two separate test methods. Will be monitoring whether this permanently fixes the issue or not.

rask avatar Jun 07 '21 13:06 rask