mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-22 06:30:59 +01:00
Api: Some tests for filesystem
This commit is contained in:
parent
2ef359f0d0
commit
94a57d6902
@ -1867,6 +1867,10 @@ GROUP BY A.fs_id';
|
|||||||
$ins_stmt = $del_stmt = null;
|
$ins_stmt = $del_stmt = null;
|
||||||
foreach($props as &$prop)
|
foreach($props as &$prop)
|
||||||
{
|
{
|
||||||
|
if(!array_key_exists('name', $prop))
|
||||||
|
{
|
||||||
|
return false; // Name is missing
|
||||||
|
}
|
||||||
if (!isset($prop['ns'])) $prop['ns'] = Vfs::DEFAULT_PROP_NAMESPACE;
|
if (!isset($prop['ns'])) $prop['ns'] = Vfs::DEFAULT_PROP_NAMESPACE;
|
||||||
|
|
||||||
if (!isset($prop['val']) || self::$pdo_type != 'mysql') // for non mysql, we have to delete the prop anyway, as there's no REPLACE!
|
if (!isset($prop['val']) || self::$pdo_type != 'mysql') // for non mysql, we have to delete the prop anyway, as there's no REPLACE!
|
||||||
|
116
api/tests/Vfs/ProppatchTest.php
Normal file
116
api/tests/Vfs/ProppatchTest.php
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test file properties (proppatch)
|
||||||
|
*
|
||||||
|
* @link http://www.egroupware.org
|
||||||
|
* @author Nathan Gray
|
||||||
|
* @copyright (c) 2020 Nathan Gray
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace EGroupware\Api\Vfs;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/StreamWrapperBase.php';
|
||||||
|
|
||||||
|
use EGroupware\Api;
|
||||||
|
use EGroupware\Api\LoggedInTest as LoggedInTest;
|
||||||
|
use EGroupware\Api\Vfs;
|
||||||
|
use EGroupware\Stylite\Vfs\Versioning;
|
||||||
|
|
||||||
|
|
||||||
|
class ProppatchTest extends StreamWrapperBase
|
||||||
|
{
|
||||||
|
protected function setUp() : void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown() : void
|
||||||
|
{
|
||||||
|
// Do local stuff first, parent will remove stuff
|
||||||
|
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check read / write / delete proppatch
|
||||||
|
*/
|
||||||
|
public function testProppatch()
|
||||||
|
{
|
||||||
|
$this->files[] = $test_file = $this->getFilename();
|
||||||
|
$contents = $this->getName() . "\nJust a test ;)\n";
|
||||||
|
$this->assertNotFalse(
|
||||||
|
file_put_contents(Vfs::PREFIX . $test_file, $contents),
|
||||||
|
"Could not write test file $test_file"
|
||||||
|
);
|
||||||
|
|
||||||
|
$proppatch = [['ns' => Vfs::DEFAULT_PROP_NAMESPACE, 'name' => 'test', 'val' => 'something']];
|
||||||
|
$this->assertTrue(
|
||||||
|
Vfs::proppatch($test_file, $proppatch),
|
||||||
|
"Could not set properties"
|
||||||
|
);
|
||||||
|
$read = Vfs::propfind($test_file);
|
||||||
|
|
||||||
|
$this->assertEquals($proppatch, $read,
|
||||||
|
"Read proppatch does not match what was written"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Try to delete, while we're here
|
||||||
|
$proppatch[0]['val'] = null;
|
||||||
|
$this->assertTrue(
|
||||||
|
Vfs::proppatch($test_file, $proppatch),
|
||||||
|
"Could not delete properties by setting val = null"
|
||||||
|
);
|
||||||
|
$read_deleted = Vfs::propfind($test_file);
|
||||||
|
$this->assertNotFalse($read_deleted, "Problem reading properties after deleting");
|
||||||
|
$this->assertEquals([], $read_deleted, "Found properties after deleting");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that an invalid proppatch is not accepted
|
||||||
|
*/
|
||||||
|
public function testInvalidProppatch()
|
||||||
|
{
|
||||||
|
$this->files[] = $test_file = $this->getFilename();
|
||||||
|
$contents = $this->getName() . "\nJust a test ;)\n";
|
||||||
|
$this->assertNotFalse(
|
||||||
|
file_put_contents(Vfs::PREFIX . $test_file, $contents),
|
||||||
|
"Could not write test file $test_file"
|
||||||
|
);
|
||||||
|
|
||||||
|
$proppatch = [['No worky']];
|
||||||
|
$this->assertFalse(
|
||||||
|
Vfs::proppatch($test_file, $proppatch),
|
||||||
|
"Managed to set invalid properties"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWriteWithNoPermissionsFails()
|
||||||
|
{
|
||||||
|
$this->files[] = $test_file = $this->getFilename();
|
||||||
|
Vfs::remove($test_file);
|
||||||
|
$contents = $this->getName() . "\nJust a test ;)\n";
|
||||||
|
$this->assertNotFalse(
|
||||||
|
file_put_contents(Vfs::PREFIX . $test_file, $contents),
|
||||||
|
"Could not write test file $test_file"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Change owner so we lose permission
|
||||||
|
Vfs::$is_root = true;
|
||||||
|
$this->assertTrue(
|
||||||
|
Vfs::chown($test_file, 'anonymous'),
|
||||||
|
"Could not chown test file '$test_file'"
|
||||||
|
);
|
||||||
|
Vfs::$is_root = false;
|
||||||
|
|
||||||
|
// Try to set property
|
||||||
|
$proppatch = [['ns' => Vfs::DEFAULT_PROP_NAMESPACE, 'name' => 'test', 'val' => 'something']];
|
||||||
|
$this->assertFalse(
|
||||||
|
Vfs::proppatch($test_file, $proppatch),
|
||||||
|
"Managed to set properties with no permission"
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
284
api/tests/Vfs/StreamWrapperBase.php
Normal file
284
api/tests/Vfs/StreamWrapperBase.php
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base for testing various stream wrappers
|
||||||
|
*
|
||||||
|
* This holds some common things so we can re-use them for the various places
|
||||||
|
*
|
||||||
|
* @link http://www.egroupware.org
|
||||||
|
* @author Nathan Gray
|
||||||
|
* @copyright (c) 2020 Nathan Gray
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace EGroupware\Api\Vfs;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../LoggedInTest.php';
|
||||||
|
|
||||||
|
use EGroupware\Api;
|
||||||
|
use EGroupware\Api\LoggedInTest as LoggedInTest;
|
||||||
|
use EGroupware\Api\Vfs;
|
||||||
|
use EGroupware\Stylite\Vfs\Versioning;
|
||||||
|
|
||||||
|
|
||||||
|
class StreamWrapperBase extends LoggedInTest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* How much should be logged to the console (stdout)
|
||||||
|
*
|
||||||
|
* 0 = Nothing
|
||||||
|
* 1 = info
|
||||||
|
* 2 = debug
|
||||||
|
*/
|
||||||
|
const LOG_LEVEL = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep track of files to remove after
|
||||||
|
* @var Array
|
||||||
|
*/
|
||||||
|
protected $files = Array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep track of mounts to remove after
|
||||||
|
*/
|
||||||
|
protected $mounts = Array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options for searching the Vfs (Vfs::find())
|
||||||
|
*/
|
||||||
|
const VFS_OPTIONS = array(
|
||||||
|
'maxdepth' => 5
|
||||||
|
);
|
||||||
|
|
||||||
|
protected function setUp() : void
|
||||||
|
{
|
||||||
|
// Check we have basic access
|
||||||
|
if(!is_readable($GLOBALS['egw_info']['server']['files_dir']))
|
||||||
|
{
|
||||||
|
$this->markTestSkipped('No read access to files dir "' .$GLOBALS['egw_info']['server']['files_dir'].'"' );
|
||||||
|
}
|
||||||
|
if(!is_writable($GLOBALS['egw_info']['server']['files_dir']))
|
||||||
|
{
|
||||||
|
$this->markTestSkipped('No write access to files dir "' .$GLOBALS['egw_info']['server']['files_dir'].'"' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown() : void
|
||||||
|
{
|
||||||
|
LoggedInTest::tearDownAfterClass();
|
||||||
|
LoggedInTest::setupBeforeClass();
|
||||||
|
|
||||||
|
// Re-init, since they look at user, fstab, etc.
|
||||||
|
// Also, further tests that access the filesystem fail if we don't
|
||||||
|
Vfs::clearstatcache();
|
||||||
|
Vfs::init_static();
|
||||||
|
Vfs\StreamWrapper::init_static();
|
||||||
|
|
||||||
|
// Need to ask about mounts, or other tests fail
|
||||||
|
Vfs::mount();
|
||||||
|
|
||||||
|
$backup = Vfs::$is_root;
|
||||||
|
Vfs::$is_root = true;
|
||||||
|
|
||||||
|
if(static::LOG_LEVEL > 1)
|
||||||
|
{
|
||||||
|
error_log($this->getName() . ' files for removal:');
|
||||||
|
error_log(implode("\n",$this->files));
|
||||||
|
error_log($this->getName() . ' mounts for removal:');
|
||||||
|
error_log(implode("\n",$this->mounts));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any added files (as root to limit versioning issues)
|
||||||
|
if(in_array('/',$this->files))
|
||||||
|
{
|
||||||
|
$this->fail('Tried to remove root');
|
||||||
|
}
|
||||||
|
foreach($this->files as $file)
|
||||||
|
{
|
||||||
|
Vfs::unlink($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any mounts
|
||||||
|
foreach($this->mounts as $mount)
|
||||||
|
{
|
||||||
|
Vfs::umount($mount);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vfs::$is_root = $backup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a filename that reflects the current test
|
||||||
|
*/
|
||||||
|
protected function getFilename($path = null)
|
||||||
|
{
|
||||||
|
if(is_null($path)) $path = Vfs::get_home_dir().'/';
|
||||||
|
if(substr($path,-1,1) !== '/') $path = $path . '/';
|
||||||
|
|
||||||
|
return $path . get_class(this) . '_' . $this->getName() . '.txt';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start versioning for the given path
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
*/
|
||||||
|
protected function mountVersioned($path)
|
||||||
|
{
|
||||||
|
if (!class_exists('EGroupware\Stylite\Vfs\Versioning\StreamWrapper'))
|
||||||
|
{
|
||||||
|
$this->markTestSkipped("No versioning available");
|
||||||
|
}
|
||||||
|
if(substr($path, -1) == '/') $path = substr($path, 0, -1);
|
||||||
|
$backup = Vfs::$is_root;
|
||||||
|
Vfs::$is_root = true;
|
||||||
|
$url = Versioning\StreamWrapper::PREFIX.$path;
|
||||||
|
$this->assertTrue(Vfs::mount($url,$path), "Unable to mount $path as versioned");
|
||||||
|
Vfs::$is_root = $backup;
|
||||||
|
|
||||||
|
$this->mounts[] = $path;
|
||||||
|
Vfs::clearstatcache();
|
||||||
|
Vfs::init_static();
|
||||||
|
Vfs\StreamWrapper::init_static();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mount a test filesystem path (api/tests/fixtures/Vfs/filesystem_mount)
|
||||||
|
* at the given VFS path
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
*/
|
||||||
|
protected function mountFilesystem($path)
|
||||||
|
{
|
||||||
|
// Vfs breaks if path has trailing /
|
||||||
|
if(substr($path, -1) == '/') $path = substr($path, 0, -1);
|
||||||
|
|
||||||
|
$backup = Vfs::$is_root;
|
||||||
|
Vfs::$is_root = true;
|
||||||
|
$fs_path = realpath(__DIR__ . '/../fixtures/Vfs/filesystem_mount');
|
||||||
|
if(!file_exists($fs_path))
|
||||||
|
{
|
||||||
|
$this->fail("Missing filesystem test directory 'api/tests/fixtures/Vfs/filesystem_mount'");
|
||||||
|
}
|
||||||
|
$url = Filesystem\StreamWrapper::SCHEME.'://default'. $fs_path.
|
||||||
|
'?user='.$GLOBALS['egw_info']['user']['account_id'].'&group=Default&mode=775';
|
||||||
|
$this->assertTrue(Vfs::mount($url,$path), "Unable to mount $url to $path");
|
||||||
|
Vfs::$is_root = $backup;
|
||||||
|
|
||||||
|
$this->mounts[] = $path;
|
||||||
|
Vfs::clearstatcache();
|
||||||
|
Vfs::init_static();
|
||||||
|
Vfs\StreamWrapper::init_static();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge a test filesystem path (api/tests/fixtures/Vfs/filesystem_mount)
|
||||||
|
* with the given VFS path
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
*/
|
||||||
|
protected function mountMerge($path)
|
||||||
|
{
|
||||||
|
// Vfs breaks if path has trailing /
|
||||||
|
if(substr($path, -1) == '/') $path = substr($path, 0, -1);
|
||||||
|
|
||||||
|
|
||||||
|
$backup = Vfs::$is_root;
|
||||||
|
Vfs::$is_root = true;
|
||||||
|
|
||||||
|
// I guess merge needs the dir in SQLFS first
|
||||||
|
if(!Vfs::is_dir($dir)) Vfs::mkdir($path);
|
||||||
|
Vfs::chmod($path, 0750);
|
||||||
|
Vfs::chown($path, $GLOBALS['egw_info']['user']['account_id']);
|
||||||
|
|
||||||
|
$url = \EGroupware\Stylite\Vfs\Merge\StreamWrapper::SCHEME.'://default'.$path.'?merge=' . realpath(__DIR__ . '/../fixtures/Vfs/filesystem_mount');
|
||||||
|
$this->assertTrue(Vfs::mount($url,$path), "Unable to mount $url to $path");
|
||||||
|
Vfs::$is_root = $backup;
|
||||||
|
|
||||||
|
$this->mounts[] = $path;
|
||||||
|
Vfs::clearstatcache();
|
||||||
|
Vfs::init_static();
|
||||||
|
Vfs\StreamWrapper::init_static();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add some files to the given path so there's something to find.
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
*
|
||||||
|
* @return array of paths
|
||||||
|
*/
|
||||||
|
protected function addFiles($path, $content = false)
|
||||||
|
{
|
||||||
|
if(substr($path, -1) != '/')
|
||||||
|
{
|
||||||
|
$path .= '/';
|
||||||
|
}
|
||||||
|
if(!$content)
|
||||||
|
{
|
||||||
|
$content = 'Test for ' . $this->getName() ."\n". Api\DateTime::to();
|
||||||
|
}
|
||||||
|
$files = array();
|
||||||
|
|
||||||
|
// Plain file
|
||||||
|
$files[] = $file = $path.'test_file.txt';
|
||||||
|
$this->assertTrue(
|
||||||
|
file_put_contents(Vfs::PREFIX.$file, $content) !== FALSE,
|
||||||
|
'Unable to write test file "' . Vfs::PREFIX . $file .'" - check file permissions for CLI user'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Subdirectory
|
||||||
|
$files[] = $dir = $path.'sub_dir/';
|
||||||
|
if(Vfs::is_dir($dir))
|
||||||
|
{
|
||||||
|
Vfs::remove($dir);
|
||||||
|
}
|
||||||
|
$this->assertTrue(
|
||||||
|
Vfs::mkdir($dir),
|
||||||
|
'Unable to create subdirectory ' . $dir
|
||||||
|
);
|
||||||
|
|
||||||
|
// File in a subdirectory
|
||||||
|
$files[] = $file = $dir.'subdir_test_file.txt';
|
||||||
|
$this->assertTrue(
|
||||||
|
file_put_contents(Vfs::PREFIX.$file, $content) !== FALSE,
|
||||||
|
'Unable to write test file "' . Vfs::PREFIX . $file .'" - check file permissions for CLI user'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Symlinked file
|
||||||
|
/* We don't test these because they don't work - the target will always
|
||||||
|
* be outside the share root
|
||||||
|
// Always says its empty
|
||||||
|
$files[] = $symlink = $path.'symlink.txt';
|
||||||
|
if(Vfs::file_exists($symlink)) Vfs::remove($symlink);
|
||||||
|
$this->assertTrue(
|
||||||
|
Vfs::symlink($file, $symlink),
|
||||||
|
"Unable to create symlink $symlink => $file"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Symlinked dir
|
||||||
|
$files[] = $symlinked_dir = $path.'sym_dir/';
|
||||||
|
$this->assertTrue(
|
||||||
|
Vfs::symlink($dir, $symlinked_dir),
|
||||||
|
'Unable to create symlinked directory ' . $symlinked_dir
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make an infolog entry
|
||||||
|
*/
|
||||||
|
protected function make_infolog()
|
||||||
|
{
|
||||||
|
$bo = new \infolog_bo();
|
||||||
|
$element = array(
|
||||||
|
'info_subject' => "Test infolog for #{$this->getName()}",
|
||||||
|
'info_des' => 'Test element for ' . $this->getName() . "\n" . Api\DateTime::to(),
|
||||||
|
'info_status' => 'open'
|
||||||
|
);
|
||||||
|
|
||||||
|
$element_id = $bo->write($element, true, true, true, true);
|
||||||
|
return $element_id;
|
||||||
|
}
|
||||||
|
}
|
89
api/tests/Vfs/StreamWrapperTest.php
Normal file
89
api/tests/Vfs/StreamWrapperTest.php
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the basic Vfs::StreamWrapper
|
||||||
|
*
|
||||||
|
* @link http://www.egroupware.org
|
||||||
|
* @author Nathan Gray
|
||||||
|
* @copyright (c) 2020 Nathan Gray
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace EGroupware\Api\Vfs;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/StreamWrapperBase.php';
|
||||||
|
|
||||||
|
use EGroupware\Api;
|
||||||
|
use EGroupware\Api\LoggedInTest as LoggedInTest;
|
||||||
|
use EGroupware\Api\Vfs;
|
||||||
|
use EGroupware\Stylite\Vfs\Versioning;
|
||||||
|
|
||||||
|
|
||||||
|
class StreamWrapperTest extends StreamWrapperBase
|
||||||
|
{
|
||||||
|
protected function setUp() : void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown() : void
|
||||||
|
{
|
||||||
|
// Do local stuff first, parent will remove stuff
|
||||||
|
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple test that we can write something and it's there
|
||||||
|
*/
|
||||||
|
public function testSimpleReadWrite() : void
|
||||||
|
{
|
||||||
|
$this->files[] = $test_file = $this->getFilename();
|
||||||
|
$contents = $this->getName() . "\nJust a test ;)\n";
|
||||||
|
$this->assertNotFalse(
|
||||||
|
file_put_contents(Vfs::PREFIX . $test_file, $contents),
|
||||||
|
"Could not write file $test_file"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check contents are unchanged
|
||||||
|
$this->assertEquals(
|
||||||
|
$contents, file_get_contents(Vfs::PREFIX . $test_file),
|
||||||
|
"Read file contents do not match what was written"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple delete of a file
|
||||||
|
*/
|
||||||
|
public function testDelete() : void
|
||||||
|
{
|
||||||
|
$this->files[] = $test_file = $this->getFilename();
|
||||||
|
|
||||||
|
// Check that the file is not there
|
||||||
|
$pre_start = Vfs::stat($test_file);
|
||||||
|
$this->assertEquals(null,$pre_start,
|
||||||
|
"File '$test_file' was there before we started, check clean up"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Write
|
||||||
|
$contents = $this->getName() . "\nJust a test ;)\n";
|
||||||
|
$this->assertNotFalse(
|
||||||
|
file_put_contents(Vfs::PREFIX . $test_file, $contents),
|
||||||
|
"Could not write file $test_file"
|
||||||
|
);
|
||||||
|
|
||||||
|
$start = Vfs::stat($test_file);
|
||||||
|
$this->assertNotNull(
|
||||||
|
$start,
|
||||||
|
"File '$test_file' was not what we expected to find after writing"
|
||||||
|
);
|
||||||
|
|
||||||
|
Vfs::unlink($test_file);
|
||||||
|
|
||||||
|
$post = Vfs::stat($test_file);
|
||||||
|
$this->assertEquals(null,$post,
|
||||||
|
"File '$test_file' was there after deleting"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user