21#include <gtest/gtest.h>
47 :
public backend_base<test_backend, database_types::sqlite>
50 static constexpr const char* backend_name() {
return "test_backend"; }
52 kcenon::common::Result<database_result> select_query(
const std::string&)
override
57 kcenon::common::VoidResult execute_query(
const std::string&)
override
59 return kcenon::common::ok();
62 kcenon::common::VoidResult begin_transaction()
override
64 return kcenon::common::ok();
67 kcenon::common::VoidResult commit_transaction()
override
69 return kcenon::common::ok();
72 kcenon::common::VoidResult rollback_transaction()
override
74 return kcenon::common::ok();
77 bool in_transaction()
const override {
return false; }
78 std::string last_error()
const override {
return ""; }
79 std::map<std::string, std::string> connection_info()
const override {
return {}; }
84 kcenon::common::VoidResult do_initialize(const connection_config&)
86 return kcenon::common::ok();
89 kcenon::common::VoidResult do_shutdown()
91 return kcenon::common::ok();
99 :
public backend_base<test_backend_alt, database_types::postgres>
102 static constexpr const char* backend_name() {
return "test_backend_alt"; }
104 kcenon::common::Result<database_result> select_query(
const std::string&)
override
109 kcenon::common::VoidResult execute_query(
const std::string&)
override
111 return kcenon::common::ok();
114 kcenon::common::VoidResult begin_transaction()
override
116 return kcenon::common::ok();
119 kcenon::common::VoidResult commit_transaction()
override
121 return kcenon::common::ok();
124 kcenon::common::VoidResult rollback_transaction()
override
126 return kcenon::common::ok();
129 bool in_transaction()
const override {
return false; }
130 std::string last_error()
const override {
return ""; }
131 std::map<std::string, std::string> connection_info()
const override {
return {}; }
136 kcenon::common::VoidResult do_initialize(const connection_config&)
138 return kcenon::common::ok();
141 kcenon::common::VoidResult do_shutdown()
143 return kcenon::common::ok();
174 "test", &test_backend::create);
175 EXPECT_TRUE(result.is_ok());
181 .register_backend(
"test1", &test_backend::create).is_ok());
183 .register_backend(
"test2", &test_backend_alt::create).is_ok());
190 .register_backend(
"test", &test_backend::create).is_ok());
193 EXPECT_FALSE(result.is_ok());
200 EXPECT_TRUE(result.is_ok());
207 EXPECT_FALSE(result.is_ok());
218 ASSERT_NE(backend,
nullptr);
219 EXPECT_EQ(backend->type(), database_types::sqlite);
225 EXPECT_EQ(backend,
nullptr);
233 ASSERT_NE(b1,
nullptr);
234 ASSERT_NE(b2,
nullptr);
235 EXPECT_NE(b1.get(), b2.get());
242 ASSERT_NE(backend,
nullptr);
243 EXPECT_FALSE(backend->is_initialized());
267 EXPECT_EQ(backends.size(), 2u);
268 EXPECT_TRUE(std::find(backends.begin(), backends.end(),
"alpha") != backends.end());
269 EXPECT_TRUE(std::find(backends.begin(), backends.end(),
"beta") != backends.end());
309 "test", &test_backend::create);
310 EXPECT_TRUE(result.is_ok());
322 ASSERT_NE(backend,
nullptr);
323 EXPECT_EQ(backend->type(), database_types::sqlite);
337 EXPECT_EQ(backends.size(), 1u);
338 EXPECT_EQ(backends[0],
"x");
347 constexpr int num_threads = 10;
348 std::atomic<int> success_count{0};
349 std::vector<std::thread> threads;
351 for (
int i = 0; i < num_threads; ++i) {
352 threads.emplace_back([i, &success_count]() {
354 "backend_" + std::to_string(i), &test_backend::create);
355 if (result.is_ok()) {
361 for (
auto& t : threads) {
365 EXPECT_EQ(success_count.load(), num_threads);
367 static_cast<size_t>(num_threads));
374 constexpr int num_threads = 20;
375 std::atomic<int> success_count{0};
376 std::vector<std::thread> threads;
378 for (
int i = 0; i < num_threads; ++i) {
379 threads.emplace_back([&success_count]() {
381 if (backend !=
nullptr) {
387 for (
auto& t : threads) {
391 EXPECT_EQ(success_count.load(), num_threads);
396 constexpr int num_threads = 10;
397 std::vector<std::thread> threads;
400 for (
int i = 0; i < num_threads; ++i) {
401 threads.emplace_back([i]() {
403 "backend_" + std::to_string(i), &test_backend::create);
408 for (
int i = 0; i < num_threads; ++i) {
409 threads.emplace_back([]() {
416 for (
auto& t : threads) {
422 static_cast<size_t>(num_threads));
432 "", &test_backend::create);
435 if (result.is_ok()) {
445 "test", &test_backend_alt::create);
446 EXPECT_TRUE(result.is_ok());
449 ASSERT_NE(backend,
nullptr);
451 EXPECT_EQ(backend->type(), database_types::postgres);
458 EXPECT_EQ(&instance1, &instance2);
463 ::testing::InitGoogleTest(&argc, argv);
464 return RUN_ALL_TESTS();
CRTP template base class for database backends.
Registry for database backend plugins.
TEST_F(BackendRegistryTest, RegisterBackendSucceeds)
CRTP template base class for database backends.
std::vector< std::string > available_backends() const
Get list of all registered backend names.
void clear()
Clear all registered backends (for testing)
kcenon::common::VoidResult unregister_backend(const std::string &name)
Unregister a backend (for testing or dynamic unloading)
static backend_registry & instance()
Get the singleton instance.
std::unique_ptr< database_backend > create(const std::string &name) const
Create a backend instance by name.
kcenon::common::VoidResult register_backend(const std::string &name, backend_factory_fn factory)
Register a backend factory function.
size_t backend_count() const
Get number of registered backends.
Abstract interface for database backends.
std::unique_ptr< database_backend > create_backend(const std::string &name)
Convenience function for creating backends (static method style)
std::vector< database_row > database_result
bool has_backend(const std::string &name)
Convenience function for checking backend availability.
std::vector< std::string > available_backends()
Convenience function for getting available backends.
database_types
Represents various database backends or modes.
@ sqlite
Indicates a SQLite database.
@ postgres
Indicates a PostgreSQL database.