From 35ebf64619296e8356f6f4f06d4084dc17c06264 Mon Sep 17 00:00:00 2001
From: Morton Jonuschat <m.jonuschat@mojocode.de>
Date: Mon, 26 Oct 2015 19:24:14 +0100
Subject: [PATCH] [TASK] Tests: Decouple InstallTool unit tests from real
 filesystem

Change the FolderStructure tests to use a vfsStream virtual filesystem
for all tests that work with files, directories and permissions to make
the tests less reliant on the capabilities of the user running the
testsuite and the real filesystem.

Resolves: #71053
Releases: master
Change-Id: Ife42f43008215b382f70d5fe956d3dcf9590f5b9
Reviewed-on: https://review.typo3.org/44301
Reviewed-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
Tested-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
---
 .../Unit/FolderStructure/AbstractNodeTest.php | 28 ++----
 .../FolderStructure/DirectoryNodeTest.php     | 70 +++++++------
 .../Unit/FolderStructure/FileNodeTest.php     | 97 ++++++++-----------
 .../Unit/FolderStructure/LinkNodeTest.php     |  2 +
 .../Tests/Unit/FolderStructureTestCase.php    | 48 +++++++++
 5 files changed, 134 insertions(+), 111 deletions(-)
 create mode 100644 typo3/sysext/install/Tests/Unit/FolderStructureTestCase.php

diff --git a/typo3/sysext/install/Tests/Unit/FolderStructure/AbstractNodeTest.php b/typo3/sysext/install/Tests/Unit/FolderStructure/AbstractNodeTest.php
index f670f1b5cf05..4ad8e562f65d 100644
--- a/typo3/sysext/install/Tests/Unit/FolderStructure/AbstractNodeTest.php
+++ b/typo3/sysext/install/Tests/Unit/FolderStructure/AbstractNodeTest.php
@@ -17,7 +17,7 @@ namespace TYPO3\CMS\Install\Tests\Unit\FolderStructure;
 /**
  * Test case
  */
-class AbstractNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
+class AbstractNodeTest extends \TYPO3\CMS\Install\Tests\Unit\FolderStructureTestCase
 {
     /**
      * @test
@@ -116,15 +116,14 @@ class AbstractNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\AbstractNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\AbstractNode::class, array('getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
-        \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($path);
-        $this->testFilesToDelete[] = $path;
+        $path = $this->getVirtualTestDir('dir_');
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $this->assertTrue($node->_call('exists'));
     }
 
     /**
      * @test
+     * @see https://github.com/mikey179/vfsStream/wiki/Known-Issues - symlink doesn't work with vfsStream
      */
     public function existsReturnsTrueIfIsLinkAndTargetIsDead()
     {
@@ -148,7 +147,7 @@ class AbstractNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\AbstractNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\AbstractNode::class, array('getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
+        $path = $this->getVirtualTestFilePath('dir_');
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $this->assertFalse($node->_call('exists'));
     }
@@ -193,12 +192,10 @@ class AbstractNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         );
         $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue(''));
         $node->expects($this->once())->method('isPermissionCorrect')->will($this->returnValue(false));
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('root_');
-        mkdir($path);
+        $path = $this->getVirtualTestDir('root_');
         $subPath = $path . '/' . $this->getUniqueId('dir_');
         mkdir($subPath);
         chmod($path, 02000);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($subPath));
         $node->_set('targetPermission', '2770');
         $this->assertInstanceOf(\TYPO3\CMS\Install\Status\NoticeStatus::class, $node->_call('fixPermission'));
@@ -226,12 +223,10 @@ class AbstractNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         );
         $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue(''));
         $node->expects($this->once())->method('isPermissionCorrect')->will($this->returnValue(false));
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('root_');
-        mkdir($path);
+        $path = $this->getVirtualTestDir('root_');
         $subPath = $path . '/' . $this->getUniqueId('dir_');
         mkdir($subPath);
         chmod($path, 02000);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($subPath));
         $node->_set('targetPermission', '2770');
         $this->assertInstanceOf(\TYPO3\CMS\Install\Status\NoticeStatus::class, $node->_call('fixPermission'));
