Files
gitea-tea/internal/services/helpers_test.go
T
bircni c8073f1b2e feat(services): classify API failures by resource and report page totals
Add NotFoundError, ConflictError and AmbiguousError so commands can report
"issue #999 not found in alice/project" or "alice/old-stuff is archived"
instead of the transport's status text. Classify wraps a failure with the
resource the caller names; ClassifyRequest infers it from the endpoint for
failures no service classified, and maps the refusals Gitea explains (archived
repository, merged or draft pull request, own review, existing resource,
unknown user, disabled workflow, completed run, reused SSH key).

Page reports the X-Total-Count that listWindow discarded, NameOrID resolves a
resource by ID or name (numeric values are IDs first, ambiguous names list
their IDs), and rawPage pages raw collection endpoints.

Signed-off-by: bircni <bircni@icloud.com>
2026-10-11 22:48:49 +02:00

78 lines
2.5 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package services
import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"gitea.dev/tea/internal/transport"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// newTestClient serves handler for the duration of the test and returns a client for it.
// Requests probing the server version or API schema fail the test: tea targets one Gitea
// release and must never gate operations on either.
func newTestClient(t *testing.T, handler http.Handler) *transport.Client {
t.Helper()
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasSuffix(r.URL.Path, "/api/v1/version") || strings.HasSuffix(r.URL.Path, "/swagger.v1.json") {
t.Errorf("unexpected capability probe %s", r.URL.Path)
w.WriteHeader(http.StatusTeapot)
return
}
handler.ServeHTTP(w, r)
}))
t.Cleanup(server.Close)
return transport.New(server.URL, "", false)
}
// requestJSON decodes the JSON object a handler received.
func requestJSON(t *testing.T, r *http.Request) map[string]any {
t.Helper()
var payload map[string]any
assert.NoError(t, json.NewDecoder(r.Body).Decode(&payload))
return payload
}
func TestNameOrIDPrefersIDsThenExactThenFoldedNames(t *testing.T) {
type label struct {
id int64
name string
}
labels := []label{{11, "bug"}, {12, "Bug"}, {13, "7"}, {7, "seven"}, {20, "kind/feature"}, {21, "dup"}, {22, "dup"}}
lookup := NameOrID[label]{Kind: "label", Scope: "alice/project", ID: func(l label) int64 { return l.id }, Name: func(l label) string { return l.name }}
for _, tc := range []struct {
raw string
byName bool
want int64
err string
}{
{raw: "7", want: 7},
{raw: "7", byName: true, want: 13},
{raw: "13", want: 13},
{raw: "bug", want: 11},
{raw: "BUG", err: `label "BUG" is ambiguous in alice/project (IDs 11, 12); pass an ID`},
{raw: "KIND/FEATURE", want: 20},
{raw: " kind/feature ", want: 20},
{raw: "dup", err: `label "dup" is ambiguous in alice/project (IDs 21, 22); pass an ID`},
{raw: "nope", err: `label "nope" not found in alice/project`},
{raw: "99", err: "label 99 not found in alice/project"},
{raw: "99", byName: true, err: `label "99" not found in alice/project`},
} {
lookup.ByName = tc.byName
got, err := lookup.Find(labels, tc.raw)
if tc.err != "" {
require.EqualError(t, err, tc.err, tc.raw)
continue
}
require.NoError(t, err, tc.raw)
require.Equal(t, tc.want, got.id, tc.raw)
}
}