@@ -20,21 +20,147 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
2020package backup
2121
2222import (
23+ "context"
24+ "testing"
25+
2326 . "github.com/onsi/ginkgo/v2"
2427 . "github.com/onsi/gomega"
2528
29+ "github.com/stretchr/testify/assert"
2630 corev1 "k8s.io/api/core/v1"
31+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32+ "k8s.io/apimachinery/pkg/runtime"
33+ "k8s.io/apimachinery/pkg/types"
34+ ctrl "sigs.k8s.io/controller-runtime"
2735 "sigs.k8s.io/controller-runtime/pkg/client"
36+ "sigs.k8s.io/controller-runtime/pkg/client/fake"
2837
2938 dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1"
3039 "github.com/apecloud/kubeblocks/pkg/constant"
3140 ctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
41+ "github.com/apecloud/kubeblocks/pkg/dataprotection/action"
42+ dptypes "github.com/apecloud/kubeblocks/pkg/dataprotection/types"
3243 "github.com/apecloud/kubeblocks/pkg/dataprotection/utils/boolptr"
3344 "github.com/apecloud/kubeblocks/pkg/generics"
3445 testapps "github.com/apecloud/kubeblocks/pkg/testutil/apps"
3546 testdp "github.com/apecloud/kubeblocks/pkg/testutil/dataprotection"
47+ viper "github.com/apecloud/kubeblocks/pkg/viperx"
3648)
3749
50+ func newRequestTestFixture (t * testing.T ) (* Request , * corev1.Pod ) {
51+ scheme := runtime .NewScheme ()
52+ assert .NoError (t , corev1 .AddToScheme (scheme ))
53+ assert .NoError (t , dpv1alpha1 .AddToScheme (scheme ))
54+ pod := & corev1.Pod {
55+ ObjectMeta : metav1.ObjectMeta {Name : "pod-0" , Namespace : "ns" , Labels : map [string ]string {constant .RoleLabelKey : "leader" }},
56+ Spec : corev1.PodSpec {
57+ NodeName : "node-0" ,
58+ Containers : []corev1.Container {{
59+ Name : "db" ,
60+ Env : []corev1.EnvVar {{Name : "EXISTING" , Value : "old" }},
61+ Ports : []corev1.ContainerPort {{Name : "mysql" , ContainerPort : 3306 }},
62+ }},
63+ Volumes : []corev1.Volume {{Name : "data" , VolumeSource : corev1.VolumeSource {PersistentVolumeClaim : & corev1.PersistentVolumeClaimVolumeSource {ClaimName : "data-pvc" }}}},
64+ },
65+ }
66+ req := & Request {
67+ RequestCtx : ctrlutil.RequestCtx {Ctx : context .Background (), Req : ctrl.Request {}},
68+ Client : fake .NewClientBuilder ().WithScheme (scheme ).Build (),
69+ Backup : & dpv1alpha1.Backup {
70+ ObjectMeta : metav1.ObjectMeta {
71+ Name : "backup" , Namespace : "ns" , UID : types .UID ("1234567890abcdef" ),
72+ Labels : map [string ]string {dptypes .ClusterUIDLabelKey : "uid" , constant .AppInstanceLabelKey : "cluster" , constant .KBAppComponentLabelKey : "mysql" },
73+ },
74+ Spec : dpv1alpha1.BackupSpec {RetentionPeriod : "7d" },
75+ },
76+ BackupPolicy : & dpv1alpha1.BackupPolicy {Spec : dpv1alpha1.BackupPolicySpec {BackoffLimit : func () * int32 { v := int32 (1 ); return & v }(), PathPrefix : "policy-path" }},
77+ BackupRepo : & dpv1alpha1.BackupRepo {Spec : dpv1alpha1.BackupRepoSpec {PathPrefix : "repo-path" }, Status : dpv1alpha1.BackupRepoStatus {BackupPVCName : "repo-pvc" }},
78+ BackupMethod : & dpv1alpha1.BackupMethod {Env : []corev1.EnvVar {{Name : "EXISTING" , Value : "method" }}},
79+ Target : & dpv1alpha1.BackupTarget {
80+ Name : "target" ,
81+ PodSelector : & dpv1alpha1.PodSelector {Strategy : dpv1alpha1 .PodSelectionStrategyAll },
82+ },
83+ TargetPods : []* corev1.Pod {pod },
84+ WorkerServiceAccount : "worker" ,
85+ }
86+ return req , pod
87+ }
88+
89+ func TestRequestGetBackupType (t * testing.T ) {
90+ req , _ := newRequestTestFixture (t )
91+ assert .Empty (t , req .GetBackupType ())
92+
93+ req .BackupMethod .SnapshotVolumes = func () * bool { v := true ; return & v }()
94+ assert .Equal (t , string (dpv1alpha1 .BackupTypeFull ), req .GetBackupType ())
95+
96+ req .ActionSet = & dpv1alpha1.ActionSet {Spec : dpv1alpha1.ActionSetSpec {BackupType : dpv1alpha1 .BackupTypeIncremental }}
97+ assert .Equal (t , string (dpv1alpha1 .BackupTypeIncremental ), req .GetBackupType ())
98+ }
99+
100+ func TestRequestBuildActionBranches (t * testing.T ) {
101+ oldNamespace := viper .GetString (constant .CfgKeyCtrlrMgrNS )
102+ oldServiceAccount := viper .GetString (dptypes .CfgKeyExecWorkerServiceAccountName )
103+ defer func () {
104+ viper .Set (constant .CfgKeyCtrlrMgrNS , oldNamespace )
105+ viper .Set (dptypes .CfgKeyExecWorkerServiceAccountName , oldServiceAccount )
106+ }()
107+ viper .Set (constant .CfgKeyCtrlrMgrNS , "kb-system" )
108+ viper .Set (dptypes .CfgKeyExecWorkerServiceAccountName , "exec-worker" )
109+
110+ req , pod := newRequestTestFixture (t )
111+ _ , err := req .buildAction (pod , "invalid" , & dpv1alpha1.ActionSpec {})
112+ assert .Error (t , err )
113+ _ , err = req .buildAction (pod , "invalid" , & dpv1alpha1.ActionSpec {Exec : & dpv1alpha1.ExecActionSpec {}, Job : & dpv1alpha1.JobActionSpec {}})
114+ assert .Error (t , err )
115+
116+ execAction , err := req .buildAction (pod , "exec" , & dpv1alpha1.ActionSpec {Exec : & dpv1alpha1.ExecActionSpec {Command : []string {"echo" , "ok" }}})
117+ assert .NoError (t , err )
118+ assert .IsType (t , & action.ExecAction {}, execAction )
119+ assert .Equal (t , "exec" , execAction .GetName ())
120+
121+ jobAction , err := req .buildAction (pod , "job" , & dpv1alpha1.ActionSpec {Job : & dpv1alpha1.JobActionSpec {BaseJobActionSpec : dpv1alpha1.BaseJobActionSpec {Image : "busybox:$(EXISTING)" , Command : []string {"backup" }}}})
122+ assert .NoError (t , err )
123+ assert .IsType (t , & action.JobAction {}, jobAction )
124+ assert .Equal (t , dpv1alpha1 .ActionTypeJob , jobAction .Type ())
125+ }
126+
127+ func TestRequestBuildBackupDataActions (t * testing.T ) {
128+ req , pod := newRequestTestFixture (t )
129+ req .ActionSet = & dpv1alpha1.ActionSet {Spec : dpv1alpha1.ActionSetSpec {BackupType : dpv1alpha1 .BackupTypeFull , Backup : & dpv1alpha1.BackupActionSpec {BackupData : & dpv1alpha1.BackupDataActionSpec {JobActionSpec : dpv1alpha1.JobActionSpec {BaseJobActionSpec : dpv1alpha1.BaseJobActionSpec {Image : "busybox" }}}}}}
130+ backupDataAction , err := req .buildBackupDataAction (pod , "backup-data" )
131+ assert .NoError (t , err )
132+ assert .IsType (t , & action.JobAction {}, backupDataAction )
133+
134+ req .ActionSet .Spec .BackupType = dpv1alpha1 .BackupTypeContinuous
135+ backupDataAction , err = req .buildBackupDataAction (pod , "continuous" )
136+ assert .NoError (t , err )
137+ assert .IsType (t , & action.StatefulSetAction {}, backupDataAction )
138+ assert .Contains (t , req .buildContinuousSyncProgressCommand (), "retryTimes" )
139+
140+ req .ActionSet .Spec .BackupType = dpv1alpha1 .BackupType ("Unknown" )
141+ _ , err = req .buildBackupDataAction (pod , "unsupported" )
142+ assert .Error (t , err )
143+ }
144+
145+ func TestRequestBuildActionsIncludesPreAndPostHooks (t * testing.T ) {
146+ req , pod := newRequestTestFixture (t )
147+ req .ActionSet = & dpv1alpha1.ActionSet {Spec : dpv1alpha1.ActionSetSpec {
148+ BackupType : dpv1alpha1 .BackupTypeFull ,
149+ Backup : & dpv1alpha1.BackupActionSpec {
150+ PreBackup : []dpv1alpha1.ActionSpec {{Exec : & dpv1alpha1.ExecActionSpec {Command : []string {"pre" }}}},
151+ BackupData : & dpv1alpha1.BackupDataActionSpec {JobActionSpec : dpv1alpha1.JobActionSpec {BaseJobActionSpec : dpv1alpha1.BaseJobActionSpec {Image : "busybox" , Command : []string {"backup" }}}},
152+ PostBackup : []dpv1alpha1.ActionSpec {{Job : & dpv1alpha1.JobActionSpec {BaseJobActionSpec : dpv1alpha1.BaseJobActionSpec {Image : "busybox" , Command : []string {"post" }}}}},
153+ },
154+ }}
155+
156+ actions , err := req .BuildActions ()
157+ assert .NoError (t , err )
158+ assert .Len (t , actions [pod .Name ], 3 )
159+ assert .Equal (t , dpv1alpha1 .ActionTypeJob , actions [pod .Name ][0 ].Type ())
160+ assert .Equal (t , dpv1alpha1 .ActionTypeJob , actions [pod .Name ][1 ].Type ())
161+ assert .Equal (t , dpv1alpha1 .ActionTypeJob , actions [pod .Name ][2 ].Type ())
162+ }
163+
38164var _ = Describe ("Request Test" , func () {
39165 buildRequest := func () * Request {
40166 return & Request {
0 commit comments