diff --git a/internal/test/controller_runtime_client.go b/internal/test/controller_runtime_client.go new file mode 100644 index 00000000..7f9187a2 --- /dev/null +++ b/internal/test/controller_runtime_client.go @@ -0,0 +1,86 @@ +package test + +import ( + "context" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type SubResourceMock struct { + UpdateErrors []error +} + +func (m SubResourceMock) Create(ctx context.Context, obj client.Object, subResource client.Object, opts ...client.SubResourceCreateOption) error { + return nil +} +func (m SubResourceMock) Update(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error { + var err error + var errs []error + if m.UpdateErrors != nil { + err, errs = m.UpdateErrors[0], m.UpdateErrors[1:] + } + m = SubResourceMock{ + UpdateErrors: errs, + } + return err +} +func (m SubResourceMock) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error { + return nil +} + +type ClientMock struct { + CreateErrors []error + UpdateErrors []error + SubResourceMock +} + +func (m ClientMock) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + return nil +} +func (m ClientMock) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { + return nil +} +func (m ClientMock) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { + var err error + var errs []error + if m.CreateErrors != nil { + err, errs = m.CreateErrors[0], m.CreateErrors[1:] + } + m = ClientMock{ + CreateErrors: errs, + UpdateErrors: m.UpdateErrors, + } + return err +} +func (m ClientMock) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error { + return nil +} +func (m ClientMock) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + var err error + var errs []error + if m.UpdateErrors != nil { + err, errs = m.UpdateErrors[0], m.UpdateErrors[1:] + } + m = ClientMock{ + CreateErrors: m.CreateErrors, + UpdateErrors: errs, + } + return err +} +func (m ClientMock) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { + return nil +} +func (m ClientMock) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error { + return nil +} +func (m ClientMock) Status() client.SubResourceWriter { return m.SubResourceMock } +func (m ClientMock) SubResource(subResource string) client.SubResourceClient { return nil } +func (m ClientMock) Scheme() *runtime.Scheme { return nil } +func (m ClientMock) RESTMapper() meta.RESTMapper { return nil } +func (m ClientMock) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) { + return schema.GroupVersionKind{}, nil +} +func (m ClientMock) IsObjectNamespaced(obj runtime.Object) (bool, error) { return false, nil } diff --git a/pkg/validationresult/validation_result.go b/pkg/validationresult/validation_result.go index a68be127..c4419dfb 100644 --- a/pkg/validationresult/validation_result.go +++ b/pkg/validationresult/validation_result.go @@ -6,7 +6,6 @@ import ( "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ktypes "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -45,21 +44,11 @@ func HandleExistingValidationResult(nn ktypes.NamespacedName, vr *v1alpha1.Valid } // HandleNewValidationResult creates a new validation result for the active validator -func HandleNewValidationResult(c client.Client, plugin string, expectedResults int, nn ktypes.NamespacedName, l logr.Logger) error { +func HandleNewValidationResult(c client.Client, vr *v1alpha1.ValidationResult, l logr.Logger) error { // Create the ValidationResult - vr := &v1alpha1.ValidationResult{ - ObjectMeta: metav1.ObjectMeta{ - Name: nn.Name, - Namespace: nn.Namespace, - }, - Spec: v1alpha1.ValidationResultSpec{ - Plugin: plugin, - ExpectedResults: expectedResults, - }, - } if err := c.Create(context.Background(), vr, &client.CreateOptions{}); err != nil { - l.V(0).Error(err, "failed to create ValidationResult", "name", nn.Name, "namespace", nn.Namespace) + l.V(0).Error(err, "failed to create ValidationResult", "name", vr.Name, "namespace", vr.Namespace) return err } @@ -68,7 +57,7 @@ func HandleNewValidationResult(c client.Client, plugin string, expectedResults i State: v1alpha1.ValidationInProgress, } if err := c.Status().Update(context.Background(), vr); err != nil { - l.V(0).Error(err, "failed to update ValidationResult status", "name", nn.Name, "namespace", nn.Namespace) + l.V(0).Error(err, "failed to update ValidationResult status", "name", vr.Name, "namespace", vr.Namespace) return err } diff --git a/pkg/validationresult/validation_result_test.go b/pkg/validationresult/validation_result_test.go index 94899eed..cc4e3fb2 100644 --- a/pkg/validationresult/validation_result_test.go +++ b/pkg/validationresult/validation_result_test.go @@ -5,9 +5,13 @@ import ( "reflect" "testing" + "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" + ktypes "k8s.io/apimachinery/pkg/types" "github.com/spectrocloud-labs/validator/api/v1alpha1" + "github.com/spectrocloud-labs/validator/internal/test" + "github.com/spectrocloud-labs/validator/pkg/constants" "github.com/spectrocloud-labs/validator/pkg/types" "github.com/spectrocloud-labs/validator/pkg/util/ptr" ) @@ -17,7 +21,8 @@ var err = errors.New("error") func res(s corev1.ConditionStatus, state v1alpha1.ValidationState) *types.ValidationResult { return &types.ValidationResult{ Condition: &v1alpha1.ValidationCondition{ - Status: s, + Status: s, + ValidationRule: constants.ValidationRulePrefix, }, State: ptr.Ptr(state), } @@ -32,7 +37,8 @@ func vr(cs []corev1.ConditionStatus, state v1alpha1.ValidationState, err error) } for _, c := range cs { condition := v1alpha1.ValidationCondition{ - Status: c, + Status: c, + ValidationRule: constants.ValidationRulePrefix, } if err != nil { condition.Message = validationErrorMsg @@ -43,6 +49,78 @@ func vr(cs []corev1.ConditionStatus, state v1alpha1.ValidationState, err error) return vr } +func TestHandleExistingValidationResult(t *testing.T) { + cs := []struct { + name string + nn ktypes.NamespacedName + res *v1alpha1.ValidationResult + }{ + { + name: "ValidationInProgress", + nn: ktypes.NamespacedName{}, + res: vr(nil, v1alpha1.ValidationInProgress, nil), + }, + { + name: "ValidationFailed", + nn: ktypes.NamespacedName{}, + res: vr([]corev1.ConditionStatus{corev1.ConditionFalse}, v1alpha1.ValidationFailed, nil), + }, + { + name: "ValidationSucceeded", + nn: ktypes.NamespacedName{}, + res: vr(nil, v1alpha1.ValidationSucceeded, nil), + }, + } + for _, c := range cs { + t.Log(c.name) + HandleExistingValidationResult(c.nn, c.res, logr.Logger{}) + } +} + +func TestHandleNewValidationResult(t *testing.T) { + cs := []struct { + name string + client test.ClientMock + res *v1alpha1.ValidationResult + expected error + }{ + { + name: "Pass", + client: test.ClientMock{ + SubResourceMock: test.SubResourceMock{}, + }, + res: vr(nil, v1alpha1.ValidationInProgress, nil), + expected: nil, + }, + { + name: "Fail (create)", + client: test.ClientMock{ + CreateErrors: []error{errors.New("creation failed")}, + SubResourceMock: test.SubResourceMock{}, + }, + res: vr([]corev1.ConditionStatus{corev1.ConditionFalse}, v1alpha1.ValidationFailed, nil), + expected: errors.New("creation failed"), + }, + { + name: "Fail (status update)", + client: test.ClientMock{ + SubResourceMock: test.SubResourceMock{ + UpdateErrors: []error{errors.New("update failed")}, + }, + }, + res: vr(nil, v1alpha1.ValidationSucceeded, nil), + expected: errors.New("update failed"), + }, + } + for _, c := range cs { + t.Log(c.name) + err := HandleNewValidationResult(c.client, c.res, logr.Logger{}) + if err != nil && !reflect.DeepEqual(c.expected.Error(), err.Error()) { + t.Errorf("expected (%v), got (%v)", c.expected, err) + } + } +} + func TestUpdateValidationResult(t *testing.T) { cs := []struct { name string