#include "PgTestEnvironment.h" #include #include #include #include #include #include "Pgsql_Connection.h" #include "Pgsql_Result.h" namespace pgtest { namespace { bool g_available = false; int g_versionNum = 0; const char *kPlainRolePassword = "pglab_plain_test"; } // namespace std::optional baseUrl() { QByteArray v = qgetenv("TEST_DATABASE_URL"); if (v.isEmpty()) return std::nullopt; return QString::fromUtf8(v); } QString urlForDb(const QString &db) { auto base = baseUrl(); if (!base) throw std::runtime_error("TEST_DATABASE_URL is not set"); QUrl url(*base); url.setPath("/" + db); return url.toString(); } bool available() { return g_available; } int serverVersionNum() { return g_versionNum; } qint64 processId() { return QCoreApplication::applicationPid(); } QString templateDbName() { return QString("tmpl_%1").arg(processId()); } QString plainRoleName() { return QString("tst_%1").arg(processId()); } QString urlForDbAsPlainRole(const QString &db) { auto base = baseUrl(); if (!base) throw std::runtime_error("TEST_DATABASE_URL is not set"); QUrl url(*base); url.setPath("/" + db); url.setUserName(plainRoleName()); url.setPassword(QString::fromUtf8(kPlainRolePassword)); return url.toString(); } QString quoteIdent(const QString &name) { QString r = name; r.replace('"', "\"\""); return "\"" + r + "\""; } void PgEnv::SetUp() { auto base = baseUrl(); if (!base) { std::cerr << "TEST_DATABASE_URL not set, integration tests will be skipped\n"; return; } const QString tmpl = templateDbName(); try { { Pgsql::Connection admin; admin.connect(*base); Pgsql::Result r = admin.query("SHOW server_version_num"); if (!r || r.rows() != 1) throw std::runtime_error("could not query server_version_num"); g_versionNum = QString::fromUtf8(r.val(0, 0)).toInt(); admin.query(QString("DROP DATABASE IF EXISTS %1 WITH (FORCE)").arg(quoteIdent(tmpl))); admin.query(QString("CREATE DATABASE %1").arg(quoteIdent(tmpl))); admin.query(QString("DROP ROLE IF EXISTS %1").arg(quoteIdent(plainRoleName()))); admin.query(QString("CREATE ROLE %1 LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE PASSWORD '%2'") .arg(quoteIdent(plainRoleName()), QString::fromUtf8(kPlainRolePassword))); } { QFile f(fixtureDir_ + "/schema.sql"); if (!f.open(QIODevice::ReadOnly)) throw std::runtime_error("cannot open " + f.fileName().toStdString()); QByteArray sql = f.readAll(); Pgsql::Connection c; c.connect(urlForDb(tmpl)); c.query(sql.constData()); } g_available = true; } catch (const std::exception &e) { ADD_FAILURE() << "Setting up template database failed: " << e.what(); try { Pgsql::Connection admin; admin.connect(*base); admin.query(QString("DROP DATABASE IF EXISTS %1 WITH (FORCE)").arg(quoteIdent(tmpl))); admin.query(QString("DROP ROLE IF EXISTS %1").arg(quoteIdent(plainRoleName()))); } catch (const std::exception &) { } } } void PgEnv::TearDown() { if (!g_available) return; try { Pgsql::Connection admin; admin.connect(*baseUrl()); admin.query(QString("DROP DATABASE IF EXISTS %1 WITH (FORCE)").arg(quoteIdent(templateDbName()))); admin.query(QString("DROP ROLE IF EXISTS %1").arg(quoteIdent(plainRoleName()))); } catch (const std::exception &e) { ADD_FAILURE() << "Dropping template database or plain role failed: " << e.what(); } g_available = false; } } // namespace pgtest