package gitea_test import ( "context" "net/http" "net/http/httptest" "sync/atomic" "testing" "gitea.d-ma.be/mathias/gitea-mcp/internal/gitea" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestSearchRepos(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "/api/v1/repos/search", r.URL.Path) assert.Equal(t, "infra", r.URL.Query().Get("q")) assert.Equal(t, "mathias", r.URL.Query().Get("owner")) w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{"data":[{"name":"infra","full_name":"mathias/infra","default_branch":"main"}],"ok":true}`)) })) defer srv.Close() c := gitea.NewClient(srv.URL, "tok") repos, err := c.SearchRepos(context.Background(), "infra", "mathias", 1, 30) require.NoError(t, err) require.Len(t, repos, 1) assert.Equal(t, "mathias/infra", repos[0].FullName) } func TestListRepos(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "/api/v1/users/mathias/repos", r.URL.Path) assert.Equal(t, "1", r.URL.Query().Get("page")) assert.Equal(t, "10", r.URL.Query().Get("limit")) w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`[{"name":"infra","full_name":"mathias/infra","default_branch":"main","description":"d","private":true}]`)) })) defer srv.Close() c := gitea.NewClient(srv.URL, "tok") repos, err := c.ListRepos(context.Background(), "mathias", 1, 10) require.NoError(t, err) require.Len(t, repos, 1) assert.Equal(t, "mathias/infra", repos[0].FullName) assert.Equal(t, "main", repos[0].DefaultBranch) } func TestCreateRepo_User(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPost, r.Method) assert.Equal(t, "/api/v1/user/repos", r.URL.Path) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) _, _ = w.Write([]byte(`{"name":"infra","full_name":"mathias/infra","default_branch":"main","private":true,"clone_url":"https://gitea.example.com/mathias/infra.git","html_url":"https://gitea.example.com/mathias/infra"}`)) })) defer srv.Close() c := gitea.NewClient(srv.URL, "tok") r, err := c.CreateRepo(context.Background(), gitea.CreateRepoArgs{ Name: "infra", Private: true, }) require.NoError(t, err) assert.Equal(t, "mathias/infra", r.FullName) assert.Equal(t, "main", r.DefaultBranch) } func TestCreateRepo_Org(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPost, r.Method) assert.Equal(t, "/api/v1/orgs/hyperguild/repos", r.URL.Path) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) _, _ = w.Write([]byte(`{"name":"infra","full_name":"hyperguild/infra","default_branch":"main","private":false,"clone_url":"https://gitea.example.com/hyperguild/infra.git","html_url":"https://gitea.example.com/hyperguild/infra"}`)) })) defer srv.Close() c := gitea.NewClient(srv.URL, "tok") r, err := c.CreateRepo(context.Background(), gitea.CreateRepoArgs{ Name: "infra", Org: "hyperguild", }) require.NoError(t, err) assert.Equal(t, "hyperguild/infra", r.FullName) } func TestUpdateRepo(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPatch, r.Method) assert.Equal(t, "/api/v1/repos/mathias/infra", r.URL.Path) w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{"name":"infra","full_name":"mathias/infra","default_branch":"main","description":"updated","private":false,"clone_url":"https://gitea.example.com/mathias/infra.git","html_url":"https://gitea.example.com/mathias/infra"}`)) })) defer srv.Close() desc := "updated" c := gitea.NewClient(srv.URL, "tok") r, err := c.UpdateRepo(context.Background(), "mathias", "infra", gitea.UpdateRepoArgs{ Description: &desc, }) require.NoError(t, err) assert.Equal(t, "updated", r.Description) } func TestGetTree(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "/api/v1/repos/mathias/infra/git/trees/main", r.URL.Path) assert.Equal(t, "1", r.URL.Query().Get("recursive")) w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{"sha":"abc","url":"http://x","tree":[{"path":"README.md","type":"blob","sha":"def","size":13},{"path":"internal","type":"tree","sha":"ghi"}],"truncated":false}`)) })) defer srv.Close() c := gitea.NewClient(srv.URL, "tok") tree, err := c.GetTree(context.Background(), "mathias", "infra", "main", true) require.NoError(t, err) assert.Equal(t, "abc", tree.SHA) require.Len(t, tree.Tree, 2) assert.Equal(t, "README.md", tree.Tree[0].Path) assert.Equal(t, "blob", tree.Tree[0].Type) assert.Equal(t, int64(13), tree.Tree[0].Size) } func TestUpdateTopics(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPut, r.Method) assert.Equal(t, "/api/v1/repos/mathias/infra/topics", r.URL.Path) w.WriteHeader(http.StatusNoContent) })) defer srv.Close() c := gitea.NewClient(srv.URL, "tok") err := c.UpdateTopics(context.Background(), "mathias", "infra", []string{"go", "mcp", "gitops"}) require.NoError(t, err) } func TestCreateRelease(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPost, r.Method) assert.Equal(t, "/api/v1/repos/mathias/infra/releases", r.URL.Path) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) _, _ = w.Write([]byte(`{"id":1,"tag_name":"v1.0.0","name":"v1.0.0","body":"first release","draft":false,"prerelease":false,"html_url":"https://gitea.example.com/mathias/infra/releases/tag/v1.0.0","created_at":"2026-05-15T00:00:00Z"}`)) })) defer srv.Close() c := gitea.NewClient(srv.URL, "tok") rel, err := c.CreateRelease(context.Background(), "mathias", "infra", gitea.CreateReleaseArgs{ TagName: "v1.0.0", Name: "v1.0.0", Body: "first release", }) require.NoError(t, err) assert.Equal(t, "v1.0.0", rel.TagName) assert.Equal(t, "first release", rel.Body) } func TestDeleteRepo(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodDelete, r.Method) assert.Equal(t, "/api/v1/repos/mathias/infra", r.URL.Path) w.WriteHeader(http.StatusNoContent) })) defer srv.Close() c := gitea.NewClient(srv.URL, "tok") err := c.DeleteRepo(context.Background(), "mathias", "infra") require.NoError(t, err) } func TestDefaultBranchCachesAcrossCalls(t *testing.T) { var hits int32 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { atomic.AddInt32(&hits, 1) w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{"name":"infra","full_name":"o/infra","default_branch":"trunk"}`)) })) defer srv.Close() c := gitea.NewClient(srv.URL, "tok") for i := 0; i < 5; i++ { b, err := c.DefaultBranch(context.Background(), "o", "infra") require.NoError(t, err) assert.Equal(t, "trunk", b) } assert.Equal(t, int32(1), atomic.LoadInt32(&hits), "5 calls should cause exactly 1 server hit due to cache") }