From e53a18c3a43e949c9420550613cb04060d3cc89e Mon Sep 17 00:00:00 2001 From: Jake Klein Date: Wed, 22 May 2024 12:23:43 +0100 Subject: [PATCH] feat: Add support for writing to top-level dir of statestore (#130) Introduces `.spec.filepath.mode` to the destination spec Co-authored-by: Abby Bangser Co-authored-by: Chunyi Lyu --- api/v1alpha1/destination_types.go | 28 ++ api/v1alpha1/zz_generated.deepcopy.go | 16 + .../platform.kratix.io_destinations.yaml | 16 + controllers/export_test.go | 17 +- controllers/shared.go | 13 +- controllers/workplacement_controller.go | 11 +- controllers/workplacement_controller_test.go | 294 ++++++++++++++++++ go.mod | 1 + go.sum | 2 + lib/writers/statestore_writer.go | 1 + .../writersfakes/fake_state_store_writer.go | 190 +++++++++++ 11 files changed, 582 insertions(+), 7 deletions(-) create mode 100644 controllers/workplacement_controller_test.go create mode 100644 lib/writers/writersfakes/fake_state_store_writer.go diff --git a/api/v1alpha1/destination_types.go b/api/v1alpha1/destination_types.go index 6df1b8b7..3f44bc38 100644 --- a/api/v1alpha1/destination_types.go +++ b/api/v1alpha1/destination_types.go @@ -58,6 +58,34 @@ type DestinationSpec struct { // to this destination, unless the destination label set is also empty // +kubebuilder:validation:Optional StrictMatchLabels bool `json:"strictMatchLabels,omitempty"` + + //The filepath mode to use when writing files to the destination. + Filepath Filepath `json:"filepath,omitempty"` +} + +const ( + //if modifying these dont forget to edit below where they are written as a + //kubebuilder comment for setting the default and Enum values. + FilepathExpressionTypeNone = "none" + FilepathExpressionTypeNestedByMetadata = "nestedByMetadata" +) + +type Filepath struct { + //+kubebuilder:default:=nestedByMetadata + //+kubebuilder:validation:Enum:={nestedByMetadata,none} + //The type of filepathExpression, either: + // - nestedByMetadata (default): files from the pipeline will be placed in a nested directory structure + // - none: file from the pipeline will be placed in a flat directory structure + Mode string `json:"type"` +} + +// it gets defaulted by the K8s API, but for unit testing it wont be defaulted +// since its not a real k8s api, so it may be empty when running unit tests. +func (d *Destination) GetFilepathExpressionType() string { + if d.Spec.Filepath.Mode == "" { + return FilepathExpressionTypeNestedByMetadata + } + return d.Spec.Filepath.Mode } // DestinationStatus defines the observed state of Destination diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ff6f5210..0629e913 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -268,6 +268,7 @@ func (in *DestinationSpec) DeepCopyInto(out *DestinationSpec) { *out = new(StateStoreReference) **out = **in } + out.Filepath = in.Filepath } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DestinationSpec. @@ -295,6 +296,21 @@ func (in *DestinationStatus) DeepCopy() *DestinationStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Filepath) DeepCopyInto(out *Filepath) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Filepath. +func (in *Filepath) DeepCopy() *Filepath { + if in == nil { + return nil + } + out := new(Filepath) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GitStateStore) DeepCopyInto(out *GitStateStore) { *out = *in diff --git a/config/crd/bases/platform.kratix.io_destinations.yaml b/config/crd/bases/platform.kratix.io_destinations.yaml index 9d7c73f0..173cf3b9 100644 --- a/config/crd/bases/platform.kratix.io_destinations.yaml +++ b/config/crd/bases/platform.kratix.io_destinations.yaml @@ -41,6 +41,22 @@ spec: spec: description: DestinationSpec defines the desired state of Destination properties: + filepath: + description: The filepath mode to use when writing files to the destination. + properties: + type: + default: nestedByMetadata + description: |- + The type of filepathExpression, either: + - nestedByMetadata (default): files from the pipeline will be placed in a nested directory structure + - none: file from the pipeline will be placed in a flat directory structure + enum: + - nestedByMetadata + - none + type: string + required: + - type + type: object path: description: |- Path within the StateStore to write documents. This path should be allocated diff --git a/controllers/export_test.go b/controllers/export_test.go index 74930ed0..70582a65 100644 --- a/controllers/export_test.go +++ b/controllers/export_test.go @@ -1,6 +1,11 @@ package controllers -import "github.com/syntasso/kratix/lib/workflow" +import ( + "github.com/go-logr/logr" + "github.com/syntasso/kratix/api/v1alpha1" + "github.com/syntasso/kratix/lib/workflow" + "github.com/syntasso/kratix/lib/writers" +) func SetReconcileConfigureWorkflow(f func(workflow.Opts) (bool, error)) { reconcileConfigure = f @@ -9,3 +14,13 @@ func SetReconcileConfigureWorkflow(f func(workflow.Opts) (bool, error)) { func SetReconcileDeleteWorkflow(f func(workflow.Opts) (bool, error)) { reconcileDelete = f } + +func SetNewS3Writer(f func(logger logr.Logger, stateStoreSpec v1alpha1.BucketStateStoreSpec, destination v1alpha1.Destination, + creds map[string][]byte) (writers.StateStoreWriter, error)) { + newS3Writer = f +} + +func SetNewGitWriter(f func(logger logr.Logger, stateStoreSpec v1alpha1.GitStateStoreSpec, destination v1alpha1.Destination, + creds map[string][]byte) (writers.StateStoreWriter, error)) { + newGitWriter = f +} diff --git a/controllers/shared.go b/controllers/shared.go index cb7881f4..86ca557a 100644 --- a/controllers/shared.go +++ b/controllers/shared.go @@ -28,6 +28,14 @@ const ( runDeleteWorkflowsFinalizer = v1alpha1.KratixPrefix + "delete-workflows" ) +var ( + newS3Writer func(logger logr.Logger, stateStoreSpec v1alpha1.BucketStateStoreSpec, destination v1alpha1.Destination, + creds map[string][]byte) (writers.StateStoreWriter, error) = writers.NewS3Writer + + newGitWriter func(logger logr.Logger, stateStoreSpec v1alpha1.GitStateStoreSpec, destination v1alpha1.Destination, + creds map[string][]byte) (writers.StateStoreWriter, error) = writers.NewGitWriter +) + type StateStore interface { client.Object GetSecretRef() *v1.SecretReference @@ -128,7 +136,7 @@ func newWriter(o opts, destination v1alpha1.Destination) (writers.StateStoreWrit data = secret.Data } - writer, err = writers.NewS3Writer(o.logger.WithName("writers").WithName("BucketStateStoreWriter"), stateStore.Spec, destination, data) + writer, err = newS3Writer(o.logger.WithName("writers").WithName("BucketStateStoreWriter"), stateStore.Spec, destination, data) case "GitStateStore": stateStore := &v1alpha1.GitStateStore{} secret, fetchErr := fetchObjectAndSecret(o, stateStoreRef, stateStore) @@ -136,13 +144,12 @@ func newWriter(o opts, destination v1alpha1.Destination) (writers.StateStoreWrit return nil, fetchErr } - writer, err = writers.NewGitWriter(o.logger.WithName("writers").WithName("GitStateStoreWriter"), stateStore.Spec, destination, secret.Data) + writer, err = newGitWriter(o.logger.WithName("writers").WithName("GitStateStoreWriter"), stateStore.Spec, destination, secret.Data) default: return nil, fmt.Errorf("unsupported kind %s", destination.Spec.StateStoreRef.Kind) } if err != nil { - //TODO: should this be a retryable error? o.logger.Error(err, "unable to create StateStoreWriter") return nil, err } diff --git a/controllers/workplacement_controller.go b/controllers/workplacement_controller.go index a74ac8bb..70049981 100644 --- a/controllers/workplacement_controller.go +++ b/controllers/workplacement_controller.go @@ -84,6 +84,7 @@ func (r *WorkPlacementReconciler) Reconcile(ctx context.Context, req ctrl.Reques logger: logger, } + //Mock this out writer, err := newWriter(opts, *destination) if err != nil { if errors.IsNotFound(err) { @@ -100,7 +101,7 @@ func (r *WorkPlacementReconciler) Reconcile(ctx context.Context, req ctrl.Reques return addFinalizers(opts, workPlacement, workPlacementFinalizers) } - err = r.writeWorkloadsToStateStore(writer, *workPlacement, logger) + err = r.writeWorkloadsToStateStore(writer, *workPlacement, *destination, logger) if err != nil { logger.Error(err, "Error writing to repository, will try again in 5 seconds") return defaultRequeue, err @@ -129,8 +130,12 @@ func (r *WorkPlacementReconciler) deleteWorkPlacement(ctx context.Context, write return fastRequeue, nil } -func (r *WorkPlacementReconciler) writeWorkloadsToStateStore(writer writers.StateStoreWriter, workPlacement v1alpha1.WorkPlacement, logger logr.Logger) error { - err := writer.WriteDirWithObjects(writers.DeleteExistingContentsInDir, getDir(workPlacement), workPlacement.Spec.Workloads...) +func (r *WorkPlacementReconciler) writeWorkloadsToStateStore(writer writers.StateStoreWriter, workPlacement v1alpha1.WorkPlacement, destination v1alpha1.Destination, logger logr.Logger) error { + dir := getDir(workPlacement) + if destination.GetFilepathExpressionType() == v1alpha1.FilepathExpressionTypeNone { + dir = "" + } + err := writer.WriteDirWithObjects(writers.DeleteExistingContentsInDir, dir, workPlacement.Spec.Workloads...) if err != nil { logger.Error(err, "Error writing resources to repository") return err diff --git a/controllers/workplacement_controller_test.go b/controllers/workplacement_controller_test.go new file mode 100644 index 00000000..8b753f6f --- /dev/null +++ b/controllers/workplacement_controller_test.go @@ -0,0 +1,294 @@ +/* +Copyright 2021 Syntasso. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllers_test + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + "github.com/go-logr/logr" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/syntasso/kratix/controllers" + "github.com/syntasso/kratix/lib/hash" + "github.com/syntasso/kratix/lib/writers" + "github.com/syntasso/kratix/lib/writers/writersfakes" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/syntasso/kratix/api/v1alpha1" + //+kubebuilder:scaffold:imports +) + +var workplacement *v1alpha1.Work + +var _ = Describe("WorkplacementReconciler", func() { + var ( + ctx context.Context + workloads []v1alpha1.Workload + destination v1alpha1.Destination + gitStateStore v1alpha1.GitStateStore + bucketStateStore v1alpha1.BucketStateStore + + workplacementName = "test-workplacement" + workPlacement v1alpha1.WorkPlacement + reconciler *controllers.WorkPlacementReconciler + fakeWriter *writersfakes.FakeStateStoreWriter + + argBucketStateStoreSpec v1alpha1.BucketStateStoreSpec + argGitStateStoreSpec v1alpha1.GitStateStoreSpec + argDestination v1alpha1.Destination + argCreds map[string][]byte + ) + + BeforeEach(func() { + ctx = context.Background() + reconciler = &controllers.WorkPlacementReconciler{ + Client: fakeK8sClient, + Log: ctrl.Log.WithName("controllers").WithName("Work"), + } + + workloads = []v1alpha1.Workload{ + { + Content: "{someApi: foo, someValue: bar}", + }, + } + workPlacement = v1alpha1.WorkPlacement{ + TypeMeta: v1.TypeMeta{ + Kind: "WorkPlacement", + APIVersion: "platform.kratix.io/v1alpha1", + }, + ObjectMeta: v1.ObjectMeta{ + Name: workplacementName, + Namespace: "default", + }, + Spec: v1alpha1.WorkPlacementSpec{ + TargetDestinationName: "test-destination", + ID: hash.ComputeHash("."), + Workloads: workloads, + PromiseName: "test-promise", + ResourceName: "test-resource", + }, + } + Expect(fakeK8sClient.Create(ctx, &workPlacement)).To(Succeed()) + fakeWriter = &writersfakes.FakeStateStoreWriter{} + + destination = v1alpha1.Destination{ + TypeMeta: v1.TypeMeta{ + Kind: "Destination", + APIVersion: "platform.kratix.io/v1alpha1", + }, + ObjectMeta: v1.ObjectMeta{ + Name: "test-destination", + }, + Spec: v1alpha1.DestinationSpec{ + Filepath: v1alpha1.Filepath{ + Mode: v1alpha1.FilepathExpressionTypeNone, + }, + StateStoreRef: &v1alpha1.StateStoreReference{ + //Set in the tests beforeach + // Kind: "Git/BucketStateStore", + // Name: "test-state-store", + }, + }, + } + }) + + When("the destination statestore is s3", func() { + When("the destination has filepathExpression type none", func() { + BeforeEach(func() { + Expect(fakeK8sClient.Create(ctx, &corev1.Secret{ + TypeMeta: v1.TypeMeta{ + Kind: "Secret", + APIVersion: "v1", + }, + ObjectMeta: v1.ObjectMeta{ + Name: "test-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "accessKeyID": []byte("test-access"), + "secretAccessKey": []byte("test-secret"), + }, + })).To(Succeed()) + + bucketStateStore = v1alpha1.BucketStateStore{ + TypeMeta: v1.TypeMeta{ + Kind: "BucketStateStore", + APIVersion: "platform.kratix.io/v1alpha1", + }, + ObjectMeta: v1.ObjectMeta{ + Name: "test-state-store", + }, + Spec: v1alpha1.BucketStateStoreSpec{ + BucketName: "test-bucket", + StateStoreCoreFields: v1alpha1.StateStoreCoreFields{ + SecretRef: &corev1.SecretReference{ + Name: "test-secret", + Namespace: "default", + }, + }, + Endpoint: "localhost:9000", + }, + } + Expect(fakeK8sClient.Create(ctx, &bucketStateStore)).To(Succeed()) + + destination.Spec.StateStoreRef.Kind = "BucketStateStore" + destination.Spec.StateStoreRef.Name = "test-state-store" + Expect(fakeK8sClient.Create(ctx, &destination)).To(Succeed()) + + controllers.SetNewS3Writer(func(logger logr.Logger, stateStoreSpec v1alpha1.BucketStateStoreSpec, destination v1alpha1.Destination, + creds map[string][]byte) (writers.StateStoreWriter, error) { + argBucketStateStoreSpec = stateStoreSpec + argDestination = destination + argCreds = creds + return fakeWriter, nil + }) + }) + It("calls the writer with an empty dir", func() { + result, err := t.reconcileUntilCompletion(reconciler, &workPlacement) + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(Equal(ctrl.Result{})) + + Expect(fakeWriter.WriteDirWithObjectsCallCount()).To(Equal(1)) + deleteExistingDir, dir, workloadsToCreate := fakeWriter.WriteDirWithObjectsArgsForCall(0) + Expect(deleteExistingDir).To(BeTrue()) + Expect(dir).To(Equal("")) + Expect(workloadsToCreate).To(Equal(workloads)) + }) + + It("constructs the writer using the statestore and destination", func() { + result, err := t.reconcileUntilCompletion(reconciler, &workPlacement) + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(Equal(ctrl.Result{})) + + Expect(argCreds).To(Equal(map[string][]byte{ + "accessKeyID": []byte("test-access"), + "secretAccessKey": []byte("test-secret"), + })) + Expect(argDestination).To(Equal(destination)) + Expect(argBucketStateStoreSpec).To(Equal(bucketStateStore.Spec)) + }) + + It("sets the finalizer", func() { + result, err := t.reconcileUntilCompletion(reconciler, &workPlacement) + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(Equal(ctrl.Result{})) + workplacement := &v1alpha1.WorkPlacement{} + Expect(fakeK8sClient.Get(ctx, types.NamespacedName{Name: workplacementName, Namespace: "default"}, workplacement)). + To(Succeed()) + Expect(workplacement.GetFinalizers()).To(ContainElement("finalizers.workplacement.kratix.io/repo-cleanup")) + }) + }) + }) + + When("the destination statestore is git", func() { + When("the destination has filepathExpression type nestedByMetdata", func() { + BeforeEach(func() { + Expect(fakeK8sClient.Create(ctx, &corev1.Secret{ + TypeMeta: v1.TypeMeta{ + Kind: "Secret", + APIVersion: "v1", + }, + ObjectMeta: v1.ObjectMeta{ + Name: "test-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "username": []byte("test-username"), + "password": []byte("test-password"), + }, + })).To(Succeed()) + gitStateStore = v1alpha1.GitStateStore{ + TypeMeta: v1.TypeMeta{ + Kind: "GitStateStore", + APIVersion: "platform.kratix.io/v1alpha1", + }, + ObjectMeta: v1.ObjectMeta{ + Name: "test-state-store", + }, + Spec: v1alpha1.GitStateStoreSpec{ + StateStoreCoreFields: v1alpha1.StateStoreCoreFields{ + SecretRef: &corev1.SecretReference{ + Name: "test-secret", + Namespace: "default", + }, + }, + URL: "", + Branch: "main", + AuthMethod: v1alpha1.BasicAuthMethod, + }, + } + Expect(fakeK8sClient.Create(ctx, &gitStateStore)).To(Succeed()) + + destination.Spec.StateStoreRef.Kind = "GitStateStore" + destination.Spec.StateStoreRef.Name = "test-state-store" + destination.Spec.Filepath.Mode = v1alpha1.FilepathExpressionTypeNestedByMetadata + Expect(fakeK8sClient.Create(ctx, &destination)).To(Succeed()) + controllers.SetNewGitWriter(func(logger logr.Logger, stateStoreSpec v1alpha1.GitStateStoreSpec, destination v1alpha1.Destination, + creds map[string][]byte) (writers.StateStoreWriter, error) { + argGitStateStoreSpec = stateStoreSpec + argDestination = destination + argCreds = creds + return fakeWriter, nil + }) + }) + + It("calls the writer with a directory nested by metadata", func() { + result, err := t.reconcileUntilCompletion(reconciler, &workPlacement) + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(Equal(ctrl.Result{})) + + Expect(fakeWriter.WriteDirWithObjectsCallCount()).To(Equal(1)) + deleteExistingDir, dir, workloadsToCreate := fakeWriter.WriteDirWithObjectsArgsForCall(0) + Expect(deleteExistingDir).To(BeTrue()) + Expect(dir).To(Equal("resources/default/test-promise/test-resource/5058f")) + Expect(workloadsToCreate).To(Equal(workloads)) + }) + + It("constructs the writer using the statestore and destination", func() { + result, err := t.reconcileUntilCompletion(reconciler, &workPlacement) + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(Equal(ctrl.Result{})) + + Expect(argCreds).To(Equal(map[string][]byte{ + "username": []byte("test-username"), + "password": []byte("test-password"), + })) + Expect(argDestination).To(Equal(destination)) + Expect(argGitStateStoreSpec).To(Equal(gitStateStore.Spec)) + }) + + When("the workplacement is for a promise", func() { + It("uses the promise directory structure", func() { + workPlacement.Spec.ResourceName = "" + Expect(fakeK8sClient.Update(ctx, &workPlacement)).To(Succeed()) + result, err := t.reconcileUntilCompletion(reconciler, &workPlacement) + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(Equal(ctrl.Result{})) + + Expect(fakeWriter.WriteDirWithObjectsCallCount()).To(Equal(1)) + deleteExistingDir, dir, _ := fakeWriter.WriteDirWithObjectsArgsForCall(0) + Expect(deleteExistingDir).To(BeTrue()) + Expect(dir).To(Equal("dependencies/test-promise/5058f")) + }) + }) + }) + }) +}) diff --git a/go.mod b/go.mod index 67921821..4a52dcb7 100644 --- a/go.mod +++ b/go.mod @@ -62,6 +62,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect + github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect diff --git a/go.sum b/go.sum index 08f8945a..6bb7bb0e 100644 --- a/go.sum +++ b/go.sum @@ -119,6 +119,8 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= +github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1 h1:NicmruxkeqHjDv03SfSxqmaLuisddudfP3h5wdXFbhM= +github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1/go.mod h1:eyp4DdUJAKkr9tvxR3jWhw2mDK7CWABMG5r9uyaKC7I= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v7 v7.0.68 h1:hTqSIfLlpXaKuNy4baAp4Jjy2sqZEN9hRxD0M4aOfrQ= diff --git a/lib/writers/statestore_writer.go b/lib/writers/statestore_writer.go index 2d85c1d8..9243d7c8 100644 --- a/lib/writers/statestore_writer.go +++ b/lib/writers/statestore_writer.go @@ -7,6 +7,7 @@ const ( PreserveExistingContentsInDir = false ) +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . StateStoreWriter type StateStoreWriter interface { WriteDirWithObjects(deleteExistingContentsInDir bool, dir string, workloads ...v1alpha1.Workload) error RemoveObject(objectName string) error diff --git a/lib/writers/writersfakes/fake_state_store_writer.go b/lib/writers/writersfakes/fake_state_store_writer.go new file mode 100644 index 00000000..50c859c4 --- /dev/null +++ b/lib/writers/writersfakes/fake_state_store_writer.go @@ -0,0 +1,190 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package writersfakes + +import ( + "sync" + + "github.com/syntasso/kratix/api/v1alpha1" + "github.com/syntasso/kratix/lib/writers" +) + +type FakeStateStoreWriter struct { + RemoveObjectStub func(string) error + removeObjectMutex sync.RWMutex + removeObjectArgsForCall []struct { + arg1 string + } + removeObjectReturns struct { + result1 error + } + removeObjectReturnsOnCall map[int]struct { + result1 error + } + WriteDirWithObjectsStub func(bool, string, ...v1alpha1.Workload) error + writeDirWithObjectsMutex sync.RWMutex + writeDirWithObjectsArgsForCall []struct { + arg1 bool + arg2 string + arg3 []v1alpha1.Workload + } + writeDirWithObjectsReturns struct { + result1 error + } + writeDirWithObjectsReturnsOnCall map[int]struct { + result1 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeStateStoreWriter) RemoveObject(arg1 string) error { + fake.removeObjectMutex.Lock() + ret, specificReturn := fake.removeObjectReturnsOnCall[len(fake.removeObjectArgsForCall)] + fake.removeObjectArgsForCall = append(fake.removeObjectArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.RemoveObjectStub + fakeReturns := fake.removeObjectReturns + fake.recordInvocation("RemoveObject", []interface{}{arg1}) + fake.removeObjectMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeStateStoreWriter) RemoveObjectCallCount() int { + fake.removeObjectMutex.RLock() + defer fake.removeObjectMutex.RUnlock() + return len(fake.removeObjectArgsForCall) +} + +func (fake *FakeStateStoreWriter) RemoveObjectCalls(stub func(string) error) { + fake.removeObjectMutex.Lock() + defer fake.removeObjectMutex.Unlock() + fake.RemoveObjectStub = stub +} + +func (fake *FakeStateStoreWriter) RemoveObjectArgsForCall(i int) string { + fake.removeObjectMutex.RLock() + defer fake.removeObjectMutex.RUnlock() + argsForCall := fake.removeObjectArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeStateStoreWriter) RemoveObjectReturns(result1 error) { + fake.removeObjectMutex.Lock() + defer fake.removeObjectMutex.Unlock() + fake.RemoveObjectStub = nil + fake.removeObjectReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeStateStoreWriter) RemoveObjectReturnsOnCall(i int, result1 error) { + fake.removeObjectMutex.Lock() + defer fake.removeObjectMutex.Unlock() + fake.RemoveObjectStub = nil + if fake.removeObjectReturnsOnCall == nil { + fake.removeObjectReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.removeObjectReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeStateStoreWriter) WriteDirWithObjects(arg1 bool, arg2 string, arg3 ...v1alpha1.Workload) error { + fake.writeDirWithObjectsMutex.Lock() + ret, specificReturn := fake.writeDirWithObjectsReturnsOnCall[len(fake.writeDirWithObjectsArgsForCall)] + fake.writeDirWithObjectsArgsForCall = append(fake.writeDirWithObjectsArgsForCall, struct { + arg1 bool + arg2 string + arg3 []v1alpha1.Workload + }{arg1, arg2, arg3}) + stub := fake.WriteDirWithObjectsStub + fakeReturns := fake.writeDirWithObjectsReturns + fake.recordInvocation("WriteDirWithObjects", []interface{}{arg1, arg2, arg3}) + fake.writeDirWithObjectsMutex.Unlock() + if stub != nil { + return stub(arg1, arg2, arg3...) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeStateStoreWriter) WriteDirWithObjectsCallCount() int { + fake.writeDirWithObjectsMutex.RLock() + defer fake.writeDirWithObjectsMutex.RUnlock() + return len(fake.writeDirWithObjectsArgsForCall) +} + +func (fake *FakeStateStoreWriter) WriteDirWithObjectsCalls(stub func(bool, string, ...v1alpha1.Workload) error) { + fake.writeDirWithObjectsMutex.Lock() + defer fake.writeDirWithObjectsMutex.Unlock() + fake.WriteDirWithObjectsStub = stub +} + +func (fake *FakeStateStoreWriter) WriteDirWithObjectsArgsForCall(i int) (bool, string, []v1alpha1.Workload) { + fake.writeDirWithObjectsMutex.RLock() + defer fake.writeDirWithObjectsMutex.RUnlock() + argsForCall := fake.writeDirWithObjectsArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +} + +func (fake *FakeStateStoreWriter) WriteDirWithObjectsReturns(result1 error) { + fake.writeDirWithObjectsMutex.Lock() + defer fake.writeDirWithObjectsMutex.Unlock() + fake.WriteDirWithObjectsStub = nil + fake.writeDirWithObjectsReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeStateStoreWriter) WriteDirWithObjectsReturnsOnCall(i int, result1 error) { + fake.writeDirWithObjectsMutex.Lock() + defer fake.writeDirWithObjectsMutex.Unlock() + fake.WriteDirWithObjectsStub = nil + if fake.writeDirWithObjectsReturnsOnCall == nil { + fake.writeDirWithObjectsReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.writeDirWithObjectsReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeStateStoreWriter) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.removeObjectMutex.RLock() + defer fake.removeObjectMutex.RUnlock() + fake.writeDirWithObjectsMutex.RLock() + defer fake.writeDirWithObjectsMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeStateStoreWriter) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ writers.StateStoreWriter = new(FakeStateStoreWriter)