PrivateBin/tst/Data/FilesystemTest.php
Felix J. Ogris 9a61e8fd48 started script for storage backend migrations
todo: GCS

added GCS, no GLOBALS, two methods for saving pastes and comments

use GLOBALS for verbosity again

added getAllPastes() to all storage providers

moved to bin, added --delete options, make use of $store->getAllPastes()

added --delete-* options to help

longopts without -- *sigh*

fixed arguments

drop singleton behaviour to allow multiple backends of the same type simultaneously

remove singleton from Model, collapse loop in migrate.php

comments is not indexed

tests without data singleton

fix

exit if scandir() fails

extended meta doc
2022-11-01 16:02:17 +01:00

180 lines
9.7 KiB
PHP

<?php
use PrivateBin\Data\Filesystem;
class FilesystemTest extends PHPUnit_Framework_TestCase
{
private $_model;
private $_path;
private $_invalidPath;
public function setUp()
{
/* Setup Routine */
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
$this->_invalidPath = $this->_path . DIRECTORY_SEPARATOR . 'bar';
$this->_model = new Filesystem(array('dir' => $this->_path));
if (!is_dir($this->_path)) {
mkdir($this->_path);
}
if (!is_dir($this->_invalidPath)) {
mkdir($this->_invalidPath);
}
}
public function tearDown()
{
/* Tear Down Routine */
chmod($this->_invalidPath, 0700);
Helper::rmDir($this->_path);
}
public function testFileBasedDataStoreWorks()
{
$this->_model->delete(Helper::getPasteId());
// storing pastes
$paste = Helper::getPaste(2, array('expire_date' => 1344803344));
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
$this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
$this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store the same paste twice');
$this->assertEquals($paste, $this->_model->read(Helper::getPasteId()));
// storing comments
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist');
$this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()), 'store comment');
$this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment exists after storing it');
$this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()), 'unable to store the same comment twice');
$comment = Helper::getComment();
$comment['id'] = Helper::getCommentId();
$comment['parentid'] = Helper::getPasteId();
$this->assertEquals(
array($comment['meta']['created'] => $comment),
$this->_model->readComments(Helper::getPasteId())
);
// deleting pastes
$this->_model->delete(Helper::getPasteId());
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste successfully deleted');
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment was deleted with paste');
$this->assertFalse($this->_model->read(Helper::getPasteId()), 'paste can no longer be found');
}
public function testFileBasedAttachmentStoreWorks()
{
$this->_model->delete(Helper::getPasteId());
$original = $paste = Helper::getPasteWithAttachment(1, array('expire_date' => 1344803344));
$paste['meta']['attachment'] = $paste['attachment'];
$paste['meta']['attachmentname'] = $paste['attachmentname'];
unset($paste['attachment'], $paste['attachmentname']);
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
$this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
$this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store the same paste twice');
$this->assertEquals($original, $this->_model->read(Helper::getPasteId()));
}
/**
* pastes a-g are expired and should get deleted, x never expires and y-z expire in an hour
*/
public function testPurge()
{
mkdir($this->_path . DIRECTORY_SEPARATOR . '00', 0777, true);
$expired = Helper::getPaste(2, array('expire_date' => 1344803344));
$paste = Helper::getPaste(2, array('expire_date' => time() + 3600));
$keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z');
$ids = array();
foreach ($keys as $key) {
$ids[$key] = hash('fnv164', $key);
$this->assertFalse($this->_model->exists($ids[$key]), "paste $key does not yet exist");
if (in_array($key, array('x', 'y', 'z'))) {
$this->assertTrue($this->_model->create($ids[$key], $paste), "store $key paste");
} elseif ($key === 'x') {
$this->assertTrue($this->_model->create($ids[$key], Helper::getPaste()), "store $key paste");
} else {
$this->assertTrue($this->_model->create($ids[$key], $expired), "store $key paste");
}
$this->assertTrue($this->_model->exists($ids[$key]), "paste $key exists after storing it");
}
$this->_model->purge(10);
foreach ($ids as $key => $id) {
if (in_array($key, array('x', 'y', 'z'))) {
$this->assertTrue($this->_model->exists($id), "paste $key exists after purge");
$this->_model->delete($id);
} else {
$this->assertFalse($this->_model->exists($id), "paste $key was purged");
}
}
}
public function testErrorDetection()
{
$this->_model->delete(Helper::getPasteId());
$paste = Helper::getPaste(2, array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
$this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
$this->assertFalse($this->_model->setValue('foo', 'non existing namespace'), 'rejects setting value in non existing namespace');
}
public function testCommentErrorDetection()
{
$this->_model->delete(Helper::getPasteId());
$comment = Helper::getComment(1, array('nickname' => "Invalid UTF-8 sequence: \xB1\x31"));
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
$this->assertTrue($this->_model->create(Helper::getPasteId(), Helper::getPaste()), 'store new paste');
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist');
$this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store broken comment');
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does still not exist');
}
public function testOldFilesGetConverted()
{
// generate 10 (default purge batch size) pastes in the old format
$paste = Helper::getPaste();
$comment = Helper::getComment();
$commentid = Helper::getCommentId();
$ids = array();
for ($i = 0, $max = 10; $i < $max; ++$i) {
// PHPs mt_rand only supports 32 bit or up 0x7fffffff on 64 bit systems to be precise :-/
$dataid = str_pad(dechex(mt_rand(0, mt_getrandmax())), 8, '0', STR_PAD_LEFT) .
str_pad(dechex(mt_rand(0, mt_getrandmax())), 8, '0', STR_PAD_LEFT);
$storagedir = $this->_path . DIRECTORY_SEPARATOR . substr($dataid, 0, 2) .
DIRECTORY_SEPARATOR . substr($dataid, 2, 2) . DIRECTORY_SEPARATOR;
$ids[$dataid] = $storagedir;
if (!is_dir($storagedir)) {
mkdir($storagedir, 0700, true);
}
file_put_contents($storagedir . $dataid, json_encode($paste));
$storagedir .= $dataid . '.discussion' . DIRECTORY_SEPARATOR;
if (!is_dir($storagedir)) {
mkdir($storagedir, 0700, true);
}
file_put_contents($storagedir . $dataid . '.' . $commentid . '.' . $dataid, json_encode($comment));
}
// check that all 10 pastes were converted after the purge
$this->_model->purge(10);
foreach ($ids as $dataid => $storagedir) {
$this->assertFileExists($storagedir . $dataid . '.php', "paste $dataid exists in new format");
$this->assertFileNotExists($storagedir . $dataid, "old format paste $dataid got removed");
$this->assertTrue($this->_model->exists($dataid), "paste $dataid exists");
$this->assertEquals($this->_model->read($dataid), $paste, "paste $dataid wasn't modified in the conversion");
$storagedir .= $dataid . '.discussion' . DIRECTORY_SEPARATOR;
$this->assertFileExists($storagedir . $dataid . '.' . $commentid . '.' . $dataid . '.php', "comment of $dataid exists in new format");
$this->assertFileNotExists($storagedir . $dataid . '.' . $commentid . '.' . $dataid, "old format comment of $dataid got removed");
$this->assertTrue($this->_model->existsComment($dataid, $dataid, $commentid), "comment in paste $dataid exists");
$comment = $comment;
$comment['id'] = $commentid;
$comment['parentid'] = $dataid;
$this->assertEquals($this->_model->readComments($dataid), array($comment['meta']['created'] => $comment), "comment of $dataid wasn't modified in the conversion");
}
}
}