1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00
kyverno/pkg/testrunner/testcase.go
2019-07-01 12:16:12 -07:00

186 lines
4.6 KiB
Go

package testrunner
import (
"bytes"
"encoding/json"
"fmt"
ospath "path"
"github.com/golang/glog"
pt "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
yaml "k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/kubernetes/scheme"
)
//testCase defines the input and the expected result
// it stores the path to the files that are to be loaded
// for references
type testCase struct {
Input *tInput `yaml:"input"`
Expected *tExpected `yaml:"expected"`
}
// load resources store the resources that are pre-requisite
// for the test case and are pre-loaded in the client before
/// test case in evaluated
type tInput struct {
Policy string `yaml:"policy"`
Resource string `yaml:"resource"`
LoadResources []string `yaml:"load_resources,omitempty"`
}
type tExpected struct {
Passes string `yaml:"passes"`
Mutation *tMutation `yaml:"mutation,omitempty"`
Validation *tValidation `yaml:"validation,omitempty"`
Generation *tGeneration `yaml:"generation,omitempty"`
}
type tMutation struct {
PatchedResource string `yaml:"patched_resource,omitempty"`
Rules []tRules `yaml:"rules"`
}
type tValidation struct {
Rules []tRules `yaml:"rules"`
}
type tGeneration struct {
Resources []string `yaml:"resources"`
Rules []tRules `yaml:"rules"`
}
type tRules struct {
Name string `yaml:"name"`
Type string `yaml:"type"`
Messages []string `yaml:"messages"`
}
type tResult struct {
Reason string `yaml:"reason, omitempty"`
}
func (tc *testCase) policyEngineTest() {
}
func (tc *testCase) loadPreloadedResources(ap string) ([]*resourceInfo, error) {
return loadResources(ap, tc.Input.LoadResources...)
// return loadResources(ap, tc.Input.LoadResources...)
}
func (tc *testCase) loadGeneratedResources(ap string) ([]*resourceInfo, error) {
if tc.Expected.Generation == nil {
return nil, nil
}
return loadResources(ap, tc.Expected.Generation.Resources...)
}
func (tc *testCase) loadPatchedResource(ap string) (*resourceInfo, error) {
if tc.Expected.Mutation == nil {
return nil, nil
}
rs, err := loadResources(ap, tc.Expected.Mutation.PatchedResource)
if err != nil {
return nil, err
}
if len(rs) != 1 {
glog.Warning("expects single resource mutation but multiple defined, will use first one")
}
return rs[0], nil
}
func (tc *testCase) loadResources(files []string) ([]*resourceInfo, error) {
lr := []*resourceInfo{}
for _, r := range files {
rs, err := loadResources(r)
if err != nil {
// return as test case will be invalid if a resource cannot be loaded
return nil, err
}
lr = append(lr, rs...)
}
return lr, nil
}
func (tc *testCase) loadTriggerResource(ap string) (*resourceInfo, error) {
rs, err := loadResources(ap, tc.Input.Resource)
if err != nil {
return nil, err
}
if len(rs) != 1 {
glog.Warning("expects single resource trigger but multiple defined, will use first one")
}
return rs[0], nil
}
// Loads a single policy
func (tc *testCase) loadPolicy(file string) (*pt.Policy, error) {
p := &pt.Policy{}
data, err := LoadFile(file)
if err != nil {
return nil, err
}
pBytes, err := yaml.ToJSON(data)
if err != nil {
return nil, err
}
if err := json.Unmarshal(pBytes, p); err != nil {
return nil, err
}
if p.TypeMeta.Kind != "Policy" {
return nil, fmt.Errorf("failed to parse policy")
}
return p, nil
}
// loads multiple resources
func loadResources(ap string, args ...string) ([]*resourceInfo, error) {
ris := []*resourceInfo{}
for _, file := range args {
data, err := LoadFile(ospath.Join(ap, file))
if err != nil {
return nil, err
}
dd := bytes.Split(data, []byte(defaultYamlSeparator))
// resources seperated by yaml seperator
for _, d := range dd {
ri, err := extractResourceRaw(d)
if err != nil {
glog.Errorf("unable to load resource. err: %s ", err)
continue
}
ris = append(ris, ri)
}
}
return ris, nil
}
func extractResourceRaw(d []byte) (*resourceInfo, error) {
// decode := scheme.Codecs.UniversalDeserializer().Decode
// obj, gvk, err := decode(d, nil, nil)
// if err != nil {
// return nil, err
// }
obj, gvk, err := extractResourceUnMarshalled(d)
// runtime.object to JSON
raw, err := json.Marshal(obj)
if err != nil {
return nil, err
}
return &resourceInfo{rawResource: raw,
gvk: gvk}, nil
}
func extractResourceUnMarshalled(d []byte) (runtime.Object, *metav1.GroupVersionKind, error) {
decode := scheme.Codecs.UniversalDeserializer().Decode
obj, gvk, err := decode(d, nil, nil)
if err != nil {
return nil, nil, err
}
return obj, &metav1.GroupVersionKind{Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind}, nil
}