pkg/controller: add unit test for daemonset target

This commit is contained in:
mathetake
2020-02-23 13:39:11 +09:00
parent a828b43463
commit 5af1665ef8
10 changed files with 1462 additions and 123 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ import (
)
var (
daemonSetScaleDownNodeSelector = map[string]string{"flux.weave.works/non-exist": "true"}
daemonSetScaleDownNodeSelector = map[string]string{"flagger.weave.works/non-exist": "true"}
)
// DaemonSetController is managing the operations for Kubernetes DaemonSet kind
-34
View File
@@ -204,40 +204,6 @@ func newDaemonSetControllerTestCanary() *flaggerv1.Canary {
return cd
}
/*func newDaemonSetControllerWithout() *appsv1.DaemonSet {
n := "nginx-without-node-selector"
d := &appsv1.DaemonSet{
TypeMeta: metav1.TypeMeta{APIVersion: appsv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: n,
},
Spec: appsv1.DaemonSetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"name": n,
},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"name": n,
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: n,
Image: "nginx",
},
},
},
},
},
}
return d
}
*/
func newDaemonSetControllerTestPodInfo() *appsv1.DaemonSet {
d := &appsv1.DaemonSet{
TypeMeta: metav1.TypeMeta{APIVersion: appsv1.SchemeGroupVersion.String()},
+1 -1
View File
@@ -222,7 +222,7 @@ func (c *Controller) syncHandler(key string) error {
// set status condition for new canaries
if cd.Status.Conditions == nil {
if ok, conditions := canary.MakeStatusConditions(cd.Status, flaggerv1.CanaryPhaseInitializing); ok {
if ok, conditions := canary.MakeStatusConditions(cd, flaggerv1.CanaryPhaseInitializing); ok {
cdCopy := cd.DeepCopy()
cdCopy.Status.Conditions = conditions
cdCopy.Status.LastTransitionTime = metav1.Now()
+4 -4
View File
@@ -116,7 +116,7 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh
return
}
// create primary deployment and hpa
// create primary
err = canaryController.Initialize(cd, skipLivenessChecks)
if err != nil {
c.recordEventWarningf(cd, "%v", err)
@@ -161,7 +161,7 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh
maxWeight = cd.Spec.CanaryAnalysis.MaxWeight
}
// check primary deployment status
// check primary status
if !skipLivenessChecks && !cd.Spec.SkipAnalysis {
if _, err := canaryController.IsPrimaryReady(cd); err != nil {
c.recordEventWarningf(cd, "%v", err)
@@ -210,7 +210,7 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh
return
}
// check canary deployment status
// check canary status
var retriable = true
if !skipLivenessChecks {
retriable, err = canaryController.IsCanaryReady(cd)
@@ -617,7 +617,7 @@ func (c *Controller) checkCanaryStatus(canary *flaggerv1.Canary, canaryControlle
}
c.recorder.SetStatus(canary, flaggerv1.CanaryPhaseInitialized)
c.recordEventInfof(canary, "Initialization done! %s.%s", canary.Name, canary.Namespace)
c.alert(canary, "New deployment detected, initialization completed.",
c.alert(canary, fmt.Sprintf("New %s detected, initialization completed.", canary.Spec.TargetRef.Kind),
true, flaggerv1.SeverityInfo)
return false
}
+10
View File
@@ -0,0 +1,10 @@
package controller
func alwaysReady() bool {
return true
}
func toFloatPtr(val int) *float64 {
v := float64(val)
return &v
}
@@ -0,0 +1,694 @@
package controller
import (
"sync"
"time"
"github.com/weaveworks/flagger/pkg/metrics/observers"
"go.uber.org/zap"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1"
istiov1alpha1 "github.com/weaveworks/flagger/pkg/apis/istio/common/v1alpha1"
istiov1alpha3 "github.com/weaveworks/flagger/pkg/apis/istio/v1alpha3"
"github.com/weaveworks/flagger/pkg/canary"
clientset "github.com/weaveworks/flagger/pkg/client/clientset/versioned"
fakeFlagger "github.com/weaveworks/flagger/pkg/client/clientset/versioned/fake"
informers "github.com/weaveworks/flagger/pkg/client/informers/externalversions"
"github.com/weaveworks/flagger/pkg/logger"
"github.com/weaveworks/flagger/pkg/metrics"
"github.com/weaveworks/flagger/pkg/router"
)
type daemonSetFixture struct {
canary *flaggerv1.Canary
kubeClient kubernetes.Interface
meshClient clientset.Interface
flaggerClient clientset.Interface
deployer canary.Controller
ctrl *Controller
logger *zap.SugaredLogger
router router.Interface
}
func newDaemonSetFixture(c *flaggerv1.Canary) daemonSetFixture {
if c == nil {
c = newDaemonSetTestCanary()
}
// init Flagger clientset and register objects
flaggerClient := fakeFlagger.NewSimpleClientset(
c,
newDaemonSetTestMetricTemplate(),
newDaemonSetTestAlertProvider(),
)
// init Kubernetes clientset and register objects
kubeClient := fake.NewSimpleClientset(
newDaemonSetTestDaemonSet(),
newDaemonSetTestService(),
newDaemonSetTestConfigMap(),
newDaemonSetTestConfigMapEnv(),
newDaemonSetTestConfigMapVol(),
newDaemonSetTestSecret(),
newDaemonSetTestSecretEnv(),
newDaemonSetTestSecretVol(),
newDaemonSetTestAlertProviderSecret(),
)
logger, _ := logger.NewLogger("debug")
// init controller
flaggerInformerFactory := informers.NewSharedInformerFactory(flaggerClient, 0)
fi := Informers{
CanaryInformer: flaggerInformerFactory.Flagger().V1beta1().Canaries(),
MetricInformer: flaggerInformerFactory.Flagger().V1beta1().MetricTemplates(),
AlertInformer: flaggerInformerFactory.Flagger().V1beta1().AlertProviders(),
}
// init router
rf := router.NewFactory(nil, kubeClient, flaggerClient, "annotationsPrefix", logger, flaggerClient)
// init observer
observerFactory, _ := observers.NewFactory("fake")
// init canary factory
configTracker := &canary.ConfigTracker{
Logger: logger,
KubeClient: kubeClient,
FlaggerClient: flaggerClient,
}
canaryFactory := canary.NewFactory(kubeClient, flaggerClient, configTracker, []string{"app", "name"}, logger)
ctrl := &Controller{
kubeClient: kubeClient,
istioClient: flaggerClient,
flaggerClient: flaggerClient,
flaggerInformers: fi,
flaggerSynced: fi.CanaryInformer.Informer().HasSynced,
workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), controllerAgentName),
eventRecorder: &record.FakeRecorder{},
logger: logger,
canaries: new(sync.Map),
flaggerWindow: time.Second,
canaryFactory: canaryFactory,
observerFactory: observerFactory,
recorder: metrics.NewRecorder(controllerAgentName, false),
routerFactory: rf,
}
ctrl.flaggerSynced = alwaysReady
ctrl.flaggerInformers.CanaryInformer.Informer().GetIndexer().Add(c)
ctrl.flaggerInformers.MetricInformer.Informer().GetIndexer().Add(newDaemonSetTestMetricTemplate())
ctrl.flaggerInformers.AlertInformer.Informer().GetIndexer().Add(newDaemonSetTestAlertProvider())
meshRouter := rf.MeshRouter("istio")
return daemonSetFixture{
canary: c,
deployer: canaryFactory.Controller("DaemonSet"),
logger: logger,
flaggerClient: flaggerClient,
meshClient: flaggerClient,
kubeClient: kubeClient,
ctrl: ctrl,
router: meshRouter,
}
}
func newDaemonSetTestConfigMap() *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo-config-env",
},
Data: map[string]string{
"color": "red",
},
}
}
func newDaemonSetTestConfigMapV2() *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo-config-env",
},
Data: map[string]string{
"color": "blue",
"output": "console",
},
}
}
func newDaemonSetTestConfigMapEnv() *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo-config-all-env",
},
Data: map[string]string{
"color": "red",
},
}
}
func newDaemonSetTestConfigMapVol() *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo-config-vol",
},
Data: map[string]string{
"color": "red",
},
}
}
func newDaemonSetTestSecret() *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo-secret-env",
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"apiKey": []byte("test"),
"username": []byte("test"),
"password": []byte("test"),
},
}
}
func newDaemonSetTestSecretV2() *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo-secret-env",
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"apiKey": []byte("test2"),
"username": []byte("test"),
"password": []byte("test"),
},
}
}
func newDaemonSetTestSecretEnv() *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo-secret-all-env",
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"apiKey": []byte("test"),
},
}
}
func newDaemonSetTestSecretVol() *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo-secret-vol",
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"apiKey": []byte("test"),
},
}
}
func newDaemonSetTestCanary() *flaggerv1.Canary {
cd := &flaggerv1.Canary{
TypeMeta: metav1.TypeMeta{APIVersion: flaggerv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo",
},
Spec: flaggerv1.CanarySpec{
TargetRef: flaggerv1.CrossNamespaceObjectReference{
Name: "podinfo",
APIVersion: "apps/v1",
Kind: "DaemonSet",
}, Service: flaggerv1.CanaryService{
Port: 9898,
}, CanaryAnalysis: flaggerv1.CanaryAnalysis{
Threshold: 10,
StepWeight: 10,
MaxWeight: 50,
Metrics: []flaggerv1.CanaryMetric{
{
Name: "request-success-rate",
Threshold: 99,
Interval: "1m",
},
{
Name: "request-duration",
ThresholdRange: &flaggerv1.CanaryThresholdRange{
Min: toFloatPtr(0),
Max: toFloatPtr(500000),
},
Interval: "1m",
},
{
Name: "custom",
ThresholdRange: &flaggerv1.CanaryThresholdRange{
Min: toFloatPtr(0),
Max: toFloatPtr(100),
},
Interval: "1m",
TemplateRef: &flaggerv1.CrossNamespaceObjectReference{
Name: "envoy",
Namespace: "default",
},
},
},
},
},
}
return cd
}
func newDaemonSetTestCanaryMirror() *flaggerv1.Canary {
cd := newDaemonSetTestCanary()
cd.Spec.CanaryAnalysis.Mirror = true
return cd
}
func newDaemonSetTestCanaryAB() *flaggerv1.Canary {
cd := &flaggerv1.Canary{
TypeMeta: metav1.TypeMeta{APIVersion: flaggerv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo",
},
Spec: flaggerv1.CanarySpec{
TargetRef: flaggerv1.CrossNamespaceObjectReference{
Name: "podinfo",
APIVersion: "apps/v1",
Kind: "DaemonSet",
}, Service: flaggerv1.CanaryService{
Port: 9898,
}, CanaryAnalysis: flaggerv1.CanaryAnalysis{
Threshold: 10,
Iterations: 10,
Match: []istiov1alpha3.HTTPMatchRequest{
{
Headers: map[string]istiov1alpha1.StringMatch{
"x-user-type": {
Exact: "test",
},
},
},
},
Metrics: []flaggerv1.CanaryMetric{
{
Name: "request-success-rate",
ThresholdRange: &flaggerv1.CanaryThresholdRange{
Min: toFloatPtr(99),
Max: toFloatPtr(100),
},
Interval: "1m",
},
{
Name: "request-duration",
Threshold: 500000,
Interval: "1m",
},
{
Name: "custom",
ThresholdRange: &flaggerv1.CanaryThresholdRange{
Min: toFloatPtr(0),
Max: toFloatPtr(500000),
},
Interval: "1m",
Query: "fake",
},
},
},
},
}
return cd
}
func newDaemonSetTestDaemonSet() *appsv1.DaemonSet {
d := &appsv1.DaemonSet{
TypeMeta: metav1.TypeMeta{APIVersion: appsv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo",
},
Spec: appsv1.DaemonSetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "podinfo",
},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": "podinfo",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "podinfo",
Image: "quay.io/stefanprodan/podinfo:1.2.0",
Command: []string{
"./podinfo",
"--port=9898",
},
Args: nil,
WorkingDir: "",
Ports: []corev1.ContainerPort{
{
Name: "http",
ContainerPort: 9898,
Protocol: corev1.ProtocolTCP,
},
{
Name: "http-metrics",
ContainerPort: 8080,
Protocol: corev1.ProtocolTCP,
},
{
ContainerPort: 8888,
},
},
Env: []corev1.EnvVar{
{
Name: "PODINFO_UI_COLOR",
ValueFrom: &corev1.EnvVarSource{
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "podinfo-config-env",
},
Key: "color",
},
},
},
{
Name: "API_KEY",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "podinfo-secret-env",
},
Key: "apiKey",
},
},
},
},
EnvFrom: []corev1.EnvFromSource{
{
ConfigMapRef: &corev1.ConfigMapEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "podinfo-config-all-env",
},
},
},
{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "podinfo-secret-all-env",
},
},
},
},
VolumeMounts: []corev1.VolumeMount{
{
Name: "config",
MountPath: "/etc/podinfo/config",
ReadOnly: true,
},
{
Name: "secret",
MountPath: "/etc/podinfo/secret",
ReadOnly: true,
},
},
},
},
Volumes: []corev1.Volume{
{
Name: "config",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "podinfo-config-vol",
},
},
},
},
{
Name: "secret",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: "podinfo-secret-vol",
},
},
},
},
},
},
},
}
return d
}
func newDaemonSetTestDaemonSetV2() *appsv1.DaemonSet {
d := &appsv1.DaemonSet{
TypeMeta: metav1.TypeMeta{APIVersion: appsv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo",
},
Spec: appsv1.DaemonSetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "podinfo",
},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": "podinfo",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "podinfo",
Image: "quay.io/stefanprodan/podinfo:1.2.1",
Ports: []corev1.ContainerPort{
{
Name: "http",
ContainerPort: 9898,
Protocol: corev1.ProtocolTCP,
},
},
Command: []string{
"./podinfo",
"--port=9898",
},
Env: []corev1.EnvVar{
{
Name: "PODINFO_UI_COLOR",
ValueFrom: &corev1.EnvVarSource{
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "podinfo-config-env",
},
Key: "color",
},
},
},
{
Name: "API_KEY",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "podinfo-secret-env",
},
Key: "apiKey",
},
},
},
},
EnvFrom: []corev1.EnvFromSource{
{
ConfigMapRef: &corev1.ConfigMapEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "podinfo-config-all-env",
},
},
},
},
VolumeMounts: []corev1.VolumeMount{
{
Name: "config",
MountPath: "/etc/podinfo/config",
ReadOnly: true,
},
{
Name: "secret",
MountPath: "/etc/podinfo/secret",
ReadOnly: true,
},
},
},
},
Volumes: []corev1.Volume{
{
Name: "config",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "podinfo-config-vol",
},
},
},
},
{
Name: "secret",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: "podinfo-secret-vol",
},
},
},
},
},
},
},
}
return d
}
func newDaemonSetTestService() *corev1.Service {
d := &corev1.Service{
TypeMeta: metav1.TypeMeta{APIVersion: appsv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo",
},
Spec: corev1.ServiceSpec{
Selector: map[string]string{
"app": "podinfo",
},
Type: corev1.ServiceTypeClusterIP,
Ports: []corev1.ServicePort{
{
Name: "http",
Port: 9898,
Protocol: corev1.ProtocolTCP,
TargetPort: intstr.FromString("http"),
},
},
},
}
return d
}
func newDaemonSetTestServiceV2() *corev1.Service {
d := &corev1.Service{
TypeMeta: metav1.TypeMeta{APIVersion: appsv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo",
},
Spec: corev1.ServiceSpec{
Selector: map[string]string{
"app": "podinfo-v2",
},
Type: corev1.ServiceTypeClusterIP,
Ports: []corev1.ServicePort{
{
Name: "http",
Port: 9898,
Protocol: corev1.ProtocolTCP,
TargetPort: intstr.FromString("http"),
},
},
},
}
return d
}
func newDaemonSetTestMetricTemplate() *flaggerv1.MetricTemplate {
provider := flaggerv1.MetricTemplateProvider{
Type: "prometheus",
Address: "fake",
SecretRef: &corev1.LocalObjectReference{
Name: "podinfo-secret-env",
},
}
template := &flaggerv1.MetricTemplate{
TypeMeta: metav1.TypeMeta{APIVersion: flaggerv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "envoy",
},
Spec: flaggerv1.MetricTemplateSpec{
Provider: provider,
Query: `sum(envoy_cluster_upstream_rq{envoy_cluster_name=~"{{ namespace }}_{{ target }}"})`,
},
}
return template
}
func newDaemonSetTestAlertProviderSecret() *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "alert-secret",
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"address": []byte("http://mock.slack"),
},
}
}
func newDaemonSetTestAlertProvider() *flaggerv1.AlertProvider {
return &flaggerv1.AlertProvider{
TypeMeta: metav1.TypeMeta{APIVersion: flaggerv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "slack",
},
Spec: flaggerv1.AlertProviderSpec{
Type: "slack",
Address: "http://fake.slack",
SecretRef: &corev1.LocalObjectReference{
Name: "alert-secret",
},
},
}
}
+678
View File
@@ -0,0 +1,678 @@
package controller
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1"
"github.com/weaveworks/flagger/pkg/notifier"
)
func TestScheduler_DaemonSetInit(t *testing.T) {
mocks := newDaemonSetFixture(nil)
mocks.ctrl.advanceCanary("podinfo", "default", true)
_, err := mocks.kubeClient.AppsV1().DaemonSets("default").Get("podinfo-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
}
func TestScheduler_DaemonSetNewRevision(t *testing.T) {
mocks := newDaemonSetFixture(nil)
mocks.ctrl.advanceCanary("podinfo", "default", true)
// update
dep2 := newDaemonSetTestDaemonSetV2()
_, err := mocks.kubeClient.AppsV1().DaemonSets("default").Update(dep2)
if err != nil {
t.Fatal(err.Error())
}
// detect changes
mocks.ctrl.advanceCanary("podinfo", "default", true)
_, err = mocks.kubeClient.AppsV1().DaemonSets("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
}
func TestScheduler_DaemonSetRollback(t *testing.T) {
mocks := newDaemonSetFixture(nil)
// init
mocks.ctrl.advanceCanary("podinfo", "default", true)
// update failed checks to max
err := mocks.deployer.SyncStatus(mocks.canary, flaggerv1.CanaryStatus{Phase: flaggerv1.CanaryPhaseProgressing, FailedChecks: 10})
if err != nil {
t.Fatal(err.Error())
}
// set a metric check to fail
c, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
cd := c.DeepCopy()
cd.Spec.CanaryAnalysis.Metrics = append(c.Spec.CanaryAnalysis.Metrics, flaggerv1.CanaryMetric{
Name: "fail",
Interval: "1m",
ThresholdRange: &flaggerv1.CanaryThresholdRange{
Min: toFloatPtr(0),
Max: toFloatPtr(50),
},
Query: "fail",
})
_, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Update(cd)
if err != nil {
t.Fatal(err.Error())
}
// run metric checks
mocks.ctrl.advanceCanary("podinfo", "default", true)
// finalise analysis
mocks.ctrl.advanceCanary("podinfo", "default", true)
// check status
c, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if c.Status.Phase != flaggerv1.CanaryPhaseFailed {
t.Errorf("Got canary state %v wanted %v", c.Status.Phase, flaggerv1.CanaryPhaseFailed)
}
}
func TestScheduler_DaemonSetSkipAnalysis(t *testing.T) {
mocks := newDaemonSetFixture(nil)
// init
mocks.ctrl.advanceCanary("podinfo", "default", true)
// enable skip
cd, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
cd.Spec.SkipAnalysis = true
_, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Update(cd)
if err != nil {
t.Fatal(err.Error())
}
// update
dep2 := newDaemonSetTestDaemonSetV2()
_, err = mocks.kubeClient.AppsV1().DaemonSets("default").Update(dep2)
if err != nil {
t.Fatal(err.Error())
}
// detect changes
mocks.ctrl.advanceCanary("podinfo", "default", true)
// advance
mocks.ctrl.advanceCanary("podinfo", "default", true)
c, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if !c.Spec.SkipAnalysis {
t.Errorf("Got skip analysis %v wanted %v", c.Spec.SkipAnalysis, true)
}
if c.Status.Phase != flaggerv1.CanaryPhaseSucceeded {
t.Errorf("Got canary state %v wanted %v", c.Status.Phase, flaggerv1.CanaryPhaseSucceeded)
}
}
func TestScheduler_DaemonSetNewRevisionReset(t *testing.T) {
mocks := newDaemonSetFixture(nil)
// init
mocks.ctrl.advanceCanary("podinfo", "default", true)
// first update
dep2 := newDaemonSetTestDaemonSetV2()
_, err := mocks.kubeClient.AppsV1().DaemonSets("default").Update(dep2)
if err != nil {
t.Fatal(err.Error())
}
// detect changes
mocks.ctrl.advanceCanary("podinfo", "default", true)
// advance
mocks.ctrl.advanceCanary("podinfo", "default", true)
primaryWeight, canaryWeight, mirrored, err := mocks.router.GetRoutes(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
if primaryWeight != 90 {
t.Errorf("Got primary route %v wanted %v", primaryWeight, 90)
}
if canaryWeight != 10 {
t.Errorf("Got canary route %v wanted %v", canaryWeight, 10)
}
if mirrored != false {
t.Errorf("Got mirrored %v wanted %v", mirrored, false)
}
// second update
dep2.Spec.Template.Spec.ServiceAccountName = "test"
_, err = mocks.kubeClient.AppsV1().DaemonSets("default").Update(dep2)
if err != nil {
t.Fatal(err.Error())
}
// detect changes
mocks.ctrl.advanceCanary("podinfo", "default", true)
primaryWeight, canaryWeight, mirrored, err = mocks.router.GetRoutes(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
if primaryWeight != 100 {
t.Errorf("Got primary route %v wanted %v", primaryWeight, 100)
}
if canaryWeight != 0 {
t.Errorf("Got canary route %v wanted %v", canaryWeight, 0)
}
if mirrored != false {
t.Errorf("Got mirrored %v wanted %v", mirrored, false)
}
}
func TestScheduler_DaemonSetPromotion(t *testing.T) {
mocks := newDaemonSetFixture(nil)
// init
mocks.ctrl.advanceCanary("podinfo", "default", true)
// check initialized status
c, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if c.Status.Phase != flaggerv1.CanaryPhaseInitialized {
t.Errorf("Got canary state %v wanted %v", c.Status.Phase, flaggerv1.CanaryPhaseInitialized)
}
// update
dep2 := newDaemonSetTestDaemonSetV2()
_, err = mocks.kubeClient.AppsV1().DaemonSets("default").Update(dep2)
if err != nil {
t.Fatal(err.Error())
}
// detect pod spec changes
mocks.ctrl.advanceCanary("podinfo", "default", true)
config2 := newDaemonSetTestConfigMapV2()
_, err = mocks.kubeClient.CoreV1().ConfigMaps("default").Update(config2)
if err != nil {
t.Fatal(err.Error())
}
secret2 := newDaemonSetTestSecretV2()
_, err = mocks.kubeClient.CoreV1().Secrets("default").Update(secret2)
if err != nil {
t.Fatal(err.Error())
}
// detect configs changes
mocks.ctrl.advanceCanary("podinfo", "default", true)
primaryWeight, canaryWeight, mirrored, err := mocks.router.GetRoutes(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
primaryWeight = 60
canaryWeight = 40
err = mocks.router.SetRoutes(mocks.canary, primaryWeight, canaryWeight, mirrored)
if err != nil {
t.Fatal(err.Error())
}
// advance
mocks.ctrl.advanceCanary("podinfo", "default", true)
// check progressing status
c, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if c.Status.Phase != flaggerv1.CanaryPhaseProgressing {
t.Errorf("Got canary state %v wanted %v", c.Status.Phase, flaggerv1.CanaryPhaseProgressing)
}
// promote
mocks.ctrl.advanceCanary("podinfo", "default", true)
// check promoting status
c, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if c.Status.Phase != flaggerv1.CanaryPhasePromoting {
t.Errorf("Got canary state %v wanted %v", c.Status.Phase, flaggerv1.CanaryPhasePromoting)
}
// finalise
mocks.ctrl.advanceCanary("podinfo", "default", true)
primaryWeight, canaryWeight, mirrored, err = mocks.router.GetRoutes(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
if primaryWeight != 100 {
t.Errorf("Got primary route %v wanted %v", primaryWeight, 100)
}
if canaryWeight != 0 {
t.Errorf("Got canary route %v wanted %v", canaryWeight, 0)
}
if mirrored != false {
t.Errorf("Got mirrored %v wanted %v", mirrored, false)
}
primaryDep, err := mocks.kubeClient.AppsV1().DaemonSets("default").Get("podinfo-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
primaryImage := primaryDep.Spec.Template.Spec.Containers[0].Image
canaryImage := dep2.Spec.Template.Spec.Containers[0].Image
if primaryImage != canaryImage {
t.Errorf("Got primary image %v wanted %v", primaryImage, canaryImage)
}
configPrimary, err := mocks.kubeClient.CoreV1().ConfigMaps("default").Get("podinfo-config-env-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if configPrimary.Data["color"] != config2.Data["color"] {
t.Errorf("Got primary ConfigMap color %s wanted %s", configPrimary.Data["color"], config2.Data["color"])
}
secretPrimary, err := mocks.kubeClient.CoreV1().Secrets("default").Get("podinfo-secret-env-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if string(secretPrimary.Data["apiKey"]) != string(secret2.Data["apiKey"]) {
t.Errorf("Got primary secret %s wanted %s", secretPrimary.Data["apiKey"], secret2.Data["apiKey"])
}
// check finalising status
c, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if c.Status.Phase != flaggerv1.CanaryPhaseFinalising {
t.Errorf("Got canary state %v wanted %v", c.Status.Phase, flaggerv1.CanaryPhaseFinalising)
}
// scale canary to zero
mocks.ctrl.advanceCanary("podinfo", "default", true)
c, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if c.Status.Phase != flaggerv1.CanaryPhaseSucceeded {
t.Errorf("Got canary state %v wanted %v", c.Status.Phase, flaggerv1.CanaryPhaseSucceeded)
}
}
func TestScheduler_DaemonSetMirroring(t *testing.T) {
mocks := newDaemonSetFixture(newDaemonSetTestCanaryMirror())
// init
mocks.ctrl.advanceCanary("podinfo", "default", true)
// update
dep2 := newDaemonSetTestDaemonSetV2()
_, err := mocks.kubeClient.AppsV1().DaemonSets("default").Update(dep2)
if err != nil {
t.Fatal(err.Error())
}
// detect pod spec changes
mocks.ctrl.advanceCanary("podinfo", "default", true)
// advance
mocks.ctrl.advanceCanary("podinfo", "default", true)
// check if traffic is mirrored to canary
primaryWeight, canaryWeight, mirrored, err := mocks.router.GetRoutes(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
if primaryWeight != 100 {
t.Errorf("Got primary route %v wanted %v", primaryWeight, 100)
}
if canaryWeight != 0 {
t.Errorf("Got canary route %v wanted %v", canaryWeight, 0)
}
if mirrored != true {
t.Errorf("Got mirrored %v wanted %v", mirrored, true)
}
// advance
mocks.ctrl.advanceCanary("podinfo", "default", true)
// check if traffic is mirrored to canary
primaryWeight, canaryWeight, mirrored, err = mocks.router.GetRoutes(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
if primaryWeight != 90 {
t.Errorf("Got primary route %v wanted %v", primaryWeight, 90)
}
if canaryWeight != 10 {
t.Errorf("Got canary route %v wanted %v", canaryWeight, 10)
}
if mirrored != false {
t.Errorf("Got mirrored %v wanted %v", mirrored, false)
}
}
func TestScheduler_DaemonSetABTesting(t *testing.T) {
mocks := newDaemonSetFixture(newDaemonSetTestCanaryAB())
// init
mocks.ctrl.advanceCanary("podinfo", "default", true)
// update
dep2 := newDaemonSetTestDaemonSetV2()
_, err := mocks.kubeClient.AppsV1().DaemonSets("default").Update(dep2)
if err != nil {
t.Fatal(err.Error())
}
// detect pod spec changes
mocks.ctrl.advanceCanary("podinfo", "default", true)
// advance
mocks.ctrl.advanceCanary("podinfo", "default", true)
// check if traffic is routed to canary
primaryWeight, canaryWeight, mirrored, err := mocks.router.GetRoutes(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
if primaryWeight != 0 {
t.Errorf("Got primary route %v wanted %v", primaryWeight, 0)
}
if canaryWeight != 100 {
t.Errorf("Got canary route %v wanted %v", canaryWeight, 100)
}
if mirrored != false {
t.Errorf("Got mirrored %v wanted %v", mirrored, false)
}
cd, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
// set max iterations
if err := mocks.deployer.SetStatusIterations(cd, 10); err != nil {
t.Fatal(err.Error())
}
// advance
mocks.ctrl.advanceCanary("podinfo", "default", true)
// finalising
mocks.ctrl.advanceCanary("podinfo", "default", true)
// check finalising status
c, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if c.Status.Phase != flaggerv1.CanaryPhaseFinalising {
t.Errorf("Got canary state %v wanted %v", c.Status.Phase, flaggerv1.CanaryPhaseFinalising)
}
// check if the container image tag was updated
primaryDep, err := mocks.kubeClient.AppsV1().DaemonSets("default").Get("podinfo-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
primaryImage := primaryDep.Spec.Template.Spec.Containers[0].Image
canaryImage := dep2.Spec.Template.Spec.Containers[0].Image
if primaryImage != canaryImage {
t.Errorf("Got primary image %v wanted %v", primaryImage, canaryImage)
}
// shutdown canary
mocks.ctrl.advanceCanary("podinfo", "default", true)
// check rollout status
c, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if c.Status.Phase != flaggerv1.CanaryPhaseSucceeded {
t.Errorf("Got canary state %v wanted %v", c.Status.Phase, flaggerv1.CanaryPhaseSucceeded)
}
}
func TestScheduler_DaemonSetPortDiscovery(t *testing.T) {
mocks := newDaemonSetFixture(nil)
// enable port discovery
cd, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
cd.Spec.Service.PortDiscovery = true
_, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Update(cd)
if err != nil {
t.Fatal(err.Error())
}
mocks.ctrl.advanceCanary("podinfo", "default", true)
canarySvc, err := mocks.kubeClient.CoreV1().Services("default").Get("podinfo-canary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if len(canarySvc.Spec.Ports) != 3 {
t.Fatalf("Got svc port count %v wanted %v", len(canarySvc.Spec.Ports), 3)
}
matchPorts := func(lookup string) bool {
switch lookup {
case
"http 9898",
"http-metrics 8080",
"tcp-podinfo-2 8888":
return true
}
return false
}
for _, port := range canarySvc.Spec.Ports {
if !matchPorts(fmt.Sprintf("%s %v", port.Name, port.Port)) {
t.Fatalf("Got wrong svc port %v", port.Name)
}
}
}
func TestScheduler_DaemonSetTargetPortNumber(t *testing.T) {
mocks := newDaemonSetFixture(nil)
cd, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
cd.Spec.Service.Port = 80
cd.Spec.Service.TargetPort = intstr.FromInt(9898)
cd.Spec.Service.PortDiscovery = true
_, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Update(cd)
if err != nil {
t.Fatal(err.Error())
}
mocks.ctrl.advanceCanary("podinfo", "default", true)
canarySvc, err := mocks.kubeClient.CoreV1().Services("default").Get("podinfo-canary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if len(canarySvc.Spec.Ports) != 3 {
t.Fatalf("Got svc port count %v wanted %v", len(canarySvc.Spec.Ports), 3)
}
matchPorts := func(lookup string) bool {
switch lookup {
case
"http 80",
"http-metrics 8080",
"tcp-podinfo-2 8888":
return true
}
return false
}
for _, port := range canarySvc.Spec.Ports {
if !matchPorts(fmt.Sprintf("%s %v", port.Name, port.Port)) {
t.Fatalf("Got wrong svc port %v", port.Name)
}
}
}
func TestScheduler_DaemonSetTargetPortName(t *testing.T) {
mocks := newDaemonSetFixture(nil)
cd, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
cd.Spec.Service.Port = 8080
cd.Spec.Service.TargetPort = intstr.FromString("http")
cd.Spec.Service.PortDiscovery = true
_, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Update(cd)
if err != nil {
t.Fatal(err.Error())
}
mocks.ctrl.advanceCanary("podinfo", "default", true)
canarySvc, err := mocks.kubeClient.CoreV1().Services("default").Get("podinfo-canary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if len(canarySvc.Spec.Ports) != 3 {
t.Fatalf("Got svc port count %v wanted %v", len(canarySvc.Spec.Ports), 3)
}
matchPorts := func(lookup string) bool {
switch lookup {
case
"http 8080",
"http-metrics 8080",
"tcp-podinfo-2 8888":
return true
}
return false
}
for _, port := range canarySvc.Spec.Ports {
if !matchPorts(fmt.Sprintf("%s %v", port.Name, port.Port)) {
t.Fatalf("Got wrong svc port %v", port.Name)
}
}
}
func TestScheduler_DaemonSetAlerts(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
b, err := ioutil.ReadAll(r.Body)
if err != nil {
t.Fatal(err)
}
var payload = notifier.SlackPayload{}
err = json.Unmarshal(b, &payload)
if err != nil {
t.Fatal(err)
}
if payload.Attachments[0].AuthorName != "podinfo.default" {
t.Fatal("wrong author name")
}
}))
defer ts.Close()
canary := newDaemonSetTestCanary()
canary.Spec.CanaryAnalysis.Alerts = []flaggerv1.CanaryAlert{
{
Name: "slack-dev",
Severity: "info",
ProviderRef: flaggerv1.CrossNamespaceObjectReference{
Name: "slack",
Namespace: "default",
},
},
{
Name: "slack-prod",
Severity: "info",
ProviderRef: flaggerv1.CrossNamespaceObjectReference{
Name: "slack",
},
},
}
mocks := newDaemonSetFixture(canary)
secret := newDaemonSetTestAlertProviderSecret()
secret.Data = map[string][]byte{
"address": []byte(ts.URL),
}
_, err := mocks.kubeClient.CoreV1().Secrets("default").Update(secret)
if err != nil {
t.Fatal(err.Error())
}
// init canary and send alerts
mocks.ctrl.advanceCanary("podinfo", "default", true)
}
@@ -1,10 +1,11 @@
package controller
import (
"github.com/weaveworks/flagger/pkg/metrics/observers"
"sync"
"time"
"github.com/weaveworks/flagger/pkg/metrics/observers"
"go.uber.org/zap"
appsv1 "k8s.io/api/apps/v1"
hpav2 "k8s.io/api/autoscaling/v2beta1"
@@ -28,11 +29,6 @@ import (
"github.com/weaveworks/flagger/pkg/router"
)
var (
alwaysReady = func() bool { return true }
noResyncPeriodFunc = func() time.Duration { return 0 }
)
type fixture struct {
canary *flaggerv1.Canary
kubeClient kubernetes.Interface
@@ -44,30 +40,30 @@ type fixture struct {
router router.Interface
}
func newFixture(c *flaggerv1.Canary) fixture {
func newDeploymentFixture(c *flaggerv1.Canary) fixture {
if c == nil {
c = newTestCanary()
c = newDeploymentTestCanary()
}
// init Flagger clientset and register objects
flaggerClient := fakeFlagger.NewSimpleClientset(
c,
newTestMetricTemplate(),
newTestAlertProvider(),
newDeploymentTestMetricTemplate(),
newDeploymentTestAlertProvider(),
)
// init Kubernetes clientset and register objects
kubeClient := fake.NewSimpleClientset(
newTestDeployment(),
newTestService(),
newTestHPA(),
newTestConfigMap(),
newTestConfigMapEnv(),
newTestConfigMapVol(),
newTestSecret(),
newTestSecretEnv(),
newTestSecretVol(),
newTestAlertProviderSecret(),
newDeploymentTestDeployment(),
newDeploymentTestService(),
newDeploymentTestHPA(),
newDeploymentTestConfigMap(),
newDeploymentTestConfigMapEnv(),
newDeploymentTestConfigMapVol(),
newDeploymentTestSecret(),
newDeploymentTestSecretEnv(),
newDeploymentTestSecretVol(),
newDeploymentTestAlertProviderSecret(),
)
logger, _ := logger.NewLogger("debug")
@@ -113,8 +109,8 @@ func newFixture(c *flaggerv1.Canary) fixture {
}
ctrl.flaggerSynced = alwaysReady
ctrl.flaggerInformers.CanaryInformer.Informer().GetIndexer().Add(c)
ctrl.flaggerInformers.MetricInformer.Informer().GetIndexer().Add(newTestMetricTemplate())
ctrl.flaggerInformers.AlertInformer.Informer().GetIndexer().Add(newTestAlertProvider())
ctrl.flaggerInformers.MetricInformer.Informer().GetIndexer().Add(newDeploymentTestMetricTemplate())
ctrl.flaggerInformers.AlertInformer.Informer().GetIndexer().Add(newDeploymentTestAlertProvider())
meshRouter := rf.MeshRouter("istio")
@@ -130,7 +126,7 @@ func newFixture(c *flaggerv1.Canary) fixture {
}
}
func newTestConfigMap() *corev1.ConfigMap {
func newDeploymentTestConfigMap() *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -143,7 +139,7 @@ func newTestConfigMap() *corev1.ConfigMap {
}
}
func newTestConfigMapV2() *corev1.ConfigMap {
func newDeploymentTestConfigMapV2() *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -157,7 +153,7 @@ func newTestConfigMapV2() *corev1.ConfigMap {
}
}
func newTestConfigMapEnv() *corev1.ConfigMap {
func newDeploymentTestConfigMapEnv() *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -170,7 +166,7 @@ func newTestConfigMapEnv() *corev1.ConfigMap {
}
}
func newTestConfigMapVol() *corev1.ConfigMap {
func newDeploymentTestConfigMapVol() *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -183,7 +179,7 @@ func newTestConfigMapVol() *corev1.ConfigMap {
}
}
func newTestSecret() *corev1.Secret {
func newDeploymentTestSecret() *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -199,7 +195,7 @@ func newTestSecret() *corev1.Secret {
}
}
func newTestSecretV2() *corev1.Secret {
func newDeploymentTestSecretV2() *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -215,7 +211,7 @@ func newTestSecretV2() *corev1.Secret {
}
}
func newTestSecretEnv() *corev1.Secret {
func newDeploymentTestSecretEnv() *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -229,7 +225,7 @@ func newTestSecretEnv() *corev1.Secret {
}
}
func newTestSecretVol() *corev1.Secret {
func newDeploymentTestSecretVol() *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -243,7 +239,7 @@ func newTestSecretVol() *corev1.Secret {
}
}
func newTestCanary() *flaggerv1.Canary {
func newDeploymentTestCanary() *flaggerv1.Canary {
cd := &flaggerv1.Canary{
TypeMeta: metav1.TypeMeta{APIVersion: flaggerv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -299,18 +295,13 @@ func newTestCanary() *flaggerv1.Canary {
return cd
}
func toFloatPtr(val int) *float64 {
v := float64(val)
return &v
}
func newTestCanaryMirror() *flaggerv1.Canary {
cd := newTestCanary()
func newDeploymentTestCanaryMirror() *flaggerv1.Canary {
cd := newDeploymentTestCanary()
cd.Spec.CanaryAnalysis.Mirror = true
return cd
}
func newTestCanaryAB() *flaggerv1.Canary {
func newDeploymentTestCanaryAB() *flaggerv1.Canary {
cd := &flaggerv1.Canary{
TypeMeta: metav1.TypeMeta{APIVersion: flaggerv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -371,7 +362,7 @@ func newTestCanaryAB() *flaggerv1.Canary {
return cd
}
func newTestDeployment() *appsv1.Deployment {
func newDeploymentTestDeployment() *appsv1.Deployment {
d := &appsv1.Deployment{
TypeMeta: metav1.TypeMeta{APIVersion: appsv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -498,7 +489,7 @@ func newTestDeployment() *appsv1.Deployment {
return d
}
func newTestDeploymentV2() *appsv1.Deployment {
func newDeploymentTestDeploymentV2() *appsv1.Deployment {
d := &appsv1.Deployment{
TypeMeta: metav1.TypeMeta{APIVersion: appsv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -608,7 +599,7 @@ func newTestDeploymentV2() *appsv1.Deployment {
return d
}
func newTestService() *corev1.Service {
func newDeploymentTestService() *corev1.Service {
d := &corev1.Service{
TypeMeta: metav1.TypeMeta{APIVersion: appsv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -634,7 +625,7 @@ func newTestService() *corev1.Service {
return d
}
func newTestServiceV2() *corev1.Service {
func newDeploymentTestServiceV2() *corev1.Service {
d := &corev1.Service{
TypeMeta: metav1.TypeMeta{APIVersion: appsv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -660,7 +651,7 @@ func newTestServiceV2() *corev1.Service {
return d
}
func newTestHPA() *hpav2.HorizontalPodAutoscaler {
func newDeploymentTestHPA() *hpav2.HorizontalPodAutoscaler {
h := &hpav2.HorizontalPodAutoscaler{
TypeMeta: metav1.TypeMeta{APIVersion: hpav2.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -688,7 +679,7 @@ func newTestHPA() *hpav2.HorizontalPodAutoscaler {
return h
}
func newTestMetricTemplate() *flaggerv1.MetricTemplate {
func newDeploymentTestMetricTemplate() *flaggerv1.MetricTemplate {
provider := flaggerv1.MetricTemplateProvider{
Type: "prometheus",
Address: "fake",
@@ -711,7 +702,7 @@ func newTestMetricTemplate() *flaggerv1.MetricTemplate {
return template
}
func newTestAlertProviderSecret() *corev1.Secret {
func newDeploymentTestAlertProviderSecret() *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -725,7 +716,7 @@ func newTestAlertProviderSecret() *corev1.Secret {
}
}
func newTestAlertProvider() *flaggerv1.AlertProvider {
func newDeploymentTestAlertProvider() *flaggerv1.AlertProvider {
return &flaggerv1.AlertProvider{
TypeMeta: metav1.TypeMeta{APIVersion: flaggerv1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -15,8 +15,8 @@ import (
"github.com/weaveworks/flagger/pkg/notifier"
)
func TestScheduler_Init(t *testing.T) {
mocks := newFixture(nil)
func TestScheduler_DeploymentInit(t *testing.T) {
mocks := newDeploymentFixture(nil)
mocks.ctrl.advanceCanary("podinfo", "default", true)
_, err := mocks.kubeClient.AppsV1().Deployments("default").Get("podinfo-primary", metav1.GetOptions{})
@@ -25,12 +25,12 @@ func TestScheduler_Init(t *testing.T) {
}
}
func TestScheduler_NewRevision(t *testing.T) {
mocks := newFixture(nil)
func TestScheduler_DeploymentNewRevision(t *testing.T) {
mocks := newDeploymentFixture(nil)
mocks.ctrl.advanceCanary("podinfo", "default", true)
// update
dep2 := newTestDeploymentV2()
dep2 := newDeploymentTestDeploymentV2()
_, err := mocks.kubeClient.AppsV1().Deployments("default").Update(dep2)
if err != nil {
t.Fatal(err.Error())
@@ -49,8 +49,8 @@ func TestScheduler_NewRevision(t *testing.T) {
}
}
func TestScheduler_Rollback(t *testing.T) {
mocks := newFixture(nil)
func TestScheduler_DeploymentRollback(t *testing.T) {
mocks := newDeploymentFixture(nil)
// init
mocks.ctrl.advanceCanary("podinfo", "default", true)
@@ -103,8 +103,8 @@ func TestScheduler_Rollback(t *testing.T) {
}
}
func TestScheduler_SkipAnalysis(t *testing.T) {
mocks := newFixture(nil)
func TestScheduler_DeploymentSkipAnalysis(t *testing.T) {
mocks := newDeploymentFixture(nil)
// init
mocks.ctrl.advanceCanary("podinfo", "default", true)
@@ -120,7 +120,7 @@ func TestScheduler_SkipAnalysis(t *testing.T) {
}
// update
dep2 := newTestDeploymentV2()
dep2 := newDeploymentTestDeploymentV2()
_, err = mocks.kubeClient.AppsV1().Deployments("default").Update(dep2)
if err != nil {
t.Fatal(err.Error())
@@ -144,13 +144,13 @@ func TestScheduler_SkipAnalysis(t *testing.T) {
}
}
func TestScheduler_NewRevisionReset(t *testing.T) {
mocks := newFixture(nil)
func TestScheduler_DeploymentNewRevisionReset(t *testing.T) {
mocks := newDeploymentFixture(nil)
// init
mocks.ctrl.advanceCanary("podinfo", "default", true)
// first update
dep2 := newTestDeploymentV2()
dep2 := newDeploymentTestDeploymentV2()
_, err := mocks.kubeClient.AppsV1().Deployments("default").Update(dep2)
if err != nil {
t.Fatal(err.Error())
@@ -206,8 +206,8 @@ func TestScheduler_NewRevisionReset(t *testing.T) {
}
}
func TestScheduler_Promotion(t *testing.T) {
mocks := newFixture(nil)
func TestScheduler_DeploymentPromotion(t *testing.T) {
mocks := newDeploymentFixture(nil)
// init
mocks.ctrl.advanceCanary("podinfo", "default", true)
@@ -223,7 +223,7 @@ func TestScheduler_Promotion(t *testing.T) {
}
// update
dep2 := newTestDeploymentV2()
dep2 := newDeploymentTestDeploymentV2()
_, err = mocks.kubeClient.AppsV1().Deployments("default").Update(dep2)
if err != nil {
t.Fatal(err.Error())
@@ -232,13 +232,13 @@ func TestScheduler_Promotion(t *testing.T) {
// detect pod spec changes
mocks.ctrl.advanceCanary("podinfo", "default", true)
config2 := newTestConfigMapV2()
config2 := newDeploymentTestConfigMapV2()
_, err = mocks.kubeClient.CoreV1().ConfigMaps("default").Update(config2)
if err != nil {
t.Fatal(err.Error())
}
secret2 := newTestSecretV2()
secret2 := newDeploymentTestSecretV2()
_, err = mocks.kubeClient.CoreV1().Secrets("default").Update(secret2)
if err != nil {
t.Fatal(err.Error())
@@ -357,13 +357,13 @@ func TestScheduler_Promotion(t *testing.T) {
}
}
func TestScheduler_Mirroring(t *testing.T) {
mocks := newFixture(newTestCanaryMirror())
func TestScheduler_DeploymentMirroring(t *testing.T) {
mocks := newDeploymentFixture(newDeploymentTestCanaryMirror())
// init
mocks.ctrl.advanceCanary("podinfo", "default", true)
// update
dep2 := newTestDeploymentV2()
dep2 := newDeploymentTestDeploymentV2()
_, err := mocks.kubeClient.AppsV1().Deployments("default").Update(dep2)
if err != nil {
t.Fatal(err.Error())
@@ -415,13 +415,13 @@ func TestScheduler_Mirroring(t *testing.T) {
}
}
func TestScheduler_ABTesting(t *testing.T) {
mocks := newFixture(newTestCanaryAB())
func TestScheduler_DeploymentABTesting(t *testing.T) {
mocks := newDeploymentFixture(newDeploymentTestCanaryAB())
// init
mocks.ctrl.advanceCanary("podinfo", "default", true)
// update
dep2 := newTestDeploymentV2()
dep2 := newDeploymentTestDeploymentV2()
_, err := mocks.kubeClient.AppsV1().Deployments("default").Update(dep2)
if err != nil {
t.Fatal(err.Error())
@@ -503,8 +503,8 @@ func TestScheduler_ABTesting(t *testing.T) {
}
}
func TestScheduler_PortDiscovery(t *testing.T) {
mocks := newFixture(nil)
func TestScheduler_DeploymentPortDiscovery(t *testing.T) {
mocks := newDeploymentFixture(nil)
// enable port discovery
cd, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
@@ -547,8 +547,8 @@ func TestScheduler_PortDiscovery(t *testing.T) {
}
}
func TestScheduler_TargetPortNumber(t *testing.T) {
mocks := newFixture(nil)
func TestScheduler_DeploymentTargetPortNumber(t *testing.T) {
mocks := newDeploymentFixture(nil)
cd, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
@@ -592,8 +592,8 @@ func TestScheduler_TargetPortNumber(t *testing.T) {
}
}
func TestScheduler_TargetPortName(t *testing.T) {
mocks := newFixture(nil)
func TestScheduler_DeploymentTargetPortName(t *testing.T) {
mocks := newDeploymentFixture(nil)
cd, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
@@ -637,7 +637,7 @@ func TestScheduler_TargetPortName(t *testing.T) {
}
}
func TestScheduler_Alerts(t *testing.T) {
func TestScheduler_DeploymentAlerts(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
b, err := ioutil.ReadAll(r.Body)
if err != nil {
@@ -654,7 +654,7 @@ func TestScheduler_Alerts(t *testing.T) {
}))
defer ts.Close()
canary := newTestCanary()
canary := newDeploymentTestCanary()
canary.Spec.CanaryAnalysis.Alerts = []flaggerv1.CanaryAlert{
{
Name: "slack-dev",
@@ -672,9 +672,9 @@ func TestScheduler_Alerts(t *testing.T) {
},
},
}
mocks := newFixture(canary)
mocks := newDeploymentFixture(canary)
secret := newTestAlertProviderSecret()
secret := newDeploymentTestAlertProviderSecret()
secret.Data = map[string][]byte{
"address": []byte(ts.URL),
}
+2 -2
View File
@@ -9,7 +9,7 @@ import (
)
func TestScheduler_ServicePromotion(t *testing.T) {
mocks := newFixture(newTestServiceCanary())
mocks := newDeploymentFixture(newTestServiceCanary())
// init
mocks.ctrl.advanceCanary("podinfo", "default", true)
@@ -25,7 +25,7 @@ func TestScheduler_ServicePromotion(t *testing.T) {
}
// update
svc2 := newTestServiceV2()
svc2 := newDeploymentTestServiceV2()
_, err = mocks.kubeClient.CoreV1().Services("default").Update(svc2)
if err != nil {
t.Fatal(err.Error())