mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 19:11:25 +01:00
org member remove and public/private exited 0 without a word for users who are not members, and member list --public showed concealed members, because Gitea lists them as public to administrators. Membership changes now check the membership first: removing a non-member warns, publicizing one fails, and a change to the current visibility warns. Member list checks each membership and gains a VISIBILITY column. org list and member list get a header and context line through writeTable, org view shows the description, website, location and member, team and repository counts, mutations print ✓ lines, and org delete asks to type the organization's name after refusing organizations that still own repositories. public and private become publicize and conceal, the old names stay as aliases, and org edit --visibility no longer shows the create default. Every command has examples, and organizations and members complete. Signed-off-by: bircni <bircni@icloud.com>
121 lines
4.0 KiB
Go
121 lines
4.0 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package services
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.dev/tea/internal/transport"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// cappedServer serves total items in pages of at most maxItems, like Gitea's MAX_RESPONSE_ITEMS.
|
|
func cappedServer(t *testing.T, total, maxItems int, link, count bool) (*httptest.Server, *int) {
|
|
t.Helper()
|
|
requests := 0
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
requests++
|
|
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
|
require.NoError(t, err)
|
|
page, err := strconv.Atoi(r.URL.Query().Get("page"))
|
|
require.NoError(t, err)
|
|
size := min(limit, maxItems)
|
|
items := []string{}
|
|
for id := (page-1)*size + 1; id <= min(page*size, total); id++ {
|
|
items = append(items, fmt.Sprintf(`{"id":%d,"name":"n%d","full_name":"o/n%d"}`, id, id, id))
|
|
}
|
|
if count {
|
|
w.Header().Set("X-Total-Count", strconv.Itoa(total))
|
|
}
|
|
if link && page*size < total {
|
|
w.Header().Set("Link", fmt.Sprintf(`<%s%s?limit=%d&page=%d>; rel="next"`, "http://"+r.Host, r.URL.Path, limit, page+1))
|
|
}
|
|
_, _ = w.Write([]byte("[" + strings.Join(items, ",") + "]"))
|
|
}))
|
|
t.Cleanup(server.Close)
|
|
return server, &requests
|
|
}
|
|
|
|
func TestListsCollectPagesBeyondServerPageSize(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
total, maxItems, limit, page int
|
|
link, count bool
|
|
}{
|
|
{120, 50, 100, 1, true, true},
|
|
{120, 50, 100, 2, true, true},
|
|
{120, 50, 60, 2, true, true},
|
|
{120, 50, 30, 3, true, true},
|
|
{120, 50, 100, 3, true, true},
|
|
{100, 50, 100, 2, true, true},
|
|
{110, 60, 100, 2, true, true},
|
|
{120, 50, 100, 1, true, false},
|
|
{120, 50, 100, 2, true, false},
|
|
{120, 50, 100, 1, false, true},
|
|
{120, 50, 100, 2, false, true},
|
|
{110, 60, 100, 2, false, true},
|
|
{40, 50, 100, 1, false, false},
|
|
{120, 100, 100, 2, true, true},
|
|
} {
|
|
t.Run(fmt.Sprintf("%+v", tc), func(t *testing.T) {
|
|
server, requests := cappedServer(t, tc.total, tc.maxItems, tc.link, tc.count)
|
|
want := []int64{}
|
|
for id := (tc.page-1)*tc.limit + 1; id <= min(tc.page*tc.limit, tc.total); id++ {
|
|
want = append(want, int64(id))
|
|
}
|
|
client := transport.New(server.URL, "", false)
|
|
orgs, err := (Organizations{Client: client}).List(context.Background(), true, "", tc.limit, tc.page)
|
|
require.NoError(t, err)
|
|
got := []int64{}
|
|
for _, item := range orgs.Items {
|
|
got = append(got, item.ID)
|
|
}
|
|
require.Equal(t, want, got)
|
|
require.Equal(t, tc.total > tc.page*tc.limit, orgs.More)
|
|
require.LessOrEqual(t, *requests, tc.limit/min(tc.limit, tc.maxItems)+2)
|
|
repos, more, err := (Repositories{Client: client}).List(context.Background(), RepositoryListOptions{Limit: tc.limit, Page: tc.page})
|
|
require.NoError(t, err)
|
|
got = []int64{}
|
|
for _, item := range repos {
|
|
got = append(got, item.ID)
|
|
}
|
|
require.Equal(t, want, got)
|
|
require.Equal(t, tc.total > tc.page*tc.limit, more)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPagesReportTheCountedTotal(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
total, maxItems, limit, page int
|
|
count, more bool
|
|
}{
|
|
{120, 50, 30, 1, true, true},
|
|
{120, 50, 1000, 1, true, false},
|
|
{120, 50, 100, 2, true, false},
|
|
{40, 50, 100, 1, false, false},
|
|
} {
|
|
t.Run(fmt.Sprintf("%+v", tc), func(t *testing.T) {
|
|
server, _ := cappedServer(t, tc.total, tc.maxItems, true, tc.count)
|
|
client := transport.New(server.URL, "", false)
|
|
query := url.Values{"state": {"open"}}
|
|
window, err := rawPage[Organization](context.Background(), client, "orgs", query, tc.limit, tc.page)
|
|
require.NoError(t, err)
|
|
require.Len(t, window.Items, min(tc.limit, max(0, tc.total-(tc.page-1)*tc.limit)))
|
|
require.Equal(t, tc.more, window.More)
|
|
require.Equal(t, tc.count, window.Counted)
|
|
if tc.count {
|
|
require.Equal(t, tc.total, window.Total)
|
|
}
|
|
require.Equal(t, url.Values{"state": {"open"}}, query, "the caller's query is not modified")
|
|
})
|
|
}
|
|
}
|