@@ -48,6 +48,7 @@ import (
4848 ctrl "sigs.k8s.io/controller-runtime"
4949 "sigs.k8s.io/controller-runtime/pkg/client"
5050 fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
51+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
5152 "sigs.k8s.io/controller-runtime/pkg/log"
5253
5354 "github.com/fluxcd/pkg/apis/meta"
@@ -591,7 +592,7 @@ func TestGitRepositoryReconciler_reconcileArtifact(t *testing.T) {
591592 },
592593 want : ctrl.Result {RequeueAfter : mockInterval },
593594 assertConditions : []metav1.Condition {
594- * conditions .TrueCondition (sourcev1 .ArtifactAvailableCondition , "ArchivedArtifact" , "Archived artifact revision main/revision" ),
595+ * conditions .TrueCondition (sourcev1 .ArtifactAvailableCondition , "ArchivedArtifact" , "Artifact revision main/revision" ),
595596 },
596597 },
597598 {
@@ -662,6 +663,251 @@ func TestGitRepositoryReconciler_reconcileArtifact(t *testing.T) {
662663 }
663664}
664665
666+ func TestGitRepositoryReconciler_reconcileInclude (t * testing.T ) {
667+ g := NewWithT (t )
668+
669+ storage , err := newTestStorage ()
670+ g .Expect (err ).NotTo (HaveOccurred ())
671+ defer os .RemoveAll (storage .BasePath )
672+
673+ dependencyInterval := 5 * time .Second
674+
675+ type dependency struct {
676+ name string
677+ withArtifact bool
678+ conditions []metav1.Condition
679+ }
680+
681+ type include struct {
682+ name string
683+ fromPath string
684+ toPath string
685+ shouldExist bool
686+ }
687+
688+ tests := []struct {
689+ name string
690+ dependencies []dependency
691+ includes []include
692+ want ctrl.Result
693+ wantErr bool
694+ assertConditions []metav1.Condition
695+ }{
696+ {
697+ name : "Includes artifacts" ,
698+ dependencies : []dependency {
699+ {
700+ name : "a" ,
701+ withArtifact : true ,
702+ conditions : []metav1.Condition {
703+ * conditions .TrueCondition (meta .ReadyCondition , "Foo" , "foo ready" ),
704+ },
705+ },
706+ {
707+ name : "b" ,
708+ withArtifact : true ,
709+ conditions : []metav1.Condition {
710+ * conditions .TrueCondition (meta .ReadyCondition , "Bar" , "bar ready" ),
711+ },
712+ },
713+ },
714+ includes : []include {
715+ {name : "a" , toPath : "a/" },
716+ {name : "b" , toPath : "b/" },
717+ },
718+ want : ctrl.Result {RequeueAfter : mockInterval },
719+ assertConditions : []metav1.Condition {
720+ * conditions .TrueCondition (sourcev1 .SourceAvailableCondition , "Foo" , "2 of 2 Ready" ),
721+ },
722+ },
723+ {
724+ name : "Non existing artifact" ,
725+ includes : []include {
726+ {name : "a" , toPath : "a/" },
727+ },
728+ want : ctrl.Result {RequeueAfter : mockInterval },
729+ wantErr : false ,
730+ assertConditions : []metav1.Condition {
731+ * conditions .FalseCondition (sourcev1 .SourceAvailableCondition , "IncludeNotFound" , "Could not find resource for include \" a\" : gitrepositories.source.toolkit.fluxcd.io \" a\" not found" ),
732+ },
733+ },
734+ {
735+ name : "Missing artifact" ,
736+ dependencies : []dependency {
737+ {
738+ name : "a" ,
739+ withArtifact : false ,
740+ conditions : []metav1.Condition {
741+ * conditions .FalseCondition (sourcev1 .SourceAvailableCondition , "Foo" , "foo unavailable" ),
742+ },
743+ },
744+ },
745+ includes : []include {
746+ {name : "a" , toPath : "a/" },
747+ },
748+ want : ctrl.Result {RequeueAfter : dependencyInterval },
749+ assertConditions : []metav1.Condition {
750+ * conditions .FalseCondition (sourcev1 .SourceAvailableCondition , "IncludeUnavailable" , "No artifact available for include \" a\" " ),
751+ },
752+ },
753+ {
754+ name : "Invalid FromPath" ,
755+ dependencies : []dependency {
756+ {
757+ name : "a" ,
758+ withArtifact : true ,
759+ },
760+ },
761+ includes : []include {
762+ {name : "a" , fromPath : "../../../path" , shouldExist : false },
763+ },
764+ wantErr : true ,
765+ assertConditions : []metav1.Condition {
766+ * conditions .FalseCondition (sourcev1 .SourceAvailableCondition , "IncludeCopyFailure" , "Failed to copy \" a\" include from ../../../path to a" ),
767+ },
768+ },
769+ {
770+ name : "Stalled include" ,
771+ dependencies : []dependency {
772+ {
773+ name : "a" ,
774+ withArtifact : true ,
775+ conditions : []metav1.Condition {
776+ * conditions .TrueCondition (meta .ReadyCondition , "Foo" , "foo ready" ),
777+ },
778+ },
779+ {
780+ name : "b" ,
781+ withArtifact : true ,
782+ conditions : []metav1.Condition {
783+ * conditions .TrueCondition (meta .StalledCondition , "Bar" , "bar stalled" ),
784+ },
785+ },
786+ },
787+ includes : []include {
788+ {name : "a" , toPath : "a/" },
789+ {name : "b" , toPath : "b/" },
790+ },
791+ want : ctrl.Result {RequeueAfter : mockInterval },
792+ assertConditions : []metav1.Condition {
793+ * conditions .FalseCondition (sourcev1 .SourceAvailableCondition , "Bar @ GitRepository/a" , "bar stalled" ),
794+ },
795+ },
796+ }
797+ for _ , tt := range tests {
798+ t .Run (tt .name , func (t * testing.T ) {
799+ g := NewWithT (t )
800+
801+ var depObjs []client.Object
802+ for _ , d := range tt .dependencies {
803+ obj := & sourcev1.GitRepository {
804+ ObjectMeta : metav1.ObjectMeta {
805+ Name : d .name ,
806+ },
807+ Status : sourcev1.GitRepositoryStatus {
808+ Conditions : d .conditions ,
809+ },
810+ }
811+ if d .withArtifact {
812+ obj .Status .Artifact = & sourcev1.Artifact {
813+ Path : d .name + ".tar.gz" ,
814+ Revision : d .name ,
815+ LastUpdateTime : metav1 .Now (),
816+ }
817+ g .Expect (storage .Archive (obj .GetArtifact (), "testdata/git/repository" , nil )).To (Succeed ())
818+ }
819+ depObjs = append (depObjs , obj )
820+ }
821+
822+ s := runtime .NewScheme ()
823+ utilruntime .Must (sourcev1 .AddToScheme (s ))
824+ builder := fakeclient .NewClientBuilder ().WithScheme (s )
825+ if len (tt .dependencies ) > 0 {
826+ builder .WithObjects (depObjs ... )
827+ }
828+
829+ r := & GitRepositoryReconciler {
830+ Client : builder .Build (),
831+ Storage : storage ,
832+ requeueDependency : dependencyInterval ,
833+ }
834+
835+ obj := & sourcev1.GitRepository {
836+ ObjectMeta : metav1.ObjectMeta {
837+ Name : "reconcile-include" ,
838+ },
839+ Spec : sourcev1.GitRepositorySpec {
840+ Interval : metav1.Duration {Duration : mockInterval },
841+ },
842+ }
843+
844+ for i , incl := range tt .includes {
845+ incl := sourcev1.GitRepositoryInclude {
846+ GitRepositoryRef : meta.LocalObjectReference {Name : incl .name },
847+ FromPath : incl .fromPath ,
848+ ToPath : incl .toPath ,
849+ }
850+ tt .includes [i ].fromPath = incl .GetFromPath ()
851+ tt .includes [i ].toPath = incl .GetToPath ()
852+ obj .Spec .Include = append (obj .Spec .Include , incl )
853+ }
854+
855+ tmpDir , err := ioutil .TempDir ("" , "include-" )
856+ g .Expect (err ).NotTo (HaveOccurred ())
857+
858+ var artifacts artifactSet
859+ got , err := r .reconcileInclude (ctx , obj , artifacts , tmpDir )
860+ g .Expect (obj .GetConditions ()).To (conditions .MatchConditions (tt .assertConditions ))
861+ g .Expect (err != nil ).To (Equal (tt .wantErr ))
862+ g .Expect (got ).To (Equal (tt .want ))
863+ for _ , i := range tt .includes {
864+ if i .toPath != "" {
865+ expect := g .Expect (filepath .Join (storage .BasePath , i .toPath ))
866+ if i .shouldExist {
867+ expect .To (BeADirectory ())
868+ } else {
869+ expect .NotTo (BeADirectory ())
870+ }
871+ }
872+ if i .shouldExist {
873+ g .Expect (filepath .Join (storage .BasePath , i .toPath )).Should (BeADirectory ())
874+ } else {
875+ g .Expect (filepath .Join (storage .BasePath , i .toPath )).ShouldNot (BeADirectory ())
876+ }
877+ }
878+ })
879+ }
880+ }
881+
882+ func TestGitRepositoryReconciler_reconcileDelete (t * testing.T ) {
883+ g := NewWithT (t )
884+
885+ r := & GitRepositoryReconciler {
886+ Storage : storage ,
887+ }
888+
889+ obj := & sourcev1.GitRepository {
890+ ObjectMeta : metav1.ObjectMeta {
891+ Name : "reconcile-delete-" ,
892+ DeletionTimestamp : & metav1.Time {Time : time .Now ()},
893+ Finalizers : []string {
894+ sourcev1 .SourceFinalizer ,
895+ },
896+ },
897+ Status : sourcev1.GitRepositoryStatus {},
898+ }
899+
900+ artifact := storage .NewArtifactFor (sourcev1 .GitRepositoryKind , obj .GetObjectMeta (), "revision" , "foo.txt" )
901+ obj .Status .Artifact = & artifact
902+
903+ got , err := r .reconcileDelete (ctx , obj )
904+ g .Expect (err ).NotTo (HaveOccurred ())
905+ g .Expect (got ).To (Equal (ctrl.Result {}))
906+ g .Expect (controllerutil .ContainsFinalizer (obj , sourcev1 .SourceFinalizer )).To (BeFalse ())
907+ g .Expect (obj .Status .Artifact ).To (BeNil ())
908+
909+ }
910+
665911func TestGitRepositoryReconciler_verifyCommitSignature (t * testing.T ) {
666912 tests := []struct {
667913 name string
0 commit comments