open-nomad/nomad/state/paginator/paginator_test.go

150 lines
3.1 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package paginator
import (
"errors"
"testing"
"github.com/hashicorp/nomad/ci"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/stretchr/testify/require"
)
func TestPaginator(t *testing.T) {
ci.Parallel(t)
ids := []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}
cases := []struct {
name string
perPage int32
nextToken string
expected []string
expectedNextToken string
expectedError string
}{
{
name: "size-3 page-1",
perPage: 3,
expected: []string{"0", "1", "2"},
expectedNextToken: "3",
},
{
name: "size-5 page-2 stop before end",
perPage: 5,
nextToken: "3",
expected: []string{"3", "4", "5", "6", "7"},
expectedNextToken: "8",
},
{
name: "page-2 reading off the end",
perPage: 10,
nextToken: "5",
expected: []string{"5", "6", "7", "8", "9"},
expectedNextToken: "",
},
{
name: "starting off the end",
perPage: 5,
nextToken: "a",
expected: []string{},
expectedNextToken: "",
},
{
name: "error during append",
expectedError: "failed to append",
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
iter := newTestIterator(ids)
tokenizer := testTokenizer{}
opts := structs.QueryOptions{
PerPage: tc.perPage,
NextToken: tc.nextToken,
}
results := []string{}
paginator, err := NewPaginator(iter, tokenizer, nil, opts,
func(raw interface{}) error {
if tc.expectedError != "" {
return errors.New(tc.expectedError)
}
result := raw.(*mockObject)
results = append(results, result.id)
return nil
},
)
require.NoError(t, err)
nextToken, err := paginator.Page()
if tc.expectedError == "" {
require.NoError(t, err)
require.Equal(t, tc.expected, results)
require.Equal(t, tc.expectedNextToken, nextToken)
} else {
require.Error(t, err)
require.Contains(t, err.Error(), tc.expectedError)
}
})
}
}
// helpers for pagination tests
// implements Iterator interface
type testResultIterator struct {
results chan interface{}
}
func (i testResultIterator) Next() interface{} {
select {
case raw := <-i.results:
if raw == nil {
return nil
}
m := raw.(*mockObject)
return m
default:
return nil
}
}
type mockObject struct {
id string
namespace string
}
func (m *mockObject) GetNamespace() string {
return m.namespace
}
func newTestIterator(ids []string) testResultIterator {
iter := testResultIterator{results: make(chan interface{}, 20)}
for _, id := range ids {
iter.results <- &mockObject{id: id}
}
return iter
}
func newTestIteratorWithMocks(mocks []*mockObject) testResultIterator {
iter := testResultIterator{results: make(chan interface{}, 20)}
for _, m := range mocks {
iter.results <- m
}
return iter
}
// implements Tokenizer interface
type testTokenizer struct{}
func (t testTokenizer) GetToken(raw interface{}) string {
return raw.(*mockObject).id
}