diff --git a/backend/plugins/testmo/tasks/shared.go b/backend/plugins/testmo/tasks/shared.go index 3a2e86dd53f..2d8187d7e32 100644 --- a/backend/plugins/testmo/tasks/shared.go +++ b/backend/plugins/testmo/tasks/shared.go @@ -45,20 +45,20 @@ func CreateTestmoApiClient(taskCtx plugin.TaskContext, connection *models.Testmo return CreateApiClient(taskCtx, connection) } +// GetTotalPagesFromResponse reads the page count of a Testmo list response. +// Testmo returns the pagination fields (page, prev_page, next_page, +// last_page, per_page, total) at the top level of the body, not in a meta +// object; last_page is nullable. func GetTotalPagesFromResponse(res *http.Response, args *helper.ApiCollectorArgs) (int, errors.Error) { - body := &models.TestmoResponse{} + body := &struct { + LastPage *int `json:"last_page"` + }{} err := helper.UnmarshalResponse(res, body) if err != nil { return 0, err } - - // Parse meta information for pagination - if meta, ok := body.Meta.(map[string]interface{}); ok { - if totalPages, exists := meta["total_pages"]; exists { - if pages, ok := totalPages.(float64); ok { - return int(pages), nil - } - } + if body.LastPage != nil && *body.LastPage > 1 { + return *body.LastPage, nil } return 1, nil } diff --git a/backend/plugins/testmo/tasks/shared_test.go b/backend/plugins/testmo/tasks/shared_test.go new file mode 100644 index 00000000000..c98a037386c --- /dev/null +++ b/backend/plugins/testmo/tasks/shared_test.go @@ -0,0 +1,65 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tasks + +import ( + "io" + "net/http" + "strings" + "testing" + + helper "github.com/apache/devlake/helpers/pluginhelper/api" + "github.com/stretchr/testify/assert" +) + +func newTestmoListResponse(body string) *http.Response { + return &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(strings.NewReader(body)), + } +} + +func TestGetTotalPagesFromResponse(t *testing.T) { + args := &helper.ApiCollectorArgs{PageSize: 100} + + t.Run("first of several pages", func(t *testing.T) { + // Testmo list endpoints (RunPage, MilestonePage, AutomationRunPage) + // return the pagination fields at the top level. + res := newTestmoListResponse(`{"page": 1, "prev_page": null, "next_page": 2, "last_page": 3, + "per_page": 100, "total": 250, "result": [{"id": 1}]}`) + totalPages, err := GetTotalPagesFromResponse(res, args) + assert.Nil(t, err) + assert.Equal(t, 3, totalPages) + }) + + t.Run("single page", func(t *testing.T) { + res := newTestmoListResponse(`{"page": 1, "prev_page": null, "next_page": null, "last_page": 1, + "per_page": 100, "total": 2, "result": [{"id": 1}, {"id": 2}]}`) + totalPages, err := GetTotalPagesFromResponse(res, args) + assert.Nil(t, err) + assert.Equal(t, 1, totalPages) + }) + + t.Run("no results", func(t *testing.T) { + res := newTestmoListResponse(`{"page": null, "prev_page": null, "next_page": null, "last_page": null, + "per_page": 100, "total": 0, "result": []}`) + totalPages, err := GetTotalPagesFromResponse(res, args) + assert.Nil(t, err) + assert.Equal(t, 1, totalPages) + }) +}