1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-07-27 17:28:41 +00:00

Use a database for mod storage (#11763)

This commit is contained in:
Jude Melton-Houghton 2022-01-07 13:28:49 -05:00 committed by GitHub
parent b81948a14c
commit bf22569019
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 798 additions and 127 deletions

View file

@ -14,6 +14,7 @@ set (UNITTEST_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/test_map_settings_manager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_mapnode.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_modchannels.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_modmetadatadatabase.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_nodedef.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_noderesolver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_noise.cpp

View file

@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gamedef.h"
#include "modchannels.h"
#include "content/mods.h"
#include "database/database-dummy.h"
#include "util/numeric.h"
#include "porting.h"
@ -55,6 +56,7 @@ public:
scene::ISceneManager *getSceneManager() { return m_scenemgr; }
IRollbackManager *getRollbackManager() { return m_rollbackmgr; }
EmergeManager *getEmergeManager() { return m_emergemgr; }
ModMetadataDatabase *getModStorageDatabase() { return m_mod_storage_database; }
scene::IAnimatedMesh *getMesh(const std::string &filename) { return NULL; }
bool checkLocalPrivilege(const std::string &priv) { return false; }
@ -68,7 +70,6 @@ public:
return testmodspec;
}
virtual const ModSpec* getModSpec(const std::string &modname) const { return NULL; }
virtual std::string getModStoragePath() const { return "."; }
virtual bool registerModStorage(ModMetadata *meta) { return true; }
virtual void unregisterModStorage(const std::string &name) {}
bool joinModChannel(const std::string &channel);
@ -89,11 +90,13 @@ private:
scene::ISceneManager *m_scenemgr = nullptr;
IRollbackManager *m_rollbackmgr = nullptr;
EmergeManager *m_emergemgr = nullptr;
ModMetadataDatabase *m_mod_storage_database = nullptr;
std::unique_ptr<ModChannelMgr> m_modchannel_mgr;
};
TestGameDef::TestGameDef() :
m_mod_storage_database(new Database_Dummy()),
m_modchannel_mgr(new ModChannelMgr())
{
m_itemdef = createItemDefManager();
@ -107,6 +110,7 @@ TestGameDef::~TestGameDef()
{
delete m_itemdef;
delete m_nodedef;
delete m_mod_storage_database;
}

View file

@ -0,0 +1,253 @@
/*
Minetest
Copyright (C) 2018 bendeutsch, Ben Deutsch <ben@bendeutsch.de>
Copyright (C) 2021 TurkeyMcMac, Jude Melton-Houghton <jwmhjwmh@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
// This file is an edited copy of test_authdatabase.cpp
#include "test.h"
#include <algorithm>
#include "database/database-files.h"
#include "database/database-sqlite3.h"
#include "filesys.h"
namespace
{
// Anonymous namespace to create classes that are only
// visible to this file
//
// These are helpers that return a *ModMetadataDatabase and
// allow us to run the same tests on different databases and
// database acquisition strategies.
class ModMetadataDatabaseProvider
{
public:
virtual ~ModMetadataDatabaseProvider() = default;
virtual ModMetadataDatabase *getModMetadataDatabase() = 0;
};
class FixedProvider : public ModMetadataDatabaseProvider
{
public:
FixedProvider(ModMetadataDatabase *mod_meta_db) : mod_meta_db(mod_meta_db){};
virtual ~FixedProvider(){};
virtual ModMetadataDatabase *getModMetadataDatabase() { return mod_meta_db; };
private:
ModMetadataDatabase *mod_meta_db;
};
class FilesProvider : public ModMetadataDatabaseProvider
{
public:
FilesProvider(const std::string &dir) : dir(dir){};
virtual ~FilesProvider()
{
if (mod_meta_db)
mod_meta_db->endSave();
delete mod_meta_db;
}
virtual ModMetadataDatabase *getModMetadataDatabase()
{
if (mod_meta_db)
mod_meta_db->endSave();
delete mod_meta_db;
mod_meta_db = new ModMetadataDatabaseFiles(dir);
mod_meta_db->beginSave();
return mod_meta_db;
};
private:
std::string dir;
ModMetadataDatabase *mod_meta_db = nullptr;
};
class SQLite3Provider : public ModMetadataDatabaseProvider
{
public:
SQLite3Provider(const std::string &dir) : dir(dir){};
virtual ~SQLite3Provider()
{
if (mod_meta_db)
mod_meta_db->endSave();
delete mod_meta_db;
}
virtual ModMetadataDatabase *getModMetadataDatabase()
{
if (mod_meta_db)
mod_meta_db->endSave();
delete mod_meta_db;
mod_meta_db = new ModMetadataDatabaseSQLite3(dir);
mod_meta_db->beginSave();
return mod_meta_db;
};
private:
std::string dir;
ModMetadataDatabase *mod_meta_db = nullptr;
};
}
class TestModMetadataDatabase : public TestBase
{
public:
TestModMetadataDatabase() { TestManager::registerTestModule(this); }
const char *getName() { return "TestModMetadataDatabase"; }
void runTests(IGameDef *gamedef);
void runTestsForCurrentDB();
void testRecallFail();
void testCreate();
void testRecall();
void testChange();
void testRecallChanged();
void testListMods();
void testRemove();
private:
ModMetadataDatabaseProvider *mod_meta_provider;
};
static TestModMetadataDatabase g_test_instance;
void TestModMetadataDatabase::runTests(IGameDef *gamedef)
{
// fixed directory, for persistence
thread_local const std::string test_dir = getTestTempDirectory();
// Each set of tests is run twice for each database type:
// one where we reuse the same ModMetadataDatabase object (to test local caching),
// and one where we create a new ModMetadataDatabase object for each call
// (to test actual persistence).
rawstream << "-------- Files database (same object)" << std::endl;
ModMetadataDatabase *mod_meta_db = new ModMetadataDatabaseFiles(test_dir);
mod_meta_provider = new FixedProvider(mod_meta_db);
runTestsForCurrentDB();
delete mod_meta_db;
delete mod_meta_provider;
// reset database
fs::RecursiveDelete(test_dir + DIR_DELIM + "mod_storage");
rawstream << "-------- Files database (new objects)" << std::endl;
mod_meta_provider = new FilesProvider(test_dir);
runTestsForCurrentDB();
delete mod_meta_provider;
rawstream << "-------- SQLite3 database (same object)" << std::endl;
mod_meta_db = new ModMetadataDatabaseSQLite3(test_dir);
mod_meta_provider = new FixedProvider(mod_meta_db);
runTestsForCurrentDB();
delete mod_meta_db;
delete mod_meta_provider;
// reset database
fs::DeleteSingleFileOrEmptyDirectory(test_dir + DIR_DELIM + "mod_storage.sqlite");
rawstream << "-------- SQLite3 database (new objects)" << std::endl;
mod_meta_provider = new SQLite3Provider(test_dir);
runTestsForCurrentDB();
delete mod_meta_provider;
}
////////////////////////////////////////////////////////////////////////////////
void TestModMetadataDatabase::runTestsForCurrentDB()
{
TEST(testRecallFail);
TEST(testCreate);
TEST(testRecall);
TEST(testChange);
TEST(testRecallChanged);
TEST(testListMods);
TEST(testRemove);
TEST(testRecallFail);
}
void TestModMetadataDatabase::testRecallFail()
{
ModMetadataDatabase *mod_meta_db = mod_meta_provider->getModMetadataDatabase();
StringMap recalled;
mod_meta_db->getModEntries("mod1", &recalled);
UASSERT(recalled.empty());
}
void TestModMetadataDatabase::testCreate()
{
ModMetadataDatabase *mod_meta_db = mod_meta_provider->getModMetadataDatabase();
StringMap recalled;
UASSERT(mod_meta_db->setModEntry("mod1", "key1", "value1"));
}
void TestModMetadataDatabase::testRecall()
{
ModMetadataDatabase *mod_meta_db = mod_meta_provider->getModMetadataDatabase();
StringMap recalled;
mod_meta_db->getModEntries("mod1", &recalled);
UASSERT(recalled.size() == 1);
UASSERT(recalled["key1"] == "value1");
}
void TestModMetadataDatabase::testChange()
{
ModMetadataDatabase *mod_meta_db = mod_meta_provider->getModMetadataDatabase();
StringMap recalled;
UASSERT(mod_meta_db->setModEntry("mod1", "key1", "value2"));
}
void TestModMetadataDatabase::testRecallChanged()
{
ModMetadataDatabase *mod_meta_db = mod_meta_provider->getModMetadataDatabase();
StringMap recalled;
mod_meta_db->getModEntries("mod1", &recalled);
UASSERT(recalled.size() == 1);
UASSERT(recalled["key1"] == "value2");
}
void TestModMetadataDatabase::testListMods()
{
ModMetadataDatabase *mod_meta_db = mod_meta_provider->getModMetadataDatabase();
UASSERT(mod_meta_db->setModEntry("mod2", "key1", "value1"));
std::vector<std::string> mod_list;
mod_meta_db->listMods(&mod_list);
UASSERT(mod_list.size() == 2);
UASSERT(std::find(mod_list.cbegin(), mod_list.cend(), "mod1") != mod_list.cend());
UASSERT(std::find(mod_list.cbegin(), mod_list.cend(), "mod2") != mod_list.cend());
}
void TestModMetadataDatabase::testRemove()
{
ModMetadataDatabase *mod_meta_db = mod_meta_provider->getModMetadataDatabase();
UASSERT(mod_meta_db->removeModEntry("mod1", "key1"));
}