cp -a %{buildroot}/%{db_test_dir}/.security-manager-test.db-journal %{buildroot}/%{db_test_dir}/.security-manager-test-corrupted.db-journal
echo -n > %{buildroot}/%{db_test_dir}/.security-manager-test-empty.db
echo -n > %{buildroot}/%{db_test_dir}/.security-manager-test-empty.db-journal
+sqlite3 %{buildroot}/%{db_test_dir}/.security-manager-test-wrong-schema.db < db/db.sql
+sqlite3 %{buildroot}/%{db_test_dir}/.security-manager-test-wrong-schema.db "drop view client_license_view"
cp -a %{SOURCE1} %{SOURCE3} %{SOURCE4} %{SOURCE5} %{buildroot}%{_datadir}/
chsmack -a System %{db_test_dir}/.security-manager-test-corrupted.db-journal
chsmack -a System %{db_test_dir}/.security-manager-test-empty.db
chsmack -a System %{db_test_dir}/.security-manager-test-empty.db-journal
+chsmack -a System %{db_test_dir}/.security-manager-test-wrong-schema.db
+chsmack -a System %{db_test_dir}/.security-manager-test-wrong-schema.db-journal
%files -n security-manager
%manifest %{_datadir}/security-manager.manifest
%attr(0600,root,root) %{db_test_dir}/.security-manager-test-corrupted.db-journal
%attr(0600,root,root) %{db_test_dir}/.security-manager-test-empty.db
%attr(0600,root,root) %{db_test_dir}/.security-manager-test-empty.db-journal
+%attr(0600,root,root) %{db_test_dir}/.security-manager-test-wrong-schema.db
+%attr(0600,root,root) %{db_test_dir}/.security-manager-test-wrong-schema.db-journal
%files -n security-license-manager
%{_libdir}/cynara/plugin/client/liblicense-manager-plugin-client.so
tryCatchDbInit([&]{ connectMigrateVerify(conn, dbPath); });
}
-void initDb(DB::SqlConnection &conn, const std::string &path, const std::string &roFallbackPath) {
+InitDbDidFallback initDb(DB::SqlConnection &conn, const std::string &path, const std::string &roFallbackPath) {
removeRecoveryFlagFile(path);
if (!FS::fileStatus(path)) {
createRecoveryFlagFile(path);
applyFallbackDb(conn, path, roFallbackPath);
} else try {
connectMigrateVerify(conn, path);
+ return InitDbDidFallback::no;
} catch (DB::SqlConnection::Exception::Base &e) {
createRecoveryFlagFile(path);
LogError("Database initialization error (" << e.DumpToString() << "), attempting fallback");
tryCatchDbInit([&]{ conn.Disconnect(); });
applyFallbackDb(conn, path, roFallbackPath);
}
+ return InitDbDidFallback::yes;
}
} //namespace
return dbPath + "-journal";
}
-void initDb() {
+InitDbDidFallback initDb() {
DB::SqlConnection conn;
- initDb(conn, Config::privilegeDbPath, Config::privilegeDbFallbackPath);
+ return initDb(conn, Config::privilegeDbPath, Config::privilegeDbFallbackPath);
}
PrivilegeDb::PrivilegeDb()
PrivilegeDb::PrivilegeDb(const std::string &path, const std::string &roFallbackPath)
{
- initDb(mSqlConnection, path, roFallbackPath);
- tryCatchDbInit([&]{ initDataCommands(); });
+ const auto didFallback = initDb(mSqlConnection, path, roFallbackPath);
+ try {
+ tryCatchDbInit([&]{ initDataCommands(); });
+ } catch (...) {
+ createRecoveryFlagFile(path);
+ switch (didFallback) {
+ case InitDbDidFallback::no:
+ LogError("Database initialization error during query preparation - attempting fallback");
+ tryCatchDbInit([&]{ mSqlConnection.Disconnect(); });
+ applyFallbackDb(mSqlConnection, path, roFallbackPath);
+ tryCatchDbInit([&]{ initDataCommands(); });
+ break;
+ case InitDbDidFallback::yes:
+ throwDbInitEx("Database initialization error during query preparation on fallback db - giving up");
+ }
+ }
}
void PrivilegeDb::initDataCommands()
{
- for (size_t i = 0; i < StmtTypeCount; i++)
- m_commands[i] = prepare(mSqlConnection, g_queries[i]);
+ for (size_t i = 0; i < StmtTypeCount; i++) {
+ try {
+ m_commands[i] = prepare(mSqlConnection, g_queries[i]);
+ } catch (...) {
+ for (size_t j = 0; j < i; j++)
+ m_commands[j].reset();
+ throw;
+ }
+ }
}
PrivilegeDb::StatementWrapper::StatementWrapper(DB::SqlConnection::DataCommandAutoPtr &ref)
}
};
+struct Empty {};
+
struct PrivilegeV0DBFixture : PrivilegeDBFixture {
PrivilegeV0DBFixture() : PrivilegeDBFixture(PRIVILEGE_DB_EXAMPLE_V0) {}
};
struct PrivilegeFallbackEmptyDBFixture : PrivilegeDBFixture {
PrivilegeFallbackEmptyDBFixture() : PrivilegeDBFixture(PRIVILEGE_DB_CORRUPTED, PRIVILEGE_DB_EMPTY, HaveBrokenFlagFile::yes) {}
};
+struct PrivilegeFallbackWrongDBFixture : PrivilegeDBFixture {
+ PrivilegeFallbackWrongDBFixture() : PrivilegeDBFixture(PRIVILEGE_DB_WRONG_SCHEMA, PRIVILEGE_DB_TEMPLATE, HaveBrokenFlagFile::yes) {}
+};
+struct PrivilegeFallbackWrongV0DBFixture : PrivilegeDBFixture {
+ PrivilegeFallbackWrongV0DBFixture() : PrivilegeDBFixture(PRIVILEGE_DB_WRONG_SCHEMA, PRIVILEGE_DB_EXAMPLE_V0, HaveBrokenFlagFile::yes) {}
+};
+struct PrivilegeFallbackWrongEmptyDBFixture : PrivilegeDBFixture {
+ PrivilegeFallbackWrongEmptyDBFixture() : PrivilegeDBFixture(PRIVILEGE_DB_WRONG_SCHEMA, PRIVILEGE_DB_EMPTY, HaveBrokenFlagFile::yes) {}
+};
+
+void testFallback() {
+ requireTestDbContents(PRIVILEGE_DB_TEMPLATE);
+ BOOST_REQUIRE(!FS::fileSize(genJournalPath(TEST_PRIVILEGE_DB_PATH)));
+}
+void testFallbackSchemaApplication() {
+ requireTestDbAndJournalContents(PRIVILEGE_DB_TEMPLATE);
+}
+void testFallbackMigration() {
+ PrivilegeDBFixture v0(PRIVILEGE_DB_EXAMPLE_V0, PRIVILEGE_DB_TEMPLATE,
+ PrivilegeDBFixture::HaveBrokenFlagFile::no, TEST_PRIVILEGE_DB_PATH_2);
+ requireTestDbContents(TEST_PRIVILEGE_DB_PATH_2);
+}
+void testFallbackMissingMigration() {
+ const std::string missingDbPath("/tmp/thisNotExists.db");
+ requireNoDb(missingDbPath);
+ const auto missingDbPathJournal = genJournalPath(missingDbPath);
+ const auto missingDbPathFlag = Config::dbRecoveryFlagFileName(missingDbPath);
+ BOOST_REQUIRE_NO_THROW(PrivilegeDb(missingDbPath, PRIVILEGE_DB_EXAMPLE_V0));
+ requireTestDbContents(missingDbPath);
+ BOOST_REQUIRE(!remove(missingDbPath.c_str()));
+ BOOST_REQUIRE(!remove(missingDbPathJournal.c_str()));
+ BOOST_REQUIRE(!FS::fileSize(missingDbPathFlag));
+ BOOST_REQUIRE(!remove(missingDbPathFlag.c_str()));
+}
} //namespace
BOOST_GLOBAL_FIXTURE(TestConfig)
BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST_FALLBACK, PrivilegeFallbackDBFixture)
BOOST_AUTO_TEST_CASE(T1510_fallback) {
- requireTestDbContents(PRIVILEGE_DB_TEMPLATE);
- BOOST_REQUIRE(!FS::fileSize(genJournalPath(TEST_PRIVILEGE_DB_PATH)));
+ testFallback();
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST_FALLBACK_EMPTY, PrivilegeFallbackEmptyDBFixture)
BOOST_AUTO_TEST_CASE(T1520_fallback_schema_application) {
- requireTestDbAndJournalContents(PRIVILEGE_DB_TEMPLATE);
+ testFallbackSchemaApplication();
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST_FALLBACK_V0, PrivilegeFallbackV0DBFixture)
BOOST_AUTO_TEST_CASE(T1530_fallback_migration) {
- PrivilegeDBFixture v0(PRIVILEGE_DB_EXAMPLE_V0, PRIVILEGE_DB_TEMPLATE,
- PrivilegeDBFixture::HaveBrokenFlagFile::no, TEST_PRIVILEGE_DB_PATH_2);
- requireTestDbContents(TEST_PRIVILEGE_DB_PATH_2);
+ testFallbackMigration();
}
BOOST_AUTO_TEST_CASE(T1540_db_missing_fallback_migration) {
- const std::string missingDbPath("/tmp/thisNotExists.db");
- requireNoDb(missingDbPath);
- const auto missingDbPathJournal = genJournalPath(missingDbPath);
- const auto missingDbPathFlag = Config::dbRecoveryFlagFileName(missingDbPath);
- BOOST_REQUIRE_NO_THROW(PrivilegeDb(missingDbPath, PRIVILEGE_DB_EXAMPLE_V0));
- requireTestDbContents(missingDbPath);
- BOOST_REQUIRE(!remove(missingDbPath.c_str()));
- BOOST_REQUIRE(!remove(missingDbPathJournal.c_str()));
- BOOST_REQUIRE(!FS::fileSize(missingDbPathFlag));
- BOOST_REQUIRE(!remove(missingDbPathFlag.c_str()));
+ testFallbackMissingMigration();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST_FALLBACK_WRONG, PrivilegeFallbackWrongDBFixture)
+BOOST_AUTO_TEST_CASE(T1550_fallback_wrong) {
+ testFallback();
+}
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST_FALLBACK_WRONG_EMPTY, PrivilegeFallbackWrongEmptyDBFixture)
+BOOST_AUTO_TEST_CASE(T1560_fallback_wrong_schema_application) {
+ testFallbackSchemaApplication();
+}
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST_FALLBACK_WRONG_V0, PrivilegeFallbackWrongV0DBFixture)
+
+BOOST_AUTO_TEST_CASE(T1570_fallback_wrong_migration) {
+ testFallbackMigration();
+}
+
+BOOST_AUTO_TEST_CASE(T1580_db_missing_fallback_wrong_migration) {
+ testFallbackMissingMigration();
}
BOOST_AUTO_TEST_SUITE_END()
+BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST_FALLBACK_MIGRATION_FAILURE, Empty)
+BOOST_AUTO_TEST_CASE(T1590_fallback_migration_failure) {
+ const auto go = [](const char *db, const char *fallback){
+ std::unique_ptr<PrivilegeDBFixture> fix;
+ BOOST_REQUIRE_THROW(fix.reset(new PrivilegeDBFixture(db, fallback, PrivilegeDBFixture::HaveBrokenFlagFile::yes)), PrivilegeDb::Exception::IOError);
+ fix.reset();
+ BOOST_REQUIRE(!remove(TEST_PRIVILEGE_DB_PATH));
+ auto journal = genJournalPath(TEST_PRIVILEGE_DB_PATH);
+ BOOST_REQUIRE(!remove(journal.c_str()));
+ auto recovered = Config::dbRecoveryFlagFileName(TEST_PRIVILEGE_DB_PATH);
+ BOOST_REQUIRE(!remove(recovered.c_str()));
+ };
+ go(PRIVILEGE_DB_CORRUPTED, PRIVILEGE_DB_CORRUPTED);
+ go(PRIVILEGE_DB_CORRUPTED, PRIVILEGE_DB_WRONG_SCHEMA);
+ go(PRIVILEGE_DB_WRONG_SCHEMA, PRIVILEGE_DB_CORRUPTED);
+ go(PRIVILEGE_DB_WRONG_SCHEMA, PRIVILEGE_DB_WRONG_SCHEMA);
+}
+BOOST_AUTO_TEST_SUITE_END()
+
//TODO
// Tests below are arbitrarily copy-pasted from test_privilege_db_transaction.cpp
// but applied to a migrated V0 database instead. The pragmatic way of doing this