diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment_run/fuzz_tests/service_fuzz_test.go b/chaoscenter/graphql/server/pkg/chaos_experiment_run/fuzz_tests/service_fuzz_test.go new file mode 100644 index 00000000000..5ae50c6ef7b --- /dev/null +++ b/chaoscenter/graphql/server/pkg/chaos_experiment_run/fuzz_tests/service_fuzz_test.go @@ -0,0 +1,145 @@ +package fuzz_tests + +import ( + "context" + "testing" + + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment_run" + dbChaosExperiment "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment" + dbChaosExperimentRun "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment_run" + dbChaosInfra "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_infrastructure" + dbMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/mocks" + + fuzz "github.com/AdaLogics/go-fuzz-headers" + store "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/data-store" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" + "github.com/stretchr/testify/mock" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +type MockServices struct { + ChaosExperimentOperator *dbChaosExperiment.Operator + ChaosExperimentRunOperator *dbChaosExperimentRun.Operator + ChaosInfrastructureOperator *dbChaosInfra.Operator + MongodbOperator *dbMocks.MongoOperator + ChaosExperimentRunService chaos_experiment_run.Service +} + +func NewMockServices() *MockServices { + var ( + mongodbMockOperator = new(dbMocks.MongoOperator) + chaosExperimentOperator = dbChaosExperiment.NewChaosExperimentOperator(mongodbMockOperator) + chaosExperimentRunOperator = dbChaosExperimentRun.NewChaosExperimentRunOperator(mongodbMockOperator) + chaosInfrastructureOperator = dbChaosInfra.NewInfrastructureOperator(mongodbMockOperator) + chaosExperimentRunService chaos_experiment_run.Service = chaos_experiment_run.NewChaosExperimentRunService( + chaosExperimentOperator, + chaosInfrastructureOperator, + chaosExperimentRunOperator, + ) + ) + return &MockServices{ + ChaosExperimentOperator: chaosExperimentOperator, + ChaosExperimentRunOperator: chaosExperimentRunOperator, + ChaosInfrastructureOperator: chaosInfrastructureOperator, + MongodbOperator: mongodbMockOperator, + ChaosExperimentRunService: chaosExperimentRunService, + } +} + +func FuzzProcessExperimentRunDelete(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + Query bson.D + WorkflowRunID *string + ExperimentRun dbChaosExperimentRun.ChaosExperimentRun + Workflow dbChaosExperiment.ChaosExperimentRequest + Username string + StoreStateData *store.StateData + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + mockServices := NewMockServices() + mockServices.MongodbOperator.On("Update", mock.Anything, mongodb.ChaosExperimentRunsCollection, mock.Anything, mock.Anything, mock.Anything).Return(&mongo.UpdateResult{}, nil).Once() + + err = mockServices.ChaosExperimentRunService.ProcessExperimentRunDelete( + context.Background(), + targetStruct.Query, + targetStruct.WorkflowRunID, + targetStruct.ExperimentRun, + targetStruct.Workflow, + targetStruct.Username, + targetStruct.StoreStateData, + ) + if err != nil { + t.Errorf("ProcessExperimentRunDelete() error = %v", err) + } + }) +} + +func FuzzProcessExperimentRunStop(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + Query bson.D + ExperimentRunID *string + Experiment dbChaosExperiment.ChaosExperimentRequest + Username string + ProjectID string + StoreStateData *store.StateData + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockServices.MongodbOperator.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&mongo.UpdateResult{}, nil).Once() + err = mockServices.ChaosExperimentRunService.ProcessExperimentRunStop( + context.Background(), + targetStruct.Query, + targetStruct.ExperimentRunID, + targetStruct.Experiment, + targetStruct.Username, + targetStruct.ProjectID, + targetStruct.StoreStateData, + ) + if err != nil { + t.Errorf("ProcessExperimentRunStop() error = %v", err) + } + }) +} + +func FuzzProcessCompletedExperimentRun(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ExecData chaos_experiment_run.ExecutionData + WfID string + RunID string + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + findResult := []interface{}{bson.D{ + {Key: "experiment_id", Value: targetStruct.WfID}, + }} + mockServices := NewMockServices() + singleResult := mongo.NewSingleResultFromDocument(findResult[0], nil, nil) + mockServices.MongodbOperator.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(singleResult, nil).Once() + + _, err = mockServices.ChaosExperimentRunService.ProcessCompletedExperimentRun( + targetStruct.ExecData, + targetStruct.WfID, + targetStruct.RunID, + ) + if err != nil { + t.Errorf("ProcessCompletedExperimentRun() error = %v", err) + } + }) +} diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler/fuzz_tests/handler_fuzz_test.go b/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler/fuzz_tests/handler_fuzz_test.go new file mode 100644 index 00000000000..56af374f378 --- /dev/null +++ b/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler/fuzz_tests/handler_fuzz_test.go @@ -0,0 +1,242 @@ +package fuzz_tests + +import ( + "context" + "strings" + "testing" + "time" + + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler" + chaosInfraMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_infrastructure/model/mocks" + dbChaosExperiment "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment" + dbChaosExperimentRun "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment_run" + dbMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/mocks" + dbGitOpsMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/gitops/model/mocks" + + fuzz "github.com/AdaLogics/go-fuzz-headers" + + "github.com/google/uuid" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" + typesMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment_run/model/mocks" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" + "github.com/stretchr/testify/mock" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +type MockServices struct { + ChaosExperimentRunService *typesMocks.ChaosExperimentRunService + InfrastructureService *chaosInfraMocks.InfraService + GitOpsService *dbGitOpsMocks.GitOpsService + ChaosExperimentOperator *dbChaosExperiment.Operator + ChaosExperimentRunOperator *dbChaosExperimentRun.Operator + MongodbOperator *dbMocks.MongoOperator + ChaosExperimentRunHandler *handler.ChaosExperimentRunHandler +} + +func NewMockServices() *MockServices { + var ( + mongodbMockOperator = new(dbMocks.MongoOperator) + infrastructureService = new(chaosInfraMocks.InfraService) + gitOpsService = new(dbGitOpsMocks.GitOpsService) + chaosExperimentRunService = new(typesMocks.ChaosExperimentRunService) + chaosExperimentOperator = dbChaosExperiment.NewChaosExperimentOperator(mongodbMockOperator) + chaosExperimentRunOperator = dbChaosExperimentRun.NewChaosExperimentRunOperator(mongodbMockOperator) + ) + var chaosExperimentRunHandler = handler.NewChaosExperimentRunHandler( + chaosExperimentRunService, + infrastructureService, + gitOpsService, + chaosExperimentOperator, + chaosExperimentRunOperator, + mongodbMockOperator, + ) + return &MockServices{ + ChaosExperimentRunService: chaosExperimentRunService, + InfrastructureService: infrastructureService, + GitOpsService: gitOpsService, + ChaosExperimentOperator: chaosExperimentOperator, + ChaosExperimentRunOperator: chaosExperimentRunOperator, + MongodbOperator: mongodbMockOperator, + ChaosExperimentRunHandler: chaosExperimentRunHandler, + } +} + +func FuzzGetExperimentRun(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ProjectID string + ExperimentRunID string + NotifyID string + }{} + + targetStruct.ProjectID = uuid.New().String() + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + ctx := context.Background() + mockServices := NewMockServices() + findResult := []interface{}{bson.D{ + {Key: "experiment_run_id", Value: targetStruct.ExperimentRunID}, + {Key: "project_id", Value: targetStruct.ProjectID}, + {Key: "infra_id", Value: "mockInfraID"}, + {Key: "kubernetesInfraDetails", Value: bson.A{ + bson.D{ + {Key: "InfraID", Value: "mockInfraID"}, + {Key: "Name", Value: "MockInfra"}, + {Key: "EnvironmentID", Value: "mockEnvID"}, + {Key: "Description", Value: "Mock Infrastructure"}, + {Key: "PlatformName", Value: "Kubernetes"}, + {Key: "IsActive", Value: true}, + {Key: "UpdatedAt", Value: time.Now().Unix()}, + {Key: "CreatedAt", Value: time.Now().Unix()}, + }, + }}, + {Key: "experiment", Value: bson.A{ + bson.D{ + {Key: "ExperimentName", Value: "MockExperiment"}, + {Key: "ExperimentType", Value: "MockType"}, + {Key: "Revision", Value: bson.A{ + bson.D{ + {Key: "RevisionID", Value: uuid.NewString()}, + {Key: "ExperimentManifest", Value: "mockManifest"}, + {Key: "Weightages", Value: bson.A{ + bson.D{{Key: "FaultName", Value: "fault1"}, {Key: "Weightage", Value: 10}}, + bson.D{{Key: "FaultName", Value: "fault2"}, {Key: "Weightage", Value: 20}}, + }}, + }, + }}, + }, + }}, + }} + + cursor, _ := mongo.NewCursorFromDocuments(findResult, nil, nil) + mockServices.MongodbOperator.On("Aggregate", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(cursor, nil).Once() + + res, err := mockServices.ChaosExperimentRunHandler.GetExperimentRun(ctx, targetStruct.ProjectID, &targetStruct.ExperimentRunID, &targetStruct.NotifyID) + if err != nil { + t.Errorf("ChaosExperimentRunHandler.GetExperimentRun() error = %v", err) + return + } + if res == nil { + t.Errorf("Returned response is nil") + } + }) +} + +func FuzzListExperimentRun(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ProjectID string + Request model.ListExperimentRunRequest + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + findResult := []interface{}{bson.D{ + {Key: "project_id", Value: targetStruct.ProjectID}, + {Key: "infra_id", Value: "abc"}, + { + Key: "revision", Value: []dbChaosExperiment.ExperimentRevision{ + { + RevisionID: uuid.NewString(), + }, + }, + }, + }} + cursor, _ := mongo.NewCursorFromDocuments(findResult, nil, nil) + mockServices.MongodbOperator.On("Aggregate", mock.Anything, mongodb.ChaosExperimentRunsCollection, mock.Anything, mock.Anything).Return(cursor, nil).Once() + + res, err := mockServices.ChaosExperimentRunHandler.ListExperimentRun(targetStruct.ProjectID, targetStruct.Request) + if err != nil { + t.Errorf("ListExperimentRun() error = %v", err) + return + } + if res == nil { + t.Errorf("Returned response is nil") + } + + }) +} + +func FuzzRunChaosWorkFlow(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ProjectID string + Workflow dbChaosExperiment.ChaosExperimentRequest + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockServices.MongodbOperator.On("StartSession").Return(mock.Anything, nil).Once() + mockServices.MongodbOperator.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&mongo.UpdateResult{}, nil).Once() + mockServices.MongodbOperator.On("CommitTransaction", mock.Anything).Return(nil).Once() + mockServices.MongodbOperator.On("AbortTransaction", mock.Anything).Return(nil).Once() + + findResult := []interface{}{bson.D{ + {Key: "infra_id", Value: targetStruct.ProjectID}, + }} + singleResult := mongo.NewSingleResultFromDocument(findResult[0], nil, nil) + mockServices.MongodbOperator.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(singleResult, nil).Once() + + res, err := mockServices.ChaosExperimentRunHandler.RunChaosWorkFlow(context.Background(), targetStruct.ProjectID, targetStruct.Workflow, nil) + if strings.Contains(err.Error(), "inactive infra") { + t.Log("Handled expected error due to inactive infrastructure: ", err) + return + } + if res == nil { + t.Errorf("Returned response is nil") + } + }) +} + +func FuzzGetExperimentRunStats(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ProjectID string + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + targetStruct.ProjectID = uuid.New().String() + + mockServices := NewMockServices() + + findResult := []interface{}{bson.D{ + {Key: "project_id", Value: targetStruct.ProjectID}, + {Key: "infra_id", Value: "abc"}, + { + Key: "revision", Value: []dbChaosExperiment.ExperimentRevision{ + { + RevisionID: uuid.NewString(), + }, + }, + }, + }} + cursor, _ := mongo.NewCursorFromDocuments(findResult, nil, nil) + mockServices.MongodbOperator.On("Aggregate", mock.Anything, mongodb.ChaosExperimentRunsCollection, mock.Anything, mock.Anything).Return(cursor, nil).Once() + + res, err := mockServices.ChaosExperimentRunHandler.GetExperimentRunStats(context.Background(), targetStruct.ProjectID) + if err != nil { + t.Errorf("GetExperimentRunStats() error = %v", err) + return + } + if res == nil { + t.Errorf("Returned response is nil") + } + }) +}