add test-debug option for cleaner tests
This commit is contained in:
parent
a0f8b27ea5
commit
a8f802c02f
4 changed files with 89 additions and 30 deletions
23
README.md
23
README.md
|
@ -65,6 +65,27 @@ Run the test suite:
|
|||
zig build test
|
||||
```
|
||||
|
||||
Run integration tests:
|
||||
|
||||
```bash
|
||||
zig build test -Dintegration=true
|
||||
```
|
||||
|
||||
Enable debug output in tests (useful for debugging test failures):
|
||||
|
||||
```bash
|
||||
zig build test -Dintegration=true -Dtest-debug=true
|
||||
```
|
||||
|
||||
Test individual providers:
|
||||
|
||||
```bash
|
||||
zig build test-github
|
||||
zig build test-gitlab
|
||||
zig build test-codeberg
|
||||
zig build test-sourcehut
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
This tool is designed to be run periodically (e.g., via cron) and commit the generated RSS file to a Git repository that can be deployed via Cloudflare Pages or similar static hosting services.
|
||||
|
@ -72,4 +93,4 @@ This tool is designed to be run periodically (e.g., via cron) and commit the gen
|
|||
Example cron job (runs every hour):
|
||||
```bash
|
||||
0 * * * * cd /path/to/release-tracker && ./zig-out/bin/release-tracker config.json && git add releases.xml && git commit -m "Update releases" && git push
|
||||
```
|
||||
```
|
||||
|
|
21
build.zig
21
build.zig
|
@ -5,6 +5,7 @@ pub fn build(b: *std.Build) void {
|
|||
const optimize = b.standardOptimizeOption(.{});
|
||||
const integration = b.option(bool, "integration", "Run integration tests") orelse false;
|
||||
const provider = b.option([]const u8, "provider", "Test specific provider (github, gitlab, codeberg, sourcehut)");
|
||||
const test_debug = b.option(bool, "test-debug", "Enable debug output in tests") orelse false;
|
||||
|
||||
// Add Zeit dependency
|
||||
const zeit_dep = b.dependency("zeit", .{
|
||||
|
@ -41,6 +42,10 @@ pub fn build(b: *std.Build) void {
|
|||
|
||||
unit_tests.root_module.addImport("zeit", zeit_dep.module("zeit"));
|
||||
|
||||
const test_debug_option = b.addOptions();
|
||||
test_debug_option.addOption(bool, "test_debug", test_debug);
|
||||
unit_tests.root_module.addOptions("build_options", test_debug_option);
|
||||
|
||||
const run_unit_tests = b.addRunArtifact(unit_tests);
|
||||
|
||||
const test_step = b.step("test", "Run unit tests");
|
||||
|
@ -57,6 +62,10 @@ pub fn build(b: *std.Build) void {
|
|||
|
||||
integration_tests.root_module.addImport("zeit", zeit_dep.module("zeit"));
|
||||
|
||||
const integration_test_debug_option = b.addOptions();
|
||||
integration_test_debug_option.addOption(bool, "test_debug", test_debug);
|
||||
integration_tests.root_module.addOptions("build_options", integration_test_debug_option);
|
||||
|
||||
// Add filter for specific provider if specified
|
||||
if (provider) |p| {
|
||||
const filter = std.fmt.allocPrint(b.allocator, "{s} provider", .{p}) catch @panic("OOM");
|
||||
|
@ -81,6 +90,9 @@ pub fn build(b: *std.Build) void {
|
|||
.filters = &[_][]const u8{"GitHub provider"},
|
||||
});
|
||||
github_tests.root_module.addImport("zeit", zeit_dep.module("zeit"));
|
||||
const github_test_debug_option = b.addOptions();
|
||||
github_test_debug_option.addOption(bool, "test_debug", test_debug);
|
||||
github_tests.root_module.addOptions("build_options", github_test_debug_option);
|
||||
|
||||
const gitlab_tests = b.addTest(.{
|
||||
.name = "gitlab-tests",
|
||||
|
@ -90,6 +102,9 @@ pub fn build(b: *std.Build) void {
|
|||
.filters = &[_][]const u8{"GitLab provider"},
|
||||
});
|
||||
gitlab_tests.root_module.addImport("zeit", zeit_dep.module("zeit"));
|
||||
const gitlab_test_debug_option = b.addOptions();
|
||||
gitlab_test_debug_option.addOption(bool, "test_debug", test_debug);
|
||||
gitlab_tests.root_module.addOptions("build_options", gitlab_test_debug_option);
|
||||
|
||||
const codeberg_tests = b.addTest(.{
|
||||
.name = "codeberg-tests",
|
||||
|
@ -99,6 +114,9 @@ pub fn build(b: *std.Build) void {
|
|||
.filters = &[_][]const u8{"Codeberg provider"},
|
||||
});
|
||||
codeberg_tests.root_module.addImport("zeit", zeit_dep.module("zeit"));
|
||||
const codeberg_test_debug_option = b.addOptions();
|
||||
codeberg_test_debug_option.addOption(bool, "test_debug", test_debug);
|
||||
codeberg_tests.root_module.addOptions("build_options", codeberg_test_debug_option);
|
||||
|
||||
const sourcehut_tests = b.addTest(.{
|
||||
.name = "sourcehut-tests",
|
||||
|
@ -108,6 +126,9 @@ pub fn build(b: *std.Build) void {
|
|||
.filters = &[_][]const u8{"SourceHut provider"},
|
||||
});
|
||||
sourcehut_tests.root_module.addImport("zeit", zeit_dep.module("zeit"));
|
||||
const sourcehut_test_debug_option = b.addOptions();
|
||||
sourcehut_test_debug_option.addOption(bool, "test_debug", test_debug);
|
||||
sourcehut_tests.root_module.addOptions("build_options", sourcehut_test_debug_option);
|
||||
|
||||
github_step.dependOn(&b.addRunArtifact(github_tests).step);
|
||||
gitlab_step.dependOn(&b.addRunArtifact(gitlab_tests).step);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const std = @import("std");
|
||||
const testing = std.testing;
|
||||
const ArrayList = std.ArrayList;
|
||||
const build_options = @import("build_options");
|
||||
|
||||
const atom = @import("atom.zig");
|
||||
const Release = @import("main.zig").Release;
|
||||
|
@ -10,6 +11,12 @@ const Codeberg = @import("providers/Codeberg.zig");
|
|||
const SourceHut = @import("providers/SourceHut.zig");
|
||||
const config = @import("config.zig");
|
||||
|
||||
fn testPrint(comptime fmt: []const u8, args: anytype) void {
|
||||
if (build_options.test_debug) {
|
||||
std.debug.print(fmt, args);
|
||||
}
|
||||
}
|
||||
|
||||
test "Atom feed validates against W3C validator" {
|
||||
const allocator = testing.allocator;
|
||||
|
||||
|
@ -43,26 +50,26 @@ test "Atom feed validates against W3C validator" {
|
|||
try testing.expect(std.mem.indexOf(u8, atom_content, "<feed xmlns=\"http://www.w3.org/2005/Atom\">") != null);
|
||||
try testing.expect(std.mem.indexOf(u8, atom_content, "</feed>") != null);
|
||||
|
||||
std.debug.print("Atom feed structure validation passed\n", .{});
|
||||
testPrint("Atom feed structure validation passed\n", .{});
|
||||
}
|
||||
test "GitHub provider integration" {
|
||||
const allocator = testing.allocator;
|
||||
|
||||
// Load config to get token
|
||||
const app_config = config.loadConfig(allocator, "config.json") catch |err| {
|
||||
std.debug.print("Skipping GitHub test - config not available: {}\n", .{err});
|
||||
testPrint("Skipping GitHub test - config not available: {}\n", .{err});
|
||||
return;
|
||||
};
|
||||
defer app_config.deinit();
|
||||
|
||||
if (app_config.github_token == null) {
|
||||
std.debug.print("Skipping GitHub test - no token configured\n", .{});
|
||||
testPrint("Skipping GitHub test - no token configured\n", .{});
|
||||
return;
|
||||
}
|
||||
|
||||
var provider = GitHub.init(app_config.github_token.?);
|
||||
const releases = provider.fetchReleases(allocator) catch |err| {
|
||||
std.debug.print("GitHub provider error: {}\n", .{err});
|
||||
testPrint("GitHub provider error: {}\n", .{err});
|
||||
return;
|
||||
};
|
||||
defer {
|
||||
|
@ -72,7 +79,7 @@ test "GitHub provider integration" {
|
|||
releases.deinit();
|
||||
}
|
||||
|
||||
std.debug.print("GitHub: Found {} releases\n", .{releases.items.len});
|
||||
testPrint("GitHub: Found {} releases\n", .{releases.items.len});
|
||||
|
||||
// Verify releases have required fields
|
||||
for (releases.items) |release| {
|
||||
|
@ -88,19 +95,19 @@ test "GitLab provider integration" {
|
|||
|
||||
// Load config to get token
|
||||
const app_config = config.loadConfig(allocator, "config.json") catch |err| {
|
||||
std.debug.print("Skipping GitLab test - config not available: {}\n", .{err});
|
||||
testPrint("Skipping GitLab test - config not available: {}\n", .{err});
|
||||
return;
|
||||
};
|
||||
defer app_config.deinit();
|
||||
|
||||
if (app_config.gitlab_token == null) {
|
||||
std.debug.print("Skipping GitLab test - no token configured\n", .{});
|
||||
testPrint("Skipping GitLab test - no token configured\n", .{});
|
||||
return;
|
||||
}
|
||||
|
||||
var provider = GitLab.init(app_config.gitlab_token.?);
|
||||
const releases = provider.fetchReleases(allocator) catch |err| {
|
||||
std.debug.print("GitLab provider error: {}\n", .{err});
|
||||
testPrint("GitLab provider error: {}\n", .{err});
|
||||
return; // Skip test if provider fails
|
||||
};
|
||||
defer {
|
||||
|
@ -110,7 +117,7 @@ test "GitLab provider integration" {
|
|||
releases.deinit();
|
||||
}
|
||||
|
||||
std.debug.print("GitLab: Found {} releases\n", .{releases.items.len});
|
||||
testPrint("GitLab: Found {} releases\n", .{releases.items.len});
|
||||
|
||||
// Note: It's normal for starred projects to have 0 releases if they don't use GitLab's release feature
|
||||
// The test passes as long as we can successfully fetch the starred projects and check for releases
|
||||
|
@ -129,19 +136,19 @@ test "Codeberg provider integration" {
|
|||
|
||||
// Load config to get token
|
||||
const app_config = config.loadConfig(allocator, "config.json") catch |err| {
|
||||
std.debug.print("Skipping Codeberg test - config not available: {}\n", .{err});
|
||||
testPrint("Skipping Codeberg test - config not available: {}\n", .{err});
|
||||
return;
|
||||
};
|
||||
defer app_config.deinit();
|
||||
|
||||
if (app_config.codeberg_token == null) {
|
||||
std.debug.print("Skipping Codeberg test - no token configured\n", .{});
|
||||
testPrint("Skipping Codeberg test - no token configured\n", .{});
|
||||
return;
|
||||
}
|
||||
|
||||
var provider = Codeberg.init(app_config.codeberg_token.?);
|
||||
const releases = provider.fetchReleases(allocator) catch |err| {
|
||||
std.debug.print("Codeberg provider error: {}\n", .{err});
|
||||
testPrint("Codeberg provider error: {}\n", .{err});
|
||||
return; // Skip test if provider fails
|
||||
};
|
||||
defer {
|
||||
|
@ -151,7 +158,7 @@ test "Codeberg provider integration" {
|
|||
releases.deinit();
|
||||
}
|
||||
|
||||
std.debug.print("Codeberg: Found {} releases\n", .{releases.items.len});
|
||||
testPrint("Codeberg: Found {} releases\n", .{releases.items.len});
|
||||
|
||||
// Verify releases have required fields
|
||||
for (releases.items) |release| {
|
||||
|
@ -167,19 +174,19 @@ test "SourceHut provider integration" {
|
|||
|
||||
// Load config to get repositories
|
||||
const app_config = config.loadConfig(allocator, "config.json") catch |err| {
|
||||
std.debug.print("Skipping SourceHut test - config not available: {}\n", .{err});
|
||||
testPrint("Skipping SourceHut test - config not available: {}\n", .{err});
|
||||
return;
|
||||
};
|
||||
defer app_config.deinit();
|
||||
|
||||
if (app_config.sourcehut == null or app_config.sourcehut.?.repositories.len == 0) {
|
||||
std.debug.print("Skipping SourceHut test - no repositories configured\n", .{});
|
||||
testPrint("Skipping SourceHut test - no repositories configured\n", .{});
|
||||
return;
|
||||
}
|
||||
|
||||
var provider = SourceHut.init(app_config.sourcehut.?.token.?, app_config.sourcehut.?.repositories);
|
||||
const releases = provider.fetchReleases(allocator) catch |err| {
|
||||
std.debug.print("SourceHut provider error: {}\n", .{err});
|
||||
testPrint("SourceHut provider error: {}\n", .{err});
|
||||
return; // Skip test if provider fails
|
||||
};
|
||||
defer {
|
||||
|
@ -189,7 +196,7 @@ test "SourceHut provider integration" {
|
|||
releases.deinit();
|
||||
}
|
||||
|
||||
std.debug.print("SourceHut: Found {} releases\n", .{releases.items.len});
|
||||
testPrint("SourceHut: Found {} releases\n", .{releases.items.len});
|
||||
|
||||
// Verify releases have required fields
|
||||
for (releases.items) |release| {
|
||||
|
@ -205,13 +212,13 @@ test "SourceHut commit date fetching" {
|
|||
|
||||
// Load config to get repositories
|
||||
const app_config = config.loadConfig(allocator, "config.json") catch |err| {
|
||||
std.debug.print("Skipping SourceHut commit date test - config not available: {}\n", .{err});
|
||||
testPrint("Skipping SourceHut commit date test - config not available: {}\n", .{err});
|
||||
return;
|
||||
};
|
||||
defer app_config.deinit();
|
||||
|
||||
if (app_config.sourcehut == null or app_config.sourcehut.?.repositories.len == 0) {
|
||||
std.debug.print("Skipping SourceHut commit date test - no repositories configured\n", .{});
|
||||
testPrint("Skipping SourceHut commit date test - no repositories configured\n", .{});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -220,7 +227,7 @@ test "SourceHut commit date fetching" {
|
|||
var provider = SourceHut.init(app_config.sourcehut.?.token.?, test_repos[0..]);
|
||||
|
||||
const releases = provider.fetchReleases(allocator) catch |err| {
|
||||
std.debug.print("SourceHut commit date test error: {}\n", .{err});
|
||||
testPrint("SourceHut commit date test error: {}\n", .{err});
|
||||
return;
|
||||
};
|
||||
defer {
|
||||
|
@ -230,11 +237,11 @@ test "SourceHut commit date fetching" {
|
|||
releases.deinit();
|
||||
}
|
||||
|
||||
std.debug.print("SourceHut commit date test: Found {} releases from {s}\n", .{ releases.items.len, test_repos[0] });
|
||||
testPrint("SourceHut commit date test: Found {} releases from {s}\n", .{ releases.items.len, test_repos[0] });
|
||||
|
||||
// Verify we have some releases
|
||||
if (releases.items.len == 0) {
|
||||
std.debug.print("FAIL: No releases found from SourceHut repository {s}\n", .{test_repos[0]});
|
||||
testPrint("FAIL: No releases found from SourceHut repository {s}\n", .{test_repos[0]});
|
||||
try testing.expect(false); // Force test failure - we should be able to fetch releases
|
||||
}
|
||||
|
||||
|
@ -243,7 +250,7 @@ test "SourceHut commit date fetching" {
|
|||
|
||||
// Check commit dates
|
||||
for (releases.items) |release| {
|
||||
std.debug.print("Release: {s} - Date: {s}\n", .{ release.tag_name, release.published_at });
|
||||
testPrint("Release: {s} - Date: {s}\n", .{ release.tag_name, release.published_at });
|
||||
|
||||
// Verify basic fields
|
||||
try testing.expect(release.repo_name.len > 0);
|
||||
|
@ -255,10 +262,10 @@ test "SourceHut commit date fetching" {
|
|||
// Check if we got a real commit date vs epoch fallback
|
||||
if (std.mem.eql(u8, release.published_at, "1970-01-01T00:00:00Z")) {
|
||||
epoch_dates += 1;
|
||||
std.debug.print(" -> Using epoch fallback date\n", .{});
|
||||
testPrint(" -> Using epoch fallback date\n", .{});
|
||||
} else {
|
||||
valid_dates += 1;
|
||||
std.debug.print(" -> Got real commit date\n", .{});
|
||||
testPrint(" -> Got real commit date\n", .{});
|
||||
|
||||
// Verify the date format looks reasonable (should be ISO 8601)
|
||||
try testing.expect(release.published_at.len >= 19); // At least YYYY-MM-DDTHH:MM:SS
|
||||
|
@ -266,17 +273,17 @@ test "SourceHut commit date fetching" {
|
|||
}
|
||||
}
|
||||
|
||||
std.debug.print("SourceHut commit date summary: {} valid dates, {} epoch fallbacks\n", .{ valid_dates, epoch_dates });
|
||||
testPrint("SourceHut commit date summary: {} valid dates, {} epoch fallbacks\n", .{ valid_dates, epoch_dates });
|
||||
|
||||
// We should have at least some valid commit dates
|
||||
// If all dates are epoch fallbacks, something is wrong with our commit date fetching
|
||||
if (releases.items.len > 0) {
|
||||
const success_rate = (valid_dates * 100) / releases.items.len;
|
||||
std.debug.print("Commit date success rate: {}%\n", .{success_rate});
|
||||
testPrint("Commit date success rate: {}%\n", .{success_rate});
|
||||
|
||||
// Test should fail if we can't fetch any real commit dates
|
||||
if (valid_dates == 0) {
|
||||
std.debug.print("FAIL: No valid commit dates were fetched from SourceHut\n", .{});
|
||||
testPrint("FAIL: No valid commit dates were fetched from SourceHut\n", .{});
|
||||
try testing.expect(false); // Force test failure
|
||||
}
|
||||
|
||||
|
|
12
src/main.zig
12
src/main.zig
|
@ -1,6 +1,5 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const print = std.debug.print;
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Thread = std.Thread;
|
||||
|
@ -18,6 +17,17 @@ const zeit = @import("zeit");
|
|||
|
||||
const Provider = @import("Provider.zig");
|
||||
|
||||
fn print(comptime fmt: []const u8, args: anytype) void {
|
||||
if (comptime @import("builtin").is_test) {
|
||||
const build_options = @import("build_options");
|
||||
if (build_options.test_debug) {
|
||||
std.debug.print(fmt, args);
|
||||
}
|
||||
} else {
|
||||
std.debug.print(fmt, args);
|
||||
}
|
||||
}
|
||||
|
||||
// Configuration: Only include releases from the last year in the output
|
||||
const RELEASE_AGE_LIMIT_SECONDS: i64 = 365 * 24 * 60 * 60; // 1 year in seconds
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue