github.com/argoproj/argo-events@v1.9.1/controllers/sensor/resource_test.go (about)

     1  /*
     2  Copyright 2020 BlackRock, Inc.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package sensor
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	"github.com/stretchr/testify/assert"
    24  	appv1 "k8s.io/api/apps/v1"
    25  	corev1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"sigs.k8s.io/controller-runtime/pkg/client"
    28  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    29  
    30  	"github.com/argoproj/argo-events/common"
    31  	"github.com/argoproj/argo-events/common/logging"
    32  	apicommon "github.com/argoproj/argo-events/pkg/apis/common"
    33  	eventbusv1alpha1 "github.com/argoproj/argo-events/pkg/apis/eventbus/v1alpha1"
    34  	"github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1"
    35  )
    36  
    37  const (
    38  	testNamespace = "test-ns"
    39  )
    40  
    41  var (
    42  	testLabels = map[string]string{"controller": "test-controller"}
    43  
    44  	sensorObj = &v1alpha1.Sensor{
    45  		ObjectMeta: metav1.ObjectMeta{
    46  			Name:      "fake-sensor",
    47  			Namespace: testNamespace,
    48  		},
    49  		Spec: v1alpha1.SensorSpec{
    50  			Template: &v1alpha1.Template{
    51  				ServiceAccountName: "fake-sa",
    52  				ImagePullSecrets: []corev1.LocalObjectReference{
    53  					{
    54  						Name: "test",
    55  					},
    56  				},
    57  				Container: &corev1.Container{
    58  					VolumeMounts: []corev1.VolumeMount{
    59  						{
    60  							MountPath: "/test-data",
    61  							Name:      "test-data",
    62  						},
    63  					},
    64  				},
    65  				Volumes: []corev1.Volume{
    66  					{
    67  						Name: "test-data",
    68  						VolumeSource: corev1.VolumeSource{
    69  							EmptyDir: &corev1.EmptyDirVolumeSource{},
    70  						},
    71  					},
    72  				},
    73  				PriorityClassName: "test-class",
    74  			},
    75  			Triggers: []v1alpha1.Trigger{
    76  				{
    77  					Template: &v1alpha1.TriggerTemplate{
    78  						Name: "fake-trigger",
    79  						K8s: &v1alpha1.StandardK8STrigger{
    80  							Operation: "create",
    81  							Source:    &v1alpha1.ArtifactLocation{},
    82  						},
    83  					},
    84  				},
    85  			},
    86  			Dependencies: []v1alpha1.EventDependency{
    87  				{
    88  					Name:            "fake-dep",
    89  					EventSourceName: "fake-source",
    90  					EventName:       "fake-one",
    91  				},
    92  			},
    93  		},
    94  	}
    95  
    96  	fakeEventBus = &eventbusv1alpha1.EventBus{
    97  		TypeMeta: metav1.TypeMeta{
    98  			APIVersion: eventbusv1alpha1.SchemeGroupVersion.String(),
    99  			Kind:       "EventBus",
   100  		},
   101  		ObjectMeta: metav1.ObjectMeta{
   102  			Namespace: testNamespace,
   103  			Name:      common.DefaultEventBusName,
   104  		},
   105  		Spec: eventbusv1alpha1.EventBusSpec{
   106  			NATS: &eventbusv1alpha1.NATSBus{
   107  				Native: &eventbusv1alpha1.NativeStrategy{
   108  					Auth: &eventbusv1alpha1.AuthStrategyToken,
   109  				},
   110  			},
   111  		},
   112  		Status: eventbusv1alpha1.EventBusStatus{
   113  			Config: eventbusv1alpha1.BusConfig{
   114  				NATS: &eventbusv1alpha1.NATSConfig{
   115  					URL:  "nats://xxxx",
   116  					Auth: &eventbusv1alpha1.AuthStrategyToken,
   117  					AccessSecret: &corev1.SecretKeySelector{
   118  						Key: "test-key",
   119  						LocalObjectReference: corev1.LocalObjectReference{
   120  							Name: "test-name",
   121  						},
   122  					},
   123  				},
   124  			},
   125  		},
   126  	}
   127  
   128  	fakeEventBusJetstream = &eventbusv1alpha1.EventBus{
   129  		TypeMeta: metav1.TypeMeta{
   130  			APIVersion: eventbusv1alpha1.SchemeGroupVersion.String(),
   131  			Kind:       "EventBus",
   132  		},
   133  		ObjectMeta: metav1.ObjectMeta{
   134  			Namespace: testNamespace,
   135  			Name:      common.DefaultEventBusName,
   136  		},
   137  		Spec: eventbusv1alpha1.EventBusSpec{
   138  			JetStream: &eventbusv1alpha1.JetStreamBus{
   139  				Version: "x.x.x",
   140  			},
   141  		},
   142  		Status: eventbusv1alpha1.EventBusStatus{
   143  			Config: eventbusv1alpha1.BusConfig{
   144  				JetStream: &eventbusv1alpha1.JetStreamConfig{
   145  					URL: "nats://xxxx",
   146  				},
   147  			},
   148  		},
   149  	}
   150  
   151  	fakeEventBusKafka = &eventbusv1alpha1.EventBus{
   152  		TypeMeta: metav1.TypeMeta{
   153  			APIVersion: eventbusv1alpha1.SchemeGroupVersion.String(),
   154  			Kind:       "EventBus",
   155  		},
   156  		ObjectMeta: metav1.ObjectMeta{
   157  			Namespace: testNamespace,
   158  			Name:      common.DefaultEventBusName,
   159  		},
   160  		Spec: eventbusv1alpha1.EventBusSpec{
   161  			Kafka: &eventbusv1alpha1.KafkaBus{
   162  				URL: "localhost:9092",
   163  			},
   164  		},
   165  		Status: eventbusv1alpha1.EventBusStatus{
   166  			Config: eventbusv1alpha1.BusConfig{
   167  				Kafka: &eventbusv1alpha1.KafkaBus{
   168  					URL: "localhost:9092",
   169  				},
   170  			},
   171  		},
   172  	}
   173  )
   174  
   175  func Test_BuildDeployment(t *testing.T) {
   176  	t.Run("test build with eventbus", func(t *testing.T) {
   177  		args := &AdaptorArgs{
   178  			Image:  testImage,
   179  			Sensor: sensorObj,
   180  			Labels: testLabels,
   181  		}
   182  		deployment, err := buildDeployment(args, fakeEventBus)
   183  		assert.Nil(t, err)
   184  		assert.NotNil(t, deployment)
   185  		volumes := deployment.Spec.Template.Spec.Volumes
   186  		assert.True(t, len(volumes) > 0)
   187  		hasAuthVolume := false
   188  		hasTmpVolume := false
   189  		for _, vol := range volumes {
   190  			if vol.Name == "auth-volume" {
   191  				hasAuthVolume = true
   192  			}
   193  			if vol.Name == "tmp" {
   194  				hasTmpVolume = true
   195  			}
   196  		}
   197  		assert.True(t, hasAuthVolume)
   198  		assert.True(t, hasTmpVolume)
   199  		assert.True(t, len(deployment.Spec.Template.Spec.ImagePullSecrets) > 0)
   200  		assert.Equal(t, deployment.Spec.Template.Spec.PriorityClassName, "test-class")
   201  		assert.Nil(t, deployment.Spec.RevisionHistoryLimit)
   202  	})
   203  	t.Run("test revisionHistoryLimit", func(t *testing.T) {
   204  		sensorWithRevisionHistoryLimit := sensorObj.DeepCopy()
   205  		sensorWithRevisionHistoryLimit.Spec.RevisionHistoryLimit = func() *int32 { i := int32(3); return &i }()
   206  		args := &AdaptorArgs{
   207  			Image:  testImage,
   208  			Sensor: sensorWithRevisionHistoryLimit,
   209  			Labels: testLabels,
   210  		}
   211  		deployment, err := buildDeployment(args, fakeEventBus)
   212  		assert.Nil(t, err)
   213  		assert.NotNil(t, deployment)
   214  		assert.Equal(t, int32(3), *deployment.Spec.RevisionHistoryLimit)
   215  	})
   216  
   217  	t.Run("test kafka eventbus secrets attached", func(t *testing.T) {
   218  		args := &AdaptorArgs{
   219  			Image:  testImage,
   220  			Sensor: sensorObj,
   221  			Labels: testLabels,
   222  		}
   223  
   224  		// add secrets to kafka eventbus
   225  		testBus := fakeEventBusKafka.DeepCopy()
   226  		testBus.Spec.Kafka.TLS = &apicommon.TLSConfig{
   227  			CACertSecret: &corev1.SecretKeySelector{Key: "cert", LocalObjectReference: corev1.LocalObjectReference{Name: "tls-secret"}},
   228  		}
   229  		testBus.Spec.Kafka.SASL = &apicommon.SASLConfig{
   230  			Mechanism:      "SCRAM-SHA-512",
   231  			UserSecret:     &corev1.SecretKeySelector{Key: "username", LocalObjectReference: corev1.LocalObjectReference{Name: "sasl-secret"}},
   232  			PasswordSecret: &corev1.SecretKeySelector{Key: "password", LocalObjectReference: corev1.LocalObjectReference{Name: "sasl-secret"}},
   233  		}
   234  
   235  		deployment, err := buildDeployment(args, testBus)
   236  		assert.Nil(t, err)
   237  		assert.NotNil(t, deployment)
   238  
   239  		hasSASLSecretVolume := false
   240  		hasSASLSecretVolumeMount := false
   241  		hasTLSSecretVolume := false
   242  		hasTLSSecretVolumeMount := false
   243  		for _, volume := range deployment.Spec.Template.Spec.Volumes {
   244  			if volume.Name == "secret-sasl-secret" {
   245  				hasSASLSecretVolume = true
   246  			}
   247  			if volume.Name == "secret-tls-secret" {
   248  				hasTLSSecretVolume = true
   249  			}
   250  		}
   251  		for _, volumeMount := range deployment.Spec.Template.Spec.Containers[0].VolumeMounts {
   252  			if volumeMount.Name == "secret-sasl-secret" {
   253  				hasSASLSecretVolumeMount = true
   254  			}
   255  			if volumeMount.Name == "secret-tls-secret" {
   256  				hasTLSSecretVolumeMount = true
   257  			}
   258  		}
   259  
   260  		assert.True(t, hasSASLSecretVolume)
   261  		assert.True(t, hasSASLSecretVolumeMount)
   262  		assert.True(t, hasTLSSecretVolume)
   263  		assert.True(t, hasTLSSecretVolumeMount)
   264  	})
   265  
   266  	t.Run("test secret volume and volumemount order deterministic", func(t *testing.T) {
   267  		args := &AdaptorArgs{
   268  			Image:  testImage,
   269  			Sensor: sensorObj,
   270  			Labels: testLabels,
   271  		}
   272  
   273  		wantVolumeNames := []string{"test-data", "auth-volume", "tmp"}
   274  		wantVolumeMountNames := []string{"test-data", "auth-volume", "tmp"}
   275  
   276  		deployment, err := buildDeployment(args, fakeEventBus)
   277  		assert.Nil(t, err)
   278  		assert.NotNil(t, deployment)
   279  		gotVolumes := deployment.Spec.Template.Spec.Volumes
   280  		gotVolumeMounts := deployment.Spec.Template.Spec.Containers[0].VolumeMounts
   281  
   282  		var gotVolumeNames []string
   283  		var gotVolumeMountNames []string
   284  
   285  		for _, v := range gotVolumes {
   286  			gotVolumeNames = append(gotVolumeNames, v.Name)
   287  		}
   288  		for _, v := range gotVolumeMounts {
   289  			gotVolumeMountNames = append(gotVolumeMountNames, v.Name)
   290  		}
   291  
   292  		assert.Equal(t, len(gotVolumes), len(wantVolumeNames))
   293  		assert.Equal(t, len(gotVolumeMounts), len(wantVolumeMountNames))
   294  
   295  		for i := range gotVolumeNames {
   296  			assert.Equal(t, gotVolumeNames[i], wantVolumeNames[i])
   297  		}
   298  		for i := range gotVolumeMountNames {
   299  			assert.Equal(t, gotVolumeMountNames[i], wantVolumeMountNames[i])
   300  		}
   301  	})
   302  }
   303  
   304  func TestResourceReconcile(t *testing.T) {
   305  	t.Run("test resource reconcile without eventbus", func(t *testing.T) {
   306  		cl := fake.NewClientBuilder().Build()
   307  		args := &AdaptorArgs{
   308  			Image:  testImage,
   309  			Sensor: sensorObj,
   310  			Labels: testLabels,
   311  		}
   312  		err := Reconcile(cl, nil, args, logging.NewArgoEventsLogger())
   313  		assert.Error(t, err)
   314  		assert.False(t, sensorObj.Status.IsReady())
   315  	})
   316  
   317  	for _, eb := range []*eventbusv1alpha1.EventBus{fakeEventBus, fakeEventBusJetstream, fakeEventBusKafka} {
   318  		testBus := eb.DeepCopy()
   319  
   320  		t.Run("test resource reconcile with eventbus", func(t *testing.T) {
   321  			ctx := context.TODO()
   322  			cl := fake.NewClientBuilder().Build()
   323  			testBus.Status.MarkDeployed("test", "test")
   324  			testBus.Status.MarkConfigured()
   325  			err := cl.Create(ctx, testBus)
   326  			assert.Nil(t, err)
   327  			args := &AdaptorArgs{
   328  				Image:  testImage,
   329  				Sensor: sensorObj,
   330  				Labels: testLabels,
   331  			}
   332  			err = Reconcile(cl, testBus, args, logging.NewArgoEventsLogger())
   333  			assert.Nil(t, err)
   334  			assert.True(t, sensorObj.Status.IsReady())
   335  
   336  			deployList := &appv1.DeploymentList{}
   337  			err = cl.List(ctx, deployList, &client.ListOptions{
   338  				Namespace: testNamespace,
   339  			})
   340  			assert.NoError(t, err)
   341  			assert.Equal(t, 1, len(deployList.Items))
   342  
   343  			svcList := &corev1.ServiceList{}
   344  			err = cl.List(ctx, svcList, &client.ListOptions{
   345  				Namespace: testNamespace,
   346  			})
   347  			assert.NoError(t, err)
   348  			assert.Equal(t, 0, len(svcList.Items))
   349  		})
   350  	}
   351  }