mono/packages/kbot/cpp/tests/e2e/test_gridsearch_ipc.cpp

145 lines
4.8 KiB
C++

#include <catch2/catch_test_macros.hpp>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include "../../src/cmd_gridsearch.h"
#include "logger/logger.h"
// ── Helpers ──────────────────────────────────────────────────────────────────
static std::string read_file_contents(const std::string &path) {
std::ifstream f(path);
if (!f.is_open())
return "";
std::stringstream ss;
ss << f.rdbuf();
return ss.str();
}
/// Read a JSON config file and inject test-safe overrides:
/// - configPath = "config/postgres.toml"
/// - enrich = false (no live HTTP / thread-pool in tests)
/// - persistencePostgres = false
static std::string load_test_payload(const std::string &config_path) {
std::string raw = read_file_contents(config_path);
if (raw.empty())
return "";
rapidjson::Document doc;
doc.Parse(raw.c_str());
if (doc.HasParseError())
return "";
auto &alloc = doc.GetAllocator();
// Remove-then-add ensures no double-add assertion from rapidjson
auto inject_bool = [&](const char *key, bool val) {
if (doc.HasMember(key))
doc.RemoveMember(key);
doc.AddMember(rapidjson::Value(key, alloc), rapidjson::Value(val), alloc);
};
auto inject_str = [&](const char *key, const char *val) {
if (doc.HasMember(key))
doc.RemoveMember(key);
doc.AddMember(rapidjson::Value(key, alloc), rapidjson::Value(val, alloc),
alloc);
};
inject_str("configPath", "config/postgres.toml");
inject_str("cacheDir", "../../packages/gadm/cache/gadm"); // server/cache/gadm
inject_bool("enrich", false); // no live enrichment in tests
inject_bool("persistencePostgres", false);
rapidjson::StringBuffer buf;
rapidjson::Writer<rapidjson::StringBuffer> writer(buf);
doc.Accept(writer);
return buf.GetString();
}
// ── Tests
// ─────────────────────────────────────────────────────────────────────
TEST_CASE("E2E: Gridsearch Country Boundary Filter (Lamu/KEN)",
"[e2e][gridsearch][boundary]") {
REQUIRE_NOTHROW(logger::init("test-gridsearch"));
// Lamu, Kenya — SerpAPI often returns US results for obscure African regions.
// boundary_KEN_0.json should filter them out.
std::string payload = load_test_payload("config/gridsearch-lamu.json");
REQUIRE(!payload.empty());
std::vector<std::string> location_events;
int error_count = 0;
polymech::GridsearchCallbacks cb;
cb.onEvent = [&](const std::string &type, const std::string &json) {
if (type == "location") {
location_events.push_back(json);
} else if (type == "error") {
error_count++;
std::cout << "[ERROR EVENT]: " << json << "\n";
}
};
int result =
polymech::run_cmd_gridsearch_ipc(payload, "test-lamu-job", cb, false, "");
REQUIRE(result == 0);
REQUIRE(error_count == 0);
// All returned locations must be within Kenya (no USA coords).
// Verify: no location has lng < -30 (Americas) or lng > 60 (not Africa/Asia)
// and lat outside [-5, 5] for Lamu county bounds.
int outside_kenya = 0;
for (const auto &loc_json : location_events) {
rapidjson::Document loc;
loc.Parse(loc_json.c_str());
if (loc.HasParseError())
continue;
if (loc.HasMember("gps") && loc["gps"].IsObject()) {
double lng =
loc["gps"].HasMember("lng") ? loc["gps"]["lng"].GetDouble() : 0;
// Kenya longitude range: ~34..42; USA is roughly -130..-60
if (lng < 20.0 || lng > 55.0)
outside_kenya++;
}
}
CHECK(outside_kenya == 0);
std::cout << "Lamu boundary test: " << location_events.size()
<< " locations kept, " << outside_kenya << " outside Kenya.\n";
}
TEST_CASE("E2E: Gridsearch Type Filter (Sample/ABW)",
"[e2e][gridsearch][filter]") {
std::string payload = load_test_payload("config/gridsearch-sample.json");
REQUIRE(!payload.empty());
std::vector<std::string> location_events;
int error_count = 0;
polymech::GridsearchCallbacks cb;
cb.onEvent = [&](const std::string &type, const std::string &json) {
if (type == "location")
location_events.push_back(json);
else if (type == "error")
error_count++;
};
int result = polymech::run_cmd_gridsearch_ipc(payload, "test-sample-job", cb,
false, "");
REQUIRE(result == 0);
REQUIRE(error_count == 0);
std::cout << "Sample (ABW) type filter test: " << location_events.size()
<< " locations.\n";
}