Initial commit: Gitea MCP Server

This commit is contained in:
2026-04-10 21:57:19 -07:00
commit 1f27844dce
119 changed files with 25001 additions and 0 deletions
+607
View File
@@ -0,0 +1,607 @@
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")
}
}