File indexing completed on 2024-11-10 04:40:19
0001 /* 0002 SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org> 0003 SPDX-FileCopyrightText: 2012 Volker Krause <vkrause@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "dbinitializertest.h" 0009 #include "unittestschema.h" 0010 #include <QIODevice> 0011 0012 #define DBINITIALIZER_UNITTEST 0013 #include "storage/dbinitializer.cpp" 0014 #undef DBINITIALIZER_UNITTEST 0015 0016 #include "shared/aktest.h" 0017 0018 #define QL1S(x) QLatin1StringView(x) 0019 0020 using namespace Akonadi::Server; 0021 0022 Q_DECLARE_METATYPE(QList<DbIntrospector::ForeignKey>) 0023 0024 class StatementCollector : public TestInterface 0025 { 0026 public: 0027 void execStatement(const QString &statement) override 0028 { 0029 statements.push_back(statement); 0030 } 0031 0032 QStringList statements; 0033 }; 0034 0035 class DbFakeIntrospector : public DbIntrospector 0036 { 0037 public: 0038 explicit DbFakeIntrospector(const QSqlDatabase &database) 0039 : DbIntrospector(database) 0040 , m_hasTable(false) 0041 , m_hasIndex(false) 0042 , m_tableEmpty(true) 0043 { 0044 } 0045 0046 bool hasTable(const QString &tableName) override 0047 { 0048 Q_UNUSED(tableName) 0049 return m_hasTable; 0050 } 0051 bool hasIndex(const QString &tableName, const QString &indexName) override 0052 { 0053 Q_UNUSED(tableName) 0054 Q_UNUSED(indexName) 0055 return m_hasIndex; 0056 } 0057 bool hasColumn(const QString &tableName, const QString &columnName) override 0058 { 0059 Q_UNUSED(tableName) 0060 Q_UNUSED(columnName) 0061 return false; 0062 } 0063 bool isTableEmpty(const QString &tableName) override 0064 { 0065 Q_UNUSED(tableName) 0066 return m_tableEmpty; 0067 } 0068 QList<ForeignKey> foreignKeyConstraints(const QString &tableName) override 0069 { 0070 Q_UNUSED(tableName) 0071 return m_foreignKeys; 0072 } 0073 0074 QString getAutoIncrementValueQuery(const QString &tableName, const QString &columnName) override 0075 { 0076 Q_UNUSED(tableName); 0077 Q_UNUSED(columnName); 0078 return {}; 0079 } 0080 0081 QString updateAutoIncrementValueQuery(const QString &tableName, const QString &columnName, qint64 value) override 0082 { 0083 Q_UNUSED(tableName); 0084 Q_UNUSED(columnName); 0085 Q_UNUSED(value); 0086 0087 return {}; 0088 } 0089 0090 QList<ForeignKey> m_foreignKeys; 0091 bool m_hasTable; 0092 bool m_hasIndex; 0093 bool m_tableEmpty; 0094 }; 0095 0096 void DbInitializerTest::initTestCase() 0097 { 0098 Q_INIT_RESOURCE(akonadidb); 0099 } 0100 0101 void DbInitializerTest::testRun_data() 0102 { 0103 QTest::addColumn<QString>("driverName"); 0104 QTest::addColumn<QString>("filename"); 0105 QTest::addColumn<bool>("hasTable"); 0106 QTest::addColumn<QList<DbIntrospector::ForeignKey>>("fks"); 0107 0108 QList<DbIntrospector::ForeignKey> fks; 0109 0110 QTest::newRow("mysql") << "QMYSQL" 0111 << ":dbinit_mysql" << false << fks; 0112 QTest::newRow("sqlite") << "QSQLITE" 0113 << ":dbinit_sqlite" << false << fks; 0114 QTest::newRow("psql") << "QPSQL" 0115 << ":dbinit_psql" << false << fks; 0116 0117 DbIntrospector::ForeignKey fk; 0118 fk.name = QL1S("myForeignKeyIdentifier"); 0119 fk.column = QL1S("collectionId"); 0120 fk.refTable = QL1S("CollectionTable"); 0121 fk.refColumn = QL1S("id"); 0122 fk.onUpdate = QL1S("RESTRICT"); 0123 fk.onDelete = QL1S("CASCADE"); 0124 fks.push_back(fk); 0125 0126 QTest::newRow("mysql (incremental)") << "QMYSQL" 0127 << ":dbinit_mysql_incremental" << true << fks; 0128 QTest::newRow("sqlite (incremental)") << "QSQLITE" 0129 << ":dbinit_sqlite_incremental" << true << fks; 0130 QTest::newRow("psql (incremental)") << "QPSQL" 0131 << ":dbinit_psql_incremental" << true << fks; 0132 } 0133 0134 void DbInitializerTest::testRun() 0135 { 0136 QFETCH(QString, driverName); 0137 QFETCH(QString, filename); 0138 QFETCH(bool, hasTable); 0139 QFETCH(QList<DbIntrospector::ForeignKey>, fks); 0140 0141 QFile file(filename); 0142 QVERIFY(file.open(QFile::ReadOnly)); 0143 0144 if (QSqlDatabase::drivers().contains(driverName)) { 0145 QSqlDatabase db = QSqlDatabase::addDatabase(driverName, driverName); 0146 UnitTestSchema schema; 0147 DbInitializer::Ptr initializer = DbInitializer::createInstance(db, &schema); 0148 QVERIFY(bool(initializer)); 0149 0150 StatementCollector collector; 0151 initializer->setTestInterface(&collector); 0152 auto introspector = new DbFakeIntrospector(db); 0153 introspector->m_hasTable = hasTable; 0154 introspector->m_hasIndex = hasTable; 0155 introspector->m_tableEmpty = !hasTable; 0156 introspector->m_foreignKeys = fks; 0157 initializer->setIntrospector(DbIntrospector::Ptr(introspector)); 0158 0159 QVERIFY(initializer->run()); 0160 QVERIFY(initializer->updateIndexesAndConstraints()); 0161 QVERIFY(!collector.statements.isEmpty()); 0162 0163 for (const QString &statement : std::as_const(collector.statements)) { 0164 const QString expected = readNextStatement(&file).simplified(); 0165 0166 QString normalized = statement.simplified(); 0167 normalized.replace(QLatin1StringView(" ,"), QLatin1StringView(",")); 0168 normalized.replace(QLatin1StringView(" )"), QLatin1StringView(")")); 0169 QCOMPARE(normalized, expected); 0170 } 0171 0172 QVERIFY(initializer->errorMsg().isEmpty()); 0173 } 0174 } 0175 0176 QString DbInitializerTest::readNextStatement(QIODevice *io) 0177 { 0178 QString statement; 0179 while (!io->atEnd()) { 0180 const QString line = QString::fromUtf8(io->readLine()); 0181 if (line.trimmed().isEmpty() && !statement.isEmpty()) { 0182 return statement; 0183 } 0184 statement += line; 0185 } 0186 0187 return statement; 0188 } 0189 0190 AKTEST_MAIN(DbInitializerTest) 0191 0192 #include "moc_dbinitializertest.cpp"