tests: add snapshot round-trip test using Orchestrator::saveSnapshot/loadSnapshot; Orchestrator reuses a DAL handle so stub mode persists within instance
This commit is contained in:
parent
c36ef7e46b
commit
d5226fe7d6
|
|
@ -71,6 +71,19 @@ Orchestrator::Orchestrator(QObject *parent)
|
||||||
connect(&timer_, &QTimer::timeout, this, &Orchestrator::processPendingTasks);
|
connect(&timer_, &QTimer::timeout, this, &Orchestrator::processPendingTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Orchestrator::~Orchestrator() {
|
||||||
|
delete dal_;
|
||||||
|
}
|
||||||
|
|
||||||
|
ki::PgDal& Orchestrator::dal() {
|
||||||
|
if (!dal_) {
|
||||||
|
dal_ = new ki::PgDal();
|
||||||
|
const QByteArray dsn = qgetenv("PG_DSN");
|
||||||
|
if (!dsn.isEmpty()) dal_->connect(dsn.toStdString()); else dal_->connect("stub://memory");
|
||||||
|
}
|
||||||
|
return *dal_;
|
||||||
|
}
|
||||||
|
|
||||||
void Orchestrator::start(int intervalMs) {
|
void Orchestrator::start(int intervalMs) {
|
||||||
ensureResolvedDirs();
|
ensureResolvedDirs();
|
||||||
continuityHandshakeOnce();
|
continuityHandshakeOnce();
|
||||||
|
|
@ -178,11 +191,7 @@ bool Orchestrator::saveSnapshot(const QString &nameSpace,
|
||||||
const QJsonObject &content,
|
const QJsonObject &content,
|
||||||
const QStringList &tags)
|
const QStringList &tags)
|
||||||
{
|
{
|
||||||
ki::PgDal dal;
|
auto nsRow = dal().ensureNamespace(nameSpace.toStdString());
|
||||||
const QByteArray dsn = qgetenv("PG_DSN");
|
|
||||||
if (!dsn.isEmpty()) dal.connect(dsn.toStdString()); else dal.connect("stub://memory");
|
|
||||||
|
|
||||||
auto nsRow = dal.ensureNamespace(nameSpace.toStdString());
|
|
||||||
if (!nsRow) return false;
|
if (!nsRow) return false;
|
||||||
|
|
||||||
ki::ItemRow row;
|
ki::ItemRow row;
|
||||||
|
|
@ -194,22 +203,18 @@ bool Orchestrator::saveSnapshot(const QString &nameSpace,
|
||||||
row.metadata_json = "{}";
|
row.metadata_json = "{}";
|
||||||
row.created_at = std::chrono::system_clock::now();
|
row.created_at = std::chrono::system_clock::now();
|
||||||
|
|
||||||
const std::string id = dal.upsertItem(row);
|
const std::string id = dal().upsertItem(row);
|
||||||
return !id.empty();
|
return !id.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QJsonObject> Orchestrator::loadSnapshot(const QString &nameSpace,
|
std::optional<QJsonObject> Orchestrator::loadSnapshot(const QString &nameSpace,
|
||||||
const QString &key)
|
const QString &key)
|
||||||
{
|
{
|
||||||
ki::PgDal dal;
|
auto nsRow = dal().findNamespace(nameSpace.toStdString());
|
||||||
const QByteArray dsn = qgetenv("PG_DSN");
|
|
||||||
if (!dsn.isEmpty()) dal.connect(dsn.toStdString()); else dal.connect("stub://memory");
|
|
||||||
|
|
||||||
auto nsRow = dal.findNamespace(nameSpace.toStdString());
|
|
||||||
if (!nsRow) return std::nullopt;
|
if (!nsRow) return std::nullopt;
|
||||||
|
|
||||||
std::vector<std::string> tags; tags.emplace_back("snapshot");
|
std::vector<std::string> tags; tags.emplace_back("snapshot");
|
||||||
auto rows = dal.fetchContext(nsRow->id, std::optional<std::string>(key.toStdString()), tags, std::nullopt, 1);
|
auto rows = dal().fetchContext(nsRow->id, std::optional<std::string>(key.toStdString()), tags, std::nullopt, 1);
|
||||||
if (rows.empty()) return std::nullopt;
|
if (rows.empty()) return std::nullopt;
|
||||||
const auto &row = rows.front();
|
const auto &row = rows.front();
|
||||||
if (row.content_json.empty()) return std::nullopt;
|
if (row.content_json.empty()) return std::nullopt;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include "kompanion_mw_export.h"
|
#include "kompanion_mw_export.h"
|
||||||
|
|
||||||
|
namespace ki { class PgDal; }
|
||||||
|
|
||||||
// Minimal model provider interface so tests can stub generation.
|
// Minimal model provider interface so tests can stub generation.
|
||||||
class IModelProvider {
|
class IModelProvider {
|
||||||
public:
|
public:
|
||||||
|
|
@ -49,6 +51,7 @@ class KOMPANION_MW_EXPORT Orchestrator : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit Orchestrator(QObject *parent=nullptr);
|
explicit Orchestrator(QObject *parent=nullptr);
|
||||||
|
~Orchestrator();
|
||||||
|
|
||||||
// Injectable model provider (Ollama by default). Ownership left to caller.
|
// Injectable model provider (Ollama by default). Ownership left to caller.
|
||||||
void setModelProvider(IModelProvider *prov) { model_ = prov; }
|
void setModelProvider(IModelProvider *prov) { model_ = prov; }
|
||||||
|
|
@ -104,4 +107,7 @@ private:
|
||||||
QTimer timer_;
|
QTimer timer_;
|
||||||
bool continuityDone_ = false;
|
bool continuityDone_ = false;
|
||||||
IModelProvider *model_ = nullptr; // not owned
|
IModelProvider *model_ = nullptr; // not owned
|
||||||
|
// Reused DB handle so in-memory stub persists across calls in tests.
|
||||||
|
ki::PgDal* dal_ = nullptr;
|
||||||
|
ki::PgDal& dal();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,3 +11,9 @@ qt_add_executable(test_orchestrator
|
||||||
)
|
)
|
||||||
target_link_libraries(test_orchestrator PRIVATE Qt6::Core Qt6::Network Qt6::Test kompanion_mw)
|
target_link_libraries(test_orchestrator PRIVATE Qt6::Core Qt6::Network Qt6::Test kompanion_mw)
|
||||||
add_test(NAME test_orchestrator COMMAND test_orchestrator)
|
add_test(NAME test_orchestrator COMMAND test_orchestrator)
|
||||||
|
|
||||||
|
qt_add_executable(test_snapshot
|
||||||
|
test_snapshot.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(test_snapshot PRIVATE Qt6::Core Qt6::Network Qt6::Test kompanion_mw)
|
||||||
|
add_test(NAME test_snapshot COMMAND test_snapshot)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include <QtTest>
|
||||||
|
#include "../src/middleware/orchestrator.h"
|
||||||
|
|
||||||
|
class SnapshotTest : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
private slots:
|
||||||
|
void round_trip() {
|
||||||
|
// Ensure no PG_DSN is required; Orchestrator maintains a shared in-memory DAL per instance
|
||||||
|
Orchestrator orch;
|
||||||
|
const QString ns = QStringLiteral("tests");
|
||||||
|
const QString key = QStringLiteral("session:last");
|
||||||
|
|
||||||
|
QJsonObject payload{{"a", 1}, {"b", QStringLiteral("x")}};
|
||||||
|
QVERIFY2(orch.saveSnapshot(ns, key, payload), "saveSnapshot should succeed");
|
||||||
|
|
||||||
|
auto loaded = orch.loadSnapshot(ns, key);
|
||||||
|
QVERIFY2(loaded.has_value(), "loadSnapshot should return value");
|
||||||
|
QCOMPARE(loaded->value("a").toInt(), 1);
|
||||||
|
QCOMPARE(loaded->value("b").toString(), QStringLiteral("x"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_MAIN(SnapshotTest)
|
||||||
|
#include "test_snapshot.moc"
|
||||||
|
|
||||||
Loading…
Reference in New Issue