608 lines
13 KiB
Go
608 lines
13 KiB
Go
package actions
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestTrimVersionPrefix(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
expected string
|
|
}{
|
|
{"v1.22.5", "1.22.5"},
|
|
{"V1.22.5", "1.22.5"},
|
|
{"1.22.5", "1.22.5"},
|
|
{"v1.23.0", "1.23.0"},
|
|
{"2.0.0", "2.0.0"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.input, func(t *testing.T) {
|
|
result := trimVersionPrefix(tt.input)
|
|
if result != tt.expected {
|
|
t.Errorf("trimVersionPrefix(%q) = %q, want %q", tt.input, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSplitVersion(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
expected []string
|
|
}{
|
|
{"1.22.5", []string{"1", "22", "5"}},
|
|
{"1.23", []string{"1", "23"}},
|
|
{"2.0.0", []string{"2", "0", "0"}},
|
|
{"1", []string{"1"}},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.input, func(t *testing.T) {
|
|
result := splitVersion(tt.input)
|
|
if len(result) != len(tt.expected) {
|
|
t.Errorf("splitVersion(%q) = %v, want %v", tt.input, result, tt.expected)
|
|
return
|
|
}
|
|
for i := range result {
|
|
if result[i] != tt.expected[i] {
|
|
t.Errorf("splitVersion(%q)[%d] = %q, want %q", tt.input, i, result[i], tt.expected[i])
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseVersionForCheck(t *testing.T) {
|
|
tests := []struct {
|
|
version string
|
|
wantMajor int
|
|
wantMinor int
|
|
wantPatch int
|
|
wantErr bool
|
|
}{
|
|
{"1.22.5", 1, 22, 5, false},
|
|
{"1.23.0", 1, 23, 0, false},
|
|
{"v1.22.5", 1, 22, 5, false},
|
|
{"V1.23.0", 1, 23, 0, false},
|
|
{"2.0.0", 2, 0, 0, false},
|
|
{"1.22", 1, 22, 0, false},
|
|
{"invalid", 0, 0, 0, true},
|
|
{"", 0, 0, 0, true},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.version, func(t *testing.T) {
|
|
major, minor, patch, err := parseVersionForCheck(tt.version)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("parseVersionForCheck(%q) error = %v, wantErr %v", tt.version, err, tt.wantErr)
|
|
return
|
|
}
|
|
if !tt.wantErr {
|
|
if major != tt.wantMajor || minor != tt.wantMinor || patch != tt.wantPatch {
|
|
t.Errorf("parseVersionForCheck(%q) = (%d, %d, %d), want (%d, %d, %d)",
|
|
tt.version, major, minor, patch, tt.wantMajor, tt.wantMinor, tt.wantPatch)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestContainsPath(t *testing.T) {
|
|
tests := []struct {
|
|
path string
|
|
substr string
|
|
expected bool
|
|
}{
|
|
{".gitea/workflows/build.yml", "build.yml", true},
|
|
{".github/workflows/test.yml", "test.yml", true},
|
|
{".gitea/workflows/build.yml", "deploy.yml", false},
|
|
{"build.yml", "build.yml", true},
|
|
{"", "test", false},
|
|
{"test", "", false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.path+"_"+tt.substr, func(t *testing.T) {
|
|
result := containsPath(tt.path, tt.substr)
|
|
if result != tt.expected {
|
|
t.Errorf("containsPath(%q, %q) = %v, want %v", tt.path, tt.substr, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetString(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
m map[string]any
|
|
key string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "string value",
|
|
m: map[string]any{"name": "test"},
|
|
key: "name",
|
|
expected: "test",
|
|
},
|
|
{
|
|
name: "float64 value",
|
|
m: map[string]any{"id": float64(123)},
|
|
key: "id",
|
|
expected: "123",
|
|
},
|
|
{
|
|
name: "missing key",
|
|
m: map[string]any{"other": "value"},
|
|
key: "name",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "nil map",
|
|
m: nil,
|
|
key: "name",
|
|
expected: "",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := getString(tt.m, tt.key)
|
|
if result != tt.expected {
|
|
t.Errorf("getString(%v, %q) = %q, want %q", tt.m, tt.key, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseJobSummaries(t *testing.T) {
|
|
jobsData := []any{
|
|
map[string]any{
|
|
"id": float64(1),
|
|
"name": "build",
|
|
"status": "completed",
|
|
"conclusion": "success",
|
|
"started_at": "2024-01-15T10:00:00Z",
|
|
"completed_at": "2024-01-15T10:05:00Z",
|
|
"steps": []any{
|
|
map[string]any{
|
|
"name": "Checkout",
|
|
"number": float64(1),
|
|
"status": "completed",
|
|
"conclusion": "success",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
summaries := parseJobSummaries(jobsData)
|
|
if len(summaries) != 1 {
|
|
t.Fatalf("expected 1 summary, got %d", len(summaries))
|
|
}
|
|
|
|
if summaries[0].ID != 1 {
|
|
t.Errorf("expected ID 1, got %d", summaries[0].ID)
|
|
}
|
|
if summaries[0].Name != "build" {
|
|
t.Errorf("expected name 'build', got %s", summaries[0].Name)
|
|
}
|
|
if len(summaries[0].Steps) != 1 {
|
|
t.Errorf("expected 1 step, got %d", len(summaries[0].Steps))
|
|
}
|
|
}
|
|
|
|
func TestParseSteps(t *testing.T) {
|
|
stepsData := []any{
|
|
map[string]any{
|
|
"name": "Checkout",
|
|
"number": float64(1),
|
|
"status": "completed",
|
|
"conclusion": "success",
|
|
},
|
|
map[string]any{
|
|
"name": "Build",
|
|
"number": float64(2),
|
|
"status": "completed",
|
|
"conclusion": "success",
|
|
},
|
|
}
|
|
|
|
steps := parseSteps(stepsData)
|
|
if len(steps) != 2 {
|
|
t.Fatalf("expected 2 steps, got %d", len(steps))
|
|
}
|
|
|
|
if steps[0].Name != "Checkout" || steps[0].Number != 1 {
|
|
t.Errorf("first step mismatch: %+v", steps[0])
|
|
}
|
|
if steps[1].Name != "Build" || steps[1].Number != 2 {
|
|
t.Errorf("second step mismatch: %+v", steps[1])
|
|
}
|
|
}
|
|
|
|
func TestMonitorResultTypes(t *testing.T) {
|
|
result := &MonitorResult{
|
|
RunID: 123,
|
|
Status: "completed",
|
|
Conclusion: "success",
|
|
WorkflowID: "build.yml",
|
|
Branch: "main",
|
|
CommitSHA: "abc123",
|
|
Duration: "5m0s",
|
|
DurationSec: 300,
|
|
Jobs: []JobSummary{
|
|
{
|
|
ID: 1,
|
|
Name: "build",
|
|
Status: "completed",
|
|
Conclusion: "success",
|
|
Steps: []StepInfo{
|
|
{Name: "Checkout", Number: 1, Status: "completed", Conclusion: "success"},
|
|
},
|
|
},
|
|
},
|
|
Logs: map[string]JobLogs{
|
|
"build": {
|
|
JobID: 1,
|
|
JobName: "build",
|
|
Log: "Building...",
|
|
Bytes: 100,
|
|
},
|
|
},
|
|
}
|
|
|
|
if result.RunID != 123 {
|
|
t.Errorf("RunID mismatch")
|
|
}
|
|
if result.Status != "completed" {
|
|
t.Errorf("Status mismatch")
|
|
}
|
|
if len(result.Jobs) != 1 {
|
|
t.Errorf("Jobs length mismatch")
|
|
}
|
|
if len(result.Logs) != 1 {
|
|
t.Errorf("Logs length mismatch")
|
|
}
|
|
}
|
|
|
|
func TestTrimOnePrefix(t *testing.T) {
|
|
tests := []struct {
|
|
s string
|
|
prefix string
|
|
expected string
|
|
}{
|
|
{"v1.22.5", "v", "1.22.5"},
|
|
{"V1.22.5", "V", "1.22.5"},
|
|
{"1.22.5", "v", "1.22.5"},
|
|
{"", "v", ""},
|
|
{"v", "v", ""},
|
|
{"test", "x", "test"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.s+"_"+tt.prefix, func(t *testing.T) {
|
|
result := trimOnePrefix(tt.s, tt.prefix)
|
|
if result != tt.expected {
|
|
t.Errorf("trimOnePrefix(%q, %q) = %q, want %q", tt.s, tt.prefix, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseVersionForCheck_EdgeCases(t *testing.T) {
|
|
tests := []struct {
|
|
version string
|
|
wantMajor int
|
|
wantMinor int
|
|
wantPatch int
|
|
wantErr bool
|
|
}{
|
|
{"1.0.0", 1, 0, 0, false},
|
|
{"0.0.1", 0, 0, 1, false},
|
|
{"1.23.0+build", 1, 23, 0, false},
|
|
{"1.23.0-rc1", 1, 23, 0, false},
|
|
{"1.23", 1, 23, 0, false},
|
|
{"1", 1, 0, 0, false},
|
|
{"", 0, 0, 0, true},
|
|
{"abc", 0, 0, 0, true},
|
|
{"1.abc.5", 0, 0, 0, true},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.version, func(t *testing.T) {
|
|
major, minor, patch, err := parseVersionForCheck(tt.version)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("parseVersionForCheck(%q) error = %v, wantErr %v", tt.version, err, tt.wantErr)
|
|
return
|
|
}
|
|
if !tt.wantErr {
|
|
if major != tt.wantMajor || minor != tt.wantMinor || patch != tt.wantPatch {
|
|
t.Errorf("parseVersionForCheck(%q) = (%d, %d, %d), want (%d, %d, %d)",
|
|
tt.version, major, minor, patch, tt.wantMajor, tt.wantMinor, tt.wantPatch)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestContainsPath_EdgeCases(t *testing.T) {
|
|
tests := []struct {
|
|
path string
|
|
substr string
|
|
expected bool
|
|
}{
|
|
{"", "", false},
|
|
{"build.yml", "", false},
|
|
{"", "build", false},
|
|
{"a/b/c/d.yml", "c/d.yml", true},
|
|
{"a/b/c/d.yml", "b/c", false},
|
|
{"build.yml", "build.yml", true},
|
|
{"/absolute/path", "path", true},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.path+"_"+tt.substr, func(t *testing.T) {
|
|
result := containsPath(tt.path, tt.substr)
|
|
if result != tt.expected {
|
|
t.Errorf("containsPath(%q, %q) = %v, want %v", tt.path, tt.substr, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetString_EdgeCases(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
m map[string]any
|
|
key string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "int value",
|
|
m: map[string]any{"count": int(42)},
|
|
key: "count",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "bool value",
|
|
m: map[string]any{"active": true},
|
|
key: "active",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "empty string value",
|
|
m: map[string]any{"name": ""},
|
|
key: "name",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "large float64",
|
|
m: map[string]any{"id": float64(9223372036854775807)},
|
|
key: "id",
|
|
expected: "9223372036854775807",
|
|
},
|
|
{
|
|
name: "zero float64",
|
|
m: map[string]any{"count": float64(0)},
|
|
key: "count",
|
|
expected: "0",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := getString(tt.m, tt.key)
|
|
if result != tt.expected {
|
|
t.Errorf("getString(%v, %q) = %q, want %q", tt.m, tt.key, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseJobSummaries_EdgeCases(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
jobsData []any
|
|
wantLen int
|
|
}{
|
|
{
|
|
name: "empty jobs",
|
|
jobsData: []any{},
|
|
wantLen: 0,
|
|
},
|
|
{
|
|
name: "nil jobs",
|
|
jobsData: nil,
|
|
wantLen: 0,
|
|
},
|
|
{
|
|
name: "job without steps",
|
|
jobsData: []any{
|
|
map[string]any{
|
|
"id": float64(1),
|
|
"name": "build",
|
|
"status": "completed",
|
|
"conclusion": "success",
|
|
},
|
|
},
|
|
wantLen: 1,
|
|
},
|
|
{
|
|
name: "job with empty steps",
|
|
jobsData: []any{
|
|
map[string]any{
|
|
"id": float64(1),
|
|
"name": "build",
|
|
"status": "completed",
|
|
"conclusion": "success",
|
|
"steps": []any{},
|
|
},
|
|
},
|
|
wantLen: 1,
|
|
},
|
|
{
|
|
name: "invalid job entry",
|
|
jobsData: []any{
|
|
"not a map",
|
|
map[string]any{
|
|
"id": float64(2),
|
|
"name": "test",
|
|
"status": "completed",
|
|
"conclusion": "success",
|
|
},
|
|
},
|
|
wantLen: 1,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
summaries := parseJobSummaries(tt.jobsData)
|
|
if len(summaries) != tt.wantLen {
|
|
t.Errorf("parseJobSummaries() returned %d summaries, want %d", len(summaries), tt.wantLen)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseSteps_EdgeCases(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
stepsData []any
|
|
wantLen int
|
|
}{
|
|
{
|
|
name: "empty steps",
|
|
stepsData: []any{},
|
|
wantLen: 0,
|
|
},
|
|
{
|
|
name: "nil steps",
|
|
stepsData: nil,
|
|
wantLen: 0,
|
|
},
|
|
{
|
|
name: "invalid step entry",
|
|
stepsData: []any{
|
|
"not a map",
|
|
map[string]any{
|
|
"name": "Checkout",
|
|
"number": float64(1),
|
|
"status": "completed",
|
|
"conclusion": "success",
|
|
},
|
|
},
|
|
wantLen: 1,
|
|
},
|
|
{
|
|
name: "step without conclusion",
|
|
stepsData: []any{
|
|
map[string]any{
|
|
"name": "Setup",
|
|
"number": float64(1),
|
|
"status": "in_progress",
|
|
},
|
|
},
|
|
wantLen: 1,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
steps := parseSteps(tt.stepsData)
|
|
if len(steps) != tt.wantLen {
|
|
t.Errorf("parseSteps() returned %d steps, want %d", len(steps), tt.wantLen)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMonitorResultStruct(t *testing.T) {
|
|
result := &MonitorResult{
|
|
RunID: 123,
|
|
Status: "completed",
|
|
Conclusion: "success",
|
|
WorkflowID: "build.yml",
|
|
WorkflowName: "Build",
|
|
Branch: "main",
|
|
CommitSHA: "abc123",
|
|
Duration: "5m0s",
|
|
DurationSec: 300,
|
|
StartedAt: "2024-01-15T10:00:00Z",
|
|
CompletedAt: "2024-01-15T10:05:00Z",
|
|
Jobs: []JobSummary{},
|
|
Logs: map[string]JobLogs{},
|
|
Error: "",
|
|
TimedOut: false,
|
|
}
|
|
|
|
if result.RunID != 123 {
|
|
t.Errorf("RunID = %d, want 123", result.RunID)
|
|
}
|
|
if result.Status != "completed" {
|
|
t.Errorf("Status = %s, want completed", result.Status)
|
|
}
|
|
if result.Conclusion != "success" {
|
|
t.Errorf("Conclusion = %s, want success", result.Conclusion)
|
|
}
|
|
if result.TimedOut {
|
|
t.Error("TimedOut should be false")
|
|
}
|
|
}
|
|
|
|
func TestMonitorResultErrorState(t *testing.T) {
|
|
result := &MonitorResult{
|
|
RunID: 456,
|
|
Status: "completed",
|
|
Conclusion: "failure",
|
|
WorkflowID: "test.yml",
|
|
Branch: "develop",
|
|
CommitSHA: "def456",
|
|
Duration: "2m30s",
|
|
DurationSec: 150,
|
|
Error: "Test failed",
|
|
TimedOut: false,
|
|
Jobs: []JobSummary{
|
|
{
|
|
ID: 1,
|
|
Name: "test",
|
|
Status: "completed",
|
|
Conclusion: "failure",
|
|
},
|
|
},
|
|
}
|
|
|
|
if result.Conclusion != "failure" {
|
|
t.Errorf("Conclusion = %s, want failure", result.Conclusion)
|
|
}
|
|
if result.Error != "Test failed" {
|
|
t.Errorf("Error = %s, want 'Test failed'", result.Error)
|
|
}
|
|
if len(result.Jobs) != 1 {
|
|
t.Errorf("Jobs count = %d, want 1", len(result.Jobs))
|
|
}
|
|
}
|
|
|
|
func TestMonitorResultTimeoutState(t *testing.T) {
|
|
result := &MonitorResult{
|
|
RunID: 789,
|
|
Status: "in_progress",
|
|
Conclusion: "",
|
|
WorkflowID: "deploy.yml",
|
|
Branch: "main",
|
|
CommitSHA: "ghi789",
|
|
Duration: "10m0s",
|
|
DurationSec: 600,
|
|
Error: "Polling timed out after 10m0s",
|
|
TimedOut: true,
|
|
Jobs: []JobSummary{},
|
|
}
|
|
|
|
if !result.TimedOut {
|
|
t.Error("TimedOut should be true")
|
|
}
|
|
if result.Error == "" {
|
|
t.Error("Error should not be empty for timeout")
|
|
}
|
|
}
|