@@ -256,12 +251,10 @@ class AbstractNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         );
         $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue(''));
         $node->expects($this->once())->method('isPermissionCorrect')->will($this->returnValue(false));
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('root_');
-        mkdir($path);
+        $path = $this->getVirtualTestDir('root_');
         $subPath = $path . '/' . $this->getUniqueId('dir_');
         mkdir($subPath);
         chmod($path, 02770);
-        $this->testFilesToDelete[] = $path;
         $node->_set('targetPermission', '2770');
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($subPath));
         $this->assertInstanceOf(\TYPO3\CMS\Install\Status\OkStatus::class, $node->_call('fixPermission'));
@@ -303,9 +296,7 @@ class AbstractNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         }
         /** @var $node \TYPO3\CMS\Install\FolderStructure\AbstractNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\AbstractNode::class, array('getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
-        \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($path);
-        $this->testFilesToDelete[] = $path;
+        $path = $this->getVirtualTestDir('dir_');
         chmod($path, 02775);
         clearstatcache();
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
@@ -322,9 +313,8 @@ class AbstractNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         }
         /** @var $node \TYPO3\CMS\Install\FolderStructure\AbstractNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\AbstractNode::class, array('getAbsolutePath'), array(), '', false);
-        $file = PATH_site . 'typo3temp/' . $this->getUniqueId('file_');
+        $file = $this->getVirtualTestFilePath('file_');
         touch($file);
-        $this->testFilesToDelete[] = $file;
         chmod($file, 0770);
         clearstatcache();
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($file));
diff --git a/typo3/sysext/install/Tests/Unit/FolderStructure/DirectoryNodeTest.php b/typo3/sysext/install/Tests/Unit/FolderStructure/DirectoryNodeTest.php
index 776a679a88e7..f1759b52cd1d 100644
--- a/typo3/sysext/install/Tests/Unit/FolderStructure/DirectoryNodeTest.php
+++ b/typo3/sysext/install/Tests/Unit/FolderStructure/DirectoryNodeTest.php
@@ -17,7 +17,7 @@ namespace TYPO3\CMS\Install\Tests\Unit\FolderStructure;
 /**
  * Test case
  */
