milestone 18: collapse duplicated infrastructure into shared listener core, crud list helper, resource shells, transport race, name and line helpers, ui modules
This commit is contained in:
+49
-4
@@ -757,9 +757,15 @@ fn checkFile(r: Runner, arena: Allocator, path: []const u8, probe: bool) !u8 {
|
||||
const cfg = std.zon.parse.fromSliceAlloc(model.Config, arena, source, &zon_diag, .{}) catch |e| switch (e) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
// The rendering carries the line and column, which is the whole value of
|
||||
// running `check` against a file the operator just edited.
|
||||
// running `check` against a file the operator just edited. It is
|
||||
// multi-line, and `check` promises one line per problem, so it goes
|
||||
// through the same `Diagnostics` channel `nxdns import` uses rather than
|
||||
// into one `FAIL` record with newlines inside it.
|
||||
error.ParseZon => {
|
||||
try r.out.print("FAIL {s}: {f}\n", .{ path, &zon_diag });
|
||||
var diags: validate.Diagnostics = .init(r.gpa);
|
||||
defer diags.deinit();
|
||||
try import.reportParseFailure(&diags, &zon_diag);
|
||||
try diags.writeAll(r.out);
|
||||
return exit_check;
|
||||
},
|
||||
};
|
||||
@@ -917,8 +923,10 @@ fn probeUpstreams(r: Runner, cfg: model.Config) !usize {
|
||||
const tls_buffers = try r.gpa.alloc(u8, 4 * chunk);
|
||||
defer r.gpa.free(tls_buffers);
|
||||
|
||||
var request_buf: [1024]u8 = undefined;
|
||||
var transfer_buf: [4096]u8 = undefined;
|
||||
// The same sizes `nxdns run` serves with, so the probe reports on the
|
||||
// buffers the server will actually use.
|
||||
var request_buf: [doh_client.default_request_buf_len]u8 = undefined;
|
||||
var transfer_buf: [doh_client.default_transfer_buf_len]u8 = undefined;
|
||||
const response_buf = try r.gpa.alloc(u8, transport.max_message_len);
|
||||
defer r.gpa.free(response_buf);
|
||||
|
||||
@@ -1461,6 +1469,43 @@ test "check --config naming a missing file is a reported failure at exit 2" {
|
||||
try testing.expectEqualStrings("", captured.err.written());
|
||||
}
|
||||
|
||||
test "check renders a multi-line ZON failure as one FAIL line per message" {
|
||||
// The rendering used to go inline into a single `FAIL` record, which put
|
||||
// newlines mid-line and broke the one-line-per-problem promise the rest of
|
||||
// `check` keeps.
|
||||
var env: CheckEnv = undefined;
|
||||
try env.init();
|
||||
defer env.deinit();
|
||||
|
||||
var captured: Captured = .init(testing.allocator);
|
||||
defer captured.deinit();
|
||||
const r = captured.runner();
|
||||
|
||||
// An unexpected field renders as an "error:" line and a "note:" line.
|
||||
try env.tmp.dir.writeFile(r.io, .{ .sub_path = "config.zon", .data = ".{ .grops = .{} }\n" });
|
||||
var path_buf: [160]u8 = undefined;
|
||||
const config_path = try env.path(&path_buf, "config.zon");
|
||||
|
||||
const code = runCheck(r, .{
|
||||
.paths = .{ .config = config_path },
|
||||
.config_explicit = true,
|
||||
}, false);
|
||||
try testing.expectEqual(exit_check, code);
|
||||
|
||||
const text = captured.out.written();
|
||||
var lines = std.mem.splitScalar(u8, std.mem.trimEnd(u8, text, "\n"), '\n');
|
||||
// The first line names what was checked; every line after it is a problem.
|
||||
try testing.expect(std.mem.startsWith(u8, lines.next().?, "checking configuration file "));
|
||||
var failures: usize = 0;
|
||||
while (lines.next()) |line| {
|
||||
try testing.expect(std.mem.startsWith(u8, line, "FAIL config: "));
|
||||
failures += 1;
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 2), failures);
|
||||
try testing.expect(std.mem.containsAtLeast(u8, text, 1, "error: unexpected field 'grops'"));
|
||||
try testing.expect(std.mem.containsAtLeast(u8, text, 1, "note: supported: "));
|
||||
}
|
||||
|
||||
test "check reads config.db without writing to it" {
|
||||
// D6: the database branch opened read/write, chmod'ed 0600, turned WAL on —
|
||||
// which is what creates the two sidecars — and committed migration steps,
|
||||
|
||||
Reference in New Issue
Block a user