Pagination deploy fix
This commit is contained in:
@@ -1439,6 +1439,7 @@ func (c *nodeBBClient) listNamespacePagesWithQuery(cid int, query string) ([]nod
|
|||||||
var out []nodeBBWikiPage
|
var out []nodeBBWikiPage
|
||||||
after := ""
|
after := ""
|
||||||
seenCursors := map[string]struct{}{}
|
seenCursors := map[string]struct{}{}
|
||||||
|
seenPages := map[string]struct{}{}
|
||||||
for {
|
for {
|
||||||
path := fmt.Sprintf("/api/v3/plugins/westgate-wiki/namespace/%d/pages?limit=80", cid)
|
path := fmt.Sprintf("/api/v3/plugins/westgate-wiki/namespace/%d/pages?limit=80", cid)
|
||||||
if query != "" {
|
if query != "" {
|
||||||
@@ -1452,14 +1453,34 @@ func (c *nodeBBClient) listNamespacePagesWithQuery(cid int, query string) ([]nod
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
pages, next, hasMore := parseNodeBBWikiPageList(doc)
|
pages, next, hasMore := parseNodeBBWikiPageList(doc)
|
||||||
out = append(out, pages...)
|
newPages := 0
|
||||||
|
for _, page := range pages {
|
||||||
|
identity := nodeBBWikiPageIdentity(page)
|
||||||
|
if identity == "" {
|
||||||
|
out = append(out, page)
|
||||||
|
newPages++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := seenPages[identity]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seenPages[identity] = struct{}{}
|
||||||
|
out = append(out, page)
|
||||||
|
newPages++
|
||||||
|
}
|
||||||
if !hasMore || next == "" {
|
if !hasMore || next == "" {
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
if after != "" && next == after {
|
if after != "" && next == after {
|
||||||
|
if newPages == 0 {
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
return nil, fmt.Errorf("NodeBB wiki namespace %d returned repeated pagination cursor %q", cid, next)
|
return nil, fmt.Errorf("NodeBB wiki namespace %d returned repeated pagination cursor %q", cid, next)
|
||||||
}
|
}
|
||||||
if _, ok := seenCursors[next]; ok {
|
if _, ok := seenCursors[next]; ok {
|
||||||
|
if newPages == 0 {
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
return nil, fmt.Errorf("NodeBB wiki namespace %d returned repeated pagination cursor %q", cid, next)
|
return nil, fmt.Errorf("NodeBB wiki namespace %d returned repeated pagination cursor %q", cid, next)
|
||||||
}
|
}
|
||||||
seenCursors[next] = struct{}{}
|
seenCursors[next] = struct{}{}
|
||||||
@@ -1467,6 +1488,18 @@ func (c *nodeBBClient) listNamespacePagesWithQuery(cid int, query string) ([]nod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func nodeBBWikiPageIdentity(page nodeBBWikiPage) string {
|
||||||
|
if page.TID != 0 {
|
||||||
|
return fmt.Sprintf("tid:%d", page.TID)
|
||||||
|
}
|
||||||
|
for _, value := range []string{page.WikiPath, page.CanonicalPath, page.Slug, page.Title} {
|
||||||
|
if trimmed := strings.TrimSpace(value); trimmed != "" {
|
||||||
|
return strings.ToLower(trimmed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (c *nodeBBClient) createTopic(cid int, title, content, summary string) (nodeBBPost, error) {
|
func (c *nodeBBClient) createTopic(cid int, title, content, summary string) (nodeBBPost, error) {
|
||||||
body := map[string]any{"cid": cid, "title": title, "content": content, "sourceContent": content}
|
body := map[string]any{"cid": cid, "title": title, "content": content, "sourceContent": content}
|
||||||
if summary != "" {
|
if summary != "" {
|
||||||
|
|||||||
@@ -226,18 +226,52 @@ func TestDeployWikiReportsLiveExecutionProgress(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNodeBBNamespacePaginationRejectsRepeatedCursor(t *testing.T) {
|
func TestNodeBBNamespacePaginationStopsWhenRepeatedCursorReturnsNoNewPages(t *testing.T) {
|
||||||
requests := 0
|
requests := 0
|
||||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
requests++
|
requests++
|
||||||
if requests > 2 {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||||
"response": map[string]any{
|
"response": map[string]any{
|
||||||
"pages": []map[string]any{},
|
"pages": []map[string]any{
|
||||||
|
{"tid": 2461, "title": "Favored Enemy: Elves", "titleLeaf": "Favored Enemy: Elves"},
|
||||||
|
},
|
||||||
|
"hasMore": true,
|
||||||
|
"nextCursor": "same-cursor",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
client := newNodeBBClient(server.URL, "nodebb-token")
|
||||||
|
pages, err := client.listNamespacePages(9)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected repeated cursor with duplicate pages to stop cleanly, got %v", err)
|
||||||
|
}
|
||||||
|
if len(pages) != 1 || pages[0].TID != 2461 {
|
||||||
|
t.Fatalf("expected one unique page from repeated cursor response, got %#v", pages)
|
||||||
|
}
|
||||||
|
if requests != 2 {
|
||||||
|
t.Fatalf("expected pagination to stop after repeated cursor, got %d requests", requests)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNodeBBNamespacePaginationRejectsRepeatedCursorWithNewPages(t *testing.T) {
|
||||||
|
requests := 0
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
requests++
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
pages := []map[string]any{
|
||||||
|
{"tid": 1, "title": "First", "titleLeaf": "First"},
|
||||||
|
}
|
||||||
|
if requests == 2 {
|
||||||
|
pages = []map[string]any{
|
||||||
|
{"tid": 2, "title": "Second", "titleLeaf": "Second"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||||
|
"response": map[string]any{
|
||||||
|
"pages": pages,
|
||||||
"hasMore": true,
|
"hasMore": true,
|
||||||
"nextCursor": "same-cursor",
|
"nextCursor": "same-cursor",
|
||||||
},
|
},
|
||||||
@@ -248,14 +282,11 @@ func TestNodeBBNamespacePaginationRejectsRepeatedCursor(t *testing.T) {
|
|||||||
client := newNodeBBClient(server.URL, "nodebb-token")
|
client := newNodeBBClient(server.URL, "nodebb-token")
|
||||||
_, err := client.listNamespacePages(9)
|
_, err := client.listNamespacePages(9)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected repeated cursor error")
|
t.Fatal("expected repeated cursor with new pages to fail")
|
||||||
}
|
}
|
||||||
if !strings.Contains(err.Error(), "repeated pagination cursor") {
|
if !strings.Contains(err.Error(), "repeated pagination cursor") {
|
||||||
t.Fatalf("expected repeated cursor error, got %v", err)
|
t.Fatalf("expected repeated cursor error, got %v", err)
|
||||||
}
|
}
|
||||||
if requests != 2 {
|
|
||||||
t.Fatalf("expected pagination to stop after repeated cursor, got %d requests", requests)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCollectLocalPagesReadsGeneratedPageIDFromMarkerWhenPathIsTitleBased(t *testing.T) {
|
func TestCollectLocalPagesReadsGeneratedPageIDFromMarkerWhenPathIsTitleBased(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user