Skip to content

Commit

Permalink
add unit tests
Browse files Browse the repository at this point in the history
Signed-off-by: odubajDT <ondrej.dubaj@dynatrace.com>
  • Loading branch information
odubajDT committed Sep 19, 2023
1 parent 349ee9f commit 9d19013
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 52 deletions.
8 changes: 8 additions & 0 deletions metrics-operator/api/v1alpha3/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,11 @@ func TestObjectReference_GetNamespace(t *testing.T) {

require.Equal(t, "ns", o.GetNamespace("default"))
}

func TestAnalysisState_IsPending(t *testing.T) {
a := StatePending
require.True(t, a.IsPending())

a = StateCompleted
require.False(t, a.IsPending())
}
21 changes: 7 additions & 14 deletions metrics-operator/controllers/analysis/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,6 @@ func (a *AnalysisReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c

if analysis.Status.State.IsPending() {
analysis.Status.State = v1alpha3.StateProgressing
if err := a.updateStatus(ctx, analysis); err != nil {
a.Log.Error(err, "Failed to update Analysis Status")
return ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second}, err
}
}

var done map[string]metricsapi.ProviderResult
Expand All @@ -105,19 +101,15 @@ func (a *AnalysisReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
}

maps.Copy(res, done)

err = a.evaluateObjectives(ctx, res, analysisDef, analysis)

// if evaluation was successful remove the stored values
if err == nil {
analysis.Status.StoredValues = nil
err = a.updateStatus(ctx, analysis)
a.evaluateObjectives(ctx, res, analysisDef, analysis)
if err := a.updateStatus(ctx, analysis); err != nil {
return ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second}, err
}

return ctrl.Result{}, err
return ctrl.Result{}, nil
}