-class DirectoryNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
+class DirectoryNodeTest extends \TYPO3\CMS\Install\Tests\Unit\FolderStructureTestCase
 {
     /**
      * @test
@@ -123,13 +123,14 @@ class DirectoryNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var $node \TYPO3\CMS\Install\FolderStructure\DirectoryNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(
             \TYPO3\CMS\Install\FolderStructure\DirectoryNode::class,
-            array('getAbsolutePath', 'exists', 'isDirectory', 'isWritable', 'isPermissionCorrect'),
+            array('getAbsolutePath', 'getRelativePathBelowSiteRoot', 'exists', 'isDirectory', 'isWritable', 'isPermissionCorrect'),
             array(),
             '',
             false
         );
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
+        $path = $this->getVirtualTestDir('dir_');
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $node->expects($this->any())->method('exists')->will($this->returnValue(true));
         $node->expects($this->any())->method('isDirectory')->will($this->returnValue(true));
         $node->expects($this->any())->method('isPermissionCorrect')->will($this->returnValue(true));
@@ -145,13 +146,14 @@ class DirectoryNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var $node \TYPO3\CMS\Install\FolderStructure\DirectoryNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(
             \TYPO3\CMS\Install\FolderStructure\DirectoryNode::class,
-            array('getAbsolutePath', 'exists', 'isDirectory', 'isWritable', 'isPermissionCorrect'),
+            array('getAbsolutePath', 'getRelativePathBelowSiteRoot', 'exists', 'isDirectory', 'isWritable', 'isPermissionCorrect'),
             array(),
             '',
             false
         );
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
+        $path = $this->getVirtualTestDir('dir_');
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $node->expects($this->any())->method('exists')->will($this->returnValue(false));
         $node->expects($this->any())->method('isDirectory')->will($this->returnValue(false));
         $node->expects($this->any())->method('isPermissionCorrect')->will($this->returnValue(false));
@@ -170,15 +172,15 @@ class DirectoryNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var $node \TYPO3\CMS\Install\FolderStructure\DirectoryNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(
             \TYPO3\CMS\Install\FolderStructure\DirectoryNode::class,
-            array('getAbsolutePath', 'exists', 'isDirectory', 'isWritable', 'isPermissionCorrect'),
+            array('getAbsolutePath', 'getRelativePathBelowSiteRoot', 'exists', 'isDirectory', 'isWritable', 'isPermissionCorrect'),
             array(),
             '',
             false
         );
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
+        $path = $this->getVirtualTestFilePath('dir_');
         touch($path);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $node->expects($this->any())->method('exists')->will($this->returnValue(true));
         $node->expects($this->any())->method('isDirectory')->will($this->returnValue(false));
         $node->expects($this->any())->method('isPermissionCorrect')->will($this->returnValue(true));
@@ -197,15 +199,15 @@ class DirectoryNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var $node \TYPO3\CMS\Install\FolderStructure\DirectoryNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(
             \TYPO3\CMS\Install\FolderStructure\DirectoryNode::class,
-            array('getAbsolutePath', 'exists', 'isDirectory', 'isWritable', 'isPermissionCorrect'),
+            array('getAbsolutePath', 'getRelativePathBelowSiteRoot', 'exists', 'isDirectory', 'isWritable', 'isPermissionCorrect'),
             array(),
             '',
             false
         );
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
+        $path = $this->getVirtualTestFilePath('dir_');
         touch($path);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $node->expects($this->any())->method('exists')->will($this->returnValue(true));
         $node->expects($this->any())->method('isDirectory')->will($this->returnValue(true));
         $node->expects($this->any())->method('isPermissionCorrect')->will($this->returnValue(true));
@@ -224,15 +226,15 @@ class DirectoryNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var $node \TYPO3\CMS\Install\FolderStructure\DirectoryNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(
             \TYPO3\CMS\Install\FolderStructure\DirectoryNode::class,
-            array('getAbsolutePath', 'exists', 'isDirectory', 'isWritable', 'isPermissionCorrect'),
+            array('getAbsolutePath', 'getRelativePathBelowSiteRoot', 'exists', 'isDirectory', 'isWritable', 'isPermissionCorrect'),
             array(),
             '',
             false
         );
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
+        $path = $this->getVirtualTestFilePath('dir_');
         touch($path);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $node->expects($this->any())->method('exists')->will($this->returnValue(true));
         $node->expects($this->any())->method('isDirectory')->will($this->returnValue(true));
         $node->expects($this->any())->method('isPermissionCorrect')->will($this->returnValue(false));
@@ -251,15 +253,15 @@ class DirectoryNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var $node \TYPO3\CMS\Install\FolderStructure\DirectoryNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(
             \TYPO3\CMS\Install\FolderStructure\DirectoryNode::class,
-            array('getAbsolutePath', 'exists', 'isDirectory', 'isWritable', 'isPermissionCorrect'),
+            array('getAbsolutePath', 'getRelativePathBelowSiteRoot', 'exists', 'isDirectory', 'isWritable', 'isPermissionCorrect'),
             array(),
             '',
             false
         );
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
+        $path = $this->getVirtualTestFilePath('dir_');
         touch($path);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $node->expects($this->any())->method('exists')->will($this->returnValue(true));
         $node->expects($this->any())->method('isDirectory')->will($this->returnValue(true));
         $node->expects($this->any())->method('isPermissionCorrect')->will($this->returnValue(true));
@@ -444,11 +446,11 @@ class DirectoryNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     public function createDirectoryCreatesDirectory()
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\DirectoryNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
-        $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\DirectoryNode::class, array('exists', 'getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
-        $this->testFilesToDelete[] = $path;
+        $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\DirectoryNode::class, array('exists', 'getAbsolutePath', 'getRelativePathBelowSiteRoot'), array(), '', false);
+        $path = $this->getVirtualTestFilePath('dir_');
         $node->expects($this->once())->method('exists')->will($this->returnValue(false));
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $node->_call('createDirectory');
         $this->assertTrue(is_dir($path));
     }
@@ -459,11 +461,11 @@ class DirectoryNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     public function createDirectoryReturnsOkStatusIfDirectoryWasCreated()
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\DirectoryNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
-        $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\DirectoryNode::class, array('exists', 'getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
-        $this->testFilesToDelete[] = $path;
+        $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\DirectoryNode::class, array('exists', 'getAbsolutePath', 'getRelativePathBelowSiteRoot'), array(), '', false);
+        $path = $this->getVirtualTestFilePath('dir_');
         $node->expects($this->once())->method('exists')->will($this->returnValue(false));
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $this->assertInstanceOf(\TYPO3\CMS\Install\Status\StatusInterface::class, $node->_call('createDirectory'));
     }
 
@@ -476,14 +478,13 @@ class DirectoryNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
             $this->markTestSkipped('Test not available on Windows OS.');
         }
         /** @var $node \TYPO3\CMS\Install\FolderStructure\DirectoryNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
-        $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\DirectoryNode::class, array('exists', 'getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('root_');
-        mkdir($path);
+        $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\DirectoryNode::class, array('exists', 'getAbsolutePath', 'getRelativePathBelowSiteRoot'), array(), '', false);
+        $path = $this->getVirtualTestDir('root_');
         chmod($path, 02550);
         $subPath = $path . '/' . $this->getUniqueId('dir_');
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->once())->method('exists')->will($this->returnValue(false));
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($subPath));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($subPath));
         $this->assertInstanceOf(\TYPO3\CMS\Install\Status\StatusInterface::class, $node->_call('createDirectory'));
     }
 
@@ -574,7 +575,7 @@ class DirectoryNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\DirectoryNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\DirectoryNode::class, array('getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
+        $path = $this->getVirtualTestFilePath('dir_');
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $this->assertFalse($node->isWritable());
     }
@@ -586,9 +587,7 @@ class DirectoryNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\DirectoryNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\DirectoryNode::class, array('getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('root_');
-        \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($path);
-        $this->testFilesToDelete[] = $path;
+        $path = $this->getVirtualTestDir('root_');
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $this->assertTrue($node->isWritable());
     }
@@ -606,9 +605,7 @@ class DirectoryNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         }
         /** @var $node \TYPO3\CMS\Install\FolderStructure\DirectoryNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\DirectoryNode::class, array('getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('root_');
-        \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($path);
-        $this->testFilesToDelete[] = $path;
+        $path = $this->getVirtualTestDir('root_');
         chmod($path, 02550);
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $this->assertFalse($node->isWritable());
@@ -621,15 +618,14 @@ class DirectoryNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\DirectoryNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\DirectoryNode::class, array('getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
-        \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($path);
-        $this->testFilesToDelete[] = $path;
+        $path = $this->getVirtualTestDir('dir_');
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $this->assertTrue($node->_call('isDirectory'));
     }
 
     /**
      * @test
+     * @see https://github.com/mikey179/vfsStream/wiki/Known-Issues - symlink doesn't work with vfsStream
      */
     public function isDirectoryReturnsFalseIfNameIsALinkToADirectory()
     {
diff --git a/typo3/sysext/install/Tests/Unit/FolderStructure/FileNodeTest.php b/typo3/sysext/install/Tests/Unit/FolderStructure/FileNodeTest.php
index 410659e29cbc..bf4e74c11a0b 100644
--- a/typo3/sysext/install/Tests/Unit/FolderStructure/FileNodeTest.php
+++ b/typo3/sysext/install/Tests/Unit/FolderStructure/FileNodeTest.php
@@ -17,7 +17,7 @@ namespace TYPO3\CMS\Install\Tests\Unit\FolderStructure;
 /**
  * Test case
  */
-class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
+class FileNodeTest extends \TYPO3\CMS\Install\Tests\Unit\FolderStructureTestCase
 {
     /**
      * @test
@@ -132,10 +132,9 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('dummy'), array(), '', false);
         $parent = $this->getMock(\TYPO3\CMS\Install\FolderStructure\RootNodeInterface::class, array(), array(), '', false);
-        $targetFile = PATH_site . 'typo3temp/' . $this->getUniqueId('test_');
+        $targetFile = $this->getVirtualTestFilePath('test_');
         $targetContent = $this->getUniqueId('content_');
         file_put_contents($targetFile, $targetContent);
-        $this->testFilesToDelete[] = $targetFile;
         $structure = array(
             'name' => 'foo',
             'targetContentFile' => $targetFile,
@@ -153,7 +152,7 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('dummy'), array(), '', false);
         $parent = $this->getMock(\TYPO3\CMS\Install\FolderStructure\RootNodeInterface::class, array(), array(), '', false);
-        $targetFile = PATH_site . 'typo3temp/' . $this->getUniqueId('test_');
+        $targetFile = $this->getVirtualTestFilePath('test_');
         $structure = array(
             'name' => 'foo',
             'targetContentFile' => $targetFile,
@@ -207,13 +206,14 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(
             \TYPO3\CMS\Install\FolderStructure\FileNode::class,
-            array('getAbsolutePath', 'exists', 'isFile', 'isWritable', 'isPermissionCorrect', 'isContentCorrect'),
+            array('getAbsolutePath', 'getRelativePathBelowSiteRoot', 'exists', 'isFile', 'isWritable', 'isPermissionCorrect', 'isContentCorrect'),
             array(),
             '',
             false
         );
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
+        $path = $this->getVirtualTestDir('dir_');
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $node->expects($this->any())->method('exists')->will($this->returnValue(false));
         $node->expects($this->any())->method('isFile')->will($this->returnValue(true));
         $node->expects($this->any())->method('isPermissionCorrect')->will($this->returnValue(true));
@@ -233,15 +233,15 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(
             \TYPO3\CMS\Install\FolderStructure\FileNode::class,
-            array('getAbsolutePath', 'exists', 'isFile', 'isWritable', 'isPermissionCorrect', 'isContentCorrect'),
+            array('getAbsolutePath', 'getRelativePathBelowSiteRoot', 'exists', 'isFile', 'isWritable', 'isPermissionCorrect', 'isContentCorrect'),
             array(),
             '',
             false
         );
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
+        $path = $this->getVirtualTestFilePath('dir_');
         touch($path);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $node->expects($this->any())->method('exists')->will($this->returnValue(true));
         $node->expects($this->any())->method('isFile')->will($this->returnValue(false));
         $node->expects($this->any())->method('isPermissionCorrect')->will($this->returnValue(true));
@@ -261,15 +261,15 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(
             \TYPO3\CMS\Install\FolderStructure\FileNode::class,
-            array('getAbsolutePath', 'exists', 'isFile', 'isWritable', 'isPermissionCorrect', 'isContentCorrect'),
+            array('getAbsolutePath', 'getRelativePathBelowSiteRoot', 'exists', 'isFile', 'isWritable', 'isPermissionCorrect', 'isContentCorrect'),
             array(),
             '',
             false
         );
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
+        $path = $this->getVirtualTestFilePath('dir_');
         touch($path);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $node->expects($this->any())->method('exists')->will($this->returnValue(true));
         $node->expects($this->any())->method('isFile')->will($this->returnValue(true));
         $node->expects($this->any())->method('isPermissionCorrect')->will($this->returnValue(true));
@@ -289,15 +289,15 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(
             \TYPO3\CMS\Install\FolderStructure\FileNode::class,
-            array('getAbsolutePath', 'exists', 'isFile', 'isWritable', 'isPermissionCorrect', 'isContentCorrect'),
+            array('getAbsolutePath', 'getRelativePathBelowSiteRoot', 'exists', 'isFile', 'isWritable', 'isPermissionCorrect', 'isContentCorrect'),
             array(),
             '',
             false
         );
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
+        $path = $this->getVirtualTestFilePath('dir_');
         touch($path);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $node->expects($this->any())->method('exists')->will($this->returnValue(true));
         $node->expects($this->any())->method('isFile')->will($this->returnValue(true));
         $node->expects($this->any())->method('isPermissionCorrect')->will($this->returnValue(false));
@@ -317,15 +317,15 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(
             \TYPO3\CMS\Install\FolderStructure\FileNode::class,
-            array('getAbsolutePath', 'exists', 'isFile', 'isWritable', 'isPermissionCorrect', 'isContentCorrect'),
+            array('getAbsolutePath', 'getRelativePathBelowSiteRoot', 'exists', 'isFile', 'isWritable', 'isPermissionCorrect', 'isContentCorrect'),
             array(),
             '',
             false
         );
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
+        $path = $this->getVirtualTestFilePath('dir_');
         touch($path);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $node->expects($this->any())->method('exists')->will($this->returnValue(true));
         $node->expects($this->any())->method('isFile')->will($this->returnValue(true));
         $node->expects($this->any())->method('isPermissionCorrect')->will($this->returnValue(true));
@@ -345,15 +345,15 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(
             \TYPO3\CMS\Install\FolderStructure\FileNode::class,
-            array('getAbsolutePath', 'exists', 'isFile', 'isWritable', 'isPermissionCorrect', 'isContentCorrect'),
+            array('getAbsolutePath', 'getRelativePathBelowSiteRoot', 'exists', 'isFile', 'isWritable', 'isPermissionCorrect', 'isContentCorrect'),
             array(),
             '',
             false
         );
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
+        $path = $this->getVirtualTestFilePath('dir_');
         touch($path);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $node->expects($this->any())->method('exists')->will($this->returnValue(true));
         $node->expects($this->any())->method('isFile')->will($this->returnValue(true));
         $node->expects($this->any())->method('isPermissionCorrect')->will($this->returnValue(true));
@@ -556,11 +556,11 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     public function createFileReturnsOkStatusIfFileWasCreated()
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
-        $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('exists', 'getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('file_');
-        $this->testFilesToDelete[] = $path;
+        $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('exists', 'getAbsolutePath', 'getRelativePathBelowSiteRoot'), array(), '', false);
+        $path = $this->getVirtualTestFilePath('file_');
         $node->expects($this->once())->method('exists')->will($this->returnValue(false));
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $this->assertInstanceOf(\TYPO3\CMS\Install\Status\StatusInterface::class, $node->_call('createFile'));
     }
 
@@ -570,11 +570,11 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     public function createFileCreatesFile()
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
-        $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('exists', 'getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('file_');
-        $this->testFilesToDelete[] = $path;
+        $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('exists', 'getAbsolutePath', 'getRelativePathBelowSiteRoot'), array(), '', false);
+        $path = $this->getVirtualTestFilePath('file_');
         $node->expects($this->once())->method('exists')->will($this->returnValue(false));
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($path));
         $node->_call('createFile');
         $this->assertTrue(is_file($path));
     }
@@ -588,14 +588,13 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
             $this->markTestSkipped('Test not available on Windows OS.');
         }
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
-        $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('exists', 'getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('root_');
-        mkdir($path);
+        $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('exists', 'getAbsolutePath', 'getRelativePathBelowSiteRoot'), array(), '', false);
+        $path = $this->getVirtualTestDir();
         chmod($path, 02550);
         $subPath = $path . '/' . $this->getUniqueId('file_');
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->once())->method('exists')->will($this->returnValue(false));
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($subPath));
+        $node->expects($this->any())->method('getRelativePathBelowSiteRoot')->will($this->returnValue($subPath));
         $this->assertInstanceOf(\TYPO3\CMS\Install\Status\StatusInterface::class, $node->_call('createFile'));
     }
 
@@ -607,9 +606,7 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
-        mkdir($path);
-        $this->testFilesToDelete[] = $path;
+        $path = $this->getVirtualTestDir('dir_');
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $node->_call('isContentCorrect');
     }
@@ -621,9 +618,8 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('file_');
+        $path = $this->getVirtualTestFilePath('file_');
         touch($path);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $node->_set('targetContent', null);
         $this->assertTrue($node->_call('isContentCorrect'));
@@ -636,10 +632,9 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('file_');
+        $path = $this->getVirtualTestFilePath('file_');
         $content = $this->getUniqueId('content_');
         file_put_contents($path, $content);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $node->_set('targetContent', $content);
         $this->assertTrue($node->_call('isContentCorrect'));
@@ -652,11 +647,10 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('file_');
+        $path = $this->getVirtualTestFilePath('file_');
         $content = $this->getUniqueId('content1_');
         $targetContent = $this->getUniqueId('content2_');
         file_put_contents($path, $content);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $node->_set('targetContent', $targetContent);
         $this->assertFalse($node->_call('isContentCorrect'));
@@ -689,9 +683,7 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
-        mkdir($path);
-        $this->testFilesToDelete[] = $path;
+        $path = $this->getVirtualTestDir('dir_');
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $node->_set('targetContent', 'foo');
         $node->_call('setContent');
@@ -705,9 +697,8 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('file_');
+        $path = $this->getVirtualTestFilePath('file_');
         touch($path);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $node->_set('targetContent', null);
         $node->_call('setContent');
@@ -720,9 +711,8 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('getAbsolutePath', 'getRelativePathBelowSiteRoot'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('file_');
+        $path = $this->getVirtualTestFilePath('file_');
         touch($path);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $targetContent = $this->getUniqueId('content_');
         $node->_set('targetContent', $targetContent);
@@ -738,9 +728,8 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('getAbsolutePath', 'getRelativePathBelowSiteRoot'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('file_');
+        $path = $this->getVirtualTestFilePath('file_');
         touch($path);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $targetContent = $this->getUniqueId('content_');
         $node->_set('targetContent', $targetContent);
@@ -760,12 +749,10 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         }
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
         $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('getAbsolutePath', 'getRelativePathBelowSiteRoot'), array(), '', false);
-        $dir = PATH_site . 'typo3temp/' . $this->getUniqueId('dir_');
-        mkdir($dir);
+        $dir = $this->getVirtualTestDir('dir_');
         $file = $dir . '/' . $this->getUniqueId('file_');
         touch($file);
         chmod($file, 0440);
-        $this->testFilesToDelete[] = $dir;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($file));
         $targetContent = $this->getUniqueId('content_');
         $node->_set('targetContent', $targetContent);
@@ -778,16 +765,16 @@ class FileNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     public function isFileReturnsTrueIfNameIsFile()
     {
         /** @var $node \TYPO3\CMS\Install\FolderStructure\FileNode|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
-        $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('getAbsolutePath'), array(), '', false);
-        $path = PATH_site . 'typo3temp/' . $this->getUniqueId('file_');
+        $node = $this->getAccessibleMock(\TYPO3\CMS\Install\FolderStructure\FileNode::class, array('getAbsolutePath', 'getRelativePathBelowSiteRoot'), array(), '', false);
+        $path = $this->getVirtualTestFilePath('file_');
         touch($path);
-        $this->testFilesToDelete[] = $path;
         $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
         $this->assertTrue($node->_call('isFile'));
     }
 
     /**
      * @test
+     * @see https://github.com/mikey179/vfsStream/wiki/Known-Issues - symlink doesn't work with vfsStream
      */
     public function isFileReturnsFalseIfNameIsALinkFile()
     {
diff --git a/typo3/sysext/install/Tests/Unit/FolderStructure/LinkNodeTest.php b/typo3/sysext/install/Tests/Unit/FolderStructure/LinkNodeTest.php
index 411946ccc46b..aef9d8212963 100644
--- a/typo3/sysext/install/Tests/Unit/FolderStructure/LinkNodeTest.php
+++ b/typo3/sysext/install/Tests/Unit/FolderStructure/LinkNodeTest.php
@@ -338,6 +338,7 @@ class LinkNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
 
     /**
      * @test
+     * @see https://github.com/mikey179/vfsStream/wiki/Known-Issues - symlink doesn't work with vfsStream
      */
     public function isTargetCorrectReturnsTrueIfActualTargetIsIdenticalToSpecifiedTarget()
     {
@@ -364,6 +365,7 @@ class LinkNodeTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
 
     /**
      * @test
+     * @see https://github.com/mikey179/vfsStream/wiki/Known-Issues - symlink doesn't work with vfsStream
      */
     public function isTargetCorrectReturnsFalseIfActualTargetIsNotIdenticalToSpecifiedTarget()
     {
diff --git a/typo3/sysext/install/Tests/Unit/FolderStructureTestCase.php b/typo3/sysext/install/Tests/Unit/FolderStructureTestCase.php
new file mode 100644
index 000000000000..7c5e3a2de4ab
--- /dev/null
+++ b/typo3/sysext/install/Tests/Unit/FolderStructureTestCase.php
@@ -0,0 +1,48 @@
+<?php
+namespace TYPO3\CMS\Install\Tests\Unit;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use org\bovigo\vfs\vfsStream;
+
+/**
+ * Test case
+ */
+abstract class FolderStructureTestCase extends \TYPO3\CMS\Core\Tests\UnitTestCase
+{
+    /**
+     * Create a random directory in the virtual file system and return the path.
+     *
+     * @param string $prefix
+     * @return string
+     */
+    protected function getVirtualTestDir($prefix = 'root_')
+    {
+        $root = vfsStream::setup();
+        $path = $root->url() . '/typo3temp/' . $this->getUniqueId($prefix);
+        \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($path);
+        return $path;
+    }
+
+    /**
+     * Return a random test filename within a virtual test directory
+     *
+     * @param string $prefix
+     * @return string
+     */
+    protected function getVirtualTestFilePath($prefix = 'file_')
+    {
+        return $this->getVirtualTestDir() . '/' . $this->getUniqueId($prefix);
+    }
+}
-- 
GitLab