PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Wednesday, January 5, 2022

[FIXED] CakePHP 3 - Unit Test tearDown() failing to remove file: 'resource temporarily unavailable'

 January 05, 2022     cakephp, cakephp-3.0, phpunit, unlink     No comments   

Issue

In my application users can upload files and other users can download them. As a part of my controller integration test I move a couple of test files into the upload directory so I can test the download action.

The moving of files in setUp() and removing them in teardown() works, as long as I don't touch the files in a test. When the files were returned by a test, the tearDown() is failing to remove them, I get the error:

Warning Error: unlink(C:\xampp\htdocs\2deal\keys_test\1_open.key): Resource temporarily unavailable

How can I fix this?

  • I tried opening and closing the file inside tearDown(), but to no effect. Interestingly the fopen() function succeeds, so the file isn't actually locked.
  • I also found this similar question, where the solution was removing the object using the file. So I added unset($this->_response); to the top of tearDown(), but again to no avail.
  • And I tried adding sleep(10); add the start of tearDown(), which also made no difference. So it's not a timing issue.

The entire test file looks like this:

    /**
     * setUp method before each test
     */
    public function setUp()
    {
        Configure::write('Keys.path', 'keys_test');

        // Config writing must happen before parent::setUp()
        parent::setUp();

        $files = [
            '1_open.key',
            '1_close.key',
            '2_open.key',
            '2_close.key'
        ];
        foreach ($files as $file)
        {
            copy(self::SOURCE_DIR . $file, ROOT . DS . Configure::read('Keys.path') . DS . $file);
        }
    }

    /**
     * tearDown method after each test
     */
    public function tearDown()
    {
        parent::tearDown();

        // Clear test upload directory
        $files = glob(ROOT . DS . Configure::read('Keys.path') . DS . '*');

        foreach ($files as $file)
        {

            if (is_file($file))
            {
                \unlink($file); // Delete file
            }
        }
    }

    /**
     * Test getFile method
     * 
     * @return void
     */
    public function testGetFile()
    {
        $this->get('/carkeys/get-file/1/open.json');

        $file = $this->_response->getFile();

        $real_file = self::SOURCE_DIR . '1_open.key';

        $this->assertResponseOk();
        $this->assertFileEquals($file->path, $real_file);
    }

Solution

The file isn't locked, but there's an open handle for it.

As of CakePHP 3.4, the response uses streams for the response body. It creates the streams when attaching body contents or files, and the stream is being opened immediately for writing or reading.

Long story short, close the stream before trying to delete the file:

$this->_response->getBody()->close();


Answered By - ndm
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing