Files
gitea-tea/internal/app/checks_test.go
T
bircni 81b0c1b99e fix: reconcile the pull request stream
Share one shortSHA helper, keep Markdown raw in view tests through the
markdown preference, and drop rawWindow now that pull request lists use
the paged helpers.

Signed-off-by: bircni <bircni@icloud.com>
2026-10-11 23:56:25 +02:00

155 lines
6.0 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package app
import (
"context"
"net/http"
"strings"
"testing"
"gitea.dev/tea/internal/clierr"
"github.com/stretchr/testify/require"
)
func TestChecksUseLatestContextAcrossPagesAndReturnFailureWithCleanJSON(t *testing.T) {
state := "success"
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodGet, r.Method)
if r.URL.Path == "/api/v1/repos/owner/repo/pulls/7" {
_, _ = w.Write([]byte(`{"head":{"sha":"abc123"}}`))
return
}
require.Equal(t, "/api/v1/repos/owner/repo/statuses/abc123", r.URL.Path)
switch r.URL.Query().Get("page") {
case "1":
_, _ = w.Write([]byte(`[{"id":1,"context":"build","status":"failure"}]`))
case "2":
_, _ = w.Write([]byte(`[{"id":2,"context":"build","status":"` + state + `","creator":{"login":"excluded"}}]`))
default:
_, _ = w.Write([]byte(`[]`))
}
}))
defer server.Close()
deps, out, diagnostics := serverDeps(t, server.URL)
args := []string{"pr", "checks", "7", "-R", "owner/repo", "--json=id,name,state"}
require.NoError(t, Execute(context.Background(), deps, args))
require.JSONEq(t, `[{"id":2,"name":"build","state":"success"}]`, out.String())
out.Reset()
state = "pending"
err := Execute(context.Background(), deps, args)
require.Equal(t, clierr.Pending, clierr.ExitCode(err))
require.True(t, clierr.IsQuiet(err))
require.JSONEq(t, `[{"id":2,"name":"build","state":"pending"}]`, out.String())
out.Reset()
state = "skipped"
require.NoError(t, Execute(context.Background(), deps, args))
require.Empty(t, diagnostics.String())
}
func TestChecksWatchWaitsForRegistrationAndEmitsOneJSONResult(t *testing.T) {
polls := 0
keepPending := false
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/api/v1/repos/owner/repo/pulls/7" {
polls++
_, _ = w.Write([]byte(`{"head":{"sha":"abc123"}}`))
return
}
if r.URL.Query().Get("page") != "1" || polls == 1 {
_, _ = w.Write([]byte(`[]`))
return
}
state := "pending"
if polls >= 3 && !keepPending {
state = "success"
}
_, _ = w.Write([]byte(`[{"id":2,"context":"build","status":"` + state + `"}]`))
}))
defer server.Close()
deps, out, diagnostics := serverDeps(t, server.URL)
require.NoError(t, Execute(context.Background(), deps, []string{"pr", "checks", "7", "-R", "owner/repo", "--watch", "--interval=1ms", "--timeout=1s", "--json=name,state"}))
require.Equal(t, 4, polls)
require.JSONEq(t, `[{"name":"build","state":"success"}]`, out.String())
require.Contains(t, diagnostics.String(), "1 pending")
keepPending = true
out.Reset()
diagnostics.Reset()
err := Execute(context.Background(), deps, []string{"pr", "checks", "7", "-R", "owner/repo", "--watch", "--interval=1ms", "--timeout=20ms", "--json"})
require.ErrorIs(t, err, context.DeadlineExceeded)
require.Equal(t, clierr.Canceled, clierr.ExitCode(err))
require.Empty(t, out.String())
ctx, cancel := context.WithCancel(context.Background())
cancel()
err = Execute(ctx, deps, []string{"pr", "checks", "7", "-R", "owner/repo", "--watch"})
require.ErrorIs(t, err, context.Canceled)
require.Equal(t, clierr.Canceled, clierr.ExitCode(err))
}
func TestChecksSummaryAndExitCodes(t *testing.T) {
for _, tc := range []struct {
name, statuses, want string
code int
}{
{
name: "pending",
statuses: `[{"id":1,"context":"ci / test (pull_request)","status":"pending","description":"Waiting to run","target_url":"/alice/x/actions/runs/18/jobs/18"}]`,
want: "Some checks are still pending\n0 failing, 0 successful, and 1 pending checks\n\n" +
" NAME STATUS DESCRIPTION LINK\n" +
"* ci / test (pull_request) pending Waiting to run SERVER/alice/x/actions/runs/18/jobs/18\n",
code: clierr.Pending,
},
{
name: "failing",
statuses: `[{"id":1,"context":"lint","status":"failure"},{"id":2,"context":"test","status":"success"}]`,
want: "Some checks were not successful\n1 failing, 1 successful, and 0 pending checks\n\n NAME STATUS DESCRIPTION LINK\nX lint failure\n✓ test success\n",
code: clierr.Failure,
},
{name: "none", statuses: `[]`},
} {
t.Run(tc.name, func(t *testing.T) {
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case r.URL.Path == "/api/v1/repos/alice/x/pulls/8":
_, _ = w.Write([]byte(`{"number":8,"head":{"sha":"abc"}}`))
case r.URL.Query().Get("page") == "1":
_, _ = w.Write([]byte(tc.statuses))
default:
_, _ = w.Write([]byte(`[]`))
}
}))
defer server.Close()
deps, out, diagnostics := serverDeps(t, server.URL)
plainTTY(t, &deps, server.URL)
err := Execute(context.Background(), deps, []string{"pr", "checks", "8", "-R", "alice/x"})
require.Equal(t, tc.code, clierr.ExitCode(err))
if tc.code != 0 {
require.True(t, clierr.IsQuiet(err), "the summary already reports the outcome")
}
require.Equal(t, strings.ReplaceAll(tc.want, "SERVER", server.URL), out.String())
if tc.want == "" {
require.Equal(t, "no checks reported for pull request alice/x#8\n", diagnostics.String())
}
})
}
}
func TestChecksWatchTimeoutCountsPendingChecks(t *testing.T) {
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case r.URL.Path == "/api/v1/repos/alice/x/pulls/8":
_, _ = w.Write([]byte(`{"number":8,"head":{"sha":"abc"}}`))
case r.URL.Query().Get("page") == "1":
_, _ = w.Write([]byte(`[{"id":1,"context":"a","status":"pending"},{"id":2,"context":"b","status":"pending"}]`))
default:
_, _ = w.Write([]byte(`[]`))
}
}))
defer server.Close()
deps, _, _ := serverDeps(t, server.URL)
err := Execute(context.Background(), deps, []string{"pr", "checks", "8", "-R", "alice/x", "--watch", "--interval=1ms", "--timeout=30ms"})
require.EqualError(t, err, "timed out after 30ms waiting for 2 pending checks")
require.ErrorIs(t, err, context.DeadlineExceeded)
}