2023-03-28 18:39:22 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2015-08-22 01:14:57 +00:00
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
2021-08-19 21:17:59 +00:00
|
|
|
"sort"
|
2015-08-22 01:14:57 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/hashicorp/go-memdb"
|
2021-01-15 23:28:32 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2022-08-01 14:33:18 +00:00
|
|
|
|
2023-02-17 21:14:46 +00:00
|
|
|
"github.com/hashicorp/consul/proto/private/pbpeering"
|
2015-08-22 01:14:57 +00:00
|
|
|
)
|
|
|
|
|
2021-02-19 19:38:07 +00:00
|
|
|
type indexerTestCase struct {
|
|
|
|
read indexValue
|
|
|
|
write indexValue
|
|
|
|
prefix []indexValue
|
|
|
|
writeMulti indexValueMulti
|
2021-03-31 18:37:21 +00:00
|
|
|
// extra test cases can be added if the indexer has special handling for
|
|
|
|
// specific cases.
|
|
|
|
extra []indexerTestCase
|
2021-02-19 19:38:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type indexValue struct {
|
|
|
|
source interface{}
|
|
|
|
expected []byte
|
2021-03-31 18:37:21 +00:00
|
|
|
// 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
|
2021-02-19 19:38:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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{
|
2021-08-17 18:29:39 +00:00
|
|
|
// acl
|
2021-09-15 13:34:19 +00:00
|
|
|
tableACLBindingRules: testIndexerTableACLBindingRules,
|
|
|
|
tableACLPolicies: testIndexerTableACLPolicies,
|
|
|
|
tableACLRoles: testIndexerTableACLRoles,
|
|
|
|
tableACLTokens: testIndexerTableACLTokens,
|
2021-08-17 18:29:39 +00:00
|
|
|
// catalog
|
2021-12-02 23:42:47 +00:00
|
|
|
tableChecks: testIndexerTableChecks,
|
|
|
|
tableServices: testIndexerTableServices,
|
|
|
|
tableNodes: testIndexerTableNodes,
|
|
|
|
tableCoordinates: testIndexerTableCoordinates,
|
|
|
|
tableMeshTopology: testIndexerTableMeshTopology,
|
|
|
|
tableGatewayServices: testIndexerTableGatewayServices,
|
|
|
|
tableServiceVirtualIPs: testIndexerTableServiceVirtualIPs,
|
2021-12-02 00:44:13 +00:00
|
|
|
tableKindServiceNames: testIndexerTableKindServiceNames,
|
2021-11-08 14:35:56 +00:00
|
|
|
// KV
|
|
|
|
tableKVs: testIndexerTableKVs,
|
|
|
|
tableTombstones: testIndexerTableTombstones,
|
2021-08-17 18:29:39 +00:00
|
|
|
// config
|
|
|
|
tableConfigEntries: testIndexerTableConfigEntries,
|
2022-06-08 22:53:32 +00:00
|
|
|
// peerings
|
2022-08-01 14:33:18 +00:00
|
|
|
tablePeering: testIndexerTablePeering,
|
|
|
|
tablePeeringSecrets: testIndexerTablePeeringSecrets,
|
|
|
|
tablePeeringSecretUUIDs: testIndexerTablePeeringSecretUUIDs,
|
2021-02-19 19:38:07 +00:00
|
|
|
}
|
2021-03-19 03:07:30 +00:00
|
|
|
addEnterpriseIndexerTestCases(testcases)
|
2021-02-19 19:38:07 +00:00
|
|
|
|
|
|
|
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")
|
|
|
|
}
|
2021-03-31 18:37:21 +00:00
|
|
|
tc.run(t, indexer)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-02-19 19:38:07 +00:00
|
|
|
|
2021-03-31 18:37:21 +00:00
|
|
|
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
|
|
|
|
}
|
2021-02-19 19:38:07 +00:00
|
|
|
|
2021-03-31 18:37:21 +00:00
|
|
|
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)
|
|
|
|
})
|
|
|
|
}
|
2021-02-19 19:38:07 +00:00
|
|
|
|
2021-03-31 18:37:21 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2021-02-19 19:38:07 +00:00
|
|
|
|
2021-03-31 18:37:21 +00:00
|
|
|
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)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-02-19 19:38:07 +00:00
|
|
|
|
2021-08-19 21:17:59 +00:00
|
|
|
sortMultiByteSlice := func(v [][]byte) {
|
|
|
|
sort.Slice(v, func(i, j int) bool {
|
|
|
|
return string(v[i]) < string(v[j])
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:37:21 +00:00
|
|
|
if i, ok := indexer.(memdb.MultiIndexer); ok {
|
2021-07-22 18:58:08 +00:00
|
|
|
t.Run("writeIndexMulti", func(t *testing.T) {
|
|
|
|
valid, actual, err := i.FromObject(tc.writeMulti.source)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, valid)
|
2021-08-19 21:17:59 +00:00
|
|
|
sortMultiByteSlice(actual)
|
|
|
|
sortMultiByteSlice(tc.writeMulti.expected)
|
|
|
|
require.ElementsMatch(t, tc.writeMulti.expected, actual)
|
2021-07-22 18:58:08 +00:00
|
|
|
})
|
2021-03-31 18:37:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, extra := range tc.extra {
|
|
|
|
t.Run("extra", func(t *testing.T) {
|
|
|
|
extra.run(t, indexer)
|
2021-02-19 19:38:07 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2022-08-01 14:33:18 +00:00
|
|
|
|
|
|
|
func testIndexerTablePeeringSecrets() map[string]indexerTestCase {
|
|
|
|
peerID := "b560e87b-934c-491a-9771-16b9d9ce41f8"
|
|
|
|
encodedPeerID := []byte{0xb5, 0x60, 0xe8, 0x7b, 0x93, 0x4c, 0x49, 0x1a, 0x97, 0x71, 0x16, 0xb9, 0xd9, 0xce, 0x41, 0xf8}
|
|
|
|
|
|
|
|
obj := &pbpeering.PeeringSecrets{
|
|
|
|
PeerID: peerID,
|
|
|
|
Establishment: &pbpeering.PeeringSecrets_Establishment{
|
|
|
|
SecretID: "432feb2f-5476-4ae2-b33c-e43640ca0e86",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
return map[string]indexerTestCase{
|
|
|
|
indexID: {
|
|
|
|
read: indexValue{
|
|
|
|
source: peerID,
|
|
|
|
expected: encodedPeerID,
|
|
|
|
},
|
|
|
|
write: indexValue{
|
|
|
|
source: obj,
|
|
|
|
expected: encodedPeerID,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testIndexerTablePeeringSecretUUIDs() map[string]indexerTestCase {
|
|
|
|
secretID := "432feb2f-5476-4ae2-b33c-e43640ca0e86"
|
|
|
|
encodedSecretID := []byte{0x43, 0x2f, 0xeb, 0x2f, 0x54, 0x76, 0x4a, 0xe2, 0xb3, 0x3c, 0xe4, 0x36, 0x40, 0xca, 0xe, 0x86}
|
|
|
|
|
|
|
|
return map[string]indexerTestCase{
|
|
|
|
indexID: {
|
|
|
|
read: indexValue{
|
|
|
|
source: secretID,
|
|
|
|
expected: encodedSecretID,
|
|
|
|
},
|
|
|
|
write: indexValue{
|
|
|
|
source: secretID,
|
|
|
|
expected: encodedSecretID,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|