feat(sql): the database helper and the TOTP helper, as subcommands
`crafter-review sql` hands the SQL to the driver's broker named in REVIEW_GATES_DB; the broker runs it as one transaction, rolled back, and streams the lines back with the exit code last. The client speaks protocol 3.0 over Crafter.Network's TCP client: cleartext, MD5 and SCRAM-SHA-256, one Parse per statement, the transaction status as the backstop. The splitter, the refusals, the table layout and every message work on code points; connect and socket errors read "[Errno 111] Connection refused" or "timed out". `crafter-review totp` prints "123456 (valid 17s)". No sleep after the last connect attempt; TOTP reads the clock once; a broker token that is no string gets the NO DATABASE answer and the exit mark. The goldens add the splitter, the comment stripping, the fingerprint, the refusals, the first words, the headline, the cell, table, error and notice layouts, the run's refusals and limits and 40 TOTP codes (2774 checks now). tests/PgWire runs the helper over a Postgres stand-in and compares its output with the goldens, line for line, plus the broker's protocol. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
61acd6a72e
commit
e8a58f893f
10 changed files with 3666 additions and 3 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -410,6 +410,60 @@ namespace {
|
|||
for (const Json& entry : c.at("redact")) Same(PgWire::Redact(entry.at(0).get<std::string>()), entry.at(1).get<std::string>(), std::format("redact {}", entry.at(0).get<std::string>()));
|
||||
for (const Json& entry : c.at("where")) Same(PgWire::Where(entry.at(0).get<std::string>()), entry.at(1).get<std::string>(), std::format("where {}", entry.at(0).get<std::string>()));
|
||||
}
|
||||
|
||||
PgWire::Fields FieldsOf(const Json& dict) {
|
||||
PgWire::Fields out;
|
||||
for (auto it = dict.begin(); it != dict.end(); ++it) out[it.key().at(0)] = it.value().get<std::string>();
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::optional<std::string>>> RowsOf(const Json& rows) {
|
||||
std::vector<std::vector<std::optional<std::string>>> out;
|
||||
for (const Json& row : rows) {
|
||||
std::vector<std::optional<std::string>> cells;
|
||||
for (const Json& cell : row) cells.push_back(OptionalString(cell));
|
||||
out.push_back(std::move(cells));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void CheckPgWire(const Json& g) {
|
||||
const Json& p = g.at("pgwire");
|
||||
for (const Json& entry : p.at("split")) SameJson(ToJson(PgWire::SplitStatements(entry.at(0).get<std::string>())), entry.at(1), std::format("split_statements {}", Dyn::Repr(entry.at(0).get<std::string>())));
|
||||
for (const Json& entry : p.at("stripComments")) Same(PgWire::StripComments(entry.at(0).get<std::string>()), entry.at(1).get<std::string>(), std::format("strip_comments {}", Dyn::Repr(entry.at(0).get<std::string>())));
|
||||
for (const Json& entry : p.at("fingerprint")) Same(PgWire::Fingerprint(entry.at(0).get<std::string>()), entry.at(1).get<std::string>(), std::format("fingerprint {}", Dyn::Repr(entry.at(0).get<std::string>())));
|
||||
for (const Json& entry : p.at("refused")) SameJson(Optional(PgWire::Refused(entry.at(0).get<std::string>())), entry.at(1), std::format("refused {}", Dyn::Repr(entry.at(0).get<std::string>())));
|
||||
for (const Json& entry : p.at("firstWords")) SameJson(ToJson(PgWire::FirstWords(entry.at(0).get<std::string>(), 4)), entry.at(1), std::format("first_words {}", Dyn::Repr(entry.at(0).get<std::string>())));
|
||||
for (const Json& entry : p.at("headline")) Same(PgWire::Headline(entry.at(0).get<std::string>()), entry.at(1).get<std::string>(), std::format("headline {}", Dyn::Repr(entry.at(0).get<std::string>())));
|
||||
for (const Json& entry : p.at("cell")) Same(PgWire::Cell(OptionalString(entry.at(0))), entry.at(1).get<std::string>(), std::format("_cell {}", DumpCompactSorted(entry.at(0))));
|
||||
for (const Json& entry : p.at("table")) Same(PgWire::Table(Strings(entry.at(0)), RowsOf(entry.at(1))), entry.at(2).get<std::string>(), std::format("table {}", DumpCompactSorted(entry.at(0))));
|
||||
for (const Json& entry : p.at("errorText")) {
|
||||
Same(PgWire::ErrorText(FieldsOf(entry.at(0)), OptionalString(entry.at(1)).value_or("")), entry.at(2).get<std::string>(), std::format("error_text {}", DumpCompactSorted(entry.at(0))));
|
||||
}
|
||||
for (const Json& entry : p.at("noticeText")) Same(PgWire::NoticeText(FieldsOf(entry.at(0))), entry.at(1).get<std::string>(), std::format("notice_text {}", DumpCompactSorted(entry.at(0))));
|
||||
for (const Json& entry : p.at("runs")) {
|
||||
if (!entry.contains("noServer")) continue;
|
||||
std::string sql;
|
||||
if (entry.at("sql").is_object()) {
|
||||
const std::string unit = entry.at("sql").at("repeat").get<std::string>();
|
||||
const auto length = entry.at("sql").at("length").get<std::size_t>();
|
||||
while (sql.size() < length) sql += unit;
|
||||
sql.resize(length);
|
||||
} else {
|
||||
sql = entry.at("sql").get<std::string>();
|
||||
}
|
||||
std::vector<std::string> lines;
|
||||
const std::int32_t code = PgWire::RunSql("postgresql://u:pw@127.0.0.1:1/db", sql, [&](const std::string& line) { lines.push_back(line); });
|
||||
SameJson(Json::array({code, ToJson(lines)}), Json::array({entry.at("code"), entry.at("out")}), std::format("run (no server) {}", Dyn::Repr(Dyn::Slice(sql, 0, 40))));
|
||||
}
|
||||
std::vector<std::string> hosted;
|
||||
const std::int32_t code = PgWire::RunSql("postgresql://u@db.x.supabase.co/x", "select 1", [&](const std::string& line) { hosted.push_back(line); });
|
||||
SameJson(Json::array({code, ToJson(hosted)}), p.at("hosted"), "run (a hosted database)");
|
||||
for (const Json& entry : p.at("totp")) {
|
||||
const Totp::Code got = Totp::At(entry.at(0).get<std::string>(), entry.at(1).get<double>());
|
||||
SameJson(Json::array({got.code, got.left}), entry.at(2), std::format("totp {} at {}", entry.at(0).get<std::string>(), Dyn::ReprValue(entry.at(1))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
|
@ -425,6 +479,7 @@ int main() {
|
|||
CheckStream(g);
|
||||
CheckState(g);
|
||||
CheckConfig(g);
|
||||
CheckPgWire(g);
|
||||
std::println("{} checks against the goldens", Checks);
|
||||
if (Failures) std::println(std::cerr, "{} failed", Failures);
|
||||
return Failures ? 1 : 0;
|
||||
|
|
|
|||
Loading…
Reference in a new issue