mirror of
https://github.com/niusmallnan/steve.git
synced 2025-08-09 09:17:23 +00:00
Add pagination to partition store
Extend the partition store to parse page and pagesize parameters and return a subset of list results. The total number of pages is included in the list response. Request an initial page: GET /v1/secrets?pagesize=10 or GET /v1/secrets?pagesize=10&page=1 Request subsequent pages, or arbitrary pages: GET /v1/secrets?pagesize=10&page=37 If a page number is out of bounds, an empty list is returned.
This commit is contained in:
parent
adecbd9122
commit
9f1a27db06
2
go.mod
2
go.mod
@ -18,7 +18,7 @@ require (
|
|||||||
github.com/pborman/uuid v1.2.0
|
github.com/pborman/uuid v1.2.0
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/prometheus/client_golang v1.12.1
|
github.com/prometheus/client_golang v1.12.1
|
||||||
github.com/rancher/apiserver v0.0.0-20221205175736-7c507bd5c076
|
github.com/rancher/apiserver v0.0.0-20221220225852-94cba4f28cfd
|
||||||
github.com/rancher/dynamiclistener v0.3.5
|
github.com/rancher/dynamiclistener v0.3.5
|
||||||
github.com/rancher/kubernetes-provider-detector v0.1.2
|
github.com/rancher/kubernetes-provider-detector v0.1.2
|
||||||
github.com/rancher/norman v0.0.0-20221205184727-32ef2e185b99
|
github.com/rancher/norman v0.0.0-20221205184727-32ef2e185b99
|
||||||
|
4
go.sum
4
go.sum
@ -502,8 +502,8 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
|
|||||||
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/rancher/apiserver v0.0.0-20221205175736-7c507bd5c076 h1:wS95KbXFI1QOVQr3Tz+qyOJ9iia1ITCnjsapxJyI/9U=
|
github.com/rancher/apiserver v0.0.0-20221220225852-94cba4f28cfd h1:g0hNrbONfmY4lxvrD2q9KkueYYY4wKUYscm6Ih0QfQ0=
|
||||||
github.com/rancher/apiserver v0.0.0-20221205175736-7c507bd5c076/go.mod h1:xwQhXv3XFxWfA6tLa4ZeaERu8ldNbyKv2sF+mT+c5WA=
|
github.com/rancher/apiserver v0.0.0-20221220225852-94cba4f28cfd/go.mod h1:xwQhXv3XFxWfA6tLa4ZeaERu8ldNbyKv2sF+mT+c5WA=
|
||||||
github.com/rancher/client-go v1.25.4-rancher1 h1:9MlBC8QbgngUkhNzMR8rZmmCIj6WNRHFOnYiwC2Kty4=
|
github.com/rancher/client-go v1.25.4-rancher1 h1:9MlBC8QbgngUkhNzMR8rZmmCIj6WNRHFOnYiwC2Kty4=
|
||||||
github.com/rancher/client-go v1.25.4-rancher1/go.mod h1:8trHCAC83XKY0wsBIpbirZU4NTUpbuhc2JnI7OruGZw=
|
github.com/rancher/client-go v1.25.4-rancher1/go.mod h1:8trHCAC83XKY0wsBIpbirZU4NTUpbuhc2JnI7OruGZw=
|
||||||
github.com/rancher/dynamiclistener v0.3.5 h1:5TaIHvkDGmZKvc96Huur16zfTKOiLhDtK4S+WV0JA6A=
|
github.com/rancher/dynamiclistener v0.3.5 h1:5TaIHvkDGmZKvc96Huur16zfTKOiLhDtK4S+WV0JA6A=
|
||||||
|
@ -18,6 +18,8 @@ const (
|
|||||||
limitParam = "limit"
|
limitParam = "limit"
|
||||||
filterParam = "filter"
|
filterParam = "filter"
|
||||||
sortParam = "sort"
|
sortParam = "sort"
|
||||||
|
pageSizeParam = "pagesize"
|
||||||
|
pageParam = "page"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ListOptions represents the query parameters that may be included in a list request.
|
// ListOptions represents the query parameters that may be included in a list request.
|
||||||
@ -26,6 +28,7 @@ type ListOptions struct {
|
|||||||
Resume string
|
Resume string
|
||||||
Filters []Filter
|
Filters []Filter
|
||||||
Sort Sort
|
Sort Sort
|
||||||
|
Pagination Pagination
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter represents a field to filter by.
|
// Filter represents a field to filter by.
|
||||||
@ -55,6 +58,12 @@ type Sort struct {
|
|||||||
order SortOrder
|
order SortOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pagination represents how to return paginated results.
|
||||||
|
type Pagination struct {
|
||||||
|
pageSize int
|
||||||
|
page int
|
||||||
|
}
|
||||||
|
|
||||||
// ParseQuery parses the query params of a request and returns a ListOptions.
|
// ParseQuery parses the query params of a request and returns a ListOptions.
|
||||||
func ParseQuery(apiOp *types.APIRequest) *ListOptions {
|
func ParseQuery(apiOp *types.APIRequest) *ListOptions {
|
||||||
chunkSize := getLimit(apiOp)
|
chunkSize := getLimit(apiOp)
|
||||||
@ -78,11 +87,22 @@ func ParseQuery(apiOp *types.APIRequest) *ListOptions {
|
|||||||
if sortKey != "" {
|
if sortKey != "" {
|
||||||
sort.field = strings.Split(sortKey, ".")
|
sort.field = strings.Split(sortKey, ".")
|
||||||
}
|
}
|
||||||
|
var err error
|
||||||
|
pagination := Pagination{}
|
||||||
|
pagination.pageSize, err = strconv.Atoi(q.Get(pageSizeParam))
|
||||||
|
if err != nil {
|
||||||
|
pagination.pageSize = 0
|
||||||
|
}
|
||||||
|
pagination.page, err = strconv.Atoi(q.Get(pageParam))
|
||||||
|
if err != nil {
|
||||||
|
pagination.page = 1
|
||||||
|
}
|
||||||
return &ListOptions{
|
return &ListOptions{
|
||||||
ChunkSize: chunkSize,
|
ChunkSize: chunkSize,
|
||||||
Resume: cont,
|
Resume: cont,
|
||||||
Filters: filterOpts,
|
Filters: filterOpts,
|
||||||
Sort: sort,
|
Sort: sort,
|
||||||
|
Pagination: pagination,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,3 +216,26 @@ func SortList(list []unstructured.Unstructured, s Sort) []unstructured.Unstructu
|
|||||||
})
|
})
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PaginateList returns a subset of the result based on the pagination criteria as well as the total number of pages the caller can expect.
|
||||||
|
func PaginateList(list []unstructured.Unstructured, p Pagination) ([]unstructured.Unstructured, int) {
|
||||||
|
if p.pageSize <= 0 {
|
||||||
|
return list, 0
|
||||||
|
}
|
||||||
|
page := p.page - 1
|
||||||
|
if p.page < 1 {
|
||||||
|
page = 0
|
||||||
|
}
|
||||||
|
pages := len(list) / p.pageSize
|
||||||
|
if len(list)%p.pageSize != 0 {
|
||||||
|
pages++
|
||||||
|
}
|
||||||
|
offset := p.pageSize * page
|
||||||
|
if offset > len(list) {
|
||||||
|
return []unstructured.Unstructured{}, pages
|
||||||
|
}
|
||||||
|
if offset+p.pageSize > len(list) {
|
||||||
|
return list[offset:], pages
|
||||||
|
}
|
||||||
|
return list[offset : offset+p.pageSize], pages
|
||||||
|
}
|
||||||
|
@ -1115,3 +1115,202 @@ func TestSortList(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPaginateList(t *testing.T) {
|
||||||
|
objects := []unstructured.Unstructured{
|
||||||
|
{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "apple",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "fuji",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "apple",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "honeycrisp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "apple",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "granny-smith",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "apple",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "red-delicious",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "apple",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "crispin",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "apple",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "bramley",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "apple",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "golden-delicious",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "apple",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "macintosh",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
objects []unstructured.Unstructured
|
||||||
|
pagination Pagination
|
||||||
|
want []unstructured.Unstructured
|
||||||
|
wantPages int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "pagesize=3, page=unset",
|
||||||
|
objects: objects,
|
||||||
|
pagination: Pagination{
|
||||||
|
pageSize: 3,
|
||||||
|
},
|
||||||
|
want: objects[:3],
|
||||||
|
wantPages: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pagesize=3, page=1",
|
||||||
|
objects: objects,
|
||||||
|
pagination: Pagination{
|
||||||
|
pageSize: 3,
|
||||||
|
page: 1,
|
||||||
|
},
|
||||||
|
want: objects[:3],
|
||||||
|
wantPages: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pagesize=3, page=2",
|
||||||
|
objects: objects,
|
||||||
|
pagination: Pagination{
|
||||||
|
pageSize: 3,
|
||||||
|
page: 2,
|
||||||
|
},
|
||||||
|
want: objects[3:6],
|
||||||
|
wantPages: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pagesize=3, page=last",
|
||||||
|
objects: objects,
|
||||||
|
pagination: Pagination{
|
||||||
|
pageSize: 3,
|
||||||
|
page: 3,
|
||||||
|
},
|
||||||
|
want: objects[6:],
|
||||||
|
wantPages: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pagesize=3, page>last",
|
||||||
|
objects: objects,
|
||||||
|
pagination: Pagination{
|
||||||
|
pageSize: 3,
|
||||||
|
page: 37,
|
||||||
|
},
|
||||||
|
want: []unstructured.Unstructured{},
|
||||||
|
wantPages: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pagesize=3, page<0",
|
||||||
|
objects: objects,
|
||||||
|
pagination: Pagination{
|
||||||
|
pageSize: 3,
|
||||||
|
page: -4,
|
||||||
|
},
|
||||||
|
want: objects[:3],
|
||||||
|
wantPages: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pagesize=0",
|
||||||
|
objects: objects,
|
||||||
|
pagination: Pagination{},
|
||||||
|
want: objects,
|
||||||
|
wantPages: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pagesize=-1",
|
||||||
|
objects: objects,
|
||||||
|
pagination: Pagination{
|
||||||
|
pageSize: -7,
|
||||||
|
},
|
||||||
|
want: objects,
|
||||||
|
wantPages: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "even page size, even list size",
|
||||||
|
objects: objects,
|
||||||
|
pagination: Pagination{
|
||||||
|
pageSize: 2,
|
||||||
|
page: 2,
|
||||||
|
},
|
||||||
|
want: objects[2:4],
|
||||||
|
wantPages: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "even page size, odd list size",
|
||||||
|
objects: objects[1:],
|
||||||
|
pagination: Pagination{
|
||||||
|
pageSize: 2,
|
||||||
|
page: 2,
|
||||||
|
},
|
||||||
|
want: objects[3:5],
|
||||||
|
wantPages: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "odd page size, even list size",
|
||||||
|
objects: objects,
|
||||||
|
pagination: Pagination{
|
||||||
|
pageSize: 5,
|
||||||
|
page: 2,
|
||||||
|
},
|
||||||
|
want: objects[5:],
|
||||||
|
wantPages: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "odd page size, odd list size",
|
||||||
|
objects: objects[1:],
|
||||||
|
pagination: Pagination{
|
||||||
|
pageSize: 3,
|
||||||
|
page: 2,
|
||||||
|
},
|
||||||
|
want: objects[4:7],
|
||||||
|
wantPages: 3,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
got, gotPages := PaginateList(test.objects, test.pagination)
|
||||||
|
assert.Equal(t, test.want, got)
|
||||||
|
assert.Equal(t, test.wantPages, gotPages)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -129,6 +129,8 @@ func (s *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.AP
|
|||||||
|
|
||||||
list := listprocessor.FilterList(stream, opts.Filters)
|
list := listprocessor.FilterList(stream, opts.Filters)
|
||||||
list = listprocessor.SortList(list, opts.Sort)
|
list = listprocessor.SortList(list, opts.Sort)
|
||||||
|
result.Count = len(list)
|
||||||
|
list, pages := listprocessor.PaginateList(list, opts.Pagination)
|
||||||
|
|
||||||
for _, item := range list {
|
for _, item := range list {
|
||||||
item := item
|
item := item
|
||||||
@ -137,6 +139,8 @@ func (s *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.AP
|
|||||||
|
|
||||||
result.Revision = lister.Revision()
|
result.Revision = lister.Revision()
|
||||||
result.Continue = lister.Continue()
|
result.Continue = lister.Continue()
|
||||||
|
result.Pages = pages
|
||||||
|
|
||||||
return result, lister.Err()
|
return result, lister.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ func TestList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: []types.APIObjectList{
|
want: []types.APIObjectList{
|
||||||
{
|
{
|
||||||
|
Count: 1,
|
||||||
Objects: []types.APIObject{
|
Objects: []types.APIObject{
|
||||||
newApple("fuji").toObj(),
|
newApple("fuji").toObj(),
|
||||||
},
|
},
|
||||||
@ -71,18 +72,21 @@ func TestList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: []types.APIObjectList{
|
want: []types.APIObjectList{
|
||||||
{
|
{
|
||||||
|
Count: 1,
|
||||||
Continue: base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf(`{"p":"all","c":"%s","l":1}`, base64.StdEncoding.EncodeToString([]byte("granny-smith"))))),
|
Continue: base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf(`{"p":"all","c":"%s","l":1}`, base64.StdEncoding.EncodeToString([]byte("granny-smith"))))),
|
||||||
Objects: []types.APIObject{
|
Objects: []types.APIObject{
|
||||||
newApple("fuji").toObj(),
|
newApple("fuji").toObj(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Count: 1,
|
||||||
Continue: base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf(`{"p":"all","c":"%s","l":1}`, base64.StdEncoding.EncodeToString([]byte("crispin"))))),
|
Continue: base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf(`{"p":"all","c":"%s","l":1}`, base64.StdEncoding.EncodeToString([]byte("crispin"))))),
|
||||||
Objects: []types.APIObject{
|
Objects: []types.APIObject{
|
||||||
newApple("granny-smith").toObj(),
|
newApple("granny-smith").toObj(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Count: 1,
|
||||||
Objects: []types.APIObject{
|
Objects: []types.APIObject{
|
||||||
newApple("crispin").toObj(),
|
newApple("crispin").toObj(),
|
||||||
},
|
},
|
||||||
@ -121,6 +125,7 @@ func TestList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: []types.APIObjectList{
|
want: []types.APIObjectList{
|
||||||
{
|
{
|
||||||
|
Count: 2,
|
||||||
Objects: []types.APIObject{
|
Objects: []types.APIObject{
|
||||||
newApple("granny-smith").toObj(),
|
newApple("granny-smith").toObj(),
|
||||||
newApple("crispin").toObj(),
|
newApple("crispin").toObj(),
|
||||||
@ -176,6 +181,7 @@ func TestList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: []types.APIObjectList{
|
want: []types.APIObjectList{
|
||||||
{
|
{
|
||||||
|
Count: 3,
|
||||||
Continue: base64.StdEncoding.EncodeToString([]byte(`{"p":"green","o":1,"l":3}`)),
|
Continue: base64.StdEncoding.EncodeToString([]byte(`{"p":"green","o":1,"l":3}`)),
|
||||||
Objects: []types.APIObject{
|
Objects: []types.APIObject{
|
||||||
newApple("fuji").toObj(),
|
newApple("fuji").toObj(),
|
||||||
@ -184,6 +190,7 @@ func TestList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Count: 3,
|
||||||
Continue: base64.StdEncoding.EncodeToString([]byte(`{"p":"red","l":3}`)),
|
Continue: base64.StdEncoding.EncodeToString([]byte(`{"p":"red","l":3}`)),
|
||||||
Objects: []types.APIObject{
|
Objects: []types.APIObject{
|
||||||
newApple("bramley").toObj(),
|
newApple("bramley").toObj(),
|
||||||
@ -192,6 +199,7 @@ func TestList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Count: 1,
|
||||||
Objects: []types.APIObject{
|
Objects: []types.APIObject{
|
||||||
newApple("red-delicious").toObj(),
|
newApple("red-delicious").toObj(),
|
||||||
},
|
},
|
||||||
@ -221,12 +229,14 @@ func TestList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: []types.APIObjectList{
|
want: []types.APIObjectList{
|
||||||
{
|
{
|
||||||
|
Count: 2,
|
||||||
Objects: []types.APIObject{
|
Objects: []types.APIObject{
|
||||||
newApple("granny-smith").toObj(),
|
newApple("granny-smith").toObj(),
|
||||||
newApple("bramley").toObj(),
|
newApple("bramley").toObj(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Count: 1,
|
||||||
Objects: []types.APIObject{
|
Objects: []types.APIObject{
|
||||||
newApple("bramley").toObj(),
|
newApple("bramley").toObj(),
|
||||||
},
|
},
|
||||||
@ -270,6 +280,7 @@ func TestList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: []types.APIObjectList{
|
want: []types.APIObjectList{
|
||||||
{
|
{
|
||||||
|
Count: 3,
|
||||||
Objects: []types.APIObject{
|
Objects: []types.APIObject{
|
||||||
newApple("honeycrisp").with(map[string]string{"category": "eating,baking"}).toObj(),
|
newApple("honeycrisp").with(map[string]string{"category": "eating,baking"}).toObj(),
|
||||||
newApple("granny-smith").with(map[string]string{"category": "baking"}).toObj(),
|
newApple("granny-smith").with(map[string]string{"category": "baking"}).toObj(),
|
||||||
@ -301,6 +312,7 @@ func TestList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: []types.APIObjectList{
|
want: []types.APIObjectList{
|
||||||
{
|
{
|
||||||
|
Count: 4,
|
||||||
Objects: []types.APIObject{
|
Objects: []types.APIObject{
|
||||||
newApple("bramley").toObj(),
|
newApple("bramley").toObj(),
|
||||||
newApple("crispin").toObj(),
|
newApple("crispin").toObj(),
|
||||||
@ -309,6 +321,7 @@ func TestList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Count: 4,
|
||||||
Objects: []types.APIObject{
|
Objects: []types.APIObject{
|
||||||
newApple("granny-smith").toObj(),
|
newApple("granny-smith").toObj(),
|
||||||
newApple("fuji").toObj(),
|
newApple("fuji").toObj(),
|
||||||
@ -350,6 +363,7 @@ func TestList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: []types.APIObjectList{
|
want: []types.APIObjectList{
|
||||||
{
|
{
|
||||||
|
Count: 2,
|
||||||
Objects: []types.APIObject{
|
Objects: []types.APIObject{
|
||||||
newApple("crispin").toObj(),
|
newApple("crispin").toObj(),
|
||||||
newApple("granny-smith").toObj(),
|
newApple("granny-smith").toObj(),
|
||||||
|
Loading…
Reference in New Issue
Block a user