package canary import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1" ) func TestDaemonSetController_Sync(t *testing.T) { mocks := newDaemonSetFixture() err := mocks.controller.Initialize(mocks.canary, true) require.NoError(t, err) daePrimary, err := mocks.kubeClient.AppsV1().DaemonSets("default").Get("podinfo-primary", metav1.GetOptions{}) require.NoError(t, err) dae := newDaemonSetControllerTestPodInfo() primaryImage := daePrimary.Spec.Template.Spec.Containers[0].Image sourceImage := dae.Spec.Template.Spec.Containers[0].Image assert.Equal(t, primaryImage, sourceImage) } func TestDaemonSetController_Promote(t *testing.T) { mocks := newDaemonSetFixture() err := mocks.controller.Initialize(mocks.canary, true) require.NoError(t, err) dae2 := newDaemonSetControllerTestPodInfoV2() _, err = mocks.kubeClient.AppsV1().DaemonSets("default").Update(dae2) require.NoError(t, err) config2 := newDaemonSetControllerTestConfigMapV2() _, err = mocks.kubeClient.CoreV1().ConfigMaps("default").Update(config2) require.NoError(t, err) err = mocks.controller.Promote(mocks.canary) require.NoError(t, err) daePrimary, err := mocks.kubeClient.AppsV1().DaemonSets("default").Get("podinfo-primary", metav1.GetOptions{}) require.NoError(t, err) primaryImage := daePrimary.Spec.Template.Spec.Containers[0].Image sourceImage := dae2.Spec.Template.Spec.Containers[0].Image assert.Equal(t, primaryImage, sourceImage) configPrimary, err := mocks.kubeClient.CoreV1().ConfigMaps("default").Get("podinfo-config-env-primary", metav1.GetOptions{}) if assert.NoError(t, err) { assert.Equal(t, configPrimary.Data["color"], config2.Data["color"]) } } func TestDaemonSetController_NoConfigTracking(t *testing.T) { mocks := newDaemonSetFixture() mocks.controller.configTracker = &NopTracker{} err := mocks.controller.Initialize(mocks.canary, true) require.NoError(t, err) daePrimary, err := mocks.kubeClient.AppsV1().DaemonSets("default").Get("podinfo-primary", metav1.GetOptions{}) require.NoError(t, err) _, err = mocks.kubeClient.CoreV1().ConfigMaps("default").Get("podinfo-config-env-primary", metav1.GetOptions{}) require.True(t, errors.IsNotFound(err), "Primary ConfigMap shouldn't have been created") configName := daePrimary.Spec.Template.Spec.Volumes[0].VolumeSource.ConfigMap.LocalObjectReference.Name assert.Equal(t, "podinfo-config-vol", configName) } func TestDaemonSetController_HasTargetChanged(t *testing.T) { mocks := newDaemonSetFixture() err := mocks.controller.Initialize(mocks.canary, true) require.NoError(t, err) // save last applied hash canary, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{}) require.NoError(t, err) err = mocks.controller.SyncStatus(canary, flaggerv1.CanaryStatus{Phase: flaggerv1.CanaryPhaseInitializing}) require.NoError(t, err) // save last promoted hash canary, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{}) require.NoError(t, err) err = mocks.controller.SetStatusPhase(canary, flaggerv1.CanaryPhaseInitialized) require.NoError(t, err) dep, err := mocks.kubeClient.AppsV1().DaemonSets("default").Get("podinfo", metav1.GetOptions{}) require.NoError(t, err) depClone := dep.DeepCopy() depClone.Spec.Template.Spec.Containers[0].Resources = corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceCPU: *resource.NewQuantity(100, resource.DecimalExponent), }, } // update pod spec _, err = mocks.kubeClient.AppsV1().DaemonSets("default").Update(depClone) require.NoError(t, err) canary, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{}) require.NoError(t, err) // detect change in last applied spec isNew, err := mocks.controller.HasTargetChanged(canary) require.NoError(t, err) assert.True(t, isNew) // save hash err = mocks.controller.SyncStatus(canary, flaggerv1.CanaryStatus{Phase: flaggerv1.CanaryPhaseProgressing}) require.NoError(t, err) dep, err = mocks.kubeClient.AppsV1().DaemonSets("default").Get("podinfo", metav1.GetOptions{}) require.NoError(t, err) depClone = dep.DeepCopy() depClone.Spec.Template.Spec.Containers[0].Resources = corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceCPU: *resource.NewQuantity(1000, resource.DecimalExponent), }, } // update pod spec _, err = mocks.kubeClient.AppsV1().DaemonSets("default").Update(depClone) require.NoError(t, err) canary, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{}) require.NoError(t, err) // ignore change as hash should be the same with last promoted isNew, err = mocks.controller.HasTargetChanged(canary) require.NoError(t, err) assert.False(t, isNew) depClone = dep.DeepCopy() depClone.Spec.Template.Spec.Containers[0].Resources = corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceCPU: *resource.NewQuantity(600, resource.DecimalExponent), }, } // update pod spec _, err = mocks.kubeClient.AppsV1().DaemonSets("default").Update(depClone) require.NoError(t, err) canary, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{}) require.NoError(t, err) // detect change isNew, err = mocks.controller.HasTargetChanged(canary) require.NoError(t, err) assert.True(t, isNew) } func TestDaemonSetController_Scale(t *testing.T) { t.Run("ScaleToZero", func(t *testing.T) { mocks := newDaemonSetFixture() err := mocks.controller.Initialize(mocks.canary, true) require.NoError(t, err) err = mocks.controller.ScaleToZero(mocks.canary) require.NoError(t, err) c, err := mocks.kubeClient.AppsV1().DaemonSets("default").Get("podinfo", metav1.GetOptions{}) require.NoError(t, err) for k := range daemonSetScaleDownNodeSelector { _, ok := c.Spec.Template.Spec.NodeSelector[k] assert.True(t, ok, "%s should exist in node selector", k) } }) t.Run("ScaleFromZeo", func(t *testing.T) { mocks := newDaemonSetFixture() err := mocks.controller.Initialize(mocks.canary, true) require.NoError(t, err) err = mocks.controller.ScaleFromZero(mocks.canary) require.NoError(t, err) c, err := mocks.kubeClient.AppsV1().DaemonSets("default").Get("podinfo", metav1.GetOptions{}) require.NoError(t, err) for k := range daemonSetScaleDownNodeSelector { _, ok := c.Spec.Template.Spec.NodeSelector[k] assert.False(t, ok, "%s should not exist in node selector", k) } }) }