Full C++23 framework tree: runtime, observability, security, data, app, realtime, supervisor, clients, CLI, example plus enterprise tenancy, audit, operability, governance, supplychain. Postgres via docker compose for tests.
95 lines
3.0 KiB
C++
95 lines
3.0 KiB
C++
// orm_hook: Model save()/remove() reach the audit Appender through the
|
|
// PATCHES section 2 hook. Without an installed Appender the hook no-ops;
|
|
// with one installed, insert/update/delete append self-describing records.
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "audit/log/appender.h"
|
|
#include "audit/log/store.h"
|
|
#include "data/orm/model.hpp"
|
|
|
|
#define CHECK(c, msg) \
|
|
if (!(c)) { \
|
|
std::cerr << "FAIL orm_hook: " << msg << "\n"; \
|
|
return 1; \
|
|
}
|
|
|
|
namespace {
|
|
|
|
using molo::data::orm::FieldDef;
|
|
using molo::data::orm::Model;
|
|
|
|
struct Item : public Model<Item> {
|
|
static std::string table_name() { return "items"; }
|
|
static std::string primary_key() { return "id"; }
|
|
static std::vector<FieldDef> fields() {
|
|
return {FieldDef::primary_key("id"), FieldDef::text("name")};
|
|
}
|
|
};
|
|
|
|
class FakeConn : public molo::data::Connection {
|
|
public:
|
|
molo::data::Backend backend() const override { return molo::data::Backend::Sqlite; }
|
|
std::string backend_id() const override { return "fake"; }
|
|
molo::data::Result exec(const molo::data::Context&,
|
|
const molo::data::BoundStatement&) override {
|
|
return molo::data::Result::command(0);
|
|
}
|
|
molo::data::Prepared prepare(const molo::data::Context&,
|
|
const molo::data::BoundStatement&) override {
|
|
return {};
|
|
}
|
|
molo::data::Result exec_prepared(const molo::data::Context&, const molo::data::Prepared&,
|
|
const std::vector<molo::data::Value>&) override {
|
|
return molo::data::Result::command(0);
|
|
}
|
|
void ping(const molo::data::Context&) override {}
|
|
void close() override {}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
int main() {
|
|
using namespace molo::audit::log;
|
|
FakeConn conn;
|
|
molo::data::Context ctx("req-1", "t1", 30);
|
|
|
|
// Without an installed Appender the hook no-ops (no crash, no store).
|
|
{
|
|
Item it;
|
|
it.set("id", molo::data::make_int(7));
|
|
it.set("name", molo::data::make_text("n1"));
|
|
it.save(conn, ctx);
|
|
it.set("name", molo::data::make_text("n2"));
|
|
it.save(conn, ctx);
|
|
it.remove(conn, ctx);
|
|
}
|
|
|
|
MemoryStore store;
|
|
Appender app(store);
|
|
Appender::Install(&app);
|
|
{
|
|
Item it;
|
|
it.set("id", molo::data::make_int(7));
|
|
it.set("name", molo::data::make_text("n1"));
|
|
it.save(conn, ctx);
|
|
it.set("name", molo::data::make_text("n2"));
|
|
it.save(conn, ctx);
|
|
it.remove(conn, ctx);
|
|
}
|
|
Appender::Install(nullptr);
|
|
|
|
auto rows = store.ReadRange(1, 10);
|
|
CHECK(rows.size() == 3, "three hook records");
|
|
CHECK(rows[0].op == "insert" && rows[0].table == "items" && rows[0].pk == "7",
|
|
"insert record shape");
|
|
CHECK(rows[0].tenant == "t1" && rows[0].request_id == "req-1", "context carried");
|
|
CHECK(rows[0].after_json.find("n1") != std::string::npos, "insert after image");
|
|
CHECK(rows[1].op == "update", "update op");
|
|
CHECK(rows[2].op == "delete" && rows[2].after_json.empty(), "delete op");
|
|
CHECK(rows[2].before_json.find("n2") != std::string::npos, "delete before image");
|
|
std::cout << "PASS orm_hook\n";
|
|
return 0;
|
|
}
|