github.com/spotahome/redis-operator@v1.2.4/operator/redisfailover/service/generator_test.go (about)

     1  package service_test
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/mock"
     9  	appsv1 "k8s.io/api/apps/v1"
    10  	corev1 "k8s.io/api/core/v1"
    11  	"k8s.io/apimachinery/pkg/api/resource"
    12  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    13  	"k8s.io/apimachinery/pkg/util/intstr"
    14  
    15  	redisfailoverv1 "github.com/spotahome/redis-operator/api/redisfailover/v1"
    16  	"github.com/spotahome/redis-operator/log"
    17  	"github.com/spotahome/redis-operator/metrics"
    18  	mK8SService "github.com/spotahome/redis-operator/mocks/service/k8s"
    19  	rfservice "github.com/spotahome/redis-operator/operator/redisfailover/service"
    20  )
    21  
    22  func TestRedisStatefulSetStorageGeneration(t *testing.T) {
    23  	configMapName := rfservice.GetRedisName(generateRF())
    24  	shutdownConfigMapName := rfservice.GetRedisShutdownConfigMapName(generateRF())
    25  	readinesConfigMapName := rfservice.GetRedisReadinessName(generateRF())
    26  	executeMode := int32(0744)
    27  	tests := []struct {
    28  		name           string
    29  		ownerRefs      []metav1.OwnerReference
    30  		expectedSS     appsv1.StatefulSet
    31  		rfRedisStorage redisfailoverv1.RedisStorage
    32  	}{
    33  		{
    34  			name: "Default values",
    35  			expectedSS: appsv1.StatefulSet{
    36  				Spec: appsv1.StatefulSetSpec{
    37  					Template: corev1.PodTemplateSpec{
    38  						Spec: corev1.PodSpec{
    39  							Containers: []corev1.Container{
    40  								{
    41  									VolumeMounts: []corev1.VolumeMount{
    42  										{
    43  											Name:      "redis-config",
    44  											MountPath: "/redis",
    45  										},
    46  										{
    47  											Name:      "redis-shutdown-config",
    48  											MountPath: "/redis-shutdown",
    49  										},
    50  										{
    51  											Name:      "redis-readiness-config",
    52  											MountPath: "/redis-readiness",
    53  										},
    54  										{
    55  											Name:      "redis-data",
    56  											MountPath: "/data",
    57  										},
    58  									},
    59  								},
    60  							},
    61  							Volumes: []corev1.Volume{
    62  								{
    63  									Name: "redis-config",
    64  									VolumeSource: corev1.VolumeSource{
    65  										ConfigMap: &corev1.ConfigMapVolumeSource{
    66  											LocalObjectReference: corev1.LocalObjectReference{
    67  												Name: configMapName,
    68  											},
    69  										},
    70  									},
    71  								},
    72  								{
    73  									Name: "redis-shutdown-config",
    74  									VolumeSource: corev1.VolumeSource{
    75  										ConfigMap: &corev1.ConfigMapVolumeSource{
    76  											LocalObjectReference: corev1.LocalObjectReference{
    77  												Name: shutdownConfigMapName,
    78  											},
    79  											DefaultMode: &executeMode,
    80  										},
    81  									},
    82  								},
    83  								{
    84  									Name: "redis-readiness-config",
    85  									VolumeSource: corev1.VolumeSource{
    86  										ConfigMap: &corev1.ConfigMapVolumeSource{
    87  											LocalObjectReference: corev1.LocalObjectReference{
    88  												Name: readinesConfigMapName,
    89  											},
    90  											DefaultMode: &executeMode,
    91  										},
    92  									},
    93  								},
    94  								{
    95  									Name: "redis-data",
    96  									VolumeSource: corev1.VolumeSource{
    97  										EmptyDir: &corev1.EmptyDirVolumeSource{},
    98  									},
    99  								},
   100  							},
   101  						},
   102  					},
   103  				},
   104  			},
   105  			rfRedisStorage: redisfailoverv1.RedisStorage{},
   106  		},
   107  		{
   108  			name: "Defined an emptydir with storage on memory",
   109  			expectedSS: appsv1.StatefulSet{
   110  				Spec: appsv1.StatefulSetSpec{
   111  					Template: corev1.PodTemplateSpec{
   112  						Spec: corev1.PodSpec{
   113  							Containers: []corev1.Container{
   114  								{
   115  									VolumeMounts: []corev1.VolumeMount{
   116  										{
   117  											Name:      "redis-config",
   118  											MountPath: "/redis",
   119  										},
   120  										{
   121  											Name:      "redis-shutdown-config",
   122  											MountPath: "/redis-shutdown",
   123  										},
   124  										{
   125  											Name:      "redis-readiness-config",
   126  											MountPath: "/redis-readiness",
   127  										},
   128  										{
   129  											Name:      "redis-data",
   130  											MountPath: "/data",
   131  										},
   132  									},
   133  								},
   134  							},
   135  							Volumes: []corev1.Volume{
   136  								{
   137  									Name: "redis-config",
   138  									VolumeSource: corev1.VolumeSource{
   139  										ConfigMap: &corev1.ConfigMapVolumeSource{
   140  											LocalObjectReference: corev1.LocalObjectReference{
   141  												Name: configMapName,
   142  											},
   143  										},
   144  									},
   145  								},
   146  								{
   147  									Name: "redis-shutdown-config",
   148  									VolumeSource: corev1.VolumeSource{
   149  										ConfigMap: &corev1.ConfigMapVolumeSource{
   150  											LocalObjectReference: corev1.LocalObjectReference{
   151  												Name: shutdownConfigMapName,
   152  											},
   153  											DefaultMode: &executeMode,
   154  										},
   155  									},
   156  								},
   157  								{
   158  									Name: "redis-readiness-config",
   159  									VolumeSource: corev1.VolumeSource{
   160  										ConfigMap: &corev1.ConfigMapVolumeSource{
   161  											LocalObjectReference: corev1.LocalObjectReference{
   162  												Name: readinesConfigMapName,
   163  											},
   164  											DefaultMode: &executeMode,
   165  										},
   166  									},
   167  								},
   168  								{
   169  									Name: "redis-data",
   170  									VolumeSource: corev1.VolumeSource{
   171  										EmptyDir: &corev1.EmptyDirVolumeSource{
   172  											Medium: corev1.StorageMediumMemory,
   173  										},
   174  									},
   175  								},
   176  							},
   177  						},
   178  					},
   179  				},
   180  			},
   181  			rfRedisStorage: redisfailoverv1.RedisStorage{
   182  				EmptyDir: &corev1.EmptyDirVolumeSource{
   183  					Medium: corev1.StorageMediumMemory,
   184  				},
   185  			},
   186  		},
   187  		{
   188  			name: "Defined an persistentvolumeclaim",
   189  			expectedSS: appsv1.StatefulSet{
   190  				Spec: appsv1.StatefulSetSpec{
   191  					Template: corev1.PodTemplateSpec{
   192  						Spec: corev1.PodSpec{
   193  							Containers: []corev1.Container{
   194  								{
   195  									VolumeMounts: []corev1.VolumeMount{
   196  										{
   197  											Name:      "redis-config",
   198  											MountPath: "/redis",
   199  										},
   200  										{
   201  											Name:      "redis-shutdown-config",
   202  											MountPath: "/redis-shutdown",
   203  										},
   204  										{
   205  											Name:      "redis-readiness-config",
   206  											MountPath: "/redis-readiness",
   207  										},
   208  										{
   209  											Name:      "pvc-data",
   210  											MountPath: "/data",
   211  										},
   212  									},
   213  								},
   214  							},
   215  							Volumes: []corev1.Volume{
   216  								{
   217  									Name: "redis-config",
   218  									VolumeSource: corev1.VolumeSource{
   219  										ConfigMap: &corev1.ConfigMapVolumeSource{
   220  											LocalObjectReference: corev1.LocalObjectReference{
   221  												Name: configMapName,
   222  											},
   223  										},
   224  									},
   225  								},
   226  								{
   227  									Name: "redis-shutdown-config",
   228  									VolumeSource: corev1.VolumeSource{
   229  										ConfigMap: &corev1.ConfigMapVolumeSource{
   230  											LocalObjectReference: corev1.LocalObjectReference{
   231  												Name: shutdownConfigMapName,
   232  											},
   233  											DefaultMode: &executeMode,
   234  										},
   235  									},
   236  								},
   237  								{
   238  									Name: "redis-readiness-config",
   239  									VolumeSource: corev1.VolumeSource{
   240  										ConfigMap: &corev1.ConfigMapVolumeSource{
   241  											LocalObjectReference: corev1.LocalObjectReference{
   242  												Name: readinesConfigMapName,
   243  											},
   244  											DefaultMode: &executeMode,
   245  										},
   246  									},
   247  								},
   248  							},
   249  						},
   250  					},
   251  					VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
   252  						{
   253  							TypeMeta: metav1.TypeMeta{
   254  								Kind:       "PersistentVolumeClaim",
   255  								APIVersion: "v1",
   256  							},
   257  							ObjectMeta: metav1.ObjectMeta{
   258  								Name: "pvc-data",
   259  							},
   260  							Spec: corev1.PersistentVolumeClaimSpec{
   261  								AccessModes: []corev1.PersistentVolumeAccessMode{
   262  									"ReadWriteOnce",
   263  								},
   264  								Resources: corev1.ResourceRequirements{
   265  									Requests: corev1.ResourceList{
   266  										corev1.ResourceStorage: resource.MustParse("1Gi"),
   267  									},
   268  								},
   269  							},
   270  						},
   271  					},
   272  				},
   273  			},
   274  			rfRedisStorage: redisfailoverv1.RedisStorage{
   275  				PersistentVolumeClaim: &redisfailoverv1.EmbeddedPersistentVolumeClaim{
   276  					EmbeddedObjectMetadata: redisfailoverv1.EmbeddedObjectMetadata{
   277  						Name: "pvc-data",
   278  					},
   279  					Spec: corev1.PersistentVolumeClaimSpec{
   280  						AccessModes: []corev1.PersistentVolumeAccessMode{
   281  							"ReadWriteOnce",
   282  						},
   283  						Resources: corev1.ResourceRequirements{
   284  							Requests: corev1.ResourceList{
   285  								corev1.ResourceStorage: resource.MustParse("1Gi"),
   286  							},
   287  						},
   288  					},
   289  				},
   290  			},
   291  		},
   292  		{
   293  			name: "Defined an persistentvolumeclaim with ownerRefs",
   294  			ownerRefs: []metav1.OwnerReference{
   295  				{
   296  					Name: "testing",
   297  				},
   298  			},
   299  			expectedSS: appsv1.StatefulSet{
   300  				Spec: appsv1.StatefulSetSpec{
   301  					Template: corev1.PodTemplateSpec{
   302  						Spec: corev1.PodSpec{
   303  							Containers: []corev1.Container{
   304  								{
   305  									VolumeMounts: []corev1.VolumeMount{
   306  										{
   307  											Name:      "redis-config",
   308  											MountPath: "/redis",
   309  										},
   310  										{
   311  											Name:      "redis-shutdown-config",
   312  											MountPath: "/redis-shutdown",
   313  										},
   314  										{
   315  											Name:      "redis-readiness-config",
   316  											MountPath: "/redis-readiness",
   317  										},
   318  										{
   319  											Name:      "pvc-data",
   320  											MountPath: "/data",
   321  										},
   322  									},
   323  								},
   324  							},
   325  							Volumes: []corev1.Volume{
   326  								{
   327  									Name: "redis-config",
   328  									VolumeSource: corev1.VolumeSource{
   329  										ConfigMap: &corev1.ConfigMapVolumeSource{
   330  											LocalObjectReference: corev1.LocalObjectReference{
   331  												Name: configMapName,
   332  											},
   333  										},
   334  									},
   335  								},
   336  								{
   337  									Name: "redis-shutdown-config",
   338  									VolumeSource: corev1.VolumeSource{
   339  										ConfigMap: &corev1.ConfigMapVolumeSource{
   340  											LocalObjectReference: corev1.LocalObjectReference{
   341  												Name: shutdownConfigMapName,
   342  											},
   343  											DefaultMode: &executeMode,
   344  										},
   345  									},
   346  								},
   347  								{
   348  									Name: "redis-readiness-config",
   349  									VolumeSource: corev1.VolumeSource{
   350  										ConfigMap: &corev1.ConfigMapVolumeSource{
   351  											LocalObjectReference: corev1.LocalObjectReference{
   352  												Name: readinesConfigMapName,
   353  											},
   354  											DefaultMode: &executeMode,
   355  										},
   356  									},
   357  								},
   358  							},
   359  						},
   360  					},
   361  					VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
   362  						{
   363  							TypeMeta: metav1.TypeMeta{
   364  								Kind:       "PersistentVolumeClaim",
   365  								APIVersion: "v1",
   366  							},
   367  							ObjectMeta: metav1.ObjectMeta{
   368  								Name: "pvc-data",
   369  								OwnerReferences: []metav1.OwnerReference{
   370  									{
   371  										Name: "testing",
   372  									},
   373  								},
   374  							},
   375  							Spec: corev1.PersistentVolumeClaimSpec{
   376  								AccessModes: []corev1.PersistentVolumeAccessMode{
   377  									"ReadWriteOnce",
   378  								},
   379  								Resources: corev1.ResourceRequirements{
   380  									Requests: corev1.ResourceList{
   381  										corev1.ResourceStorage: resource.MustParse("1Gi"),
   382  									},
   383  								},
   384  							},
   385  						},
   386  					},
   387  				},
   388  			},
   389  			rfRedisStorage: redisfailoverv1.RedisStorage{
   390  				PersistentVolumeClaim: &redisfailoverv1.EmbeddedPersistentVolumeClaim{
   391  					EmbeddedObjectMetadata: redisfailoverv1.EmbeddedObjectMetadata{
   392  						Name: "pvc-data",
   393  					},
   394  					Spec: corev1.PersistentVolumeClaimSpec{
   395  						AccessModes: []corev1.PersistentVolumeAccessMode{
   396  							"ReadWriteOnce",
   397  						},
   398  						Resources: corev1.ResourceRequirements{
   399  							Requests: corev1.ResourceList{
   400  								corev1.ResourceStorage: resource.MustParse("1Gi"),
   401  							},
   402  						},
   403  					},
   404  				},
   405  			},
   406  		},
   407  		{
   408  			name: "Defined an persistentvolumeclaim with ownerRefs keeping the pvc",
   409  			ownerRefs: []metav1.OwnerReference{
   410  				{
   411  					Name: "testing",
   412  				},
   413  			},
   414  			expectedSS: appsv1.StatefulSet{
   415  				Spec: appsv1.StatefulSetSpec{
   416  					Template: corev1.PodTemplateSpec{
   417  						Spec: corev1.PodSpec{
   418  							Containers: []corev1.Container{
   419  								{
   420  									VolumeMounts: []corev1.VolumeMount{
   421  										{
   422  											Name:      "redis-config",
   423  											MountPath: "/redis",
   424  										},
   425  										{
   426  											Name:      "redis-shutdown-config",
   427  											MountPath: "/redis-shutdown",
   428  										},
   429  										{
   430  											Name:      "redis-readiness-config",
   431  											MountPath: "/redis-readiness",
   432  										},
   433  										{
   434  											Name:      "pvc-data",
   435  											MountPath: "/data",
   436  										},
   437  									},
   438  								},
   439  							},
   440  							Volumes: []corev1.Volume{
   441  								{
   442  									Name: "redis-config",
   443  									VolumeSource: corev1.VolumeSource{
   444  										ConfigMap: &corev1.ConfigMapVolumeSource{
   445  											LocalObjectReference: corev1.LocalObjectReference{
   446  												Name: configMapName,
   447  											},
   448  										},
   449  									},
   450  								},
   451  								{
   452  									Name: "redis-shutdown-config",
   453  									VolumeSource: corev1.VolumeSource{
   454  										ConfigMap: &corev1.ConfigMapVolumeSource{
   455  											LocalObjectReference: corev1.LocalObjectReference{
   456  												Name: shutdownConfigMapName,
   457  											},
   458  											DefaultMode: &executeMode,
   459  										},
   460  									},
   461  								},
   462  								{
   463  									Name: "redis-readiness-config",
   464  									VolumeSource: corev1.VolumeSource{
   465  										ConfigMap: &corev1.ConfigMapVolumeSource{
   466  											LocalObjectReference: corev1.LocalObjectReference{
   467  												Name: readinesConfigMapName,
   468  											},
   469  											DefaultMode: &executeMode,
   470  										},
   471  									},
   472  								},
   473  							},
   474  						},
   475  					},
   476  					VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
   477  						{
   478  							TypeMeta: metav1.TypeMeta{
   479  								Kind:       "PersistentVolumeClaim",
   480  								APIVersion: "v1",
   481  							},
   482  							ObjectMeta: metav1.ObjectMeta{
   483  								Name: "pvc-data",
   484  							},
   485  							Spec: corev1.PersistentVolumeClaimSpec{
   486  								AccessModes: []corev1.PersistentVolumeAccessMode{
   487  									"ReadWriteOnce",
   488  								},
   489  								Resources: corev1.ResourceRequirements{
   490  									Requests: corev1.ResourceList{
   491  										corev1.ResourceStorage: resource.MustParse("1Gi"),
   492  									},
   493  								},
   494  							},
   495  						},
   496  					},
   497  				},
   498  			},
   499  			rfRedisStorage: redisfailoverv1.RedisStorage{
   500  				KeepAfterDeletion: true,
   501  				PersistentVolumeClaim: &redisfailoverv1.EmbeddedPersistentVolumeClaim{
   502  					EmbeddedObjectMetadata: redisfailoverv1.EmbeddedObjectMetadata{
   503  						Name: "pvc-data",
   504  					},
   505  					Spec: corev1.PersistentVolumeClaimSpec{
   506  						AccessModes: []corev1.PersistentVolumeAccessMode{
   507  							"ReadWriteOnce",
   508  						},
   509  						Resources: corev1.ResourceRequirements{
   510  							Requests: corev1.ResourceList{
   511  								corev1.ResourceStorage: resource.MustParse("1Gi"),
   512  							},
   513  						},
   514  					},
   515  				},
   516  			},
   517  		},
   518  	}
   519  
   520  	for _, test := range tests {
   521  		assert := assert.New(t)
   522  
   523  		// Generate a default RedisFailover and attaching the required storage
   524  		rf := generateRF()
   525  		rf.Spec.Redis.Storage = test.rfRedisStorage
   526  
   527  		generatedStatefulSet := appsv1.StatefulSet{}
   528  
   529  		ms := &mK8SService.Services{}
   530  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
   531  		ms.On("CreateOrUpdateStatefulSet", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
   532  			ss := args.Get(1).(*appsv1.StatefulSet)
   533  			generatedStatefulSet = *ss
   534  		}).Return(nil)
   535  
   536  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
   537  		err := client.EnsureRedisStatefulset(rf, nil, test.ownerRefs)
   538  
   539  		// Check that the storage-related fields are as spected
   540  		assert.Equal(test.expectedSS.Spec.Template.Spec.Volumes, generatedStatefulSet.Spec.Template.Spec.Volumes)
   541  		assert.Equal(test.expectedSS.Spec.Template.Spec.Containers[0].VolumeMounts, generatedStatefulSet.Spec.Template.Spec.Containers[0].VolumeMounts)
   542  		assert.Equal(test.expectedSS.Spec.VolumeClaimTemplates, generatedStatefulSet.Spec.VolumeClaimTemplates)
   543  		assert.NoError(err)
   544  	}
   545  }
   546  
   547  func TestRedisStatefulSetCommands(t *testing.T) {
   548  	tests := []struct {
   549  		name             string
   550  		givenCommands    []string
   551  		expectedCommands []string
   552  	}{
   553  		{
   554  			name:          "Default values",
   555  			givenCommands: []string{},
   556  			expectedCommands: []string{
   557  				"redis-server",
   558  				"/redis/redis.conf",
   559  			},
   560  		},
   561  		{
   562  			name: "Given commands should be used in redis container",
   563  			givenCommands: []string{
   564  				"test",
   565  				"command",
   566  			},
   567  			expectedCommands: []string{
   568  				"test",
   569  				"command",
   570  			},
   571  		},
   572  	}
   573  
   574  	for _, test := range tests {
   575  		assert := assert.New(t)
   576  
   577  		// Generate a default RedisFailover and attaching the required storage
   578  		rf := generateRF()
   579  		rf.Spec.Redis.Command = test.givenCommands
   580  
   581  		gotCommands := []string{}
   582  
   583  		ms := &mK8SService.Services{}
   584  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
   585  		ms.On("CreateOrUpdateStatefulSet", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
   586  			ss := args.Get(1).(*appsv1.StatefulSet)
   587  			gotCommands = ss.Spec.Template.Spec.Containers[0].Command
   588  		}).Return(nil)
   589  
   590  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
   591  		err := client.EnsureRedisStatefulset(rf, nil, []metav1.OwnerReference{})
   592  
   593  		assert.Equal(test.expectedCommands, gotCommands)
   594  		assert.NoError(err)
   595  	}
   596  }
   597  
   598  func TestSentinelDeploymentCommands(t *testing.T) {
   599  	tests := []struct {
   600  		name             string
   601  		givenCommands    []string
   602  		expectedCommands []string
   603  	}{
   604  		{
   605  			name:          "Default values",
   606  			givenCommands: []string{},
   607  			expectedCommands: []string{
   608  				"redis-server",
   609  				"/redis/sentinel.conf",
   610  				"--sentinel",
   611  			},
   612  		},
   613  		{
   614  			name: "Given commands should be used in sentinel container",
   615  			givenCommands: []string{
   616  				"test",
   617  				"command",
   618  			},
   619  			expectedCommands: []string{
   620  				"test",
   621  				"command",
   622  			},
   623  		},
   624  	}
   625  
   626  	for _, test := range tests {
   627  		assert := assert.New(t)
   628  
   629  		// Generate a default RedisFailover and attaching the required storage
   630  		rf := generateRF()
   631  		rf.Spec.Sentinel.Command = test.givenCommands
   632  
   633  		gotCommands := []string{}
   634  
   635  		ms := &mK8SService.Services{}
   636  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
   637  		ms.On("CreateOrUpdateDeployment", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
   638  			d := args.Get(1).(*appsv1.Deployment)
   639  			gotCommands = d.Spec.Template.Spec.Containers[0].Command
   640  		}).Return(nil)
   641  
   642  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
   643  		err := client.EnsureSentinelDeployment(rf, nil, []metav1.OwnerReference{})
   644  
   645  		assert.Equal(test.expectedCommands, gotCommands)
   646  		assert.NoError(err)
   647  	}
   648  }
   649  
   650  func TestRedisStatefulSetPodAnnotations(t *testing.T) {
   651  	tests := []struct {
   652  		name                   string
   653  		givenPodAnnotations    map[string]string
   654  		expectedPodAnnotations map[string]string
   655  	}{
   656  		{
   657  			name:                   "PodAnnotations was not defined",
   658  			givenPodAnnotations:    nil,
   659  			expectedPodAnnotations: nil,
   660  		},
   661  		{
   662  			name: "PodAnnotations is defined",
   663  			givenPodAnnotations: map[string]string{
   664  				"some":               "annotation",
   665  				"path/to/annotation": "here",
   666  			},
   667  			expectedPodAnnotations: map[string]string{
   668  				"some":               "annotation",
   669  				"path/to/annotation": "here",
   670  			},
   671  		},
   672  	}
   673  
   674  	for _, test := range tests {
   675  		assert := assert.New(t)
   676  
   677  		// Generate a default RedisFailover and attaching the required annotations
   678  		rf := generateRF()
   679  		rf.Spec.Redis.PodAnnotations = test.givenPodAnnotations
   680  
   681  		gotPodAnnotations := map[string]string{}
   682  
   683  		ms := &mK8SService.Services{}
   684  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
   685  		ms.On("CreateOrUpdateStatefulSet", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
   686  			ss := args.Get(1).(*appsv1.StatefulSet)
   687  			gotPodAnnotations = ss.Spec.Template.ObjectMeta.Annotations
   688  		}).Return(nil)
   689  
   690  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
   691  		err := client.EnsureRedisStatefulset(rf, nil, []metav1.OwnerReference{})
   692  
   693  		assert.Equal(test.expectedPodAnnotations, gotPodAnnotations)
   694  		assert.NoError(err)
   695  	}
   696  }
   697  
   698  func TestSentinelDeploymentPodAnnotations(t *testing.T) {
   699  	tests := []struct {
   700  		name                   string
   701  		givenPodAnnotations    map[string]string
   702  		expectedPodAnnotations map[string]string
   703  	}{
   704  		{
   705  			name:                   "PodAnnotations was not defined",
   706  			givenPodAnnotations:    nil,
   707  			expectedPodAnnotations: nil,
   708  		},
   709  		{
   710  			name: "PodAnnotations is defined",
   711  			givenPodAnnotations: map[string]string{
   712  				"some":               "annotation",
   713  				"path/to/annotation": "here",
   714  			},
   715  			expectedPodAnnotations: map[string]string{
   716  				"some":               "annotation",
   717  				"path/to/annotation": "here",
   718  			},
   719  		},
   720  	}
   721  
   722  	for _, test := range tests {
   723  		assert := assert.New(t)
   724  
   725  		// Generate a default RedisFailover and attaching the required annotations
   726  		rf := generateRF()
   727  		rf.Spec.Sentinel.PodAnnotations = test.givenPodAnnotations
   728  
   729  		gotPodAnnotations := map[string]string{}
   730  
   731  		ms := &mK8SService.Services{}
   732  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
   733  		ms.On("CreateOrUpdateDeployment", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
   734  			d := args.Get(1).(*appsv1.Deployment)
   735  			gotPodAnnotations = d.Spec.Template.ObjectMeta.Annotations
   736  		}).Return(nil)
   737  
   738  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
   739  		err := client.EnsureSentinelDeployment(rf, nil, []metav1.OwnerReference{})
   740  
   741  		assert.Equal(test.expectedPodAnnotations, gotPodAnnotations)
   742  		assert.NoError(err)
   743  	}
   744  }
   745  
   746  func TestRedisStatefulSetServiceAccountName(t *testing.T) {
   747  	tests := []struct {
   748  		name                       string
   749  		givenServiceAccountName    string
   750  		expectedServiceAccountName string
   751  	}{
   752  		{
   753  			name:                       "ServiceAccountName was not defined",
   754  			givenServiceAccountName:    "",
   755  			expectedServiceAccountName: "",
   756  		},
   757  		{
   758  			name:                       "ServiceAccountName is defined",
   759  			givenServiceAccountName:    "redis-sa",
   760  			expectedServiceAccountName: "redis-sa",
   761  		},
   762  	}
   763  
   764  	for _, test := range tests {
   765  		assert := assert.New(t)
   766  
   767  		// Generate a default RedisFailover and attaching the required Service Account
   768  		rf := generateRF()
   769  		rf.Spec.Redis.ServiceAccountName = test.givenServiceAccountName
   770  
   771  		gotServiceAccountName := ""
   772  
   773  		ms := &mK8SService.Services{}
   774  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
   775  		ms.On("CreateOrUpdateStatefulSet", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
   776  			ss := args.Get(1).(*appsv1.StatefulSet)
   777  			gotServiceAccountName = ss.Spec.Template.Spec.ServiceAccountName
   778  		}).Return(nil)
   779  
   780  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
   781  		err := client.EnsureRedisStatefulset(rf, nil, []metav1.OwnerReference{})
   782  
   783  		assert.Equal(test.expectedServiceAccountName, gotServiceAccountName)
   784  		assert.NoError(err)
   785  	}
   786  }
   787  
   788  func TestSentinelDeploymentServiceAccountName(t *testing.T) {
   789  	tests := []struct {
   790  		name                       string
   791  		givenServiceAccountName    string
   792  		expectedServiceAccountName string
   793  	}{
   794  		{
   795  			name:                       "ServiceAccountName was not defined",
   796  			givenServiceAccountName:    "",
   797  			expectedServiceAccountName: "",
   798  		},
   799  		{
   800  			name:                       "ServiceAccountName is defined",
   801  			givenServiceAccountName:    "sentinel-sa",
   802  			expectedServiceAccountName: "sentinel-sa",
   803  		},
   804  	}
   805  
   806  	for _, test := range tests {
   807  		assert := assert.New(t)
   808  
   809  		// Generate a default RedisFailover and attaching the required Service Account
   810  		rf := generateRF()
   811  		rf.Spec.Sentinel.ServiceAccountName = test.givenServiceAccountName
   812  
   813  		gotServiceAccountName := ""
   814  
   815  		ms := &mK8SService.Services{}
   816  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
   817  		ms.On("CreateOrUpdateDeployment", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
   818  			d := args.Get(1).(*appsv1.Deployment)
   819  			gotServiceAccountName = d.Spec.Template.Spec.ServiceAccountName
   820  		}).Return(nil)
   821  
   822  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
   823  		err := client.EnsureSentinelDeployment(rf, nil, []metav1.OwnerReference{})
   824  
   825  		assert.Equal(test.expectedServiceAccountName, gotServiceAccountName)
   826  		assert.NoError(err)
   827  	}
   828  }
   829  
   830  func TestSentinelService(t *testing.T) {
   831  	tests := []struct {
   832  		name            string
   833  		rfName          string
   834  		rfNamespace     string
   835  		rfLabels        map[string]string
   836  		rfAnnotations   map[string]string
   837  		expectedService corev1.Service
   838  	}{
   839  		{
   840  			name: "with defaults",
   841  			expectedService: corev1.Service{
   842  				ObjectMeta: metav1.ObjectMeta{
   843  					Name:      sentinelName,
   844  					Namespace: namespace,
   845  					Labels: map[string]string{
   846  						"app.kubernetes.io/component": "sentinel",
   847  						"app.kubernetes.io/name":      name,
   848  						"app.kubernetes.io/part-of":   "redis-failover",
   849  					},
   850  					OwnerReferences: []metav1.OwnerReference{
   851  						{
   852  							Name: "testing",
   853  						},
   854  					},
   855  				},
   856  				Spec: corev1.ServiceSpec{
   857  					Selector: map[string]string{
   858  						"app.kubernetes.io/component": "sentinel",
   859  						"app.kubernetes.io/name":      name,
   860  						"app.kubernetes.io/part-of":   "redis-failover",
   861  					},
   862  					Ports: []corev1.ServicePort{
   863  						{
   864  							Name:       "sentinel",
   865  							Port:       26379,
   866  							TargetPort: intstr.FromInt(26379),
   867  							Protocol:   "TCP",
   868  						},
   869  					},
   870  				},
   871  			},
   872  		},
   873  		{
   874  			name:   "with Name provided",
   875  			rfName: "custom-name",
   876  			expectedService: corev1.Service{
   877  				ObjectMeta: metav1.ObjectMeta{
   878  					Name:      "rfs-custom-name",
   879  					Namespace: namespace,
   880  					Labels: map[string]string{
   881  						"app.kubernetes.io/component": "sentinel",
   882  						"app.kubernetes.io/name":      "custom-name",
   883  						"app.kubernetes.io/part-of":   "redis-failover",
   884  					},
   885  					OwnerReferences: []metav1.OwnerReference{
   886  						{
   887  							Name: "testing",
   888  						},
   889  					},
   890  				},
   891  				Spec: corev1.ServiceSpec{
   892  					Selector: map[string]string{
   893  						"app.kubernetes.io/component": "sentinel",
   894  						"app.kubernetes.io/name":      "custom-name",
   895  						"app.kubernetes.io/part-of":   "redis-failover",
   896  					},
   897  					Ports: []corev1.ServicePort{
   898  						{
   899  							Name:       "sentinel",
   900  							Port:       26379,
   901  							TargetPort: intstr.FromInt(26379),
   902  							Protocol:   "TCP",
   903  						},
   904  					},
   905  				},
   906  			},
   907  		},
   908  		{
   909  			name:        "with Namespace provided",
   910  			rfNamespace: "custom-namespace",
   911  			expectedService: corev1.Service{
   912  				ObjectMeta: metav1.ObjectMeta{
   913  					Name:      sentinelName,
   914  					Namespace: "custom-namespace",
   915  					Labels: map[string]string{
   916  						"app.kubernetes.io/component": "sentinel",
   917  						"app.kubernetes.io/name":      name,
   918  						"app.kubernetes.io/part-of":   "redis-failover",
   919  					},
   920  					OwnerReferences: []metav1.OwnerReference{
   921  						{
   922  							Name: "testing",
   923  						},
   924  					},
   925  				},
   926  				Spec: corev1.ServiceSpec{
   927  					Selector: map[string]string{
   928  						"app.kubernetes.io/component": "sentinel",
   929  						"app.kubernetes.io/name":      name,
   930  						"app.kubernetes.io/part-of":   "redis-failover",
   931  					},
   932  					Ports: []corev1.ServicePort{
   933  						{
   934  							Name:       "sentinel",
   935  							Port:       26379,
   936  							TargetPort: intstr.FromInt(26379),
   937  							Protocol:   "TCP",
   938  						},
   939  					},
   940  				},
   941  			},
   942  		},
   943  		{
   944  			name:     "with Labels provided",
   945  			rfLabels: map[string]string{"some": "label"},
   946  			expectedService: corev1.Service{
   947  				ObjectMeta: metav1.ObjectMeta{
   948  					Name:      sentinelName,
   949  					Namespace: namespace,
   950  					Labels: map[string]string{
   951  						"app.kubernetes.io/component": "sentinel",
   952  						"app.kubernetes.io/name":      name,
   953  						"app.kubernetes.io/part-of":   "redis-failover",
   954  						"some":                        "label",
   955  					},
   956  					OwnerReferences: []metav1.OwnerReference{
   957  						{
   958  							Name: "testing",
   959  						},
   960  					},
   961  				},
   962  				Spec: corev1.ServiceSpec{
   963  					Selector: map[string]string{
   964  						"app.kubernetes.io/component": "sentinel",
   965  						"app.kubernetes.io/name":      name,
   966  						"app.kubernetes.io/part-of":   "redis-failover",
   967  					},
   968  					Ports: []corev1.ServicePort{
   969  						{
   970  							Name:       "sentinel",
   971  							Port:       26379,
   972  							TargetPort: intstr.FromInt(26379),
   973  							Protocol:   "TCP",
   974  						},
   975  					},
   976  				},
   977  			},
   978  		},
   979  		{
   980  			name:          "with Annotations provided",
   981  			rfAnnotations: map[string]string{"some": "annotation"},
   982  			expectedService: corev1.Service{
   983  				ObjectMeta: metav1.ObjectMeta{
   984  					Name:      sentinelName,
   985  					Namespace: namespace,
   986  					Labels: map[string]string{
   987  						"app.kubernetes.io/component": "sentinel",
   988  						"app.kubernetes.io/name":      name,
   989  						"app.kubernetes.io/part-of":   "redis-failover",
   990  					},
   991  					Annotations: map[string]string{"some": "annotation"},
   992  					OwnerReferences: []metav1.OwnerReference{
   993  						{
   994  							Name: "testing",
   995  						},
   996  					},
   997  				},
   998  				Spec: corev1.ServiceSpec{
   999  					Selector: map[string]string{
  1000  						"app.kubernetes.io/component": "sentinel",
  1001  						"app.kubernetes.io/name":      name,
  1002  						"app.kubernetes.io/part-of":   "redis-failover",
  1003  					},
  1004  					Ports: []corev1.ServicePort{
  1005  						{
  1006  							Name:       "sentinel",
  1007  							Port:       26379,
  1008  							TargetPort: intstr.FromInt(26379),
  1009  							Protocol:   "TCP",
  1010  						},
  1011  					},
  1012  				},
  1013  			},
  1014  		},
  1015  	}
  1016  
  1017  	for _, test := range tests {
  1018  		t.Run(test.name, func(t *testing.T) {
  1019  			assert := assert.New(t)
  1020  
  1021  			// Generate a default RedisFailover and attaching the required annotations
  1022  			rf := generateRF()
  1023  			if test.rfName != "" {
  1024  				rf.Name = test.rfName
  1025  			}
  1026  			if test.rfNamespace != "" {
  1027  				rf.Namespace = test.rfNamespace
  1028  			}
  1029  			rf.Spec.Sentinel.ServiceAnnotations = test.rfAnnotations
  1030  
  1031  			generatedService := corev1.Service{}
  1032  
  1033  			ms := &mK8SService.Services{}
  1034  			ms.On("CreateOrUpdateService", rf.Namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
  1035  				s := args.Get(1).(*corev1.Service)
  1036  				generatedService = *s
  1037  			}).Return(nil)
  1038  
  1039  			client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
  1040  			err := client.EnsureSentinelService(rf, test.rfLabels, []metav1.OwnerReference{{Name: "testing"}})
  1041  
  1042  			assert.Equal(test.expectedService, generatedService)
  1043  			assert.NoError(err)
  1044  		})
  1045  	}
  1046  }
  1047  
  1048  func TestRedisService(t *testing.T) {
  1049  	tests := []struct {
  1050  		name            string
  1051  		rfName          string
  1052  		rfNamespace     string
  1053  		rfLabels        map[string]string
  1054  		rfAnnotations   map[string]string
  1055  		expectedService corev1.Service
  1056  	}{
  1057  		{
  1058  			name: "with defaults",
  1059  			expectedService: corev1.Service{
  1060  				ObjectMeta: metav1.ObjectMeta{
  1061  					Name:      redisName,
  1062  					Namespace: namespace,
  1063  					Labels: map[string]string{
  1064  						"app.kubernetes.io/component": "redis",
  1065  						"app.kubernetes.io/name":      name,
  1066  						"app.kubernetes.io/part-of":   "redis-failover",
  1067  					},
  1068  					Annotations: map[string]string{
  1069  						"prometheus.io/scrape": "true",
  1070  						"prometheus.io/path":   "/metrics",
  1071  						"prometheus.io/port":   "http",
  1072  					},
  1073  					OwnerReferences: []metav1.OwnerReference{
  1074  						{
  1075  							Name: "testing",
  1076  						},
  1077  					},
  1078  				},
  1079  				Spec: corev1.ServiceSpec{
  1080  					Type:      corev1.ServiceTypeClusterIP,
  1081  					ClusterIP: corev1.ClusterIPNone,
  1082  					Selector: map[string]string{
  1083  						"app.kubernetes.io/component": "redis",
  1084  						"app.kubernetes.io/name":      name,
  1085  						"app.kubernetes.io/part-of":   "redis-failover",
  1086  					},
  1087  					Ports: []corev1.ServicePort{
  1088  						{
  1089  							Name:     "http-metrics",
  1090  							Port:     9121,
  1091  							Protocol: corev1.ProtocolTCP,
  1092  						},
  1093  					},
  1094  				},
  1095  			},
  1096  		},
  1097  		{
  1098  			name:   "with Name provided",
  1099  			rfName: "custom-name",
  1100  			expectedService: corev1.Service{
  1101  				ObjectMeta: metav1.ObjectMeta{
  1102  					Name:      "rfr-custom-name",
  1103  					Namespace: namespace,
  1104  					Labels: map[string]string{
  1105  						"app.kubernetes.io/component": "redis",
  1106  						"app.kubernetes.io/name":      "custom-name",
  1107  						"app.kubernetes.io/part-of":   "redis-failover",
  1108  					},
  1109  					Annotations: map[string]string{
  1110  						"prometheus.io/scrape": "true",
  1111  						"prometheus.io/path":   "/metrics",
  1112  						"prometheus.io/port":   "http",
  1113  					},
  1114  					OwnerReferences: []metav1.OwnerReference{
  1115  						{
  1116  							Name: "testing",
  1117  						},
  1118  					},
  1119  				},
  1120  				Spec: corev1.ServiceSpec{
  1121  					Type:      corev1.ServiceTypeClusterIP,
  1122  					ClusterIP: corev1.ClusterIPNone,
  1123  					Selector: map[string]string{
  1124  						"app.kubernetes.io/component": "redis",
  1125  						"app.kubernetes.io/name":      "custom-name",
  1126  						"app.kubernetes.io/part-of":   "redis-failover",
  1127  					},
  1128  					Ports: []corev1.ServicePort{
  1129  						{
  1130  							Name:     "http-metrics",
  1131  							Port:     9121,
  1132  							Protocol: corev1.ProtocolTCP,
  1133  						},
  1134  					},
  1135  				},
  1136  			},
  1137  		},
  1138  		{
  1139  			name:        "with Namespace provided",
  1140  			rfNamespace: "custom-namespace",
  1141  			expectedService: corev1.Service{
  1142  				ObjectMeta: metav1.ObjectMeta{
  1143  					Name:      redisName,
  1144  					Namespace: "custom-namespace",
  1145  					Labels: map[string]string{
  1146  						"app.kubernetes.io/component": "redis",
  1147  						"app.kubernetes.io/name":      name,
  1148  						"app.kubernetes.io/part-of":   "redis-failover",
  1149  					},
  1150  					Annotations: map[string]string{
  1151  						"prometheus.io/scrape": "true",
  1152  						"prometheus.io/path":   "/metrics",
  1153  						"prometheus.io/port":   "http",
  1154  					},
  1155  					OwnerReferences: []metav1.OwnerReference{
  1156  						{
  1157  							Name: "testing",
  1158  						},
  1159  					},
  1160  				},
  1161  				Spec: corev1.ServiceSpec{
  1162  					Type:      corev1.ServiceTypeClusterIP,
  1163  					ClusterIP: corev1.ClusterIPNone,
  1164  					Selector: map[string]string{
  1165  						"app.kubernetes.io/component": "redis",
  1166  						"app.kubernetes.io/name":      name,
  1167  						"app.kubernetes.io/part-of":   "redis-failover",
  1168  					},
  1169  					Ports: []corev1.ServicePort{
  1170  						{
  1171  							Name:     "http-metrics",
  1172  							Port:     9121,
  1173  							Protocol: corev1.ProtocolTCP,
  1174  						},
  1175  					},
  1176  				},
  1177  			},
  1178  		},
  1179  		{
  1180  			name:     "with Labels provided",
  1181  			rfLabels: map[string]string{"some": "label"},
  1182  			expectedService: corev1.Service{
  1183  				ObjectMeta: metav1.ObjectMeta{
  1184  					Name:      redisName,
  1185  					Namespace: namespace,
  1186  					Labels: map[string]string{
  1187  						"app.kubernetes.io/component": "redis",
  1188  						"app.kubernetes.io/name":      name,
  1189  						"app.kubernetes.io/part-of":   "redis-failover",
  1190  						"some":                        "label",
  1191  					},
  1192  					Annotations: map[string]string{
  1193  						"prometheus.io/scrape": "true",
  1194  						"prometheus.io/path":   "/metrics",
  1195  						"prometheus.io/port":   "http",
  1196  					},
  1197  					OwnerReferences: []metav1.OwnerReference{
  1198  						{
  1199  							Name: "testing",
  1200  						},
  1201  					},
  1202  				},
  1203  				Spec: corev1.ServiceSpec{
  1204  					Type:      corev1.ServiceTypeClusterIP,
  1205  					ClusterIP: corev1.ClusterIPNone,
  1206  					Selector: map[string]string{
  1207  						"app.kubernetes.io/component": "redis",
  1208  						"app.kubernetes.io/name":      name,
  1209  						"app.kubernetes.io/part-of":   "redis-failover",
  1210  					},
  1211  					Ports: []corev1.ServicePort{
  1212  						{
  1213  							Name:     "http-metrics",
  1214  							Port:     9121,
  1215  							Protocol: corev1.ProtocolTCP,
  1216  						},
  1217  					},
  1218  				},
  1219  			},
  1220  		},
  1221  		{
  1222  			name:          "with Annotations provided",
  1223  			rfAnnotations: map[string]string{"some": "annotation"},
  1224  			expectedService: corev1.Service{
  1225  				ObjectMeta: metav1.ObjectMeta{
  1226  					Name:      redisName,
  1227  					Namespace: namespace,
  1228  					Labels: map[string]string{
  1229  						"app.kubernetes.io/component": "redis",
  1230  						"app.kubernetes.io/name":      name,
  1231  						"app.kubernetes.io/part-of":   "redis-failover",
  1232  					},
  1233  					Annotations: map[string]string{
  1234  						"prometheus.io/scrape": "true",
  1235  						"prometheus.io/path":   "/metrics",
  1236  						"prometheus.io/port":   "http",
  1237  						"some":                 "annotation",
  1238  					},
  1239  					OwnerReferences: []metav1.OwnerReference{
  1240  						{
  1241  							Name: "testing",
  1242  						},
  1243  					},
  1244  				},
  1245  				Spec: corev1.ServiceSpec{
  1246  					Type:      corev1.ServiceTypeClusterIP,
  1247  					ClusterIP: corev1.ClusterIPNone,
  1248  					Selector: map[string]string{
  1249  						"app.kubernetes.io/component": "redis",
  1250  						"app.kubernetes.io/name":      name,
  1251  						"app.kubernetes.io/part-of":   "redis-failover",
  1252  					},
  1253  					Ports: []corev1.ServicePort{
  1254  						{
  1255  							Name:     "http-metrics",
  1256  							Port:     9121,
  1257  							Protocol: corev1.ProtocolTCP,
  1258  						},
  1259  					},
  1260  				},
  1261  			},
  1262  		},
  1263  	}
  1264  
  1265  	for _, test := range tests {
  1266  		t.Run(test.name, func(t *testing.T) {
  1267  			assert := assert.New(t)
  1268  
  1269  			// Generate a default RedisFailover and attaching the required annotations
  1270  			rf := generateRF()
  1271  			if test.rfName != "" {
  1272  				rf.Name = test.rfName
  1273  			}
  1274  			if test.rfNamespace != "" {
  1275  				rf.Namespace = test.rfNamespace
  1276  			}
  1277  			rf.Spec.Redis.ServiceAnnotations = test.rfAnnotations
  1278  
  1279  			generatedService := corev1.Service{}
  1280  
  1281  			ms := &mK8SService.Services{}
  1282  			ms.On("CreateOrUpdateService", rf.Namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
  1283  				s := args.Get(1).(*corev1.Service)
  1284  				generatedService = *s
  1285  			}).Return(nil)
  1286  
  1287  			client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
  1288  			err := client.EnsureRedisService(rf, test.rfLabels, []metav1.OwnerReference{{Name: "testing"}})
  1289  
  1290  			assert.Equal(test.expectedService, generatedService)
  1291  			assert.NoError(err)
  1292  		})
  1293  	}
  1294  }
  1295  
  1296  func TestRedisHostNetworkAndDnsPolicy(t *testing.T) {
  1297  	tests := []struct {
  1298  		name                string
  1299  		hostNetwork         bool
  1300  		expectedHostNetwork bool
  1301  		dnsPolicy           corev1.DNSPolicy
  1302  		expectedDnsPolicy   corev1.DNSPolicy
  1303  	}{
  1304  		{
  1305  			name:                "Default",
  1306  			expectedHostNetwork: false,
  1307  			expectedDnsPolicy:   corev1.DNSClusterFirst,
  1308  		},
  1309  		{
  1310  			name:                "Custom",
  1311  			hostNetwork:         true,
  1312  			expectedHostNetwork: true,
  1313  			dnsPolicy:           corev1.DNSClusterFirstWithHostNet,
  1314  			expectedDnsPolicy:   corev1.DNSClusterFirstWithHostNet,
  1315  		},
  1316  	}
  1317  
  1318  	for _, test := range tests {
  1319  		assert := assert.New(t)
  1320  
  1321  		rf := generateRF()
  1322  		rf.Spec.Redis.HostNetwork = test.hostNetwork
  1323  		rf.Spec.Redis.DNSPolicy = test.dnsPolicy
  1324  
  1325  		var actualHostNetwork bool
  1326  		var actualDnsPolicy corev1.DNSPolicy
  1327  
  1328  		ms := &mK8SService.Services{}
  1329  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
  1330  		ms.On("CreateOrUpdateStatefulSet", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
  1331  			ss := args.Get(1).(*appsv1.StatefulSet)
  1332  			actualHostNetwork = ss.Spec.Template.Spec.HostNetwork
  1333  			actualDnsPolicy = ss.Spec.Template.Spec.DNSPolicy
  1334  		}).Return(nil)
  1335  
  1336  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
  1337  		err := client.EnsureRedisStatefulset(rf, nil, []metav1.OwnerReference{})
  1338  		assert.NoError(err)
  1339  
  1340  		assert.Equal(test.expectedHostNetwork, actualHostNetwork)
  1341  		assert.Equal(test.expectedDnsPolicy, actualDnsPolicy)
  1342  	}
  1343  }
  1344  
  1345  func TestSentinelHostNetworkAndDnsPolicy(t *testing.T) {
  1346  	tests := []struct {
  1347  		name                string
  1348  		hostNetwork         bool
  1349  		expectedHostNetwork bool
  1350  		dnsPolicy           corev1.DNSPolicy
  1351  		expectedDnsPolicy   corev1.DNSPolicy
  1352  	}{
  1353  		{
  1354  			name:                "Default",
  1355  			expectedHostNetwork: false,
  1356  			expectedDnsPolicy:   corev1.DNSClusterFirst,
  1357  		},
  1358  		{
  1359  			name:                "Custom",
  1360  			hostNetwork:         true,
  1361  			expectedHostNetwork: true,
  1362  			dnsPolicy:           corev1.DNSClusterFirstWithHostNet,
  1363  			expectedDnsPolicy:   corev1.DNSClusterFirstWithHostNet,
  1364  		},
  1365  	}
  1366  
  1367  	for _, test := range tests {
  1368  		assert := assert.New(t)
  1369  
  1370  		rf := generateRF()
  1371  		rf.Spec.Sentinel.HostNetwork = test.hostNetwork
  1372  		rf.Spec.Sentinel.DNSPolicy = test.dnsPolicy
  1373  
  1374  		var actualHostNetwork bool
  1375  		var actualDnsPolicy corev1.DNSPolicy
  1376  
  1377  		ms := &mK8SService.Services{}
  1378  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
  1379  		ms.On("CreateOrUpdateDeployment", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
  1380  			d := args.Get(1).(*appsv1.Deployment)
  1381  			actualHostNetwork = d.Spec.Template.Spec.HostNetwork
  1382  			actualDnsPolicy = d.Spec.Template.Spec.DNSPolicy
  1383  		}).Return(nil)
  1384  
  1385  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
  1386  		err := client.EnsureSentinelDeployment(rf, nil, []metav1.OwnerReference{})
  1387  		assert.NoError(err)
  1388  
  1389  		assert.Equal(test.expectedHostNetwork, actualHostNetwork)
  1390  		assert.Equal(test.expectedDnsPolicy, actualDnsPolicy)
  1391  	}
  1392  }
  1393  
  1394  func TestRedisImagePullPolicy(t *testing.T) {
  1395  	tests := []struct {
  1396  		name                   string
  1397  		policy                 corev1.PullPolicy
  1398  		exporterPolicy         corev1.PullPolicy
  1399  		expectedPolicy         corev1.PullPolicy
  1400  		expectedExporterPolicy corev1.PullPolicy
  1401  	}{
  1402  		{
  1403  			name:                   "Default",
  1404  			expectedPolicy:         corev1.PullAlways,
  1405  			expectedExporterPolicy: corev1.PullAlways,
  1406  		},
  1407  		{
  1408  			name:                   "Custom",
  1409  			policy:                 corev1.PullIfNotPresent,
  1410  			exporterPolicy:         corev1.PullNever,
  1411  			expectedPolicy:         corev1.PullIfNotPresent,
  1412  			expectedExporterPolicy: corev1.PullNever,
  1413  		},
  1414  	}
  1415  
  1416  	for _, test := range tests {
  1417  		assert := assert.New(t)
  1418  
  1419  		var policy corev1.PullPolicy
  1420  		var exporterPolicy corev1.PullPolicy
  1421  
  1422  		rf := generateRF()
  1423  		rf.Spec.Redis.ImagePullPolicy = test.policy
  1424  		rf.Spec.Redis.Exporter.Enabled = true
  1425  		rf.Spec.Redis.Exporter.ImagePullPolicy = test.expectedExporterPolicy
  1426  
  1427  		ms := &mK8SService.Services{}
  1428  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
  1429  		ms.On("CreateOrUpdateStatefulSet", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
  1430  			ss := args.Get(1).(*appsv1.StatefulSet)
  1431  			policy = ss.Spec.Template.Spec.Containers[0].ImagePullPolicy
  1432  			exporterPolicy = ss.Spec.Template.Spec.Containers[1].ImagePullPolicy
  1433  		}).Return(nil)
  1434  
  1435  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
  1436  		err := client.EnsureRedisStatefulset(rf, nil, []metav1.OwnerReference{})
  1437  
  1438  		assert.NoError(err)
  1439  		assert.Equal(string(test.expectedPolicy), string(policy))
  1440  		assert.Equal(string(test.expectedExporterPolicy), string(exporterPolicy))
  1441  	}
  1442  }
  1443  
  1444  func TestSentinelImagePullPolicy(t *testing.T) {
  1445  	tests := []struct {
  1446  		name                 string
  1447  		policy               corev1.PullPolicy
  1448  		expectedPolicy       corev1.PullPolicy
  1449  		expectedConfigPolicy corev1.PullPolicy
  1450  	}{
  1451  		{
  1452  			name:                 "Default",
  1453  			expectedPolicy:       corev1.PullAlways,
  1454  			expectedConfigPolicy: corev1.PullAlways,
  1455  		},
  1456  		{
  1457  			name:                 "Custom",
  1458  			policy:               corev1.PullIfNotPresent,
  1459  			expectedPolicy:       corev1.PullIfNotPresent,
  1460  			expectedConfigPolicy: corev1.PullIfNotPresent,
  1461  		},
  1462  	}
  1463  
  1464  	for _, test := range tests {
  1465  		assert := assert.New(t)
  1466  
  1467  		var policy corev1.PullPolicy
  1468  		var configPolicy corev1.PullPolicy
  1469  
  1470  		rf := generateRF()
  1471  		rf.Spec.Sentinel.ImagePullPolicy = test.policy
  1472  
  1473  		ms := &mK8SService.Services{}
  1474  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
  1475  		ms.On("CreateOrUpdateDeployment", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
  1476  			d := args.Get(1).(*appsv1.Deployment)
  1477  			policy = d.Spec.Template.Spec.Containers[0].ImagePullPolicy
  1478  			configPolicy = d.Spec.Template.Spec.InitContainers[0].ImagePullPolicy
  1479  		}).Return(nil)
  1480  
  1481  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
  1482  		err := client.EnsureSentinelDeployment(rf, nil, []metav1.OwnerReference{})
  1483  
  1484  		assert.NoError(err)
  1485  		assert.Equal(string(test.expectedPolicy), string(policy))
  1486  		assert.Equal(string(test.expectedConfigPolicy), string(configPolicy))
  1487  	}
  1488  }
  1489  
  1490  func TestRedisExtraVolumeMounts(t *testing.T) {
  1491  	mode := int32(755)
  1492  	tests := []struct {
  1493  		name                 string
  1494  		expectedVolumes      []corev1.Volume
  1495  		expectedVolumeMounts []corev1.VolumeMount
  1496  	}{
  1497  		{
  1498  			name: "EmptyDir",
  1499  			expectedVolumes: []corev1.Volume{
  1500  				{
  1501  					Name: "foo",
  1502  					VolumeSource: corev1.VolumeSource{
  1503  						EmptyDir: &corev1.EmptyDirVolumeSource{},
  1504  					},
  1505  				},
  1506  			},
  1507  			expectedVolumeMounts: []corev1.VolumeMount{
  1508  				{
  1509  					Name:      "foo",
  1510  					MountPath: "/mnt/foo",
  1511  				},
  1512  			},
  1513  		},
  1514  		{
  1515  			name: "ConfigMap",
  1516  			expectedVolumes: []corev1.Volume{
  1517  				{
  1518  					Name: "bar",
  1519  					VolumeSource: corev1.VolumeSource{
  1520  						ConfigMap: &corev1.ConfigMapVolumeSource{
  1521  							LocalObjectReference: corev1.LocalObjectReference{
  1522  								Name: "bar-cm",
  1523  							},
  1524  							DefaultMode: &mode,
  1525  						},
  1526  					},
  1527  				},
  1528  			},
  1529  			expectedVolumeMounts: []corev1.VolumeMount{
  1530  				{
  1531  					Name:      "bar",
  1532  					MountPath: "/mnt/scripts",
  1533  				},
  1534  			},
  1535  		},
  1536  	}
  1537  
  1538  	for _, test := range tests {
  1539  		assert := assert.New(t)
  1540  
  1541  		var extraVolume corev1.Volume
  1542  		var extraVolumeMount corev1.VolumeMount
  1543  
  1544  		rf := generateRF()
  1545  		rf.Spec.Redis.ExtraVolumes = test.expectedVolumes
  1546  		rf.Spec.Redis.ExtraVolumeMounts = test.expectedVolumeMounts
  1547  
  1548  		ms := &mK8SService.Services{}
  1549  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
  1550  		ms.On("CreateOrUpdateStatefulSet", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
  1551  			s := args.Get(1).(*appsv1.StatefulSet)
  1552  			extraVolume = s.Spec.Template.Spec.Volumes[3]
  1553  			extraVolumeMount = s.Spec.Template.Spec.Containers[0].VolumeMounts[4]
  1554  		}).Return(nil)
  1555  
  1556  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
  1557  		err := client.EnsureRedisStatefulset(rf, nil, []metav1.OwnerReference{})
  1558  
  1559  		assert.NoError(err)
  1560  		assert.Equal(test.expectedVolumes[0], extraVolume)
  1561  		assert.Equal(test.expectedVolumeMounts[0], extraVolumeMount)
  1562  	}
  1563  }
  1564  
  1565  func TestSentinelExtraVolumeMounts(t *testing.T) {
  1566  	mode := int32(755)
  1567  	tests := []struct {
  1568  		name                 string
  1569  		expectedVolumes      []corev1.Volume
  1570  		expectedVolumeMounts []corev1.VolumeMount
  1571  	}{
  1572  		{
  1573  			name: "EmptyDir",
  1574  			expectedVolumes: []corev1.Volume{
  1575  				{
  1576  					Name: "foo",
  1577  					VolumeSource: corev1.VolumeSource{
  1578  						EmptyDir: &corev1.EmptyDirVolumeSource{},
  1579  					},
  1580  				},
  1581  			},
  1582  			expectedVolumeMounts: []corev1.VolumeMount{
  1583  				{
  1584  					Name:      "foo",
  1585  					MountPath: "/mnt/foo",
  1586  				},
  1587  			},
  1588  		},
  1589  		{
  1590  			name: "ConfigMap",
  1591  			expectedVolumes: []corev1.Volume{
  1592  				{
  1593  					Name: "bar",
  1594  					VolumeSource: corev1.VolumeSource{
  1595  						ConfigMap: &corev1.ConfigMapVolumeSource{
  1596  							LocalObjectReference: corev1.LocalObjectReference{
  1597  								Name: "bar-cm",
  1598  							},
  1599  							DefaultMode: &mode,
  1600  						},
  1601  					},
  1602  				},
  1603  			},
  1604  			expectedVolumeMounts: []corev1.VolumeMount{
  1605  				{
  1606  					Name:      "bar",
  1607  					MountPath: "/mnt/scripts",
  1608  				},
  1609  			},
  1610  		},
  1611  	}
  1612  
  1613  	for _, test := range tests {
  1614  		assert := assert.New(t)
  1615  
  1616  		var extraVolume corev1.Volume
  1617  		var extraVolumeMount corev1.VolumeMount
  1618  
  1619  		rf := generateRF()
  1620  		rf.Spec.Sentinel.ExtraVolumes = test.expectedVolumes
  1621  		rf.Spec.Sentinel.ExtraVolumeMounts = test.expectedVolumeMounts
  1622  
  1623  		ms := &mK8SService.Services{}
  1624  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
  1625  		ms.On("CreateOrUpdateDeployment", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
  1626  			d := args.Get(1).(*appsv1.Deployment)
  1627  			extraVolume = d.Spec.Template.Spec.Volumes[2]
  1628  			extraVolumeMount = d.Spec.Template.Spec.Containers[0].VolumeMounts[1]
  1629  		}).Return(nil)
  1630  
  1631  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
  1632  		err := client.EnsureSentinelDeployment(rf, nil, []metav1.OwnerReference{})
  1633  
  1634  		assert.NoError(err)
  1635  		assert.Equal(test.expectedVolumes[0], extraVolume)
  1636  		assert.Equal(test.expectedVolumeMounts[0], extraVolumeMount)
  1637  	}
  1638  }
  1639  
  1640  func TestCustomPort(t *testing.T) {
  1641  	default_port := int32(6379)
  1642  	custom_port := int32(12345)
  1643  	tests := []struct {
  1644  		name                  string
  1645  		port                  int32
  1646  		expectedContainerPort []corev1.ContainerPort
  1647  	}{
  1648  		{
  1649  			name: "Default port",
  1650  			port: default_port,
  1651  			expectedContainerPort: []corev1.ContainerPort{
  1652  				{
  1653  					Name:          "redis",
  1654  					ContainerPort: default_port,
  1655  					Protocol:      corev1.ProtocolTCP,
  1656  				},
  1657  			},
  1658  		},
  1659  		{
  1660  			name: "Custom port",
  1661  			port: custom_port,
  1662  			expectedContainerPort: []corev1.ContainerPort{
  1663  				{
  1664  					Name:          "redis",
  1665  					ContainerPort: custom_port,
  1666  					Protocol:      corev1.ProtocolTCP,
  1667  				},
  1668  			},
  1669  		},
  1670  	}
  1671  
  1672  	for _, test := range tests {
  1673  		assert := assert.New(t)
  1674  
  1675  		var port corev1.ContainerPort
  1676  
  1677  		rf := generateRF()
  1678  		rf.Spec.Redis.Port = test.port
  1679  
  1680  		ms := &mK8SService.Services{}
  1681  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
  1682  		ms.On("CreateOrUpdateStatefulSet", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
  1683  			s := args.Get(1).(*appsv1.StatefulSet)
  1684  			port = s.Spec.Template.Spec.Containers[0].Ports[0]
  1685  		}).Return(nil)
  1686  
  1687  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
  1688  		err := client.EnsureRedisStatefulset(rf, nil, []metav1.OwnerReference{})
  1689  
  1690  		assert.NoError(err)
  1691  		assert.Equal(test.expectedContainerPort[0], port)
  1692  	}
  1693  }
  1694  
  1695  func TestRedisEnv(t *testing.T) {
  1696  	default_port := int32(6379)
  1697  	tests := []struct {
  1698  		name             string
  1699  		auth             string
  1700  		expectedRedisEnv []corev1.EnvVar
  1701  	}{
  1702  		{
  1703  			name: "without auth",
  1704  			auth: "",
  1705  			expectedRedisEnv: []corev1.EnvVar{
  1706  				{
  1707  					Name:  "REDIS_ADDR",
  1708  					Value: fmt.Sprintf("redis://127.0.0.1:%[1]v", default_port),
  1709  				},
  1710  				{
  1711  					Name:  "REDIS_PORT",
  1712  					Value: fmt.Sprintf("%[1]v", default_port),
  1713  				},
  1714  				{
  1715  					Name:  "REDIS_USER",
  1716  					Value: "default",
  1717  				},
  1718  			},
  1719  		},
  1720  		{
  1721  			name: "with auth",
  1722  			auth: "redis-secret",
  1723  			expectedRedisEnv: []corev1.EnvVar{
  1724  				{
  1725  					Name:  "REDIS_ADDR",
  1726  					Value: fmt.Sprintf("redis://127.0.0.1:%[1]v", default_port),
  1727  				},
  1728  				{
  1729  					Name:  "REDIS_PORT",
  1730  					Value: fmt.Sprintf("%[1]v", default_port),
  1731  				},
  1732  				{
  1733  					Name:  "REDIS_USER",
  1734  					Value: "default",
  1735  				},
  1736  				{
  1737  					Name: "REDIS_PASSWORD",
  1738  					ValueFrom: &corev1.EnvVarSource{
  1739  						SecretKeyRef: &corev1.SecretKeySelector{
  1740  							LocalObjectReference: corev1.LocalObjectReference{
  1741  								Name: "redis-secret",
  1742  							},
  1743  							Key: "password",
  1744  						},
  1745  					},
  1746  				},
  1747  			},
  1748  		},
  1749  	}
  1750  
  1751  	for _, test := range tests {
  1752  		assert := assert.New(t)
  1753  
  1754  		var env []corev1.EnvVar
  1755  
  1756  		rf := generateRF()
  1757  		rf.Spec.Redis.Port = default_port
  1758  		if test.auth != "" {
  1759  			rf.Spec.Auth.SecretPath = test.auth
  1760  		}
  1761  
  1762  		ms := &mK8SService.Services{}
  1763  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
  1764  		ms.On("CreateOrUpdateStatefulSet", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
  1765  			s := args.Get(1).(*appsv1.StatefulSet)
  1766  			env = s.Spec.Template.Spec.Containers[0].Env
  1767  		}).Return(nil)
  1768  
  1769  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
  1770  		err := client.EnsureRedisStatefulset(rf, nil, []metav1.OwnerReference{})
  1771  
  1772  		assert.NoError(err)
  1773  		assert.Equal(test.expectedRedisEnv, env)
  1774  	}
  1775  }
  1776  
  1777  func TestRedisStartupProbe(t *testing.T) {
  1778  	mode := int32(0744)
  1779  	tests := []struct {
  1780  		name                string
  1781  		expectedVolume      corev1.Volume
  1782  		expectedVolumeMount corev1.VolumeMount
  1783  	}{
  1784  		{
  1785  			name: "startup_config",
  1786  			expectedVolume: corev1.Volume{
  1787  				Name: "redis-startup-config",
  1788  				VolumeSource: corev1.VolumeSource{
  1789  					ConfigMap: &corev1.ConfigMapVolumeSource{
  1790  						LocalObjectReference: corev1.LocalObjectReference{
  1791  							Name: "startup_config",
  1792  						},
  1793  						DefaultMode: &mode,
  1794  					},
  1795  				},
  1796  			},
  1797  			expectedVolumeMount: corev1.VolumeMount{
  1798  				Name:      "redis-startup-config",
  1799  				MountPath: "/redis-startup",
  1800  			},
  1801  		},
  1802  	}
  1803  
  1804  	for _, test := range tests {
  1805  		assert := assert.New(t)
  1806  
  1807  		var startupVolumes []corev1.Volume
  1808  		var startupVolumeMounts []corev1.VolumeMount
  1809  
  1810  		rf := generateRF()
  1811  		rf.Spec.Redis.StartupConfigMap = test.name
  1812  
  1813  		ms := &mK8SService.Services{}
  1814  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
  1815  		ms.On("CreateOrUpdateStatefulSet", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
  1816  			s := args.Get(1).(*appsv1.StatefulSet)
  1817  			startupVolumes = s.Spec.Template.Spec.Volumes
  1818  			startupVolumeMounts = s.Spec.Template.Spec.Containers[0].VolumeMounts
  1819  		}).Return(nil)
  1820  
  1821  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
  1822  		err := client.EnsureRedisStatefulset(rf, nil, []metav1.OwnerReference{})
  1823  
  1824  		assert.NoError(err)
  1825  		assert.Contains(startupVolumes, test.expectedVolume)
  1826  		assert.Contains(startupVolumeMounts, test.expectedVolumeMount)
  1827  	}
  1828  }
  1829  
  1830  func TestSentinelStartupProbe(t *testing.T) {
  1831  	mode := int32(0744)
  1832  	tests := []struct {
  1833  		name                string
  1834  		expectedVolume      corev1.Volume
  1835  		expectedVolumeMount corev1.VolumeMount
  1836  	}{
  1837  		{
  1838  			name: "startup_config",
  1839  			expectedVolume: corev1.Volume{
  1840  				Name: "sentinel-startup-config",
  1841  				VolumeSource: corev1.VolumeSource{
  1842  					ConfigMap: &corev1.ConfigMapVolumeSource{
  1843  						LocalObjectReference: corev1.LocalObjectReference{
  1844  							Name: "startup_config",
  1845  						},
  1846  						DefaultMode: &mode,
  1847  					},
  1848  				},
  1849  			},
  1850  			expectedVolumeMount: corev1.VolumeMount{
  1851  				Name:      "sentinel-startup-config",
  1852  				MountPath: "/sentinel-startup",
  1853  			},
  1854  		},
  1855  	}
  1856  
  1857  	for _, test := range tests {
  1858  		assert := assert.New(t)
  1859  
  1860  		var startupVolumes []corev1.Volume
  1861  		var startupVolumeMounts []corev1.VolumeMount
  1862  
  1863  		rf := generateRF()
  1864  		rf.Spec.Sentinel.StartupConfigMap = test.name
  1865  
  1866  		ms := &mK8SService.Services{}
  1867  		ms.On("CreateOrUpdatePodDisruptionBudget", namespace, mock.Anything).Once().Return(nil, nil)
  1868  		ms.On("CreateOrUpdateDeployment", namespace, mock.Anything).Once().Run(func(args mock.Arguments) {
  1869  			d := args.Get(1).(*appsv1.Deployment)
  1870  			startupVolumes = d.Spec.Template.Spec.Volumes
  1871  			startupVolumeMounts = d.Spec.Template.Spec.Containers[0].VolumeMounts
  1872  		}).Return(nil)
  1873  
  1874  		client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy)
  1875  		err := client.EnsureSentinelDeployment(rf, nil, []metav1.OwnerReference{})
  1876  
  1877  		assert.NoError(err)
  1878  		assert.Contains(startupVolumes, test.expectedVolume)
  1879  		assert.Contains(startupVolumeMounts, test.expectedVolumeMount)
  1880  	}
  1881  }