consul/internal/controller/cache/index/convenience_test.go

384 lines
9.2 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package index
import (
"errors"
"testing"
"github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/internal/storage"
"github.com/hashicorp/consul/proto-public/pbresource"
"github.com/stretchr/testify/require"
)
func TestIndexFromID(t *testing.T) {
id := &pbresource.ID{
Type: &pbresource.Type{
Group: "test",
GroupVersion: "v1",
Kind: "fake",
},
Tenancy: &pbresource.Tenancy{
Partition: "foo",
Namespace: "bar",
},
Name: "baz",
Uid: "01G9R78VJ5VXAJRA2K7V0RXB87",
}
val := IndexFromID(id, false)
expected := []byte("test\x00fake\x00foo\x00bar\x00baz\x00")
require.Equal(t, expected, val)
val = IndexFromID(id, true)
expected = []byte("test\x00fake\x00foo\x00bar\x00baz\x0001G9R78VJ5VXAJRA2K7V0RXB87\x00")
require.Equal(t, expected, val)
}
func TestIndexFromRefOrID(t *testing.T) {
id := &pbresource.ID{
Type: &pbresource.Type{
Group: "test",
GroupVersion: "v1",
Kind: "fake",
},
Tenancy: &pbresource.Tenancy{
Partition: "foo",
Namespace: "bar",
},
Name: "baz",
Uid: "01G9R78VJ5VXAJRA2K7V0RXB87",
}
ref := resource.Reference(id, "")
idVal := IndexFromRefOrID(id)
refVal := IndexFromRefOrID(ref)
expected := "test\x00fake\x00foo\x00bar\x00baz\x00"
require.Equal(t, []byte(expected), idVal)
require.Equal(t, []byte(expected), refVal)
}
func TestPrefixIndexFromRefOrID(t *testing.T) {
t.Run("no partition", func(t *testing.T) {
ref := &pbresource.Reference{
Type: &pbresource.Type{
Group: "test",
GroupVersion: "v1",
Kind: "fake",
},
}
require.Equal(t, []byte("test\x00fake\x00"), PrefixIndexFromRefOrID(ref))
})
t.Run("no namespace", func(t *testing.T) {
ref := &pbresource.Reference{
Type: &pbresource.Type{
Group: "test",
GroupVersion: "v1",
Kind: "fake",
},
Tenancy: &pbresource.Tenancy{
Partition: "test",
},
}
require.Equal(t, []byte("test\x00fake\x00test\x00"), PrefixIndexFromRefOrID(ref))
})
t.Run("name prefix", func(t *testing.T) {
id := &pbresource.ID{
Type: &pbresource.Type{
Group: "test",
GroupVersion: "v1",
Kind: "fake",
},
Tenancy: &pbresource.Tenancy{
Partition: "test",
Namespace: "test",
},
Name: "prefix",
}
require.Equal(t, []byte("test\x00fake\x00test\x00test\x00prefix"), PrefixIndexFromRefOrID(id))
})
}
func TestPrefixIndexFromTenancy(t *testing.T) {
t.Run("nil tenancy", func(t *testing.T) {
idx, done := prefixIndexFromTenancy(nil)
require.Len(t, idx, 0)
require.True(t, done)
})
t.Run("partition empty", func(t *testing.T) {
tenant := &pbresource.Tenancy{}
idx, done := prefixIndexFromTenancy(tenant)
require.Len(t, idx, 0)
require.True(t, done)
})
t.Run("partition wildcard", func(t *testing.T) {
tenant := &pbresource.Tenancy{
Partition: storage.Wildcard,
}
idx, done := prefixIndexFromTenancy(tenant)
require.Len(t, idx, 0)
require.True(t, done)
})
t.Run("namespace empty", func(t *testing.T) {
tenant := &pbresource.Tenancy{
Partition: "test",
Namespace: "",
}
idx, done := prefixIndexFromTenancy(tenant)
require.Equal(t, []byte("test\x00"), idx)
require.True(t, done)
})
t.Run("namespace wildcard", func(t *testing.T) {
tenant := &pbresource.Tenancy{
Partition: "test",
Namespace: storage.Wildcard,
}
idx, done := prefixIndexFromTenancy(tenant)
require.Equal(t, []byte("test\x00"), idx)
require.True(t, done)
})
t.Run("namespace populated", func(t *testing.T) {
tenant := &pbresource.Tenancy{
Partition: "test",
Namespace: "blah",
}
idx, done := prefixIndexFromTenancy(tenant)
require.Equal(t, []byte("test\x00blah\x00"), idx)
require.False(t, done)
})
}
func TestIndexFromType(t *testing.T) {
val := IndexFromType(&pbresource.Type{
Group: "test",
GroupVersion: "v1",
Kind: "fake",
})
require.Equal(t, []byte("test\x00fake\x00"), val)
val = IndexFromType(&pbresource.Type{
Group: "test",
GroupVersion: "v1",
})
require.Equal(t, []byte("test\x00\x00"), val)
}
func TestReferenceOrIDFromArgs(t *testing.T) {
ref := &pbresource.Reference{
Type: &pbresource.Type{
Group: "test",
GroupVersion: "v1",
Kind: "fake",
},
Tenancy: &pbresource.Tenancy{
Partition: "default",
Namespace: "default",
},
Name: "foo",
}
t.Run("invalid length", func(t *testing.T) {
// the second arg will cause a validation error
val, err := ReferenceOrIDFromArgs(ref, 2)
require.Nil(t, val)
require.Error(t, err)
})
t.Run("invalid type", func(t *testing.T) {
val, err := ReferenceOrIDFromArgs("string type unexpected")
require.Nil(t, val)
require.Error(t, err)
})
t.Run("ok", func(t *testing.T) {
val, err := ReferenceOrIDFromArgs(ref)
require.NoError(t, err)
require.Equal(t, IndexFromRefOrID(ref), val)
})
}
func TestPrefixReferenceOrIDFromArgs(t *testing.T) {
ref := &pbresource.Reference{
Type: &pbresource.Type{
Group: "test",
GroupVersion: "v1",
Kind: "fake",
},
Tenancy: &pbresource.Tenancy{
Partition: "default",
},
}
t.Run("invalid length", func(t *testing.T) {
// the second arg will cause a validation error
val, err := PrefixReferenceOrIDFromArgs(ref, 2)
require.Nil(t, val)
require.Error(t, err)
})
t.Run("invalid type", func(t *testing.T) {
val, err := PrefixReferenceOrIDFromArgs("string type unexpected")
require.Nil(t, val)
require.Error(t, err)
})
t.Run("ok", func(t *testing.T) {
val, err := PrefixReferenceOrIDFromArgs(ref)
require.NoError(t, err)
require.Equal(t, PrefixIndexFromRefOrID(ref), val)
})
}
func TestMaybePrefixReferenceOrIDFromArgs(t *testing.T) {
ref := &pbresource.Reference{
Type: &pbresource.Type{
Group: "test",
GroupVersion: "v1",
Kind: "fake",
},
Tenancy: &pbresource.Tenancy{
Partition: "default",
},
}
t.Run("invalid length", func(t *testing.T) {
// the second arg will cause a validation error
val, err := MaybePrefixReferenceOrIDFromArgs(ref, IndexQueryOptions{Prefix: false}, 3)
require.Nil(t, val)
require.Error(t, err)
})
t.Run("invalid type arg 1", func(t *testing.T) {
val, err := MaybePrefixReferenceOrIDFromArgs("string type unexpected", IndexQueryOptions{Prefix: true})
require.Nil(t, val)
require.Error(t, err)
})
t.Run("invalid type arg 2", func(t *testing.T) {
val, err := MaybePrefixReferenceOrIDFromArgs(ref, "string type unexpected")
require.Nil(t, val)
require.Error(t, err)
})
t.Run("ok single arg", func(t *testing.T) {
val, err := MaybePrefixReferenceOrIDFromArgs(ref)
require.NoError(t, err)
require.Equal(t, IndexFromRefOrID(ref), val)
})
t.Run("ok two args no prefix", func(t *testing.T) {
val, err := MaybePrefixReferenceOrIDFromArgs(ref, IndexQueryOptions{Prefix: false})
require.NoError(t, err)
require.Equal(t, IndexFromRefOrID(ref), val)
})
t.Run("ok two args with prefix", func(t *testing.T) {
val, err := MaybePrefixReferenceOrIDFromArgs(ref, IndexQueryOptions{Prefix: true})
require.NoError(t, err)
require.Equal(t, PrefixIndexFromRefOrID(ref), val)
})
}
func TestSingleValueFromArgs(t *testing.T) {
injectedError := errors.New("injected test error")
idx := SingleValueFromArgs(func(val string) ([]byte, error) {
return []byte(val), nil
})
errIdx := SingleValueFromArgs(func(val string) ([]byte, error) {
return nil, injectedError
})
t.Run("invalid length", func(t *testing.T) {
// the second arg will cause a validation error
val, err := idx("blah", 2)
require.Nil(t, val)
require.Error(t, err)
})
t.Run("invalid type", func(t *testing.T) {
val, err := idx(3)
require.Nil(t, val)
require.Error(t, err)
})
t.Run("propagate error", func(t *testing.T) {
val, err := errIdx("blah")
require.Nil(t, val)
require.ErrorIs(t, err, injectedError)
})
t.Run("ok", func(t *testing.T) {
val, err := idx("blah")
require.NoError(t, err)
require.Equal(t, []byte("blah"), val)
})
}
func TestSingleValueFromOneOrTwoArgs(t *testing.T) {
injectedError := errors.New("injected test error")
idx := SingleValueFromOneOrTwoArgs(func(val string, optional bool) ([]byte, error) {
if optional {
return []byte(val + val), nil
}
return []byte(val), nil
})
errIdx := SingleValueFromOneOrTwoArgs(func(val string, optional bool) ([]byte, error) {
return nil, injectedError
})
t.Run("invalid length", func(t *testing.T) {
// the third arg will cause a validation error
val, err := idx("blah", true, 4)
require.Nil(t, val)
require.Error(t, err)
})
t.Run("invalid first type", func(t *testing.T) {
val, err := idx(4, true)
require.Nil(t, val)
require.Error(t, err)
})
t.Run("invalid second type", func(t *testing.T) {
val, err := idx("blah", 3)
require.Nil(t, val)
require.Error(t, err)
})
t.Run("propagate error", func(t *testing.T) {
val, err := errIdx("blah")
require.Nil(t, val)
require.ErrorIs(t, err, injectedError)
})
t.Run("one arg ok", func(t *testing.T) {
val, err := idx("blah")
require.NoError(t, err)
require.Equal(t, []byte("blah"), val)
})
t.Run("two arg ok", func(t *testing.T) {
val, err := idx("blah", true)
require.NoError(t, err)
require.Equal(t, []byte("blahblah"), val)
})
}