Skip to content

Commit

Permalink
add unit test for FillVault and validateVault
Browse files Browse the repository at this point in the history
  • Loading branch information
randmonkey committed Dec 29, 2023
1 parent 0140e3b commit b2f1092
Show file tree
Hide file tree
Showing 9 changed files with 284 additions and 14 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ require (
github.com/google/uuid v1.5.0
github.com/jpillora/backoff v1.0.0
github.com/kong/go-database-reconciler v1.1.0
// TODO: Update to latest release version after the following PR merged:
// https://github.com/Kong/go-kong/pull/391
// https://github.com/Kong/go-kong/pull/392
github.com/kong/go-kong v0.48.1-0.20231228093107-7e35dcb56df9
github.com/kong/kubernetes-telemetry v0.1.3
github.com/kong/kubernetes-testing-framework v0.43.0
Expand Down
5 changes: 0 additions & 5 deletions internal/admission/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
ctrlref "github.com/kong/kubernetes-ingress-controller/v3/internal/controllers/reference"
"github.com/kong/kubernetes-ingress-controller/v3/internal/util"
kongv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1"
kongv1alpha1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1alpha1"
kongv1beta1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1beta1"
)

Expand All @@ -38,10 +37,6 @@ var (
APIVersion: kongv1.GroupVersion.String(),
Kind: "KongClusterPlugin",
}
kongVaultMeta = metav1.TypeMeta{
APIVersion: kongv1alpha1.GroupVersion.String(),
Kind: "KongVault",
}
)

func TestHandleKongIngress(t *testing.T) {
Expand Down
2 changes: 2 additions & 0 deletions internal/admission/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,8 @@ func (validator KongHTTPValidator) ValidateVault(ctx context.Context, k8sKongVau
Description: kong.String(k8sKongVault.Spec.Description),
Config: config,
}
// TODO: /schemas/vaults/test does not check "unique" restraint on `prefix` field.
// We may need implement the uniqueness check of `prefix`.
errText, err := validator.validateVaultAgainstGatewaySchema(ctx, kongVault)
if err != nil || errText != "" {
return false, errText, err
Expand Down
90 changes: 89 additions & 1 deletion internal/admission/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/kong/kubernetes-ingress-controller/v3/internal/store"
"github.com/kong/kubernetes-ingress-controller/v3/internal/util/builder"
kongv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1"
kongv1alpha1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1alpha1"
kongv1beta1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1beta1"
incubatorv1alpha1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/incubator/v1alpha1"
)
Expand Down Expand Up @@ -101,7 +102,7 @@ func (f fakeServicesProvider) GetRoutesService() (kong.AbstractRouteService, boo
}

func (f fakeServicesProvider) GetVaultsService() (kong.AbstractVaultService, bool) {
if f.routeSvc != nil {
if f.vaultSvc != nil {
return f.vaultSvc, true
}
return nil, false
Expand Down Expand Up @@ -1235,3 +1236,90 @@ func (f *fakeRouteSvc) Validate(context.Context, *kong.Route) (bool, string, err
}
return true, "", nil
}

func TestValidator_ValidateVault(t *testing.T) {
testCases := []struct {
name string
kongVault kongv1alpha1.KongVault
validateSvcFail bool
expectedOK bool
expectedMessage string
expectedError string
}{
{
name: "valid vault",
kongVault: kongv1alpha1.KongVault{
ObjectMeta: metav1.ObjectMeta{
Name: "vault-1",
},
Spec: kongv1alpha1.KongVaultSpec{
Backend: "env",
Prefix: "env-1",
},
},
expectedOK: true,
},
{
name: "vault with invalid(malformed) configuration",
kongVault: kongv1alpha1.KongVault{
ObjectMeta: metav1.ObjectMeta{
Name: "vault-1",
},
Spec: kongv1alpha1.KongVaultSpec{
Backend: "env",
Prefix: "env-1",
Config: apiextensionsv1.JSON{
Raw: []byte(`{{}`),
},
},
},
expectedOK: false,
expectedMessage: "failed to unmarshal validate configurations",
},
{
name: "vault with failure in validating service",
kongVault: kongv1alpha1.KongVault{
ObjectMeta: metav1.ObjectMeta{
Name: "vault-1",
},
Spec: kongv1alpha1.KongVaultSpec{
Backend: "env",
Prefix: "env-1",
},
},
validateSvcFail: true,
expectedOK: false,
expectedMessage: "something is wrong with the vault",
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
validator := KongHTTPValidator{
AdminAPIServicesProvider: fakeServicesProvider{
vaultSvc: &fakeVaultSvc{
shouldFail: tc.validateSvcFail,
},
},
ingressClassMatcher: fakeClassMatcher,
Logger: logr.Discard(),
}
ok, msg, err := validator.ValidateVault(context.Background(), tc.kongVault)
require.NoError(t, err)
assert.Equal(t, tc.expectedOK, ok)
assert.Contains(t, msg, tc.expectedMessage)
})
}
}

type fakeVaultSvc struct {
kong.AbstractVaultService
shouldFail bool
}

func (s fakeVaultSvc) Validate(context.Context, *kong.Vault) (bool, string, error) {
if s.shouldFail {
return false, "something is wrong with the vault", nil
}
return true, "", nil
}
3 changes: 0 additions & 3 deletions internal/dataplane/failures/failures.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ func NewResourceFailure(reason string, causingObjects ...client.Object) (Resourc
if obj.GetName() == "" {
return ResourceFailure{}, fmt.Errorf("one of causing objects (%s) has no name", gvk.String())
}
if obj.GetNamespace() == "" {
return ResourceFailure{}, fmt.Errorf("one of causing objects (%s) has no namespace", gvk.String())
}
}

return ResourceFailure{
Expand Down
5 changes: 0 additions & 5 deletions internal/dataplane/failures/failures_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,6 @@ func TestResourceFailure(t *testing.T) {
noName.Name = ""
_, err = NewResourceFailure(someValidResourceFailureReason, noName)
assert.Error(t, err, "expected an empty name object to be rejected")

noNamespace := validCausingObject()
noNamespace.Namespace = ""
_, err = NewResourceFailure(someValidResourceFailureReason, noNamespace)
assert.Error(t, err, "expected an empty namespace object to be rejected")
})
}

