142d8193e5
This table purposefully does not index by partition/namespace. It's a global view into all service names. This table is intended to replace the current serviceListTxn watch in intentionTopologyTxn. For cross-partition transparent proxying we need to be able to calculate upstreams from intentions in any partition. This means that the existing serviceListTxn function is insufficient since it's scoped to a partition. Moving away from that function is also beneficial because it watches the main "services" table, so watchers will wake up when any instance is registered or deregistered.
144 lines
3.9 KiB
Go
144 lines
3.9 KiB
Go
package state
|
|
|
|
import (
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/go-memdb"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type indexerTestCase struct {
|
|
read indexValue
|
|
write indexValue
|
|
prefix []indexValue
|
|
writeMulti indexValueMulti
|
|
// extra test cases can be added if the indexer has special handling for
|
|
// specific cases.
|
|
extra []indexerTestCase
|
|
}
|
|
|
|
type indexValue struct {
|
|
source interface{}
|
|
expected []byte
|
|
// expectedIndexMissing indicates that this test case should not produce an
|
|
// expected value. The indexer should report a required value was missing.
|
|
// This field is only relevant for the writeIndex.
|
|
expectedIndexMissing bool
|
|
}
|
|
|
|
type indexValueMulti struct {
|
|
source interface{}
|
|
expected [][]byte
|
|
}
|
|
|
|
func TestNewDBSchema_Indexers(t *testing.T) {
|
|
schema := newDBSchema()
|
|
require.NoError(t, schema.Validate())
|
|
|
|
var testcases = map[string]func() map[string]indexerTestCase{
|
|
// acl
|
|
tableACLBindingRules: testIndexerTableACLBindingRules,
|
|
tableACLPolicies: testIndexerTableACLPolicies,
|
|
tableACLRoles: testIndexerTableACLRoles,
|
|
tableACLTokens: testIndexerTableACLTokens,
|
|
// catalog
|
|
tableChecks: testIndexerTableChecks,
|
|
tableServices: testIndexerTableServices,
|
|
tableNodes: testIndexerTableNodes,
|
|
tableCoordinates: testIndexerTableCoordinates,
|
|
tableMeshTopology: testIndexerTableMeshTopology,
|
|
tableGatewayServices: testIndexerTableGatewayServices,
|
|
tableServiceVirtualIPs: testIndexerTableServiceVirtualIPs,
|
|
tableKindServiceNames: testIndexerTableKindServiceNames,
|
|
// KV
|
|
tableKVs: testIndexerTableKVs,
|
|
tableTombstones: testIndexerTableTombstones,
|
|
// config
|
|
tableConfigEntries: testIndexerTableConfigEntries,
|
|
}
|
|
addEnterpriseIndexerTestCases(testcases)
|
|
|
|
for _, table := range schema.Tables {
|
|
if testcases[table.Name] == nil {
|
|
continue
|
|
}
|
|
t.Run(table.Name, func(t *testing.T) {
|
|
tableTCs := testcases[table.Name]()
|
|
|
|
for _, index := range table.Indexes {
|
|
t.Run(index.Name, func(t *testing.T) {
|
|
indexer := index.Indexer
|
|
tc, ok := tableTCs[index.Name]
|
|
if !ok {
|
|
t.Skip("TODO: missing test case")
|
|
}
|
|
tc.run(t, indexer)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (tc indexerTestCase) run(t *testing.T, indexer memdb.Indexer) {
|
|
args := []interface{}{tc.read.source}
|
|
if s, ok := tc.read.source.([]interface{}); ok {
|
|
// Indexes using memdb.CompoundIndex must be expanded to multiple args
|
|
args = s
|
|
}
|
|
|
|
if tc.read.source != nil {
|
|
t.Run("readIndex", func(t *testing.T) {
|
|
actual, err := indexer.FromArgs(args...)
|
|
require.NoError(t, err)
|
|
require.Equal(t, tc.read.expected, actual)
|
|
})
|
|
}
|
|
|
|
if i, ok := indexer.(memdb.SingleIndexer); ok {
|
|
t.Run("writeIndex", func(t *testing.T) {
|
|
valid, actual, err := i.FromObject(tc.write.source)
|
|
require.NoError(t, err)
|
|
if tc.write.expectedIndexMissing {
|
|
require.False(t, valid, "expected the indexer to produce no index value")
|
|
} else {
|
|
require.True(t, valid, "indexer was missing a required value")
|
|
require.Equal(t, tc.write.expected, actual)
|
|
}
|
|
})
|
|
}
|
|
|
|
if i, ok := indexer.(memdb.PrefixIndexer); ok {
|
|
for _, c := range tc.prefix {
|
|
t.Run("prefixIndex", func(t *testing.T) {
|
|
actual, err := i.PrefixFromArgs(c.source)
|
|
require.NoError(t, err)
|
|
require.Equal(t, c.expected, actual)
|
|
})
|
|
}
|
|
}
|
|
|
|
sortMultiByteSlice := func(v [][]byte) {
|
|
sort.Slice(v, func(i, j int) bool {
|
|
return string(v[i]) < string(v[j])
|
|
})
|
|
}
|
|
|
|
if i, ok := indexer.(memdb.MultiIndexer); ok {
|
|
t.Run("writeIndexMulti", func(t *testing.T) {
|
|
valid, actual, err := i.FromObject(tc.writeMulti.source)
|
|
require.NoError(t, err)
|
|
require.True(t, valid)
|
|
sortMultiByteSlice(actual)
|
|
sortMultiByteSlice(tc.writeMulti.expected)
|
|
require.ElementsMatch(t, tc.writeMulti.expected, actual)
|
|
})
|
|
}
|
|
|
|
for _, extra := range tc.extra {
|
|
t.Run("extra", func(t *testing.T) {
|
|
extra.run(t, indexer)
|
|
})
|
|
}
|
|
}
|