2019-05-01 15:50:19 +08:00
/*
Copyright © 2019 by The qTox Project Contributors
This file is part of qTox , a Qt - based graphical interface for Tox .
qTox is libre software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
qTox is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with qTox . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "src/persistence/db/rawdatabase.h"
// normally we should only test public API instead of implementation, but there's no reason to expose db schema
// upgrade externally, and the complexity of each version upgrade benefits from being individually testable
# include "src/persistence/history.cpp"
# include <QtTest/QtTest>
# include <QString>
# include <memory>
class TestDbSchema : public QObject
{
Q_OBJECT
private slots :
void initTestCase ( ) ;
void testCreation ( ) ;
void testIsNewDb ( ) ;
void test0to1 ( ) ;
void cleanupTestCase ( ) ;
private :
bool initSucess { false } ;
2019-10-06 15:58:59 +08:00
void createSchemaAtVersion ( std : : shared_ptr < RawDatabase > , const QMap < QString , QString > & schema ) ;
2019-05-01 15:50:19 +08:00
void verifyDb ( std : : shared_ptr < RawDatabase > db , const QMap < QString , QString > & expectedSql ) ;
} ;
const QString testFileList [ ] = {
" testCreation.db " ,
" testIsNewDbTrue.db " ,
" testIsNewDbFalse.db " ,
" test0to1.db "
} ;
2019-10-06 15:58:59 +08:00
const QMap < QString , QString > schema0 {
{ " aliases " , " CREATE TABLE aliases (id INTEGER PRIMARY KEY, owner INTEGER, display_name BLOB NOT NULL, UNIQUE(owner, display_name)) " } ,
{ " faux_offline_pending " , " CREATE TABLE faux_offline_pending (id INTEGER PRIMARY KEY) " } ,
{ " history " , " CREATE TABLE history (id INTEGER PRIMARY KEY, timestamp INTEGER NOT NULL, chat_id INTEGER NOT NULL, sender_alias INTEGER NOT NULL, message BLOB NOT NULL) " } ,
{ " peers " , " CREATE TABLE peers (id INTEGER PRIMARY KEY, public_key TEXT NOT NULL UNIQUE) " }
} ;
// added file transfer history
const QMap < QString , QString > schema1 {
{ " aliases " , " CREATE TABLE aliases (id INTEGER PRIMARY KEY, owner INTEGER, display_name BLOB NOT NULL, UNIQUE(owner, display_name)) " } ,
{ " faux_offline_pending " , " CREATE TABLE faux_offline_pending (id INTEGER PRIMARY KEY) " } ,
{ " file_transfers " , " CREATE TABLE file_transfers (id INTEGER PRIMARY KEY, chat_id INTEGER NOT NULL, file_restart_id BLOB NOT NULL, file_name BLOB NOT NULL, file_path BLOB NOT NULL, file_hash BLOB NOT NULL, file_size INTEGER NOT NULL, direction INTEGER NOT NULL, file_state INTEGER NOT NULL) " } ,
{ " history " , " CREATE TABLE history (id INTEGER PRIMARY KEY, timestamp INTEGER NOT NULL, chat_id INTEGER NOT NULL, sender_alias INTEGER NOT NULL, message BLOB NOT NULL, file_id INTEGER) " } ,
{ " peers " , " CREATE TABLE peers (id INTEGER PRIMARY KEY, public_key TEXT NOT NULL UNIQUE) " }
} ;
2019-05-01 15:50:19 +08:00
void TestDbSchema : : initTestCase ( )
{
for ( const auto & path : testFileList ) {
QVERIFY ( ! QFileInfo { path } . exists ( ) ) ;
}
initSucess = true ;
}
void TestDbSchema : : cleanupTestCase ( )
{
if ( ! initSucess ) {
qWarning ( ) < < " init failed, skipping cleanup to avoid loss of data " ;
return ;
}
for ( const auto & path : testFileList ) {
QFile : : remove ( path ) ;
}
}
void TestDbSchema : : verifyDb ( std : : shared_ptr < RawDatabase > db , const QMap < QString , QString > & expectedSql )
{
2019-10-06 15:58:59 +08:00
QVERIFY ( db - > execNow ( RawDatabase : : Query ( QStringLiteral (
" SELECT name, sql FROM sqlite_master "
" WHERE type='table'; " ) ,
2019-05-01 15:50:19 +08:00
[ & ] ( const QVector < QVariant > & row ) {
const QString tableName = row [ 0 ] . toString ( ) ;
2019-10-06 15:58:59 +08:00
QString tableSql = row [ 1 ] . toString ( ) ;
2019-05-01 15:50:19 +08:00
QVERIFY ( expectedSql . contains ( tableName ) ) ;
2019-10-06 15:58:59 +08:00
// table and column names can be quoted. UPDATE TEABLE automatically quotes the new names, but this
// has no functional impact on the schema. Strip quotes for comparison so that our created schema
// matches schema made from UPDATE TABLEs.
const QString unquotedTableSql = tableSql . remove ( " \" " ) ;
QVERIFY ( expectedSql . value ( tableName ) = = unquotedTableSql ) ;
2019-05-01 15:50:19 +08:00
} ) ) ) ;
}
2019-10-06 15:58:59 +08:00
void TestDbSchema : : createSchemaAtVersion ( std : : shared_ptr < RawDatabase > db , const QMap < QString , QString > & schema )
{
QVector < RawDatabase : : Query > queries ;
for ( auto const & tableCreation : schema . values ( ) ) {
queries + = tableCreation ;
}
QVERIFY ( db - > execNow ( queries ) ) ;
}
2019-05-01 15:50:19 +08:00
void TestDbSchema : : testCreation ( )
{
QVector < RawDatabase : : Query > queries ;
auto db = std : : shared_ptr < RawDatabase > { new RawDatabase { " testCreation.db " , { } , { } } } ;
2019-10-07 10:09:42 +08:00
QVERIFY ( createCurrentSchema ( db ) ) ;
2019-10-06 15:58:59 +08:00
verifyDb ( db , schema1 ) ;
2019-05-01 15:50:19 +08:00
}
void TestDbSchema : : testIsNewDb ( )
{
auto db = std : : shared_ptr < RawDatabase > { new RawDatabase { " testIsNewDbTrue.db " , { } , { } } } ;
QVERIFY ( isNewDb ( db ) = = true ) ;
db = std : : shared_ptr < RawDatabase > { new RawDatabase { " testIsNewDbFalse.db " , { } , { } } } ;
2019-10-06 15:58:59 +08:00
createSchemaAtVersion ( db , schema0 ) ;
2019-05-01 15:50:19 +08:00
QVERIFY ( isNewDb ( db ) = = false ) ;
}
void TestDbSchema : : test0to1 ( )
{
auto db = std : : shared_ptr < RawDatabase > { new RawDatabase { " test0to1.db " , { } , { } } } ;
2019-10-06 15:58:59 +08:00
createSchemaAtVersion ( db , schema0 ) ;
2019-10-07 10:09:42 +08:00
QVERIFY ( dbSchema0to1 ( db ) ) ;
2019-10-06 15:58:59 +08:00
verifyDb ( db , schema1 ) ;
2019-05-01 15:50:19 +08:00
}
QTEST_GUILESS_MAIN ( TestDbSchema )
# include "dbschema_test.moc"