Expand Down
1 change: 1 addition & 0 deletions internal/dataplane/kongstate/kongstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ func (ks *KongState) FillIDs(logger logr.Logger) {
}

// TODO: Add FillID() for vaults in go-kong to fill IDs for vaults.
// https://github.com/Kong/go-kong/pull/391
}

// maybeLogKongIngressDeprecationError iterates over services and logs a deprecation error if a service
Expand Down
187 changes: 187 additions & 0 deletions internal/dataplane/kongstate/kongstate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import (
"testing"

"github.com/go-logr/logr"
"github.com/go-logr/logr/testr"
"github.com/go-logr/zapr"
"github.com/kong/go-kong/kong"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8stypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
Expand All @@ -25,6 +27,7 @@ import (
"github.com/kong/kubernetes-ingress-controller/v3/internal/store"
"github.com/kong/kubernetes-ingress-controller/v3/internal/util"
kongv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1"
kongv1alpha1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1alpha1"
kongv1beta1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1beta1"
)

Expand Down Expand Up @@ -1154,3 +1157,187 @@ func TestKongState_FillUpstreamOverrides(t *testing.T) {
})
}
}

func TestFillVaults(t *testing.T) {
kongVaultTypeMeta := metav1.TypeMeta{
APIVersion: kongv1alpha1.GroupVersion.String(),
Kind: "KongVault",
}
testCases := []struct {
name string
kongVaults []*kongv1alpha1.KongVault
expectedTranslatedVaults []Vault
// name of KongVault -> failure message
expectedTranslationFailures map[string]string
}{
{
name: "single valid KongVault",
kongVaults: []*kongv1alpha1.KongVault{
{
TypeMeta: kongVaultTypeMeta,
ObjectMeta: metav1.ObjectMeta{
Namespace: "",
Name: "vault-1",
Annotations: map[string]string{
annotations.IngressClassKey: annotations.DefaultIngressClass,
},
},
Spec: kongv1alpha1.KongVaultSpec{
Backend: "env",
Prefix: "env-1",
},
},
},
expectedTranslatedVaults: []Vault{
{
Vault: kong.Vault{
Name: kong.String("env"),
Prefix: kong.String("env-1"),
},
K8sKongVault: &kongv1alpha1.KongVault{
ObjectMeta: metav1.ObjectMeta{
Name: "vault-1",
},
},
},
},
},
{
name: "one valid KongVault with correct ingress class, and one KongVault with other ingress class",
kongVaults: []*kongv1alpha1.KongVault{
{
TypeMeta: kongVaultTypeMeta,
ObjectMeta: metav1.ObjectMeta{
Name: "vault-1",
Annotations: map[string]string{
annotations.IngressClassKey: annotations.DefaultIngressClass,
},
},
Spec: kongv1alpha1.KongVaultSpec{
Backend: "env",
Prefix: "env-1",
},
},
{
TypeMeta: kongVaultTypeMeta,
ObjectMeta: metav1.ObjectMeta{
Name: "vault-2",
Annotations: map[string]string{
annotations.IngressClassKey: "other-ingress-class",
},
},
Spec: kongv1alpha1.KongVaultSpec{
Backend: "env",
Prefix: "env-2",
},
},
},
expectedTranslatedVaults: []Vault{
{
Vault: kong.Vault{
Name: kong.String("env"),
Prefix: kong.String("env-1"),
},
K8sKongVault: &kongv1alpha1.KongVault{
ObjectMeta: metav1.ObjectMeta{
Name: "vault-1",
},
},
},
},
},
{
name: "one valid KongVault with correct ingress class, and one invalid KongVault",
kongVaults: []*kongv1alpha1.KongVault{
{
TypeMeta: kongVaultTypeMeta,
ObjectMeta: metav1.ObjectMeta{
Name: "vault-1",
Annotations: map[string]string{
annotations.IngressClassKey: annotations.DefaultIngressClass,
},
},
Spec: kongv1alpha1.KongVaultSpec{
Backend: "env",
Prefix: "env-1",
Config: apiextensionsv1.JSON{
Raw: []byte(`{}`),
},
},
},
{
TypeMeta: kongVaultTypeMeta,
ObjectMeta: metav1.ObjectMeta{
Name: "vault-invalid",
Annotations: map[string]string{
annotations.IngressClassKey: annotations.DefaultIngressClass,
},
},
Spec: kongv1alpha1.KongVaultSpec{
Backend: "env",
Prefix: "env-invalid",
Config: apiextensionsv1.JSON{
Raw: []byte(`{{}`),
},
},
},
},
expectedTranslatedVaults: []Vault{
{
Vault: kong.Vault{
Name: kong.String("env"),
Prefix: kong.String("env-1"),
},
K8sKongVault: &kongv1alpha1.KongVault{
ObjectMeta: metav1.ObjectMeta{
Name: "vault-1",
},
},
},
},
expectedTranslationFailures: map[string]string{
"vault-invalid": "failed to parse configuration of vault",
},
},
}

for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
s, err := store.NewFakeStore(store.FakeObjects{
KongVaults: tc.kongVaults,
})

require.NoError(t, err)
logger := testr.New(t)
f := failures.NewResourceFailuresCollector(logger)
ks := &KongState{}
ks.FillVaults(logger, s, f)

assert.Len(t, ks.Vaults, len(tc.expectedTranslatedVaults), "should have expected number of translated vaults")
for _, expectedVault := range tc.expectedTranslatedVaults {
assert.Truef(t, lo.ContainsBy(ks.Vaults, func(v Vault) bool {
return (v.Name != nil && *v.Name == *expectedVault.Name) &&
(v.Prefix != nil && *v.Prefix == *expectedVault.Prefix) &&
(v.K8sKongVault != nil && v.K8sKongVault.Name == expectedVault.K8sKongVault.Name)
}),
"cannot find translated vault for KongVault %q", expectedVault.K8sKongVault.Name,
)
}

translationFailures := f.PopResourceFailures()
assert.Len(t, translationFailures, len(tc.expectedTranslationFailures), "should have expected number of translation failures")
for vaultName, msg := range tc.expectedTranslationFailures {
require.Truef(t, lo.ContainsBy(translationFailures, func(translationFailure failures.ResourceFailure) bool {
objects := translationFailure.CausingObjects()
if len(objects) != 1 && objects[0].GetName() != vaultName {
return false
}
return strings.Contains(translationFailure.Message(), msg)
}),
"cannot find expected translation failure message %q for KongVault %q",
msg, vaultName)
}
})
}
}
2 changes: 2 additions & 0 deletions internal/dataplane/translator/translator.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ func (t *Translator) BuildKongConfig() KongConfigBuildingResult {
t.registerSuccessfullyTranslatedObject(&result.Consumers[i].K8sKongConsumer)
}

// genereate vaults
// REVIEW: add check for Kong gateway enterprise here?
result.FillVaults(t.logger, t.storer, t.failuresCollector)
for i := range result.Vaults {
t.registerSuccessfullyTranslatedObject(result.Vaults[i].K8sKongVault)
Expand Down

0 comments on commit b2f1092

Please sign in to comment.