mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 21:22:40 +00:00
Database update tests
This commit is contained in:
parent
6c16ba133c
commit
18c8076a0f
8 changed files with 126 additions and 25 deletions
|
@ -22,11 +22,13 @@ abstract class AbstractException extends \Exception {
|
||||||
"Db/Exception.fileUncreatable" => 10206,
|
"Db/Exception.fileUncreatable" => 10206,
|
||||||
"Db/Exception.fileCorrupt" => 10207,
|
"Db/Exception.fileCorrupt" => 10207,
|
||||||
"Db/Exception.updateTooNew" => 10211,
|
"Db/Exception.updateTooNew" => 10211,
|
||||||
"Db/Exception.updateFileMissing" => 10212,
|
"Db/Exception.updateManual" => 10212,
|
||||||
"Db/Exception.updateFileUnusable" => 10213,
|
"Db/Exception.updateManualOnly" => 10213,
|
||||||
"Db/Exception.updateFileUnreadable" => 10214,
|
"Db/Exception.updateFileMissing" => 10214,
|
||||||
"Db/Exception.updateManual" => 10215,
|
"Db/Exception.updateFileUnusable" => 10215,
|
||||||
"Db/Exception.updateManualOnly" => 10216,
|
"Db/Exception.updateFileUnreadable" => 10216,
|
||||||
|
"Db/Exception.updateFileError" => 10217,
|
||||||
|
"Db/Exception.updateFileIncomplete" => 10218,
|
||||||
"Db/Exception.paramTypeInvalid" => 10221,
|
"Db/Exception.paramTypeInvalid" => 10221,
|
||||||
"Db/Exception.paramTypeUnknown" => 10222,
|
"Db/Exception.paramTypeUnknown" => 10222,
|
||||||
"Db/Exception.paramTypeMissing" => 10223,
|
"Db/Exception.paramTypeMissing" => 10223,
|
||||||
|
@ -39,12 +41,12 @@ abstract class AbstractException extends \Exception {
|
||||||
"Db/ExceptionInput.constraintViolation" => 10236,
|
"Db/ExceptionInput.constraintViolation" => 10236,
|
||||||
"Db/ExceptionInput.typeViolation" => 10237,
|
"Db/ExceptionInput.typeViolation" => 10237,
|
||||||
"Db/ExceptionTimeout.general" => 10241,
|
"Db/ExceptionTimeout.general" => 10241,
|
||||||
"Conf/Exception.fileMissing" => 10302,
|
"Conf/Exception.fileMissing" => 10301,
|
||||||
"Conf/Exception.fileUnusable" => 10303,
|
"Conf/Exception.fileUnusable" => 10302,
|
||||||
"Conf/Exception.fileUnreadable" => 10304,
|
"Conf/Exception.fileUnreadable" => 10303,
|
||||||
"Conf/Exception.fileUnwritable" => 10305,
|
"Conf/Exception.fileUnwritable" => 10304,
|
||||||
"Conf/Exception.fileUncreatable" => 10306,
|
"Conf/Exception.fileUncreatable" => 10305,
|
||||||
"Conf/Exception.fileCorrupt" => 10307,
|
"Conf/Exception.fileCorrupt" => 10306,
|
||||||
"User/Exception.functionNotImplemented" => 10401,
|
"User/Exception.functionNotImplemented" => 10401,
|
||||||
"User/Exception.doesNotExist" => 10402,
|
"User/Exception.doesNotExist" => 10402,
|
||||||
"User/Exception.alreadyExists" => 10403,
|
"User/Exception.alreadyExists" => 10403,
|
||||||
|
@ -61,7 +63,7 @@ abstract class AbstractException extends \Exception {
|
||||||
"Feed/Exception.malformed" => 10511,
|
"Feed/Exception.malformed" => 10511,
|
||||||
"Feed/Exception.xmlEntity" => 10512,
|
"Feed/Exception.xmlEntity" => 10512,
|
||||||
"Feed/Exception.subscriptionNotFound" => 10521,
|
"Feed/Exception.subscriptionNotFound" => 10521,
|
||||||
"Feed/Exception.unsupportedFeedFormat" => 10522
|
"Feed/Exception.unsupportedFeedFormat" => 10522,
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(string $msgID = "", $vars = null, \Throwable $e = null) {
|
public function __construct(string $msgID = "", $vars = null, \Throwable $e = null) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ class Conf {
|
||||||
public $lang = "en";
|
public $lang = "en";
|
||||||
|
|
||||||
public $dbDriver = Db\SQLite3\Driver::class;
|
public $dbDriver = Db\SQLite3\Driver::class;
|
||||||
|
public $dbSchemaBase = BASE.'sql';
|
||||||
public $dbSQLite3File = BASE."newssync.db";
|
public $dbSQLite3File = BASE."newssync.db";
|
||||||
public $dbSQLite3Key = "";
|
public $dbSQLite3Key = "";
|
||||||
public $dbSQLite3AutoUpd = true;
|
public $dbSQLite3AutoUpd = true;
|
||||||
|
@ -28,8 +29,6 @@ class Conf {
|
||||||
public $userComposeNames = true;
|
public $userComposeNames = true;
|
||||||
public $userTempPasswordLength = 20;
|
public $userTempPasswordLength = 20;
|
||||||
|
|
||||||
public $simplepieCache = BASE.".cache";
|
|
||||||
|
|
||||||
|
|
||||||
public function __construct(string $import_file = "") {
|
public function __construct(string $import_file = "") {
|
||||||
if($import_file != "") $this->importFile($import_file);
|
if($import_file != "") $this->importFile($import_file);
|
||||||
|
|
|
@ -57,6 +57,7 @@ abstract class AbstractDriver implements Driver {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function unlock(): bool {
|
public function unlock(): bool {
|
||||||
|
if($this->schemaVersion() < 1) return true;
|
||||||
$this->exec("DELETE from newssync_settings where key is 'lock'");
|
$this->exec("DELETE from newssync_settings where key is 'lock'");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,21 +61,27 @@ class Driver extends \JKingWeb\NewsSync\Db\AbstractDriver {
|
||||||
if(!$this->data->conf->dbSQLite3AutoUpd) throw new Exception("updateManual", ['version' => $ver, 'driver_name' => $this->driverName()]);
|
if(!$this->data->conf->dbSQLite3AutoUpd) throw new Exception("updateManual", ['version' => $ver, 'driver_name' => $this->driverName()]);
|
||||||
if($ver >= $to) throw new Exception("updateTooNew", ['difference' => ($ver - $to), 'current' => $ver, 'target' => $to, 'driver_name' => $this->driverName()]);
|
if($ver >= $to) throw new Exception("updateTooNew", ['difference' => ($ver - $to), 'current' => $ver, 'target' => $to, 'driver_name' => $this->driverName()]);
|
||||||
$sep = \DIRECTORY_SEPARATOR;
|
$sep = \DIRECTORY_SEPARATOR;
|
||||||
$path = \JKingWeb\NewsSync\BASE."sql".$sep."SQLite3".$sep;
|
$path = $this->data->conf->dbSchemaBase.$sep."SQLite3".$sep;
|
||||||
$this->lock();
|
$this->lock();
|
||||||
$this->begin();
|
$this->begin();
|
||||||
for($a = $ver; $a < $to; $a++) {
|
for($a = $ver; $a < $to; $a++) {
|
||||||
$this->begin();
|
$this->begin();
|
||||||
try {
|
try {
|
||||||
$file = $path.$a.".sql";
|
$file = $path.$a.".sql";
|
||||||
if(!file_exists($file)) throw new Exception("updateFileMissing", ['file' => $file, 'driver_name' => $this->driverName()]);
|
if(!file_exists($file)) throw new Exception("updateFileMissing", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]);
|
||||||
if(!is_readable($file)) throw new Exception("updateFileUnreadable", ['file' => $file, 'driver_name' => $this->driverName()]);
|
if(!is_readable($file)) throw new Exception("updateFileUnreadable", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]);
|
||||||
$sql = @file_get_contents($file);
|
$sql = @file_get_contents($file);
|
||||||
if($sql===false) throw new Exception("updateFileUnusable", ['file' => $file, 'driver_name' => $this->driverName()]);
|
if($sql===false) throw new Exception("updateFileUnusable", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]);
|
||||||
$this->exec($sql);
|
try {
|
||||||
|
$this->exec($sql);
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
throw new Exception("updateFileError", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a, 'message' => $this->getError()]);
|
||||||
|
}
|
||||||
|
if($this->schemaVersion() != $a+1) throw new Exception("updateFileIncomplete", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]);
|
||||||
} catch(\Throwable $e) {
|
} catch(\Throwable $e) {
|
||||||
// undo any partial changes from the failed update
|
// undo any partial changes from the failed update
|
||||||
$this->rollback();
|
$this->rollback();
|
||||||
|
$this->unlock();
|
||||||
// commit any successful updates if updating by more than one version
|
// commit any successful updates if updating by more than one version
|
||||||
$this->commit(true);
|
$this->commit(true);
|
||||||
// throw the error received
|
// throw the error received
|
||||||
|
@ -88,6 +94,10 @@ class Driver extends \JKingWeb\NewsSync\Db\AbstractDriver {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getError(): string {
|
||||||
|
return $this->db->lastErrorMsg();
|
||||||
|
}
|
||||||
|
|
||||||
public function exec(string $query): bool {
|
public function exec(string $query): bool {
|
||||||
try {
|
try {
|
||||||
return (bool) $this->db->exec($query);
|
return (bool) $this->db->exec($query);
|
||||||
|
|
|
@ -42,6 +42,8 @@ return [
|
||||||
'Exception.JKingWeb/NewsSync/Db/Exception.updateFileMissing' => 'Automatic updating of the {driver_name} database failed due to instructions for updating from version {current} not being available',
|
'Exception.JKingWeb/NewsSync/Db/Exception.updateFileMissing' => 'Automatic updating of the {driver_name} database failed due to instructions for updating from version {current} not being available',
|
||||||
'Exception.JKingWeb/NewsSync/Db/Exception.updateFileUnreadable' => 'Automatic updating of the {driver_name} database failed due to insufficient permissions to read instructions for updating from version {current}',
|
'Exception.JKingWeb/NewsSync/Db/Exception.updateFileUnreadable' => 'Automatic updating of the {driver_name} database failed due to insufficient permissions to read instructions for updating from version {current}',
|
||||||
'Exception.JKingWeb/NewsSync/Db/Exception.updateFileUnusable' => 'Automatic updating of the {driver_name} database failed due to an error reading instructions for updating from version {current}',
|
'Exception.JKingWeb/NewsSync/Db/Exception.updateFileUnusable' => 'Automatic updating of the {driver_name} database failed due to an error reading instructions for updating from version {current}',
|
||||||
|
'Exception.JKingWeb/NewsSync/Db/Exception.updateFileError' => 'Automatic updating of the {driver_name} database failed updating from version {current} with the following error: "{message}"',
|
||||||
|
'Exception.JKingWeb/NewsSync/Db/Exception.updateFileIncomplete' => 'Automatic updating of the {driver_name} database failed due to instructions for updating from version {current} being incomplete',
|
||||||
'Exception.JKingWeb/NewsSync/Db/Exception.updateTooNew' =>
|
'Exception.JKingWeb/NewsSync/Db/Exception.updateTooNew' =>
|
||||||
'{difference, select,
|
'{difference, select,
|
||||||
0 {Automatic updating of the {driver_name} database failed because it is already up to date with the requested version, {target}}
|
0 {Automatic updating of the {driver_name} database failed because it is already up to date with the requested version, {target}}
|
||||||
|
|
|
@ -6,7 +6,8 @@ namespace JKingWeb\NewsSync;
|
||||||
class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase {
|
class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase {
|
||||||
use Test\Tools;
|
use Test\Tools;
|
||||||
|
|
||||||
protected $c;
|
protected $data;
|
||||||
|
protected $drv;
|
||||||
|
|
||||||
function setUp() {
|
function setUp() {
|
||||||
$conf = new Conf();
|
$conf = new Conf();
|
||||||
|
@ -262,6 +263,7 @@ class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
function testManipulateAdvisoryLock() {
|
function testManipulateAdvisoryLock() {
|
||||||
|
$this->assertTrue($this->drv->unlock());
|
||||||
$this->assertFalse($this->drv->isLocked());
|
$this->assertFalse($this->drv->isLocked());
|
||||||
$this->assertTrue($this->drv->lock());
|
$this->assertTrue($this->drv->lock());
|
||||||
$this->assertFalse($this->drv->isLocked());
|
$this->assertFalse($this->drv->isLocked());
|
||||||
|
@ -278,9 +280,4 @@ class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase {
|
||||||
$this->assertTrue($this->drv->unlock());
|
$this->assertTrue($this->drv->unlock());
|
||||||
$this->assertFalse($this->drv->isLocked());
|
$this->assertFalse($this->drv->isLocked());
|
||||||
}
|
}
|
||||||
|
|
||||||
function testUpdateTheSchema() {
|
|
||||||
// FIXME: This should be its own test suite with VFS schemata to simulate various error conditions
|
|
||||||
$this->assertTrue($this->drv->schemaUpdate(1));
|
|
||||||
}
|
|
||||||
}
|
}
|
89
tests/Db/SQLite3/TestDbUpdateSQLite3.php
Normal file
89
tests/Db/SQLite3/TestDbUpdateSQLite3.php
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
namespace JKingWeb\NewsSync;
|
||||||
|
use \org\bovigo\vfs\vfsStream;
|
||||||
|
|
||||||
|
|
||||||
|
class TestDbUpdateSQLite3 extends \PHPUnit\Framework\TestCase {
|
||||||
|
use Test\Tools;
|
||||||
|
|
||||||
|
protected $data;
|
||||||
|
protected $drv;
|
||||||
|
protected $vfs;
|
||||||
|
protected $base;
|
||||||
|
|
||||||
|
const MINIMAL1 = "create table newssync_settings(key text primary key not null, value text, type text not null); pragma user_version=1";
|
||||||
|
const MINIMAL2 = "pragma user_version=2";
|
||||||
|
|
||||||
|
function setUp() {
|
||||||
|
$this->vfs = vfsStream::setup("schemata", null, ['SQLite3' => []]);
|
||||||
|
$conf = new Conf();
|
||||||
|
$conf->dbDriver = Db\SQLite3\Driver::class;
|
||||||
|
$conf->dbSchemaBase = $this->vfs->url();
|
||||||
|
$this->base = $this->vfs->url()."/SQLite3/";
|
||||||
|
$conf->dbSQLite3File = ":memory:";
|
||||||
|
$this->data = new Test\RuntimeData($conf);
|
||||||
|
$this->drv = new Db\SQLite3\Driver($this->data, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tearDown() {
|
||||||
|
unset($this->drv);
|
||||||
|
unset($this->data);
|
||||||
|
unset($this->vfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testLoadMissingFile() {
|
||||||
|
$this->assertException("updateFileMissing", "Db");
|
||||||
|
$this->drv->schemaUpdate(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testLoadUnreadableFile() {
|
||||||
|
touch($this->base."0.sql");
|
||||||
|
chmod($this->base."0.sql", 0000);
|
||||||
|
$this->assertException("updateFileUnreadable", "Db");
|
||||||
|
$this->drv->schemaUpdate(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testLoadCorruptFile() {
|
||||||
|
file_put_contents($this->base."0.sql", "This is a corrupt file");
|
||||||
|
$this->assertException("updateFileError", "Db");
|
||||||
|
$this->drv->schemaUpdate(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testLoadIncompleteFile() {
|
||||||
|
file_put_contents($this->base."0.sql", "create table newssync_settings(key text primary key not null, value text, type text not null);");
|
||||||
|
$this->assertException("updateFileIncomplete", "Db");
|
||||||
|
$this->drv->schemaUpdate(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testLoadCorrectFile() {
|
||||||
|
file_put_contents($this->base."0.sql", self::MINIMAL1);
|
||||||
|
$this->drv->schemaUpdate(1);
|
||||||
|
$this->assertEquals(1, $this->drv->schemaVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPerformPartialUpdate() {
|
||||||
|
file_put_contents($this->base."0.sql", self::MINIMAL1);
|
||||||
|
file_put_contents($this->base."1.sql", "");
|
||||||
|
$this->assertException("updateFileIncomplete", "Db");
|
||||||
|
try {
|
||||||
|
$this->drv->schemaUpdate(2);
|
||||||
|
} catch(Exception $e) {
|
||||||
|
$this->assertEquals(1, $this->drv->schemaVersion());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPerformSequentialUpdate() {
|
||||||
|
file_put_contents($this->base."0.sql", self::MINIMAL1);
|
||||||
|
file_put_contents($this->base."1.sql", self::MINIMAL2);
|
||||||
|
$this->drv->schemaUpdate(2);
|
||||||
|
$this->assertEquals(2, $this->drv->schemaVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPerformActualUpdate() {
|
||||||
|
$this->data->conf->dbSchemaBase = (new Conf())->dbSchemaBase;
|
||||||
|
$this->drv->schemaUpdate(Database::SCHEMA_VERSION);
|
||||||
|
$this->assertEquals(Database::SCHEMA_VERSION, $this->drv->schemaVersion());
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,7 @@
|
||||||
<file>Db/SQLite3/TestDbResultSQLite3.php</file>
|
<file>Db/SQLite3/TestDbResultSQLite3.php</file>
|
||||||
<file>Db/SQLite3/TestDbStatementSQLite3.php</file>
|
<file>Db/SQLite3/TestDbStatementSQLite3.php</file>
|
||||||
<file>Db/SQLite3/TestDbDriverSQLite3.php</file>
|
<file>Db/SQLite3/TestDbDriverSQLite3.php</file>
|
||||||
|
<file>Db/SQLite3/TestDbUpdateSQLite3.php</file>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
|
|
||||||
</phpunit>
|
</phpunit>
|
Loading…
Reference in a new issue