mirror of https://github.com/fluxcd/flagger.git
482 lines
11 KiB
Go
482 lines
11 KiB
Go
package controller
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha3"
|
|
fakeFlagger "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/fake"
|
|
"github.com/stefanprodan/flagger/pkg/logging"
|
|
appsv1 "k8s.io/api/apps/v1"
|
|
hpav1 "k8s.io/api/autoscaling/v1"
|
|
hpav2 "k8s.io/api/autoscaling/v2beta1"
|
|
corev1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/client-go/kubernetes/fake"
|
|
)
|
|
|
|
func newTestCanary() *v1alpha3.Canary {
|
|
cd := &v1alpha3.Canary{
|
|
TypeMeta: metav1.TypeMeta{APIVersion: v1alpha3.SchemeGroupVersion.String()},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Namespace: "default",
|
|
Name: "podinfo",
|
|
},
|
|
Spec: v1alpha3.CanarySpec{
|
|
TargetRef: hpav1.CrossVersionObjectReference{
|
|
Name: "podinfo",
|
|
APIVersion: "apps/v1",
|
|
Kind: "Deployment",
|
|
},
|
|
AutoscalerRef: &hpav1.CrossVersionObjectReference{
|
|
Name: "podinfo",
|
|
APIVersion: "autoscaling/v2beta1",
|
|
Kind: "HorizontalPodAutoscaler",
|
|
}, Service: v1alpha3.CanaryService{
|
|
Port: 9898,
|
|
}, CanaryAnalysis: v1alpha3.CanaryAnalysis{
|
|
Threshold: 10,
|
|
StepWeight: 10,
|
|
MaxWeight: 50,
|
|
Metrics: []v1alpha3.CanaryMetric{
|
|
{
|
|
Name: "istio_requests_total",
|
|
Threshold: 99,
|
|
Interval: "1m",
|
|
},
|
|
{
|
|
Name: "istio_request_duration_seconds_bucket",
|
|
Threshold: 500,
|
|
Interval: "1m",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
return cd
|
|
}
|
|
|
|
func newTestDeployment() *appsv1.Deployment {
|
|
d := &appsv1.Deployment{
|
|
TypeMeta: metav1.TypeMeta{APIVersion: appsv1.SchemeGroupVersion.String()},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Namespace: "default",
|
|
Name: "podinfo",
|
|
},
|
|
Spec: appsv1.DeploymentSpec{
|
|
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",
|
|
Ports: []corev1.ContainerPort{
|
|
{
|
|
Name: "http",
|
|
ContainerPort: 9898,
|
|
Protocol: corev1.ProtocolTCP,
|
|
},
|
|
},
|
|
Command: []string{
|
|
"./podinfo",
|
|
"--port=9898",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
return d
|
|
}
|
|
|
|
func newTestDeploymentUpdated() *appsv1.Deployment {
|
|
d := &appsv1.Deployment{
|
|
TypeMeta: metav1.TypeMeta{APIVersion: appsv1.SchemeGroupVersion.String()},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Namespace: "default",
|
|
Name: "podinfo",
|
|
},
|
|
Spec: appsv1.DeploymentSpec{
|
|
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",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
return d
|
|
}
|
|
|
|
func newTestHPA() *hpav2.HorizontalPodAutoscaler {
|
|
h := &hpav2.HorizontalPodAutoscaler{
|
|
TypeMeta: metav1.TypeMeta{APIVersion: hpav2.SchemeGroupVersion.String()},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Namespace: "default",
|
|
Name: "podinfo",
|
|
},
|
|
Spec: hpav2.HorizontalPodAutoscalerSpec{
|
|
ScaleTargetRef: hpav2.CrossVersionObjectReference{
|
|
Name: "podinfo",
|
|
APIVersion: "apps/v1",
|
|
Kind: "Deployment",
|
|
},
|
|
Metrics: []hpav2.MetricSpec{
|
|
{
|
|
Type: "Resource",
|
|
Resource: &hpav2.ResourceMetricSource{
|
|
Name: "cpu",
|
|
TargetAverageUtilization: int32p(99),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
return h
|
|
}
|
|
|
|
func TestCanaryDeployer_Sync(t *testing.T) {
|
|
canary := newTestCanary()
|
|
dep := newTestDeployment()
|
|
hpa := newTestHPA()
|
|
|
|
flaggerClient := fakeFlagger.NewSimpleClientset(canary)
|
|
|
|
kubeClient := fake.NewSimpleClientset(dep, hpa)
|
|
|
|
logger, _ := logging.NewLogger("debug")
|
|
deployer := &CanaryDeployer{
|
|
flaggerClient: flaggerClient,
|
|
kubeClient: kubeClient,
|
|
logger: logger,
|
|
}
|
|
|
|
err := deployer.Sync(canary)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
depPrimary, err := kubeClient.AppsV1().Deployments("default").Get("podinfo-primary", metav1.GetOptions{})
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
primaryImage := depPrimary.Spec.Template.Spec.Containers[0].Image
|
|
sourceImage := dep.Spec.Template.Spec.Containers[0].Image
|
|
if primaryImage != sourceImage {
|
|
t.Errorf("Got image %s wanted %s", primaryImage, sourceImage)
|
|
}
|
|
|
|
hpaPrimary, err := kubeClient.AutoscalingV2beta1().HorizontalPodAutoscalers("default").Get("podinfo-primary", metav1.GetOptions{})
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
if hpaPrimary.Spec.ScaleTargetRef.Name != depPrimary.Name {
|
|
t.Errorf("Got HPA target %s wanted %s", hpaPrimary.Spec.ScaleTargetRef.Name, depPrimary.Name)
|
|
}
|
|
}
|
|
|
|
func TestCanaryDeployer_IsNewSpec(t *testing.T) {
|
|
canary := newTestCanary()
|
|
dep := newTestDeployment()
|
|
dep2 := newTestDeploymentUpdated()
|
|
|
|
hpa := newTestHPA()
|
|
|
|
flaggerClient := fakeFlagger.NewSimpleClientset(canary)
|
|
|
|
kubeClient := fake.NewSimpleClientset(dep, hpa)
|
|
|
|
logger, _ := logging.NewLogger("debug")
|
|
deployer := &CanaryDeployer{
|
|
flaggerClient: flaggerClient,
|
|
kubeClient: kubeClient,
|
|
logger: logger,
|
|
}
|
|
|
|
err := deployer.Sync(canary)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
_, err = kubeClient.AppsV1().Deployments("default").Update(dep2)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
isNew, err := deployer.IsNewSpec(canary)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
if !isNew {
|
|
t.Errorf("Got %v wanted %v", isNew, true)
|
|
}
|
|
}
|
|
|
|
func TestCanaryDeployer_Promote(t *testing.T) {
|
|
canary := newTestCanary()
|
|
dep := newTestDeployment()
|
|
dep2 := newTestDeploymentUpdated()
|
|
|
|
hpa := newTestHPA()
|
|
|
|
flaggerClient := fakeFlagger.NewSimpleClientset(canary)
|
|
|
|
kubeClient := fake.NewSimpleClientset(dep, hpa)
|
|
|
|
logger, _ := logging.NewLogger("debug")
|
|
deployer := &CanaryDeployer{
|
|
flaggerClient: flaggerClient,
|
|
kubeClient: kubeClient,
|
|
logger: logger,
|
|
}
|
|
|
|
err := deployer.Sync(canary)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
_, err = kubeClient.AppsV1().Deployments("default").Update(dep2)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
err = deployer.Promote(canary)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
depPrimary, err := kubeClient.AppsV1().Deployments("default").Get("podinfo-primary", metav1.GetOptions{})
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
primaryImage := depPrimary.Spec.Template.Spec.Containers[0].Image
|
|
sourceImage := dep2.Spec.Template.Spec.Containers[0].Image
|
|
if primaryImage != sourceImage {
|
|
t.Errorf("Got image %s wanted %s", primaryImage, sourceImage)
|
|
}
|
|
}
|
|
|
|
func TestCanaryDeployer_IsReady(t *testing.T) {
|
|
canary := newTestCanary()
|
|
dep := newTestDeployment()
|
|
hpa := newTestHPA()
|
|
|
|
flaggerClient := fakeFlagger.NewSimpleClientset(canary)
|
|
|
|
kubeClient := fake.NewSimpleClientset(dep, hpa)
|
|
|
|
logger, _ := logging.NewLogger("debug")
|
|
deployer := &CanaryDeployer{
|
|
flaggerClient: flaggerClient,
|
|
kubeClient: kubeClient,
|
|
logger: logger,
|
|
}
|
|
|
|
err := deployer.Sync(canary)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
_, err = deployer.IsPrimaryReady(canary)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
_, err = deployer.IsCanaryReady(canary)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
}
|
|
|
|
func TestCanaryDeployer_SetFailedChecks(t *testing.T) {
|
|
canary := newTestCanary()
|
|
dep := newTestDeployment()
|
|
hpa := newTestHPA()
|
|
|
|
flaggerClient := fakeFlagger.NewSimpleClientset(canary)
|
|
|
|
kubeClient := fake.NewSimpleClientset(dep, hpa)
|
|
|
|
logger, _ := logging.NewLogger("debug")
|
|
deployer := &CanaryDeployer{
|
|
flaggerClient: flaggerClient,
|
|
kubeClient: kubeClient,
|
|
logger: logger,
|
|
}
|
|
|
|
err := deployer.Sync(canary)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
err = deployer.SetStatusFailedChecks(canary, 1)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
res, err := flaggerClient.FlaggerV1alpha3().Canaries("default").Get("podinfo", metav1.GetOptions{})
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
if res.Status.FailedChecks != 1 {
|
|
t.Errorf("Got %v wanted %v", res.Status.FailedChecks, 1)
|
|
}
|
|
}
|
|
|
|
func TestCanaryDeployer_SetState(t *testing.T) {
|
|
canary := newTestCanary()
|
|
dep := newTestDeployment()
|
|
hpa := newTestHPA()
|
|
|
|
flaggerClient := fakeFlagger.NewSimpleClientset(canary)
|
|
|
|
kubeClient := fake.NewSimpleClientset(dep, hpa)
|
|
|
|
logger, _ := logging.NewLogger("debug")
|
|
deployer := &CanaryDeployer{
|
|
flaggerClient: flaggerClient,
|
|
kubeClient: kubeClient,
|
|
logger: logger,
|
|
}
|
|
|
|
err := deployer.Sync(canary)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
err = deployer.SetStatusPhase(canary, v1alpha3.CanaryProgressing)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
res, err := flaggerClient.FlaggerV1alpha3().Canaries("default").Get("podinfo", metav1.GetOptions{})
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
if res.Status.Phase != v1alpha3.CanaryProgressing {
|
|
t.Errorf("Got %v wanted %v", res.Status.Phase, v1alpha3.CanaryProgressing)
|
|
}
|
|
}
|
|
|
|
func TestCanaryDeployer_SyncStatus(t *testing.T) {
|
|
canary := newTestCanary()
|
|
dep := newTestDeployment()
|
|
hpa := newTestHPA()
|
|
|
|
flaggerClient := fakeFlagger.NewSimpleClientset(canary)
|
|
|
|
kubeClient := fake.NewSimpleClientset(dep, hpa)
|
|
|
|
logger, _ := logging.NewLogger("debug")
|
|
deployer := &CanaryDeployer{
|
|
flaggerClient: flaggerClient,
|
|
kubeClient: kubeClient,
|
|
logger: logger,
|
|
}
|
|
|
|
err := deployer.Sync(canary)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
status := v1alpha3.CanaryStatus{
|
|
Phase: v1alpha3.CanaryProgressing,
|
|
FailedChecks: 2,
|
|
}
|
|
err = deployer.SyncStatus(canary, status)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
res, err := flaggerClient.FlaggerV1alpha3().Canaries("default").Get("podinfo", metav1.GetOptions{})
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
if res.Status.Phase != status.Phase {
|
|
t.Errorf("Got state %v wanted %v", res.Status.Phase, status.Phase)
|
|
}
|
|
|
|
if res.Status.FailedChecks != status.FailedChecks {
|
|
t.Errorf("Got failed checks %v wanted %v", res.Status.FailedChecks, status.FailedChecks)
|
|
}
|
|
}
|
|
|
|
func TestCanaryDeployer_Scale(t *testing.T) {
|
|
canary := newTestCanary()
|
|
dep := newTestDeployment()
|
|
hpa := newTestHPA()
|
|
|
|
flaggerClient := fakeFlagger.NewSimpleClientset(canary)
|
|
|
|
kubeClient := fake.NewSimpleClientset(dep, hpa)
|
|
|
|
logger, _ := logging.NewLogger("debug")
|
|
deployer := &CanaryDeployer{
|
|
flaggerClient: flaggerClient,
|
|
kubeClient: kubeClient,
|
|
logger: logger,
|
|
}
|
|
|
|
err := deployer.Sync(canary)
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
err = deployer.Scale(canary, 2)
|
|
|
|
c, err := kubeClient.AppsV1().Deployments("default").Get("podinfo", metav1.GetOptions{})
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
|
|
if *c.Spec.Replicas != 2 {
|
|
t.Errorf("Got replicas %v wanted %v", *c.Spec.Replicas, 2)
|
|
}
|
|
|
|
}
|