Initial commit: Gitea MCP Server
This commit is contained in:
@@ -0,0 +1,483 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
gitea_errors "gitea.com/gitea/gitea-mcp/pkg/errors"
|
||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
||||
)
|
||||
|
||||
func TestParseStatusState(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
state string
|
||||
wantState gitea_sdk.StatusState
|
||||
wantErr bool
|
||||
errContains string
|
||||
}{
|
||||
{
|
||||
name: "pending",
|
||||
state: "pending",
|
||||
wantState: gitea_sdk.StatusPending,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "success",
|
||||
state: "success",
|
||||
wantState: gitea_sdk.StatusSuccess,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "failure",
|
||||
state: "failure",
|
||||
wantState: gitea_sdk.StatusFailure,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "error",
|
||||
state: "error",
|
||||
wantState: gitea_sdk.StatusError,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid state",
|
||||
state: "invalid",
|
||||
wantErr: true,
|
||||
errContains: "invalid state",
|
||||
},
|
||||
{
|
||||
name: "empty state",
|
||||
state: "",
|
||||
wantErr: true,
|
||||
errContains: "invalid state",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseStatusState(tt.state)
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Errorf("parseStatusState() error = nil, wantErr %v", tt.wantErr)
|
||||
return
|
||||
}
|
||||
if tt.errContains != "" && !errors.Is(err, errors.New(tt.errContains)) {
|
||||
if !contains(err.Error(), tt.errContains) {
|
||||
t.Errorf("parseStatusState() error = %v, should contain %v", err.Error(), tt.errContains)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("parseStatusState() unexpected error = %v", err)
|
||||
return
|
||||
}
|
||||
if got != tt.wantState {
|
||||
t.Errorf("parseStatusState() = %v, want %v", got, tt.wantState)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSlimStatus(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
status *gitea_sdk.Status
|
||||
want map[string]any
|
||||
}{
|
||||
{
|
||||
name: "nil status",
|
||||
status: nil,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "full status",
|
||||
status: &gitea_sdk.Status{
|
||||
ID: 123,
|
||||
State: gitea_sdk.StatusSuccess,
|
||||
TargetURL: "https://review.lumbridgecorp.com/project/commit/248ade7",
|
||||
Context: "ci/metal",
|
||||
Description: "Build succeeded on Metal",
|
||||
CreatedAt: "2024-01-15T10:30:00Z",
|
||||
},
|
||||
want: map[string]any{
|
||||
"id": int64(123),
|
||||
"state": gitea_sdk.StatusSuccess,
|
||||
"target_url": "https://review.lumbridgecorp.com/project/commit/248ade7",
|
||||
"context": "ci/metal",
|
||||
"description": "Build succeeded on Metal",
|
||||
"created_at": "2024-01-15T10:30:00Z",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "pending status",
|
||||
status: &gitea_sdk.Status{
|
||||
ID: 456,
|
||||
State: gitea_sdk.StatusPending,
|
||||
Context: "ci/cloud-1",
|
||||
CreatedAt: "2024-01-15T10:31:00Z",
|
||||
},
|
||||
want: map[string]any{
|
||||
"id": int64(456),
|
||||
"state": gitea_sdk.StatusPending,
|
||||
"target_url": "",
|
||||
"context": "ci/cloud-1",
|
||||
"created_at": "2024-01-15T10:31:00Z",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := slimStatus(tt.status)
|
||||
if tt.want == nil {
|
||||
if got != nil {
|
||||
t.Errorf("slimStatus() = %v, want nil", got)
|
||||
}
|
||||
return
|
||||
}
|
||||
if got == nil {
|
||||
t.Errorf("slimStatus() = nil, want %v", tt.want)
|
||||
return
|
||||
}
|
||||
for key, wantVal := range tt.want {
|
||||
gotVal, ok := got[key]
|
||||
if !ok {
|
||||
t.Errorf("slimStatus() missing key %s", key)
|
||||
continue
|
||||
}
|
||||
if gotVal != wantVal {
|
||||
t.Errorf("slimStatus()[%s] = %v, want %v", key, gotVal, wantVal)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorTranslation_CreateCommitStatus(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
errMsg string
|
||||
expectedOp string
|
||||
expectedCtxKey string
|
||||
}{
|
||||
{
|
||||
name: "404 not found",
|
||||
errMsg: "CreateStatus: 404 Not Found",
|
||||
expectedOp: "CreateCommitStatus",
|
||||
expectedCtxKey: "sha",
|
||||
},
|
||||
{
|
||||
name: "401 unauthorized",
|
||||
errMsg: "CreateStatus: 401 Unauthorized",
|
||||
expectedOp: "CreateCommitStatus",
|
||||
expectedCtxKey: "context",
|
||||
},
|
||||
{
|
||||
name: "403 forbidden",
|
||||
errMsg: "CreateStatus: 403 Forbidden",
|
||||
expectedOp: "CreateCommitStatus",
|
||||
expectedCtxKey: "repo",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := errors.New(tt.errMsg)
|
||||
translated := gitea_errors.TranslateError(err, map[string]string{
|
||||
"operation": "CreateCommitStatus",
|
||||
"owner": "karti-ai",
|
||||
"repo": "gitcoffee",
|
||||
"sha": "248ade7a9c...",
|
||||
"state": "success",
|
||||
"context": "ci/metal",
|
||||
})
|
||||
|
||||
var enhanced *gitea_errors.EnhancedError
|
||||
if !errors.As(translated, &enhanced) {
|
||||
t.Fatal("expected translated error to be EnhancedError")
|
||||
}
|
||||
|
||||
if enhanced.Operation != tt.expectedOp {
|
||||
t.Errorf("expected operation %s, got %s", tt.expectedOp, enhanced.Operation)
|
||||
}
|
||||
|
||||
if enhanced.Context[tt.expectedCtxKey] == "" {
|
||||
t.Errorf("expected context key %s to be set", tt.expectedCtxKey)
|
||||
}
|
||||
|
||||
t.Logf("Translated error: %s", enhanced.Error())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseStatusState_EdgeCases(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
state string
|
||||
wantState gitea_sdk.StatusState
|
||||
wantErr bool
|
||||
errContains string
|
||||
}{
|
||||
{
|
||||
name: "mixed case pending",
|
||||
state: "Pending",
|
||||
wantErr: true,
|
||||
errContains: "invalid state",
|
||||
},
|
||||
{
|
||||
name: "mixed case success",
|
||||
state: "Success",
|
||||
wantErr: true,
|
||||
errContains: "invalid state",
|
||||
},
|
||||
{
|
||||
name: "whitespace pending",
|
||||
state: " pending",
|
||||
wantErr: true,
|
||||
errContains: "invalid state",
|
||||
},
|
||||
{
|
||||
name: "whitespace success",
|
||||
state: "success ",
|
||||
wantErr: true,
|
||||
errContains: "invalid state",
|
||||
},
|
||||
{
|
||||
name: "long invalid string",
|
||||
state: "this_is_not_a_valid_state",
|
||||
wantErr: true,
|
||||
errContains: "invalid state",
|
||||
},
|
||||
{
|
||||
name: "numeric string",
|
||||
state: "123",
|
||||
wantErr: true,
|
||||
errContains: "invalid state",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseStatusState(tt.state)
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Errorf("parseStatusState() error = nil, wantErr %v", tt.wantErr)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("parseStatusState() unexpected error = %v", err)
|
||||
return
|
||||
}
|
||||
if got != tt.wantState {
|
||||
t.Errorf("parseStatusState() = %v, want %v", got, tt.wantState)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSlimStatus_EdgeCases(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
status *gitea_sdk.Status
|
||||
want map[string]any
|
||||
}{
|
||||
{
|
||||
name: "nil status",
|
||||
status: nil,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "status with zero ID",
|
||||
status: &gitea_sdk.Status{
|
||||
ID: 0,
|
||||
State: gitea_sdk.StatusPending,
|
||||
TargetURL: "",
|
||||
Context: "",
|
||||
CreatedAt: "2024-01-15T10:30:00Z",
|
||||
},
|
||||
want: map[string]any{
|
||||
"id": int64(0),
|
||||
"state": gitea_sdk.StatusPending,
|
||||
"target_url": "",
|
||||
"context": "",
|
||||
"created_at": "2024-01-15T10:30:00Z",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "status with long URL",
|
||||
status: &gitea_sdk.Status{
|
||||
ID: 789,
|
||||
State: gitea_sdk.StatusSuccess,
|
||||
TargetURL: "https://very-long-review-environment-url.example.com/path/to/project/commit/248ade7a9c.../build/12345/logs?filter=all#section-2",
|
||||
Context: "continuous-integration/jenkins/build-and-test-all-platforms",
|
||||
Description: "Build succeeded on all platforms including Windows, macOS, and Linux with full test suite",
|
||||
CreatedAt: "2024-01-15T10:30:00Z",
|
||||
},
|
||||
want: map[string]any{
|
||||
"id": int64(789),
|
||||
"state": gitea_sdk.StatusSuccess,
|
||||
"target_url": "https://very-long-review-environment-url.example.com/path/to/project/commit/248ade7a9c.../build/12345/logs?filter=all#section-2",
|
||||
"context": "continuous-integration/jenkins/build-and-test-all-platforms",
|
||||
"created_at": "2024-01-15T10:30:00Z",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "failure status",
|
||||
status: &gitea_sdk.Status{
|
||||
ID: 101,
|
||||
State: gitea_sdk.StatusFailure,
|
||||
TargetURL: "https://ci.example.com/build/101",
|
||||
Context: "ci/build",
|
||||
Description: "Build failed",
|
||||
CreatedAt: "2024-01-15T11:00:00Z",
|
||||
},
|
||||
want: map[string]any{
|
||||
"id": int64(101),
|
||||
"state": gitea_sdk.StatusFailure,
|
||||
"target_url": "https://ci.example.com/build/101",
|
||||
"context": "ci/build",
|
||||
"created_at": "2024-01-15T11:00:00Z",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "error status",
|
||||
status: &gitea_sdk.Status{
|
||||
ID: 102,
|
||||
State: gitea_sdk.StatusError,
|
||||
TargetURL: "",
|
||||
Context: "ci/error",
|
||||
Description: "Error occurred",
|
||||
CreatedAt: "2024-01-15T11:01:00Z",
|
||||
},
|
||||
want: map[string]any{
|
||||
"id": int64(102),
|
||||
"state": gitea_sdk.StatusError,
|
||||
"target_url": "",
|
||||
"context": "ci/error",
|
||||
"created_at": "2024-01-15T11:01:00Z",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := slimStatus(tt.status)
|
||||
if tt.want == nil {
|
||||
if got != nil {
|
||||
t.Errorf("slimStatus() = %v, want nil", got)
|
||||
}
|
||||
return
|
||||
}
|
||||
if got == nil {
|
||||
t.Errorf("slimStatus() = nil, want %v", tt.want)
|
||||
return
|
||||
}
|
||||
for key, wantVal := range tt.want {
|
||||
gotVal, ok := got[key]
|
||||
if !ok {
|
||||
t.Errorf("slimStatus() missing key %s", key)
|
||||
continue
|
||||
}
|
||||
if gotVal != wantVal {
|
||||
t.Errorf("slimStatus()[%s] = %v, want %v", key, gotVal, wantVal)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorTranslation_EdgeCases(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
errMsg string
|
||||
ctx map[string]string
|
||||
checkField string
|
||||
wantValue string
|
||||
}{
|
||||
{
|
||||
name: "timeout error",
|
||||
errMsg: "request timeout",
|
||||
ctx: map[string]string{"operation": "CreateCommitStatus"},
|
||||
checkField: "operation",
|
||||
wantValue: "CreateCommitStatus",
|
||||
},
|
||||
{
|
||||
name: "network error",
|
||||
errMsg: "connection refused",
|
||||
ctx: map[string]string{"operation": "CreateCommitStatus"},
|
||||
checkField: "operation",
|
||||
wantValue: "CreateCommitStatus",
|
||||
},
|
||||
{
|
||||
name: "500 server error",
|
||||
errMsg: "500 Internal Server Error",
|
||||
ctx: map[string]string{"operation": "CreateCommitStatus"},
|
||||
checkField: "operation",
|
||||
wantValue: "CreateCommitStatus",
|
||||
},
|
||||
{
|
||||
name: "rate limit error",
|
||||
errMsg: "429 Too Many Requests",
|
||||
ctx: map[string]string{"operation": "CreateCommitStatus"},
|
||||
checkField: "operation",
|
||||
wantValue: "CreateCommitStatus",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := errors.New(tt.errMsg)
|
||||
translated := gitea_errors.TranslateError(err, tt.ctx)
|
||||
|
||||
var enhanced *gitea_errors.EnhancedError
|
||||
if !errors.As(translated, &enhanced) {
|
||||
t.Fatal("expected translated error to be EnhancedError")
|
||||
}
|
||||
|
||||
if enhanced.Context[tt.checkField] != tt.wantValue {
|
||||
t.Errorf("expected context[%s] = %s, got %s", tt.checkField, tt.wantValue, enhanced.Context[tt.checkField])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSlimStatusFieldTypes(t *testing.T) {
|
||||
status := &gitea_sdk.Status{
|
||||
ID: int64(999),
|
||||
State: gitea_sdk.StatusSuccess,
|
||||
TargetURL: "https://example.com",
|
||||
Context: "test",
|
||||
Description: "desc",
|
||||
CreatedAt: "2024-01-15T10:30:00Z",
|
||||
}
|
||||
|
||||
slimmed := slimStatus(status)
|
||||
|
||||
if slimmed == nil {
|
||||
t.Fatal("slimStatus returned nil")
|
||||
}
|
||||
|
||||
if id, ok := slimmed["id"].(int64); !ok {
|
||||
t.Errorf("id should be int64, got %T", slimmed["id"])
|
||||
} else if id != 999 {
|
||||
t.Errorf("id = %d, want 999", id)
|
||||
}
|
||||
|
||||
if state, ok := slimmed["state"].(gitea_sdk.StatusState); !ok {
|
||||
t.Errorf("state should be StatusState, got %T", slimmed["state"])
|
||||
} else if state != gitea_sdk.StatusSuccess {
|
||||
t.Errorf("state = %v, want %v", state, gitea_sdk.StatusSuccess)
|
||||
}
|
||||
|
||||
for _, key := range []string{"target_url", "context", "description", "created_at"} {
|
||||
if val, ok := slimmed[key].(string); !ok && slimmed[key] != nil {
|
||||
t.Errorf("%s should be string, got %T", key, slimmed[key])
|
||||
} else if !ok {
|
||||
t.Errorf("%s should not be nil", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user