github.com/hernad/nomad@v1.6.112/nomad/state/paginator/paginator_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package paginator
     5  
     6  import (
     7  	"errors"
     8  	"testing"
     9  
    10  	"github.com/hernad/nomad/ci"
    11  	"github.com/hernad/nomad/nomad/structs"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestPaginator(t *testing.T) {
    16  	ci.Parallel(t)
    17  	ids := []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}
    18  
    19  	cases := []struct {
    20  		name              string
    21  		perPage           int32
    22  		nextToken         string
    23  		expected          []string
    24  		expectedNextToken string
    25  		expectedError     string
    26  	}{
    27  		{
    28  			name:              "size-3 page-1",
    29  			perPage:           3,
    30  			expected:          []string{"0", "1", "2"},
    31  			expectedNextToken: "3",
    32  		},
    33  		{
    34  			name:              "size-5 page-2 stop before end",
    35  			perPage:           5,
    36  			nextToken:         "3",
    37  			expected:          []string{"3", "4", "5", "6", "7"},
    38  			expectedNextToken: "8",
    39  		},
    40  		{
    41  			name:              "page-2 reading off the end",
    42  			perPage:           10,
    43  			nextToken:         "5",
    44  			expected:          []string{"5", "6", "7", "8", "9"},
    45  			expectedNextToken: "",
    46  		},
    47  		{
    48  			name:              "starting off the end",
    49  			perPage:           5,
    50  			nextToken:         "a",
    51  			expected:          []string{},
    52  			expectedNextToken: "",
    53  		},
    54  		{
    55  			name:          "error during append",
    56  			expectedError: "failed to append",
    57  		},
    58  	}
    59  
    60  	for _, tc := range cases {
    61  		t.Run(tc.name, func(t *testing.T) {
    62  
    63  			iter := newTestIterator(ids)
    64  			tokenizer := testTokenizer{}
    65  			opts := structs.QueryOptions{
    66  				PerPage:   tc.perPage,
    67  				NextToken: tc.nextToken,
    68  			}
    69  
    70  			results := []string{}
    71  			paginator, err := NewPaginator(iter, tokenizer, nil, opts,
    72  				func(raw interface{}) error {
    73  					if tc.expectedError != "" {
    74  						return errors.New(tc.expectedError)
    75  					}
    76  
    77  					result := raw.(*mockObject)
    78  					results = append(results, result.id)
    79  					return nil
    80  				},
    81  			)
    82  			require.NoError(t, err)
    83  
    84  			nextToken, err := paginator.Page()
    85  			if tc.expectedError == "" {
    86  				require.NoError(t, err)
    87  				require.Equal(t, tc.expected, results)
    88  				require.Equal(t, tc.expectedNextToken, nextToken)
    89  			} else {
    90  				require.Error(t, err)
    91  				require.Contains(t, err.Error(), tc.expectedError)
    92  			}
    93  		})
    94  	}
    95  
    96  }
    97  
    98  // helpers for pagination tests
    99  
   100  // implements Iterator interface
   101  type testResultIterator struct {
   102  	results chan interface{}
   103  }
   104  
   105  func (i testResultIterator) Next() interface{} {
   106  	select {
   107  	case raw := <-i.results:
   108  		if raw == nil {
   109  			return nil
   110  		}
   111  
   112  		m := raw.(*mockObject)
   113  		return m
   114  	default:
   115  		return nil
   116  	}
   117  }
   118  
   119  type mockObject struct {
   120  	id        string
   121  	namespace string
   122  }
   123  
   124  func (m *mockObject) GetNamespace() string {
   125  	return m.namespace
   126  }
   127  
   128  func newTestIterator(ids []string) testResultIterator {
   129  	iter := testResultIterator{results: make(chan interface{}, 20)}
   130  	for _, id := range ids {
   131  		iter.results <- &mockObject{id: id}
   132  	}
   133  	return iter
   134  }
   135  
   136  func newTestIteratorWithMocks(mocks []*mockObject) testResultIterator {
   137  	iter := testResultIterator{results: make(chan interface{}, 20)}
   138  	for _, m := range mocks {
   139  		iter.results <- m
   140  	}
   141  	return iter
   142  }
   143  
   144  // implements Tokenizer interface
   145  type testTokenizer struct{}
   146  
   147  func (t testTokenizer) GetToken(raw interface{}) string {
   148  	return raw.(*mockObject).id
   149  }