Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add ListServicesPaginated to services api (and tests) #260

Merged
merged 7 commits into from
Feb 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 11 additions & 1 deletion client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io"
"net"
"net/http"
"path"
"runtime"
"strings"
"time"
Expand Down Expand Up @@ -356,6 +357,14 @@ func (c *Client) getErrorFromResponse(resp *http.Response) APIError {
return document
}

// Helper function to determine wither additional parameters should use ? or & to append args
func getBasePrefix(basePath string) string {
if strings.Contains(path.Base(basePath), "?") {
return basePath + "&"
}
return basePath + "?"
}
theckman marked this conversation as resolved.
Show resolved Hide resolved

// responseHandler is capable of parsing a response. At a minimum it must
// extract the page information for the current page. It can also execute
// additional necessary handling; for example, if a closure, it has access
Expand All @@ -370,9 +379,10 @@ func (c *Client) pagedGet(ctx context.Context, basePath string, handler response
// Offset to set for the next page request.
var nextOffset uint

basePrefix := getBasePrefix(basePath)
// While there are more pages, keep adjusting the offset to get all results.
for stillMore, nextOffset = true, 0; stillMore; {
response, err := c.do(ctx, http.MethodGet, fmt.Sprintf("%s?offset=%d", basePath, nextOffset), nil, nil)
response, err := c.do(ctx, http.MethodGet, fmt.Sprintf("%soffset=%d", basePrefix, nextOffset), nil, nil)
if err != nil {
return err
}
Expand Down
19 changes: 19 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,25 @@ func testEqual(t *testing.T, expected interface{}, actual interface{}) {
}
}

func TestGetBasePrefix(t *testing.T) {
var testTable = []struct {
in string
out string
}{
{"base.com/noparams", "base.com/noparams?"},
{"base.com/?/noparams", "base.com/?/noparams?"},
{"base.com/params?value=1", "base.com/params?value=1&"},
{"base.com/?/params?value=1", "base.com/?/params?value=1&"},
{"noslashes", "noslashes?"}, // this is what it will do... tbd what it should actually do
}
for _, tt := range testTable {
s := getBasePrefix(tt.in)
if s != tt.out {
t.Errorf("got %q, want %q", s, tt.out)
}
}
}

func TestAPIError_Error(t *testing.T) {
const jsonBody = `{"error":{"code": 420, "message": "Enhance Your Calm", "errors":["Enhance Your Calm", "Slow Your Roll"]}}`

Expand Down
27 changes: 27 additions & 0 deletions service.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,33 @@ func (c *Client) ListServices(o ListServiceOptions) (*ListServiceResponse, error
return &result, c.decodeJSON(resp, &result)
}

// ListServices lists existing services processing paginated responses
func (c *Client) ListServicesPaginated(ctx context.Context, o ListServiceOptions) ([]Service, error) {
var services []Service
v, err := query.Values(o)
if err != nil {
return nil, err
}
responseHandler := func(response *http.Response) (APIListObject, error) {
var result ListServiceResponse
if err := c.decodeJSON(response, &result); err != nil {
return APIListObject{}, err
}

services = append(services, result.Services...)

return APIListObject{
More: result.More,
Offset: result.Offset,
Limit: result.Limit,
}, nil
}
if err := c.pagedGet(ctx, "/services?"+v.Encode(), responseHandler); err != nil {
return nil, err
}
return services, nil
}

// GetServiceOptions is the data structure used when calling the GetService API endpoint.
type GetServiceOptions struct {
Includes []string `url:"include,brackets,omitempty"`
Expand Down
56 changes: 56 additions & 0 deletions service_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package pagerduty

import (
"context"
"fmt"
"net/http"
"strconv"
"testing"
)

Expand Down Expand Up @@ -44,6 +47,59 @@ func TestService_List(t *testing.T) {
testEqual(t, want, res)
}

// ListServices
func TestService_ListPaginated(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/services", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
offsetStr := r.URL.Query()["offset"][0]
offset, _ := strconv.ParseInt(offsetStr, 10, 32)

var more string
if offset == 0 {
more = "true"
} else {
more = "false"
}
resp := fmt.Sprintf(`{"services": [{"id": "%d"}],
"More": %s,
"Offset": %d,
"Limit": 1}`, offset, more, offset)
w.Write([]byte(resp))
})

var listObj = APIListObject{Limit: 1, Offset: 0, More: false, Total: 0}
var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient}
var opts = ListServiceOptions{
APIListObject: listObj,
TeamIDs: []string{},
TimeZone: "foo",
SortBy: "bar",
Query: "baz",
Includes: []string{},
}
res, err := client.ListServicesPaginated(context.Background(), opts)

want := []Service{
{
APIObject: APIObject{
ID: "0",
},
}, {
APIObject: APIObject{
ID: "1",
},
},
}

if err != nil {
t.Fatal(err)
}
testEqual(t, want, res)
}

// Get Service
func TestService_Get(t *testing.T) {
setup()
Expand Down