Skip to content

Commit

Permalink
chore: add unit tests (#522)
Browse files Browse the repository at this point in the history
Signed-off-by: Charles-Edouard Brétéché <[email protected]>
  • Loading branch information
eddycharly authored Nov 28, 2023
1 parent f563017 commit a8e1ab0
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 87 deletions.
19 changes: 9 additions & 10 deletions pkg/runner/operations/command/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,22 @@ func (o *operation) Exec(ctx context.Context) (_err error) {
}
args := expand(map[string]string{"NAMESPACE": o.namespace}, o.command.Args...)
cmd := exec.CommandContext(ctx, o.command.Entrypoint, args...) //nolint:gosec
cwd, err := os.Getwd()
if err != nil {
env := os.Environ()
if cwd, err := os.Getwd(); err != nil {
return fmt.Errorf("failed to get current working directory (%w)", err)
} else {
env = append(env, fmt.Sprintf("PATH=%s/bin/:%s", cwd, os.Getenv("PATH")))
}
env := os.Environ()
env = append(env, fmt.Sprintf("NAMESPACE=%s", o.namespace))
env = append(env, fmt.Sprintf("PATH=%s/bin/:%s", cwd, os.Getenv("PATH")))
// TODO
// env = append(env, fmt.Sprintf("KUBECONFIG=%s/bin/:%s", cwd, os.Getenv("PATH")))
cmd.Env = env
cmd.Dir = o.basePath
logger.Log(logging.Command, logging.RunStatus, color.BoldFgCyan, logging.Section("COMMAND", cmd.String()))
cmd.Stdout = &output.Stdout
cmd.Stderr = &output.Stderr
cmdErr := cmd.Run()
if o.command.Check == nil || o.command.Check.Value == nil {
return cmdErr
if err := cmd.Run(); o.command.Check == nil || o.command.Check.Value == nil {
return err
} else {
bindings := binding.NewBindings()
if err == nil {
Expand All @@ -72,11 +71,11 @@ func (o *operation) Exec(ctx context.Context) (_err error) {
}
bindings = bindings.Register("$stdout", binding.NewBinding(output.Out()))
bindings = bindings.Register("$stderr", binding.NewBinding(output.Err()))
errs, err := assert.Validate(ctx, o.command.Check.Value, nil, bindings)
if err != nil {
if errs, err := assert.Validate(ctx, o.command.Check.Value, nil, bindings); err != nil {
return err
} else {
return errs.ToAggregate()
}
return errs.ToAggregate()
}
}

Expand Down
15 changes: 15 additions & 0 deletions pkg/runner/operations/command/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,21 @@ func Test_operationCommand(t *testing.T) {
basePath: "..",
namespace: "test-namespace",
wantErr: false,
}, {
name: "with check",
command: v1alpha1.Command{
Entrypoint: "foo",
Args: []string{"operation.go"},
SkipLogOutput: true,
Check: &v1alpha1.Check{
Value: map[string]interface{}{
"($error != null)": true,
},
},
},
basePath: "..",
namespace: "test-namespace",
wantErr: false,
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
196 changes: 129 additions & 67 deletions pkg/runner/operations/error/error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ import (
"testing"
"time"

"github.com/kyverno/chainsaw/pkg/client"
tclient "github.com/kyverno/chainsaw/pkg/client/testing"
"github.com/kyverno/chainsaw/pkg/runner/logging"
tlogging "github.com/kyverno/chainsaw/pkg/runner/logging/testing"
"github.com/kyverno/chainsaw/pkg/runner/namespacer"
ttesting "github.com/kyverno/chainsaw/pkg/testing"
"github.com/stretchr/testify/assert"
kerrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
)

Expand All @@ -31,101 +35,159 @@ func Test_operationError(t *testing.T) {
name string
expected unstructured.Unstructured
client *tclient.FakeClient
namespacer func(c client.Client) namespacer.Namespacer
expectedErr error
expectedLogs []string
}{
{
name: "Resource not found",
expected: expected,
client: &tclient.FakeClient{
ListFn: func(ctx context.Context, _ int, list ctrlclient.ObjectList, opts ...ctrlclient.ListOption) error {
return kerrors.NewNotFound(list.GetObjectKind().GroupVersionKind().GroupVersion().WithResource("pod").GroupResource(), "test-pod")
},
GetFn: func(ctx context.Context, _ int, key ctrlclient.ObjectKey, obj ctrlclient.Object, opts ...ctrlclient.GetOption) error {
return kerrors.NewNotFound(obj.GetObjectKind().GroupVersionKind().GroupVersion().WithResource("pod").GroupResource(), "test-pod")
},
}{{
name: "Resource not found",
expected: expected,
client: &tclient.FakeClient{
ListFn: func(ctx context.Context, _ int, list ctrlclient.ObjectList, opts ...ctrlclient.ListOption) error {
return kerrors.NewNotFound(list.GetObjectKind().GroupVersionKind().GroupVersion().WithResource("pod").GroupResource(), "test-pod")
},
GetFn: func(ctx context.Context, _ int, key ctrlclient.ObjectKey, obj ctrlclient.Object, opts ...ctrlclient.GetOption) error {
return kerrors.NewNotFound(obj.GetObjectKind().GroupVersionKind().GroupVersion().WithResource("pod").GroupResource(), "test-pod")
},
expectedErr: nil,
expectedLogs: []string{"ERROR: RUN - []", "ERROR: DONE - []"},
},
{
name: "Internal error",
expected: expected,
client: &tclient.FakeClient{
ListFn: func(ctx context.Context, _ int, list ctrlclient.ObjectList, opts ...ctrlclient.ListOption) error {
return errors.New("internal error")
},
GetFn: func(ctx context.Context, _ int, key ctrlclient.ObjectKey, obj ctrlclient.Object, opts ...ctrlclient.GetOption) error {
return errors.New("internal error")
},
expectedErr: nil,
expectedLogs: []string{"ERROR: RUN - []", "ERROR: DONE - []"},
}, {
name: "Internal error",
expected: expected,
client: &tclient.FakeClient{
ListFn: func(ctx context.Context, _ int, list ctrlclient.ObjectList, opts ...ctrlclient.ListOption) error {
return errors.New("internal error")
},
GetFn: func(ctx context.Context, _ int, key ctrlclient.ObjectKey, obj ctrlclient.Object, opts ...ctrlclient.GetOption) error {
return errors.New("internal error")
},
expectedErr: errors.New("internal error"),
expectedLogs: []string{"ERROR: RUN - []", "ERROR: ERROR - [=== ERROR\ninternal error]"},
},
{
name: "Resource matches actual",
expected: expected,
client: &tclient.FakeClient{
ListFn: func(ctx context.Context, _ int, list ctrlclient.ObjectList, opts ...ctrlclient.ListOption) error {
return nil
expectedErr: errors.New("internal error"),
expectedLogs: []string{"ERROR: RUN - []", "ERROR: ERROR - [=== ERROR\ninternal error]"},
}, {
name: "Resource matches actual",
expected: expected,
client: &tclient.FakeClient{
ListFn: func(ctx context.Context, _ int, list ctrlclient.ObjectList, opts ...ctrlclient.ListOption) error {
return nil
},
GetFn: func(ctx context.Context, _ int, key ctrlclient.ObjectKey, obj ctrlclient.Object, opts ...ctrlclient.GetOption) error {
uObj, ok := obj.(*unstructured.Unstructured)
if !ok {
t.Fatalf("obj is not of type *unstructured.Unstructured, it's %T", obj)
}
uObj.Object = expected.Object
return nil
},
},
expectedErr: fmt.Errorf("v1/Pod/foo/test-pod - resource matches expectation"),
expectedLogs: []string{"ERROR: RUN - []", "ERROR: ERROR - [=== ERROR\nv1/Pod/foo/test-pod - resource matches expectation]"},
}, {
name: "Bad assert",
expected: unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "Pod",
"metadata": map[string]interface{}{
"name": "test-pod",
},
GetFn: func(ctx context.Context, _ int, key ctrlclient.ObjectKey, obj ctrlclient.Object, opts ...ctrlclient.GetOption) error {
uObj, ok := obj.(*unstructured.Unstructured)
if !ok {
t.Fatalf("obj is not of type *unstructured.Unstructured, it's %T", obj)
}
uObj.Object = expected.Object
return nil
"spec": map[string]interface{}{
"(foo('bar'))": "test-pod",
},
},
expectedErr: fmt.Errorf("v1/Pod/foo/test-pod - resource matches expectation"),
expectedLogs: []string{"ERROR: RUN - []", "ERROR: ERROR - [=== ERROR\nv1/Pod/foo/test-pod - resource matches expectation]"},
},
{
name: "No resources found using List",
expected: unstructured.Unstructured{
Object: map[string]interface{}{
client: &tclient.FakeClient{
GetFn: func(ctx context.Context, _ int, key ctrlclient.ObjectKey, obj ctrlclient.Object, opts ...ctrlclient.GetOption) error {
t.Helper()
obj.(*unstructured.Unstructured).Object = map[string]interface{}{
"apiVersion": "v1",
"kind": "Pod",
"metadata": map[string]interface{}{
"namespace": "test-ns",
"labels": map[string]interface{}{
"app": "my-app",
},
"name": "test-pod",
},
}
return nil
},
},
expectedErr: fmt.Errorf("spec.(foo('bar')): Internal error: unknown function: foo"),
expectedLogs: []string{"ERROR: RUN - []", "ERROR: ERROR - [=== ERROR\nspec.(foo('bar')): Internal error: unknown function: foo]"},
}, {
name: "No resources found using List",
expected: unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "Pod",
"metadata": map[string]interface{}{
"namespace": "test-ns",
"labels": map[string]interface{}{
"app": "my-app",
},
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "test-container",
"image": "test-image",
},
},
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "test-container",
"image": "test-image",
},
},
},
},
client: &tclient.FakeClient{
ListFn: func(ctx context.Context, _ int, list ctrlclient.ObjectList, opts ...ctrlclient.ListOption) error {
t.Helper()
uList := list.(*unstructured.UnstructuredList)
uList.Items = nil
return nil
},
client: &tclient.FakeClient{
ListFn: func(ctx context.Context, _ int, list ctrlclient.ObjectList, opts ...ctrlclient.ListOption) error {
t.Helper()
uList := list.(*unstructured.UnstructuredList)
uList.Items = nil
return nil
},
},
expectedErr: nil,
expectedLogs: []string{"ERROR: RUN - []", "ERROR: DONE - []"},
}, {
name: "with namespacer",
expected: unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"app": "my-app",
},
},
},
expectedErr: nil,
expectedLogs: []string{"ERROR: RUN - []", "ERROR: DONE - []"},
},
}
client: &tclient.FakeClient{
ListFn: func(ctx context.Context, _ int, list ctrlclient.ObjectList, opts ...ctrlclient.ListOption) error {
t := ttesting.FromContext(ctx)
assert.Contains(t, opts, ctrlclient.InNamespace("bar"))
uList := list.(*unstructured.UnstructuredList)
uList.Items = nil
return nil
},
IsObjectNamespacedFn: func(int, runtime.Object) (bool, error) {
return true, nil
},
},
namespacer: func(c client.Client) namespacer.Namespacer {
return namespacer.New(c, "bar")
},
expectedLogs: []string{"ERROR: RUN - []", "ERROR: DONE - []"},
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
logger := &tlogging.FakeLogger{}
ctx, cancel := context.WithTimeout(logging.IntoContext(context.TODO(), logger), 1*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
var nspacer namespacer.Namespacer
if tt.namespacer != nil {
nspacer = tt.namespacer(tt.client)
}
operation := New(
tt.client,
tt.expected,
nil,
nspacer,
)
err := operation.Exec(ctx)
logger := &tlogging.FakeLogger{}
err := operation.Exec(ttesting.IntoContext(logging.IntoContext(ctx, logger), t))
if tt.expectedErr != nil {
assert.EqualError(t, err, tt.expectedErr.Error())
} else {
Expand Down
19 changes: 9 additions & 10 deletions pkg/runner/operations/script/script.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,22 @@ func (o *operation) Exec(ctx context.Context) (_err error) {
}()
}
cmd := exec.CommandContext(ctx, "sh", "-c", o.script.Content) //nolint:gosec
cwd, err := os.Getwd()
if err != nil {
env := os.Environ()
if cwd, err := os.Getwd(); err != nil {
return fmt.Errorf("failed to get current working directory (%w)", err)
} else {
env = append(env, fmt.Sprintf("PATH=%s/bin/:%s", cwd, os.Getenv("PATH")))
}
env := os.Environ()
env = append(env, fmt.Sprintf("NAMESPACE=%s", o.namespace))
env = append(env, fmt.Sprintf("PATH=%s/bin/:%s", cwd, os.Getenv("PATH")))
// TODO
// env = append(env, fmt.Sprintf("KUBECONFIG=%s/bin/:%s", cwd, os.Getenv("PATH")))
cmd.Env = env
cmd.Dir = o.basePath
logger.Log(logging.Script, logging.RunStatus, color.BoldFgCyan, logging.Section("COMMAND", cmd.String()))
cmd.Stdout = &output.Stdout
cmd.Stderr = &output.Stderr
cmdErr := cmd.Run()
if o.script.Check == nil || o.script.Check.Value == nil {
return cmdErr
if err := cmd.Run(); o.script.Check == nil || o.script.Check.Value == nil {
return err
} else {
bindings := binding.NewBindings()
if err == nil {
Expand All @@ -71,10 +70,10 @@ func (o *operation) Exec(ctx context.Context) (_err error) {
}
bindings = bindings.Register("$stdout", binding.NewBinding(output.Out()))
bindings = bindings.Register("$stderr", binding.NewBinding(output.Err()))
errs, err := assert.Validate(ctx, o.script.Check.Value, nil, bindings)
if err != nil {
if errs, err := assert.Validate(ctx, o.script.Check.Value, nil, bindings); err != nil {
return err
} else {
return errs.ToAggregate()
}
return errs.ToAggregate()
}
}
14 changes: 14 additions & 0 deletions pkg/runner/operations/script/script_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@ func Test_operationScript(t *testing.T) {
basePath: "..",
namespace: "test-namespace",
wantErr: false,
}, {
name: "with check",
script: v1alpha1.Script{
Content: "foo",
SkipLogOutput: true,
Check: &v1alpha1.Check{
Value: map[string]interface{}{
"($error != null)": true,
},
},
},
basePath: "..",
namespace: "test-namespace",
wantErr: false,
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down

0 comments on commit a8e1ab0

Please sign in to comment.