fetch_ml/tests/unit/api/helpers/validation_helpers_test.go
Jeremie Fraeys 7305e2bc21
test: add comprehensive test coverage and command improvements
- Add logs and debug end-to-end tests
- Add test helper utilities
- Improve test fixtures and templates
- Update API server and config lint commands
- Add multi-user database initialization
2026-02-16 20:38:15 -05:00

486 lines
12 KiB
Go

package helpers
import (
"testing"
"github.com/jfraeys/fetch_ml/internal/api/helpers"
"github.com/jfraeys/fetch_ml/internal/manifest"
"github.com/jfraeys/fetch_ml/internal/queue"
)
func TestValidateCommitIDFormat(t *testing.T) {
tests := []struct {
name string
commitID string
wantOk bool
wantErr string
}{
{
name: "valid commit ID",
commitID: "aabbccddeeff00112233445566778899aabbccdd",
wantOk: true,
wantErr: "",
},
{
name: "too short",
commitID: "aabbcc",
wantOk: false,
wantErr: "invalid commit_id length",
},
{
name: "too long",
commitID: "aabbccddeeff00112233445566778899aabbccddeeff",
wantOk: false,
wantErr: "invalid commit_id length",
},
{
name: "invalid hex",
commitID: "gggggggggggggggggggggggggggggggggggggggg",
wantOk: false,
wantErr: "invalid commit_id hex",
},
{
name: "mixed case valid",
commitID: "AABBCCDDEEFF00112233445566778899AABBCCDD",
wantOk: true,
wantErr: "",
},
{
name: "empty",
commitID: "",
wantOk: false,
wantErr: "invalid commit_id length",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotOk, gotErr := helpers.ValidateCommitIDFormat(tt.commitID)
if gotOk != tt.wantOk {
t.Errorf("ValidateCommitIDFormat() ok = %v, want %v", gotOk, tt.wantOk)
}
if gotErr != tt.wantErr {
t.Errorf("ValidateCommitIDFormat() err = %q, want %q", gotErr, tt.wantErr)
}
})
}
}
func TestShouldRequireRunManifest(t *testing.T) {
tests := []struct {
name string
status string
want bool
}{
{"running", "running", true},
{"completed", "completed", true},
{"failed", "failed", true},
{"queued", "queued", false},
{"pending", "pending", false},
{"cancelled", "cancelled", false},
{"unknown", "unknown", false},
{"empty", "", false},
{"RUNNING uppercase", "RUNNING", true},
{"Completed mixed", "Completed", true},
{" Running with space", " running", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
task := &queue.Task{Status: tt.status}
got := helpers.ShouldRequireRunManifest(task)
if got != tt.want {
t.Errorf("ShouldRequireRunManifest() = %v, want %v", got, tt.want)
}
})
}
}
func TestExpectedRunManifestBucketForStatus(t *testing.T) {
tests := []struct {
name string
status string
wantBucket string
wantOk bool
}{
{"queued", "queued", "pending", true},
{"pending", "pending", "pending", true},
{"running", "running", "running", true},
{"completed", "completed", "finished", true},
{"finished", "finished", "finished", true},
{"failed", "failed", "failed", true},
{"unknown", "unknown", "", false},
{"empty", "", "", false},
{"RUNNING uppercase", "RUNNING", "running", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotBucket, gotOk := helpers.ExpectedRunManifestBucketForStatus(tt.status)
if gotBucket != tt.wantBucket {
t.Errorf("ExpectedRunManifestBucketForStatus() bucket = %q, want %q", gotBucket, tt.wantBucket)
}
if gotOk != tt.wantOk {
t.Errorf("ExpectedRunManifestBucketForStatus() ok = %v, want %v", gotOk, tt.wantOk)
}
})
}
}
func TestValidateTaskIDMatch(t *testing.T) {
tests := []struct {
name string
rmTaskID string
expectedID string
wantOk bool
wantExpected string
wantActual string
}{
{
name: "match",
rmTaskID: "task-123",
expectedID: "task-123",
wantOk: true,
wantExpected: "task-123",
wantActual: "task-123",
},
{
name: "mismatch",
rmTaskID: "task-123",
expectedID: "task-456",
wantOk: false,
wantExpected: "task-456",
wantActual: "task-123",
},
{
name: "empty rm task ID",
rmTaskID: "",
expectedID: "task-123",
wantOk: false,
wantExpected: "task-123",
wantActual: "",
},
{
name: "whitespace trimmed - match",
rmTaskID: "task-123",
expectedID: "task-123",
wantOk: true,
wantExpected: "task-123",
wantActual: "task-123",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rm := &manifest.RunManifest{TaskID: tt.rmTaskID}
got := helpers.ValidateTaskIDMatch(rm, tt.expectedID)
if got.OK != tt.wantOk {
t.Errorf("ValidateTaskIDMatch() OK = %v, want %v", got.OK, tt.wantOk)
}
if got.Expected != tt.wantExpected {
t.Errorf("ValidateTaskIDMatch() Expected = %q, want %q", got.Expected, tt.wantExpected)
}
if got.Actual != tt.wantActual {
t.Errorf("ValidateTaskIDMatch() Actual = %q, want %q", got.Actual, tt.wantActual)
}
})
}
}
func TestValidateCommitIDMatch(t *testing.T) {
tests := []struct {
name string
rmCommitID string
expectedID string
wantOk bool
wantExpected string
wantActual string
}{
{
name: "both empty",
rmCommitID: "",
expectedID: "",
wantOk: true,
wantExpected: "",
wantActual: "",
},
{
name: "match",
rmCommitID: "abc123",
expectedID: "abc123",
wantOk: true,
wantExpected: "abc123",
wantActual: "abc123",
},
{
name: "mismatch",
rmCommitID: "abc123",
expectedID: "def456",
wantOk: false,
wantExpected: "def456",
wantActual: "abc123",
},
{
name: "expected empty",
rmCommitID: "abc123",
expectedID: "",
wantOk: true,
wantExpected: "",
wantActual: "",
},
{
name: "rm empty",
rmCommitID: "",
expectedID: "abc123",
wantOk: true,
wantExpected: "abc123",
wantActual: "",
},
{
name: "whitespace trimmed",
rmCommitID: " abc123 ",
expectedID: "abc123",
wantOk: true,
wantExpected: "abc123",
wantActual: "abc123",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := helpers.ValidateCommitIDMatch(tt.rmCommitID, tt.expectedID)
if got.OK != tt.wantOk {
t.Errorf("ValidateCommitIDMatch() OK = %v, want %v", got.OK, tt.wantOk)
}
if got.Expected != tt.wantExpected {
t.Errorf("ValidateCommitIDMatch() Expected = %q, want %q", got.Expected, tt.wantExpected)
}
if got.Actual != tt.wantActual {
t.Errorf("ValidateCommitIDMatch() Actual = %q, want %q", got.Actual, tt.wantActual)
}
})
}
}
func TestValidateDepsProvenance(t *testing.T) {
tests := []struct {
name string
wantName string
wantSHA string
gotName string
gotSHA string
wantOk bool
wantExpected string
wantActual string
}{
{
name: "match",
wantName: "requirements.txt",
wantSHA: "abc123",
gotName: "requirements.txt",
gotSHA: "abc123",
wantOk: true,
wantExpected: "requirements.txt:abc123",
wantActual: "requirements.txt:abc123",
},
{
name: "name mismatch",
wantName: "requirements.txt",
wantSHA: "abc123",
gotName: "Pipfile",
gotSHA: "abc123",
wantOk: false,
wantExpected: "requirements.txt:abc123",
wantActual: "Pipfile:abc123",
},
{
name: "sha mismatch",
wantName: "requirements.txt",
wantSHA: "abc123",
gotName: "requirements.txt",
gotSHA: "def456",
wantOk: false,
wantExpected: "requirements.txt:abc123",
wantActual: "requirements.txt:def456",
},
{
name: "want empty",
wantName: "",
wantSHA: "",
gotName: "requirements.txt",
gotSHA: "abc123",
wantOk: true,
wantExpected: "",
wantActual: "",
},
{
name: "got empty",
wantName: "requirements.txt",
wantSHA: "abc123",
gotName: "",
gotSHA: "",
wantOk: true,
wantExpected: "",
wantActual: "",
},
{
name: "both empty",
wantName: "",
wantSHA: "",
gotName: "",
gotSHA: "",
wantOk: true,
wantExpected: "",
wantActual: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := helpers.ValidateDepsProvenance(tt.wantName, tt.wantSHA, tt.gotName, tt.gotSHA)
if got.OK != tt.wantOk {
t.Errorf("ValidateDepsProvenance() OK = %v, want %v", got.OK, tt.wantOk)
}
if got.Expected != tt.wantExpected {
t.Errorf("ValidateDepsProvenance() Expected = %q, want %q", got.Expected, tt.wantExpected)
}
if got.Actual != tt.wantActual {
t.Errorf("ValidateDepsProvenance() Actual = %q, want %q", got.Actual, tt.wantActual)
}
})
}
}
func TestValidateSnapshotID(t *testing.T) {
tests := []struct {
name string
wantID string
gotID string
wantOk bool
wantExpected string
wantActual string
}{
{
name: "match",
wantID: "snap-123",
gotID: "snap-123",
wantOk: true,
wantExpected: "snap-123",
wantActual: "snap-123",
},
{
name: "mismatch",
wantID: "snap-123",
gotID: "snap-456",
wantOk: false,
wantExpected: "snap-123",
wantActual: "snap-456",
},
{
name: "want empty",
wantID: "",
gotID: "snap-123",
wantOk: true,
wantExpected: "",
wantActual: "snap-123",
},
{
name: "got empty",
wantID: "snap-123",
gotID: "",
wantOk: true,
wantExpected: "snap-123",
wantActual: "",
},
{
name: "both empty",
wantID: "",
gotID: "",
wantOk: true,
wantExpected: "",
wantActual: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := helpers.ValidateSnapshotID(tt.wantID, tt.gotID)
if got.OK != tt.wantOk {
t.Errorf("ValidateSnapshotID() OK = %v, want %v", got.OK, tt.wantOk)
}
if got.Expected != tt.wantExpected {
t.Errorf("ValidateSnapshotID() Expected = %q, want %q", got.Expected, tt.wantExpected)
}
if got.Actual != tt.wantActual {
t.Errorf("ValidateSnapshotID() Actual = %q, want %q", got.Actual, tt.wantActual)
}
})
}
}
func TestValidateSnapshotSHA(t *testing.T) {
tests := []struct {
name string
wantSHA string
gotSHA string
wantOk bool
wantExpected string
wantActual string
}{
{
name: "match",
wantSHA: "sha256:abc123",
gotSHA: "sha256:abc123",
wantOk: true,
wantExpected: "sha256:abc123",
wantActual: "sha256:abc123",
},
{
name: "mismatch",
wantSHA: "sha256:abc123",
gotSHA: "sha256:def456",
wantOk: false,
wantExpected: "sha256:abc123",
wantActual: "sha256:def456",
},
{
name: "want empty",
wantSHA: "",
gotSHA: "sha256:abc123",
wantOk: true,
wantExpected: "",
wantActual: "sha256:abc123",
},
{
name: "got empty",
wantSHA: "sha256:abc123",
gotSHA: "",
wantOk: true,
wantExpected: "sha256:abc123",
wantActual: "",
},
{
name: "both empty",
wantSHA: "",
gotSHA: "",
wantOk: true,
wantExpected: "",
wantActual: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := helpers.ValidateSnapshotSHA(tt.wantSHA, tt.gotSHA)
if got.OK != tt.wantOk {
t.Errorf("ValidateSnapshotSHA() OK = %v, want %v", got.OK, tt.wantOk)
}
if got.Expected != tt.wantExpected {
t.Errorf("ValidateSnapshotSHA() Expected = %q, want %q", got.Expected, tt.wantExpected)
}
if got.Actual != tt.wantActual {
t.Errorf("ValidateSnapshotSHA() Actual = %q, want %q", got.Actual, tt.wantActual)
}
})
}
}