func (a *AnalysisReconciler) evaluateObjectives(ctx context.Context, res map[string]metricsapi.ProviderResult, analysisDef *metricsapi.AnalysisDefinition, analysis *metricsapi.Analysis) error {
func (a *AnalysisReconciler) evaluateObjectives(ctx context.Context, res map[string]metricsapi.ProviderResult, analysisDef *metricsapi.AnalysisDefinition, analysis *metricsapi.Analysis) {
eval := a.Evaluate(res, analysisDef)
analysisResultJSON, err := json.Marshal(eval)
if err != nil {
Expand All @@ -128,7 +120,8 @@ func (a *AnalysisReconciler) evaluateObjectives(ctx context.Context, res map[str
analysis.Status.Warning = eval.Warning
analysis.Status.Pass = eval.Pass
analysis.Status.State = metricsapi.StateCompleted
return a.updateStatus(ctx, analysis)
// if evaluation was successful remove the stored values
analysis.Status.StoredValues = nil
}

func (a *AnalysisReconciler) updateStatus(ctx context.Context, analysis *metricsapi.Analysis) error {
Expand Down
104 changes: 66 additions & 38 deletions metrics-operator/controllers/analysis/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package analysis

import (
"context"
"fmt"
"reflect"
"testing"
"time"
Expand Down Expand Up @@ -73,66 +74,90 @@ func TestAnalysisReconciler_Reconcile_BasicControlLoop(t *testing.T) {
},
}

req := controllerruntime.Request{
NamespacedName: types.NamespacedName{Namespace: "default", Name: "my-analysis"},
}
mockFactory := func(ctx context.Context, analysisMoqParam *metricsapi.Analysis, obj []metricsapi.Objective, numWorkers int, c client.Client, log logr.Logger, namespace string) (context.Context, IAnalysisPool) {
mymock := fake.IAnalysisPoolMock{
DispatchAndCollectFunc: func(ctx context.Context) (map[string]metricsapi.ProviderResult, error) {
return map[string]metricsapi.ProviderResult{}, nil
},
}
return ctx, &mymock
}

tests := []struct {
name string
client client.Client
req controllerruntime.Request
want controllerruntime.Result
wantErr bool
status *metricsapi.AnalysisStatus
res metricstypes.AnalysisResult
name string
client client.Client
req controllerruntime.Request
want controllerruntime.Result
wantErr bool
status *metricsapi.AnalysisStatus
res metricstypes.AnalysisResult
mockFactory NewWorkersPoolFactory
}{
{
name: "analysis does not exist, reconcile no status update",
client: fake2.NewClient(),
want: controllerruntime.Result{},
wantErr: false,
status: nil,
res: metricstypes.AnalysisResult{},
name: "analysis does not exist, reconcile no status update",
client: fake2.NewClient(),
want: controllerruntime.Result{},
wantErr: false,
status: nil,
res: metricstypes.AnalysisResult{},
mockFactory: mockFactory,
}, {
name: "analysisDefinition does not exist, requeue no status update",
client: fake2.NewClient(&analysis),
want: controllerruntime.Result{Requeue: true, RequeueAfter: 10 * time.Second},
wantErr: false,
status: &metricsapi.AnalysisStatus{},
res: metricstypes.AnalysisResult{Pass: false},
status: &metricsapi.AnalysisStatus{
State: metricsapi.StatePending,
},
res: metricstypes.AnalysisResult{Pass: false},
mockFactory: mockFactory,
}, {
name: "succeeded, status updated",
name: "mockfactory failed",
client: fake2.NewClient(&analysis, &analysisDef, &template),
want: controllerruntime.Result{},
want: controllerruntime.Result{Requeue: true, RequeueAfter: 10 * time.Second},
wantErr: false,
status: &metricsapi.AnalysisStatus{Raw: "{\"objectiveResults\":null,\"totalScore\":0,\"maximumScore\":0,\"pass\":true,\"warning\":false}", Pass: true, State: metricsapi.StateCompleted},
res: metricstypes.AnalysisResult{Pass: true},
status: &metricsapi.AnalysisStatus{
State: metricsapi.StateProgressing,
},
res: metricstypes.AnalysisResult{Pass: false},
mockFactory: func(ctx context.Context, analysisMoqParam *metricsapi.Analysis, obj []metricsapi.Objective, numWorkers int, c client.Client, log logr.Logger, namespace string) (context.Context, IAnalysisPool) {
mymock := fake.IAnalysisPoolMock{
DispatchAndCollectFunc: func(ctx context.Context) (map[string]metricsapi.ProviderResult, error) {
return map[string]metricsapi.ProviderResult{}, fmt.Errorf("error")
},
}
return ctx, &mymock
},
}, {
name: "succeeded - analysis in different namespace, status updated",
client: fake2.NewClient(&analysis2, &analysisDef2, &template),
want: controllerruntime.Result{},
wantErr: false,
status: &metricsapi.AnalysisStatus{Raw: "{\"objectiveResults\":null,\"totalScore\":0,\"maximumScore\":0,\"pass\":true,\"warning\":false}", Pass: true, State: metricsapi.StateCompleted},
res: metricstypes.AnalysisResult{Pass: true},
name: "succeeded, status updated",
client: fake2.NewClient(&analysis, &analysisDef, &template),
want: controllerruntime.Result{},
wantErr: false,
status: &metricsapi.AnalysisStatus{Raw: "{\"objectiveResults\":null,\"totalScore\":0,\"maximumScore\":0,\"pass\":true,\"warning\":false}", Pass: true, State: metricsapi.StateCompleted},
res: metricstypes.AnalysisResult{Pass: true},
mockFactory: mockFactory,
}, {
name: "succeeded - analysis in different namespace, status updated",
client: fake2.NewClient(&analysis2, &analysisDef2, &template),
want: controllerruntime.Result{},
wantErr: false,
status: &metricsapi.AnalysisStatus{Raw: "{\"objectiveResults\":null,\"totalScore\":0,\"maximumScore\":0,\"pass\":true,\"warning\":false}", Pass: true, State: metricsapi.StateCompleted},
res: metricstypes.AnalysisResult{Pass: true},
mockFactory: mockFactory,
},
}

req := controllerruntime.Request{
NamespacedName: types.NamespacedName{Namespace: "default", Name: "my-analysis"},
}
mockFactory := func(ctx context.Context, analysisMoqParam *metricsapi.Analysis, obj []metricsapi.Objective, numWorkers int, c client.Client, log logr.Logger, namespace string) (context.Context, IAnalysisPool) {
mymock := fake.IAnalysisPoolMock{
DispatchAndCollectFunc: func(ctx context.Context) (map[string]metricsapi.ProviderResult, error) {
return map[string]metricsapi.ProviderResult{}, nil
},
}
return ctx, &mymock
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := &AnalysisReconciler{
Client: tt.client,
Scheme: tt.client.Scheme(),
Log: testr.New(t),
MaxWorkers: 2,
NewWorkersPoolFactory: mockFactory,
NewWorkersPoolFactory: tt.mockFactory,
IAnalysisEvaluator: &fakeEvaluator.IAnalysisEvaluatorMock{
EvaluateFunc: func(values map[string]metricsapi.ProviderResult, ad *metricsapi.AnalysisDefinition) metricstypes.AnalysisResult {
return tt.res
Expand Down Expand Up @@ -235,6 +260,9 @@ func getTestCRDs() (metricsapi.Analysis, metricsapi.AnalysisDefinition, metricsa
Namespace: "default",
},
},
Status: metricsapi.AnalysisStatus{
State: metricsapi.StatePending,
},
}

analysisDef := metricsapi.AnalysisDefinition{
Expand Down

0 comments on commit 9d19013

Please sign in to comment.