1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-09 01:16:55 +00:00
kyverno/pkg/testrunner/test.go

181 lines
4.8 KiB
Go
Raw Normal View History

2019-06-17 18:11:22 -07:00
package testrunner
import (
"fmt"
"testing"
ospath "path"
"github.com/golang/glog"
pt "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
client "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/engine"
"github.com/nirmata/kyverno/pkg/result"
kscheme "k8s.io/client-go/kubernetes/scheme"
)
type test struct {
ap string
t *testing.T
testCase *testCase
// input
policy *pt.Policy
tResource *resourceInfo
loadResources []*resourceInfo
// expected
genResources []*resourceInfo
patchedResource *resourceInfo
}
func (t *test) run() {
var client *client.Client
var err error
//mock client is used if generate is defined
if t.testCase.Expected.Generation != nil {
// create mock client & load resources
client, err = createClient(t.loadResources)
if err != nil {
t.t.Errorf("Unable to create client. err %s", err)
}
// TODO: handle generate
// assuming its namespaces creation
decode := kscheme.Codecs.UniversalDeserializer().Decode
obj, _, err := decode([]byte(t.tResource.rawResource), nil, nil)
2019-06-19 15:12:48 -07:00
_, err = client.CreateResource(getResourceFromKind(t.tResource.gvk.Kind), "", obj, false)
2019-06-17 18:11:22 -07:00
if err != nil {
t.t.Errorf("error while creating namespace %s", err)
}
}
// apply the policy engine
pr, mResult, vResult, err := t.applyPolicy(t.policy, t.tResource, client)
if err != nil {
t.t.Error(err)
return
}
// Expected Result
t.checkMutationResult(pr, mResult)
t.checkValidationResult(vResult)
t.checkGenerationResult(client)
}
func (t *test) checkMutationResult(pr *resourceInfo, result result.Result) {
if t.testCase.Expected.Mutation == nil {
glog.Info("No Mutation check defined")
return
}
// patched resource
if !compareResource(pr, t.patchedResource) {
fmt.Printf("Expected Resource %s \n", string(t.patchedResource.rawResource))
fmt.Printf("Patched Resource %s \n", string(pr.rawResource))
glog.Warningf("Expected resource %s ", string(pr.rawResource))
t.t.Error("Patched resources not as expected")
}
// reason
reason := t.testCase.Expected.Mutation.Reason
if len(reason) > 0 && result.GetReason().String() != reason {
t.t.Error("Reason not matching")
}
}
func (t *test) checkValidationResult(result result.Result) {
if t.testCase.Expected.Validation == nil {
glog.Info("No Validation check defined")
return
}
// reason
reason := t.testCase.Expected.Validation.Reason
if len(reason) > 0 && result.GetReason().String() != reason {
t.t.Error("Reason not matching")
}
}
func (t *test) checkGenerationResult(client *client.Client) {
if t.testCase.Expected.Generation == nil {
glog.Info("No Generate check defined")
return
}
if client == nil {
glog.Info("client needs to be configured")
}
// check if the expected resources are generated
for _, r := range t.genResources {
n := ParseNameFromObject(r.rawResource)
ns := ParseNamespaceFromObject(r.rawResource)
_, err := client.GetResource(getResourceFromKind(r.gvk.Kind), ns, n)
if err != nil {
t.t.Errorf("Resource %s/%s of kinf %s not found", ns, n, r.gvk.Kind)
}
// compare if the resources are same
//TODO: comapre []bytes vs unstrcutured resource
}
}
func (t *test) applyPolicy(policy *pt.Policy,
tresource *resourceInfo,
client *client.Client) (*resourceInfo, result.Result, result.Result, error) {
// apply policy on the trigger resource
// Mutate
var vResult result.Result
var patchedResource []byte
mPatches, mResult := engine.Mutate(*policy, tresource.rawResource, *tresource.gvk)
// TODO: only validate if there are no errors in mutate, why?
err := mResult.ToError()
if err == nil && len(mPatches) != 0 {
patchedResource, err = engine.ApplyPatches(tresource.rawResource, mPatches)
if err != nil {
return nil, nil, nil, err
}
// Validate
vResult = engine.Validate(*policy, patchedResource, *tresource.gvk)
}
// Generate
if client != nil {
engine.Generate(client, *policy, tresource.rawResource, *tresource.gvk)
}
// transform the patched Resource into resource Info
ri, err := extractResourceRaw(patchedResource)
if err != nil {
return nil, nil, nil, err
}
// return the results
return ri, mResult, vResult, nil
}
func NewTest(ap string, t *testing.T, tc *testCase) (*test, error) {
//---INPUT---
p, err := tc.loadPolicy(ospath.Join(ap, tc.Input.Policy))
if err != nil {
return nil, err
}
r, err := tc.loadTriggerResource(ap)
if err != nil {
return nil, err
}
lr, err := tc.loadPreloadedResources(ap)
if err != nil {
return nil, err
}
//---EXPECTED---
pr, err := tc.loadPatchedResource(ap)
if err != nil {
return nil, err
}
gr, err := tc.loadGeneratedResources(ap)
if err != nil {
return nil, err
}
return &test{
ap: ap,
t: t,
testCase: tc,
policy: p,
tResource: r,
loadResources: lr,
genResources: gr,
patchedResource: pr,
}, nil
}