eedb/tests/utils/DbTestBase.hpp
2018-02-07 12:27:49 +01:00

129 lines
3.7 KiB
C++

#include <gtest/gtest.h>
#include <eedb/db/RawSql.hpp>
#include <eedb/db/config.hpp>
#include <eedb/db/connection.hpp>
#include <sqlpp11/postgresql/exception.h>
#include <boost/process.hpp>
#include <nlohmann/json.hpp>
#include <thread>
class DockerRunner {
enum class Status { Running, Exited, Missing };
public:
DockerRunner(std::string name) : _name{std::move(name)} {
using namespace boost::process;
auto getStatus = [this]() {
ipstream is; // reading pipe-stream
auto status = system(search_path("docker"), "inspect", _name, std_out > is);
if(!status) {
std::string statusBuf, line;
statusBuf.reserve(10240);
while(std::getline(is, line) && !line.empty())
statusBuf.append(line);
auto status = nlohmann::json::parse(std::move(statusBuf))[0]["State"]["Status"];
if(status == "running") {
return Status::Running;
} else if(status == "exited") {
return Status::Exited;
}
}
return Status::Missing;
};
auto status = getStatus();
if(status == Status::Exited) {
system(search_path("docker"), "start", _name);
} else if(status == Status::Missing) {
system(search_path("docker"),
"run --detach",
"--name",
_name,
"-p 5432:5432",
"-e POSTGRES_PASSWORD=postgres",
"-e POSTGRES_DB=eedb",
"postgres:9.5-alpine");
}
}
~DockerRunner() {
// using namespace boost::process;
// auto p = search_path("docker");
// system(p, "stop", _name);
// system(p, "rm", "-v", _name);
}
private:
std::string _name;
};
class PgTestDatabasePrepare {
public:
PgTestDatabasePrepare() {
_docker = std::make_unique< DockerRunner >("eedb_test_database");
auto dbConfig = std::make_shared< eedb::db::PgConfig >();
dbConfig->host = "localhost";
dbConfig->port = 5432;
dbConfig->password = "postgres";
dbConfig->user = "postgres";
dbConfig->dbname = "eedb";
dbConfig->debug = false;
bool conOk{false};
int faild_attempts_count{0};
do {
try {
_db = std::make_unique< eedb::db::PgConnection >(dbConfig);
conOk = true;
} catch(sqlpp::postgresql::broken_connection &) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
faild_attempts_count++;
}
} while(!conOk && faild_attempts_count < 30);
if(faild_attempts_count >= 30)
std::terminate();
}
eedb::db::PgConnection & db() {
if(!_db)
throw std::runtime_error("db not initialized");
return *_db;
}
private:
std::unique_ptr< DockerRunner > _docker;
std::unique_ptr< eedb::db::PgConnection > _db;
};
template < typename T >
class DbTestBase : public testing::Test {
public:
static void SetUpTestCase() {
_test_db = std::make_unique< PgTestDatabasePrepare >();
_test_db->db().native()->start_transaction();
_test_db->db().native()->execute("SET synchronous_commit=off;");
eedb::db::exec_file(_test_db->db(), "/home/bwieczor/src/eedb/sql/schema.sql");
_test_db->db().native()->commit_transaction();
}
static void TearDownTestCase() {
_test_db.reset();
}
eedb::db::PgConnection & db() {
return _test_db->db();
}
protected:
static std::unique_ptr< PgTestDatabasePrepare > _test_db;
};