Skip to content

Commit

Permalink
refactor(tests): 586 refactor unhappy path e2e tests (#598)
Browse files Browse the repository at this point in the history
* feat: create domain/provider fcns, unit tests

* feat: updated tests, schema, error handling

* feat: updated tests, evaluating specific err types

* Update src/pkg/common/types_test.go

Co-authored-by: Brandt Keller <43887158+brandtkeller@users.noreply.github.com>

* Update src/pkg/common/types_test.go

Co-authored-by: Brandt Keller <43887158+brandtkeller@users.noreply.github.com>

* Update src/pkg/domains/kubernetes/types.go

Co-authored-by: Brandt Keller <43887158+brandtkeller@users.noreply.github.com>

---------

Co-authored-by: Brandt Keller <43887158+brandtkeller@users.noreply.github.com>
  • Loading branch information
meganwolf0 and brandtkeller authored Aug 20, 2024
1 parent 6601566 commit 26898b8
Show file tree
Hide file tree
Showing 27 changed files with 1,422 additions and 307 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ require (
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
github.com/vladimirvivien/gexe v0.2.0 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
Expand Down
9 changes: 2 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -290,17 +290,12 @@ github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3k
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0=
github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
Expand Down
31 changes: 10 additions & 21 deletions src/pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,42 +138,31 @@ func SetCwdToFileDir(dirPath string) (resetFunc func(), err error) {
}

// Get the domain and providers
func GetDomain(domain *Domain, ctx context.Context) types.Domain {
func GetDomain(domain *Domain, ctx context.Context) (types.Domain, error) {
if domain == nil {
return nil
return nil, fmt.Errorf("domain is nil")
}
switch domain.Type {
case "kubernetes":
return kube.KubernetesDomain{
Context: ctx,
Spec: domain.KubernetesSpec,
}
return kube.CreateKubernetesDomain(ctx, domain.KubernetesSpec)
case "api":
return api.ApiDomain{
Spec: domain.ApiSpec,
}
return api.CreateApiDomain(domain.ApiSpec)
default:
return nil
return nil, fmt.Errorf("domain is unsupported")
}
}

func GetProvider(provider *Provider, ctx context.Context) types.Provider {
func GetProvider(provider *Provider, ctx context.Context) (types.Provider, error) {
if provider == nil {
return nil
return nil, fmt.Errorf("provider is nil")
}
switch provider.Type {
case "opa":
return opa.OpaProvider{
Context: ctx,
Spec: provider.OpaSpec,
}
return opa.CreateOpaProvider(ctx, provider.OpaSpec)
case "kyverno":
return kyverno.KyvernoProvider{
Context: ctx,
Spec: provider.KyvernoSpec,
}
return kyverno.CreateKyvernoProvider(ctx, provider.KyvernoSpec)
default:
return nil
return nil, fmt.Errorf("provider is unsupported")
}
}

Expand Down
242 changes: 183 additions & 59 deletions src/pkg/common/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,10 @@ import (
kube "github.com/defenseunicorns/lula/src/pkg/domains/kubernetes"
"github.com/defenseunicorns/lula/src/pkg/providers/kyverno"
"github.com/defenseunicorns/lula/src/pkg/providers/opa"
kjson "github.com/kyverno/kyverno-json/pkg/apis/policy/v1alpha1"
"sigs.k8s.io/yaml"
)

const validKubernetesPath = "../../test/unit/common/valid-kubernetes-spec.yaml"
const validApiPath = "../../test/unit/common/valid-api-spec.yaml"
const validOpaPath = "../../test/unit/common/valid-opa-spec.yaml"
const validKyvernoPath = "../../test/unit/common/valid-kyverno-spec.yaml"
const multiValidationPath = "../../test/e2e/scenarios/remote-validations/multi-validations.yaml"
const singleValidationPath = "../../test/e2e/scenarios/remote-validations/validation.opa.yaml"

Expand All @@ -33,57 +30,101 @@ func loadTestData(t *testing.T, path string) []byte {
}

func TestGetDomain(t *testing.T) {
validKubernetesBytes := loadTestData(t, validKubernetesPath)
validApiBytes := loadTestData(t, validApiPath)

var validKubernetes kube.KubernetesSpec
if err := yaml.Unmarshal(validKubernetesBytes, &validKubernetes); err != nil {
t.Fatalf("yaml.Unmarshal failed: %v", err)
}

var validApi api.ApiSpec
if err := yaml.Unmarshal(validApiBytes, &validApi); err != nil {
t.Fatalf("yaml.Unmarshal failed: %v", err)
}
t.Parallel()

// Define test cases
tests := []struct {
name string
domain common.Domain
expected string
name string
domain common.Domain
expectedErr bool
expectedDomain string
}{
{
name: "kubernetes domain",
name: "valid kubernetes domain",
domain: common.Domain{
Type: "kubernetes",
KubernetesSpec: &kube.KubernetesSpec{
Resources: []kube.Resource{
{
Name: "podsvt",
ResourceRule: &kube.ResourceRule{
Version: "v1",
Resource: "pods",
Namespaces: []string{"validation-test"},
},
},
},
},
},
expectedErr: false,
expectedDomain: "kube.KubernetesDomain",
},
{
name: "invalid kubernetes domain",
domain: common.Domain{
Type: "kubernetes",
KubernetesSpec: &kube.KubernetesSpec{
Resources: []kube.Resource{
{
Name: "podsvt",
ResourceRule: &kube.ResourceRule{
Version: "v1",
Namespaces: []string{"validation-test"},
},
},
},
},
},
expectedErr: true,
},
{
name: "valid api domain",
domain: common.Domain{
Type: "kubernetes",
KubernetesSpec: &validKubernetes,
Type: "api",
ApiSpec: &api.ApiSpec{
Requests: []api.Request{
{
Name: "local",
URL: "http://localhost",
},
},
},
},
expected: "kube.KubernetesDomain",
expectedErr: false,
expectedDomain: "api.ApiDomain",
},
{
name: "api domain",
name: "invalid api domain",
domain: common.Domain{
Type: "api",
ApiSpec: &validApi,
Type: "api",
ApiSpec: &api.ApiSpec{
Requests: []api.Request{
{
Name: "local",
},
},
},
},
expected: "api.ApiDomain",
expectedErr: true,
},
{
name: "unsupported domain",
name: "invalid type domain",
domain: common.Domain{
Type: "unsupported",
Type: "foo",
},
expected: "nil",
expectedErr: true,
},
}

ctx := context.Background()

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := common.GetDomain(&tt.domain, ctx)
result, err := common.GetDomain(&tt.domain, ctx)
if (err != nil) != tt.expectedErr {
t.Fatalf("expected error: %v, got: %v", tt.expectedErr, err)
}

switch tt.expected {
switch tt.expectedDomain {
case "kube.KubernetesDomain":
if _, ok := result.(kube.KubernetesDomain); !ok {
t.Errorf("Expected result to be kube.KubernetesDomain, got %T", result)
Expand All @@ -102,56 +143,73 @@ func TestGetDomain(t *testing.T) {
}

func TestGetProvider(t *testing.T) {
validOpaBytes := loadTestData(t, validOpaPath)
validKyvernoBytes := loadTestData(t, validKyvernoPath)

var validOpa opa.OpaSpec
if err := yaml.Unmarshal(validOpaBytes, &validOpa); err != nil {
t.Fatalf("yaml.Unmarshal failed: %v", err)
}

var validKyverno kyverno.KyvernoSpec
if err := yaml.Unmarshal(validKyvernoBytes, &validKyverno); err != nil {
t.Fatalf("yaml.Unmarshal failed: %v", err)
}
t.Parallel()

tests := []struct {
name string
provider common.Provider
expected string
name string
provider common.Provider
expectedErr bool
expectedProvider string
}{
{
name: "opa provider",
name: "valid opa provider",
provider: common.Provider{
Type: "opa",
OpaSpec: &opa.OpaSpec{
Rego: "package validate\n\ndefault validate = false",
},
},
expectedErr: false,
expectedProvider: "opa.OpaProvider",
},
{
name: "invalid opa provider",
provider: common.Provider{
Type: "opa",
OpaSpec: &validOpa,
OpaSpec: &opa.OpaSpec{},
},
expectedErr: true,
},
{
name: "valid kyverno provider",
provider: common.Provider{
Type: "kyverno",
KyvernoSpec: &kyverno.KyvernoSpec{
Policy: &kjson.ValidatingPolicy{
Spec: kjson.ValidatingPolicySpec{},
},
},
},
expected: "opa.OpaProvider",
expectedErr: false,
expectedProvider: "kyverno.KyvernoProvider",
},
{
name: "kyverno provider",
name: "invalid kyverno provider",
provider: common.Provider{
Type: "kyverno",
KyvernoSpec: &validKyverno,
KyvernoSpec: &kyverno.KyvernoSpec{},
},
expected: "kyverno.KyvernoProvider",
expectedErr: true,
},
{
name: "unsupported provider",
name: "invalid type provider",
provider: common.Provider{
Type: "unsupported",
Type: "foo",
},
expected: "nil",
expectedErr: true,
},
}

ctx := context.Background()

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := common.GetProvider(&tt.provider, ctx)
result, err := common.GetProvider(&tt.provider, ctx)
if (err != nil) != tt.expectedErr {
t.Fatalf("expected error: %v, got: %v", tt.expectedErr, err)
}

switch tt.expected {
switch tt.expectedProvider {
case "opa.OpaProvider":
if _, ok := result.(opa.OpaProvider); !ok {
t.Errorf("Expected result to be opa.OpaProvider, got %T", result)
Expand Down Expand Up @@ -374,3 +432,69 @@ func TestReadValidationsFromYaml(t *testing.T) {
})
}
}

func TestIsVersionValid(t *testing.T) {
t.Parallel()
tests := []struct {
name string
versionConstraint string
version string
expectedValid bool
expectedErr bool
}{
{
name: "Valid constraint and version",
versionConstraint: ">= 1.0.0, < 2.0.0",
version: "1.5.0",
expectedValid: true,
expectedErr: false,
},
{
name: "Valid constraint and version (exact match)",
versionConstraint: "1.0.0",
version: "1.0.0",
expectedValid: true,
expectedErr: false,
},
{
name: "Invalid version",
versionConstraint: ">= 1.0.0, < 2.0.0",
version: "2.5.0",
expectedValid: false,
expectedErr: false,
},
{
name: "Invalid constraint syntax",
versionConstraint: ">=> 1.0.0",
version: "1.5.0",
expectedValid: false,
expectedErr: true,
},
{
name: "Invalid version syntax",
versionConstraint: ">= 1.0.0, < 2.0.0",
version: "invalid",
expectedValid: false,
expectedErr: true,
},
{
name: "Unset version",
versionConstraint: ">= 1.0.0, < 2.0.0",
version: "unset",
expectedValid: true,
expectedErr: false,
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
valid, err := common.IsVersionValid(tc.versionConstraint, tc.version)
if (err != nil) != tc.expectedErr {
t.Fatalf("expected error: %v, got: %v", tc.expectedErr, err)
}
if valid != tc.expectedValid {
t.Fatalf("expected valid: %v, got: %v", tc.expectedValid, valid)
}
})
}
}
Loading

0 comments on commit 26898b8

Please sign in to comment.