ReviewOS

also looking at this

zig-utils/zig-test-framework

Add retries, repeated runs, and flaky-test reporting

#25
Merged glennmichael123 wants to merge codex/issue-7-retries-repeat-flaky into main
15 files +719 -53
src/suite.zigmodified+31-0
Changes to src/suite.zig
@@ -24,10 +24,21 @@ pub const TestStatus = enum {
2424 pending,
2525 running,
2626 passed,
27 flaky,
2728 failed,
2829 skipped,
2930};
3031
32/// The outcome of one execution of a test. A logical test may have several
33/// attempts when retries or repeated runs are enabled.
34pub const TestAttempt = struct {
35 number: usize,
36 repetition: usize,
37 status: TestStatus,
38 duration_ns: u64,
39 error_message: ?[]const u8 = null,
40};
41
3142/// Individual test case
3243pub const TestCase = struct {
3344 name: []const u8,
@@ -37,6 +48,9 @@ pub const TestCase = struct {
3748 status: TestStatus = .pending,
3849 error_message: ?[]const u8 = null,
3950 execution_time_ns: u64 = 0,
51 /// Override the runner retry count for this test when non-null.
52 retry_count: ?usize = null,
53 attempts: std.ArrayList(TestAttempt) = .empty,
4054 skip: bool = false,
4155 only: bool = false,
4256 file: []const u8 = "",
@@ -65,6 +79,20 @@ pub const TestCase = struct {
6579 .timeout_ms = timeout_ms,
6680 };
6781 }
82
83 /// Configure an additional-attempt count for this individual test.
84 pub fn withRetries(self: TestCase, retries: usize) TestCase {
85 var configured = self;
86 configured.retry_count = retries;
87 return configured;
88 }
89
90 pub fn deinit(self: *TestCase, allocator: std.mem.Allocator) void {
91 for (self.attempts.items) |attempt| {
92 if (attempt.error_message) |message| allocator.free(message);
93 }
94 self.attempts.deinit(allocator);
95 }
6896};
6997
7098/// Test suite (describe block)
@@ -103,6 +131,7 @@ pub const TestSuite = struct {
103131 for (self.suites.items) |suite| {
104132 suite.deinit();
105133 }
134 for (self.tests.items) |*test_case| test_case.deinit(self.allocator);
106135 self.tests.deinit(self.allocator);
107136 self.suites.deinit(self.allocator);
108137 self.before_each_hooks.deinit(self.allocator);
@@ -456,12 +485,14 @@ test "TestStatus enum values" {
456485 const pending_status = TestStatus.pending;
457486 const running_status = TestStatus.running;
458487 const passed_status = TestStatus.passed;
488 const flaky_status = TestStatus.flaky;
459489 const failed_status = TestStatus.failed;
460490 const skipped_status = TestStatus.skipped;
461491
462492 try std.testing.expect(pending_status == .pending);
463493 try std.testing.expect(running_status == .running);
464494 try std.testing.expect(passed_status == .passed);
495 try std.testing.expect(flaky_status == .flaky);
465496 try std.testing.expect(failed_status == .failed);
466497 try std.testing.expect(skipped_status == .skipped);
467498}