Add framework for executing tests against multiple postgresql versions using docker compose.

This commit is contained in:
eelke 2026-10-18 12:09:54 +02:00
parent 655c6fceb1
commit c3bf9e88e4
13 changed files with 457 additions and 0 deletions

View file

@ -0,0 +1,125 @@
#include "PgTestEnvironment.h"
#include <QCoreApplication>
#include <QFile>
#include <QUrl>
#include <iostream>
#include <stdexcept>
#include "Pgsql_Connection.h"
#include "Pgsql_Result.h"
namespace pgtest {
namespace {
bool g_available = false;
int g_versionNum = 0;
} // namespace
std::optional<QString> 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 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)));
}
{
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)));
}
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())));
}
catch (const std::exception &e) {
ADD_FAILURE() << "Dropping template database failed: " << e.what();
}
g_available = false;
}
} // namespace pgtest