Files
moloapp/tests/src/audit/orm_hook.cpp
T

95 lines
3.0 KiB
C++
Raw Normal View History

// 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;
}