lib/trace/src/store/writer/test.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const sys = @import("sys");
3 const subject = @import("root.zig");
4 const event = @import("../../root.zig").event;
5 const format = @import("../format/root.zig");
6 const capacity_mod = @import("capacity.zig");
7
8 const Limits = subject.Limits;
9 const Storage = subject.Storage;
10 const Writer = subject.Writer;
11
12 test "trace writer state does not embed caller storage" {
13 try std.testing.expect(@sizeOf(Writer) < capacity_mod.default_manifest_io_bytes);
14 }
15
16 test "trace writer capacity rejection preserves existing trace path" {
17 comptime {
18 @stardustClaim(
19 @import("alloc_phase").capacity.witness(@import("./root.zig").Storage, "trace_trace_writer_open_atomic"),
20 null,
21 null,
22 null,
23 null,
24 null,
25 null,
26 );
27 }
28
29 const allocator = std.testing.allocator;
30 var tmp = std.testing.tmpDir(.{});
31 defer tmp.cleanup();
32 const root = try tmp.parent_dir.realPathFileAlloc(sys.fs.debugIo(), tmp.sub_path[0..], allocator);
33 defer allocator.free(root);
34 const path = try sys.path.join(allocator, &.{ root, "existing.trace" });
35 defer allocator.free(path);
36 try sys.fs.createDirPath(path);
37 const sentinel_path = try sys.path.join(allocator, &.{ path, "sentinel" });
38 defer allocator.free(sentinel_path);
39 try sys.fs.writeFile(sentinel_path, "preserved");
40 const manifest = format.Manifest{ .build_id = "atomic" };
41 const trace_limits = format.Limits{ .max_event_bytes = 512, .max_chunk_bytes = 512 };
42 var storage_limits = Limits.fromOpen(path, manifest, trace_limits);
43 storage_limits.root_path_bytes -= 1;
44 var storage = try Storage.init(allocator, storage_limits);
45 defer storage.deinit(allocator);
46 storage.activate();
47 var writer: Writer = .{};
48 try std.testing.expectError(
49 error.RootPathCapacityExceeded,
50 writer.open(&storage, path, manifest, trace_limits),
51 );
52 try std.testing.expect(sys.fs.exists(sentinel_path));
53 try std.testing.expect(!storage.status().in_use);
54 }
55
56 test "trace writer remains allocation-free through SQL checkpoints and finish" {
57 comptime {
58 @stardustClaim(
59 @import("alloc_phase").capacity.witness(@import("./root.zig").Storage, "trace_trace_writer_sealed"),
60 null,
61 null,
62 null,
63 null,
64 null,
65 null,
66 );
67 }
68
69 const allocator = std.testing.allocator;
70 var tmp = std.testing.tmpDir(.{});
71 defer tmp.cleanup();
72 const root = try tmp.parent_dir.realPathFileAlloc(sys.fs.debugIo(), tmp.sub_path[0..], allocator);
73 defer allocator.free(root);
74 const path = try sys.path.join(allocator, &.{ root, "sealed.trace" });
75 defer allocator.free(path);
76 const manifest = format.Manifest{ .build_id = "sealed" };
77 const trace_limits = format.Limits{ .max_event_bytes = 512, .max_chunk_bytes = 512 };
78 var failing = std.testing.FailingAllocator.init(allocator, .{});
79 var storage = try Storage.init(failing.allocator(), Limits.fromOpen(path, manifest, trace_limits));
80 defer storage.deinit(failing.allocator());
81 storage.activate();
82 failing.fail_index = failing.alloc_index;
83 failing.resize_fail_index = failing.resize_index;
84 var writer: Writer = .{};
85 try writer.open(&storage, path, manifest, trace_limits);
86 defer writer.deinit();
87 for (0..40) |index| {
88 try writer.append(event.Event.user(
89 .{ .thread_id = 1, .seq = index + 1 },
90 "sealed",
91 "production-shaped-payload-0123456789abcdef",
92 ));
93 }
94 try writer.finish();
95 try std.testing.expect(writer.manifest.chunk_count > 1);
96 try std.testing.expect(!failing.has_induced_failure);
97 }