github.com/argoproj/argo-events@v1.9.1/controllers/eventbus/installer/jetstream_test.go (about)

     1  package installer
     2  
     3  import (
     4  	"context"
     5  
     6  	"testing"
     7  
     8  	"github.com/argoproj/argo-events/common"
     9  	"github.com/argoproj/argo-events/pkg/apis/eventbus/v1alpha1"
    10  	"github.com/stretchr/testify/assert"
    11  	"go.uber.org/zap/zaptest"
    12  	appv1 "k8s.io/api/apps/v1"
    13  	corev1 "k8s.io/api/core/v1"
    14  	apiresource "k8s.io/apimachinery/pkg/api/resource"
    15  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    16  	"k8s.io/apimachinery/pkg/types"
    17  	k8sfake "k8s.io/client-go/kubernetes/fake"
    18  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    19  )
    20  
    21  var (
    22  	testJetStreamEventBus = &v1alpha1.EventBus{
    23  		TypeMeta: metav1.TypeMeta{
    24  			APIVersion: v1alpha1.SchemeGroupVersion.String(),
    25  			Kind:       "EventBus",
    26  		},
    27  		ObjectMeta: metav1.ObjectMeta{
    28  			Namespace: testNamespace,
    29  			Name:      testName,
    30  		},
    31  		Spec: v1alpha1.EventBusSpec{
    32  			JetStream: &v1alpha1.JetStreamBus{
    33  				Version: "2.7.3",
    34  			},
    35  		},
    36  	}
    37  
    38  	testJetStreamExoticBus = &v1alpha1.EventBus{
    39  		TypeMeta: metav1.TypeMeta{
    40  			APIVersion: v1alpha1.SchemeGroupVersion.String(),
    41  			Kind:       "EventBus",
    42  		},
    43  		ObjectMeta: metav1.ObjectMeta{
    44  			Namespace: testNamespace,
    45  			Name:      testName,
    46  		},
    47  		Spec: v1alpha1.EventBusSpec{
    48  			JetStreamExotic: &v1alpha1.JetStreamConfig{
    49  				URL: "nats://nats:4222",
    50  			},
    51  		},
    52  	}
    53  )
    54  
    55  func TestJetStreamBadInstallation(t *testing.T) {
    56  	t.Run("bad installation", func(t *testing.T) {
    57  		badEventBus := testJetStreamEventBus.DeepCopy()
    58  		badEventBus.Spec.JetStream = nil
    59  		installer := &jetStreamInstaller{
    60  			client:     fake.NewClientBuilder().Build(),
    61  			kubeClient: k8sfake.NewSimpleClientset(),
    62  			eventBus:   badEventBus,
    63  			config:     fakeConfig,
    64  			labels:     testLabels,
    65  			logger:     zaptest.NewLogger(t).Sugar(),
    66  		}
    67  		_, err := installer.Install(context.TODO())
    68  		assert.Error(t, err)
    69  	})
    70  }
    71  
    72  func TestJetStreamGenerateNames(t *testing.T) {
    73  	n := generateJetStreamStatefulSetName(testJetStreamEventBus)
    74  	assert.Equal(t, "eventbus-"+testJetStreamEventBus.Name+"-js", n)
    75  	n = generateJetStreamServerSecretName(testJetStreamEventBus)
    76  	assert.Equal(t, "eventbus-"+testJetStreamEventBus.Name+"-js-server", n)
    77  	n = generateJetStreamClientAuthSecretName(testJetStreamEventBus)
    78  	assert.Equal(t, "eventbus-"+testJetStreamEventBus.Name+"-js-client-auth", n)
    79  	n = generateJetStreamConfigMapName(testJetStreamEventBus)
    80  	assert.Equal(t, "eventbus-"+testJetStreamEventBus.Name+"-js-config", n)
    81  	n = generateJetStreamPVCName(testJetStreamEventBus)
    82  	assert.Equal(t, "eventbus-"+testJetStreamEventBus.Name+"-js-vol", n)
    83  	n = generateJetStreamServiceName(testJetStreamEventBus)
    84  	assert.Equal(t, "eventbus-"+testJetStreamEventBus.Name+"-js-svc", n)
    85  }
    86  
    87  func TestJetStreamCreateObjects(t *testing.T) {
    88  	cl := fake.NewClientBuilder().Build()
    89  	ctx := context.TODO()
    90  	i := &jetStreamInstaller{
    91  		client:     cl,
    92  		kubeClient: k8sfake.NewSimpleClientset(),
    93  		eventBus:   testJetStreamEventBus,
    94  		config:     fakeConfig,
    95  		labels:     testLabels,
    96  		logger:     zaptest.NewLogger(t).Sugar(),
    97  	}
    98  
    99  	t.Run("test create sts", func(t *testing.T) {
   100  		testObj := testJetStreamEventBus.DeepCopy()
   101  		i.eventBus = testObj
   102  		err := i.createStatefulSet(ctx)
   103  		assert.NoError(t, err)
   104  		sts := &appv1.StatefulSet{}
   105  		err = cl.Get(ctx, types.NamespacedName{Namespace: testObj.Namespace, Name: generateJetStreamStatefulSetName(testObj)}, sts)
   106  		assert.NoError(t, err)
   107  		assert.Equal(t, 3, len(sts.Spec.Template.Spec.Containers))
   108  		assert.Contains(t, sts.Annotations, common.AnnotationResourceSpecHash)
   109  		assert.Equal(t, testJetStreamImage, sts.Spec.Template.Spec.Containers[0].Image)
   110  		assert.Equal(t, testJSReloaderImage, sts.Spec.Template.Spec.Containers[1].Image)
   111  		assert.Equal(t, testJetStreamExporterImage, sts.Spec.Template.Spec.Containers[2].Image)
   112  		assert.True(t, len(sts.Spec.Template.Spec.Volumes) > 1)
   113  		envNames := []string{}
   114  		for _, e := range sts.Spec.Template.Spec.Containers[0].Env {
   115  			envNames = append(envNames, e.Name)
   116  		}
   117  		for _, e := range []string{"POD_NAME", "SERVER_NAME", "POD_NAMESPACE", "CLUSTER_ADVERTISE", "JS_KEY"} {
   118  			assert.Contains(t, envNames, e)
   119  		}
   120  	})
   121  
   122  	t.Run("test create svc", func(t *testing.T) {
   123  		testObj := testJetStreamEventBus.DeepCopy()
   124  		i.eventBus = testObj
   125  		err := i.createService(ctx)
   126  		assert.NoError(t, err)
   127  		svc := &corev1.Service{}
   128  		err = cl.Get(ctx, types.NamespacedName{Namespace: testObj.Namespace, Name: generateJetStreamServiceName(testObj)}, svc)
   129  		assert.NoError(t, err)
   130  		assert.Equal(t, 4, len(svc.Spec.Ports))
   131  		assert.Contains(t, svc.Annotations, common.AnnotationResourceSpecHash)
   132  	})
   133  
   134  	t.Run("test create auth secrets", func(t *testing.T) {
   135  		testObj := testJetStreamEventBus.DeepCopy()
   136  		i.eventBus = testObj
   137  		err := i.createSecrets(ctx)
   138  		assert.NoError(t, err)
   139  		s := &corev1.Secret{}
   140  		err = cl.Get(ctx, types.NamespacedName{Namespace: testObj.Namespace, Name: generateJetStreamServerSecretName(testObj)}, s)
   141  		assert.NoError(t, err)
   142  		assert.Equal(t, 8, len(s.Data))
   143  		assert.Contains(t, s.Data, common.JetStreamServerSecretAuthKey)
   144  		assert.Contains(t, s.Data, common.JetStreamServerSecretEncryptionKey)
   145  		assert.Contains(t, s.Data, common.JetStreamServerPrivateKeyKey)
   146  		assert.Contains(t, s.Data, common.JetStreamServerCertKey)
   147  		assert.Contains(t, s.Data, common.JetStreamServerCACertKey)
   148  		assert.Contains(t, s.Data, common.JetStreamClusterPrivateKeyKey)
   149  		assert.Contains(t, s.Data, common.JetStreamClusterCertKey)
   150  		assert.Contains(t, s.Data, common.JetStreamClusterCACertKey)
   151  		s = &corev1.Secret{}
   152  		err = cl.Get(ctx, types.NamespacedName{Namespace: testObj.Namespace, Name: generateJetStreamClientAuthSecretName(testObj)}, s)
   153  		assert.NoError(t, err)
   154  		assert.Equal(t, 1, len(s.Data))
   155  		assert.Contains(t, s.Data, common.JetStreamClientAuthSecretKey)
   156  	})
   157  
   158  	t.Run("test create configmap", func(t *testing.T) {
   159  		testObj := testJetStreamEventBus.DeepCopy()
   160  		i.eventBus = testObj
   161  		err := i.createConfigMap(ctx)
   162  		assert.NoError(t, err)
   163  		c := &corev1.ConfigMap{}
   164  		err = cl.Get(ctx, types.NamespacedName{Namespace: testObj.Namespace, Name: generateJetStreamConfigMapName(testObj)}, c)
   165  		assert.NoError(t, err)
   166  		assert.Equal(t, 1, len(c.Data))
   167  		assert.Contains(t, c.Annotations, common.AnnotationResourceSpecHash)
   168  	})
   169  }
   170  
   171  func TestBuildJetStreamStatefulSetSpec(t *testing.T) {
   172  	cl := fake.NewClientBuilder().Build()
   173  	i := &jetStreamInstaller{
   174  		client:   cl,
   175  		eventBus: testJetStreamEventBus,
   176  		config:   fakeConfig,
   177  		labels:   testLabels,
   178  		logger:   zaptest.NewLogger(t).Sugar(),
   179  	}
   180  
   181  	t.Run("without persistence", func(t *testing.T) {
   182  		s := i.buildStatefulSetSpec(&fakeConfig.EventBus.JetStream.Versions[0])
   183  		assert.Equal(t, int32(3), *s.Replicas)
   184  		assert.Equal(t, generateJetStreamServiceName(testJetStreamEventBus), s.ServiceName)
   185  		assert.Equal(t, testJetStreamImage, s.Template.Spec.Containers[0].Image)
   186  		assert.Equal(t, testJSReloaderImage, s.Template.Spec.Containers[1].Image)
   187  		assert.Equal(t, testJetStreamExporterImage, s.Template.Spec.Containers[2].Image)
   188  		assert.Equal(t, "test-controller", s.Selector.MatchLabels["controller"])
   189  		assert.Equal(t, jsClientPort, s.Template.Spec.Containers[0].Ports[0].ContainerPort)
   190  		assert.Equal(t, jsClusterPort, s.Template.Spec.Containers[0].Ports[1].ContainerPort)
   191  		assert.Equal(t, jsMonitorPort, s.Template.Spec.Containers[0].Ports[2].ContainerPort)
   192  		assert.Equal(t, jsMetricsPort, s.Template.Spec.Containers[2].Ports[0].ContainerPort)
   193  		assert.False(t, len(s.VolumeClaimTemplates) > 0)
   194  		assert.True(t, len(s.Template.Spec.Volumes) > 0)
   195  	})
   196  
   197  	t.Run("with persistence", func(t *testing.T) {
   198  		st := "test"
   199  		i.eventBus.Spec.JetStream = &v1alpha1.JetStreamBus{
   200  			Persistence: &v1alpha1.PersistenceStrategy{
   201  				StorageClassName: &st,
   202  			},
   203  		}
   204  		s := i.buildStatefulSetSpec(&fakeConfig.EventBus.JetStream.Versions[0])
   205  		assert.True(t, len(s.VolumeClaimTemplates) > 0)
   206  	})
   207  
   208  	t.Run("with resource requests", func(t *testing.T) {
   209  		i.eventBus.Spec.JetStream = &v1alpha1.JetStreamBus{
   210  			ContainerTemplate: &v1alpha1.ContainerTemplate{
   211  				Resources: corev1.ResourceRequirements{
   212  					Limits: corev1.ResourceList{
   213  						corev1.ResourceCPU:    apiresource.Quantity{Format: "1"},
   214  						corev1.ResourceMemory: apiresource.Quantity{Format: "350Mi"},
   215  					},
   216  					Requests: corev1.ResourceList{
   217  						corev1.ResourceCPU:    apiresource.Quantity{Format: "1"},
   218  						corev1.ResourceMemory: apiresource.Quantity{Format: "400Mi"},
   219  					},
   220  				},
   221  			},
   222  
   223  			MetricsContainerTemplate: &v1alpha1.ContainerTemplate{
   224  				Resources: corev1.ResourceRequirements{
   225  					Limits: corev1.ResourceList{
   226  						corev1.ResourceCPU:    apiresource.Quantity{Format: "1"},
   227  						corev1.ResourceMemory: apiresource.Quantity{Format: "200Mi"},
   228  					},
   229  					Requests: corev1.ResourceList{
   230  						corev1.ResourceCPU:    apiresource.Quantity{Format: "1"},
   231  						corev1.ResourceMemory: apiresource.Quantity{Format: "200Mi"},
   232  					},
   233  				},
   234  			},
   235  
   236  			ReloaderContainerTemplate: &v1alpha1.ContainerTemplate{
   237  				Resources: corev1.ResourceRequirements{
   238  					Limits: corev1.ResourceList{
   239  						corev1.ResourceCPU:    apiresource.Quantity{Format: ".3"},
   240  						corev1.ResourceMemory: apiresource.Quantity{Format: "100Mi"},
   241  					},
   242  					Requests: corev1.ResourceList{
   243  						corev1.ResourceCPU:    apiresource.Quantity{Format: ".5"},
   244  						corev1.ResourceMemory: apiresource.Quantity{Format: "100Mi"},
   245  					},
   246  				},
   247  			},
   248  		}
   249  
   250  		statefulSpec := i.buildStatefulSetSpec(&fakeConfig.EventBus.JetStream.Versions[0])
   251  
   252  		podContainers := statefulSpec.Template.Spec.Containers
   253  		containers := map[string]*corev1.Container{}
   254  		for idx := range podContainers {
   255  			containers[podContainers[idx].Name] = &podContainers[idx]
   256  		}
   257  
   258  		js := i.eventBus.Spec.JetStream
   259  		assert.Equal(t, js.ContainerTemplate.Resources, containers["main"].Resources)
   260  		assert.Equal(t, js.MetricsContainerTemplate.Resources, containers["metrics"].Resources)
   261  		assert.Equal(t, js.ReloaderContainerTemplate.Resources, containers["reloader"].Resources)
   262  	})
   263  }
   264  
   265  func TestJetStreamGetServiceSpec(t *testing.T) {
   266  	cl := fake.NewClientBuilder().Build()
   267  	i := &jetStreamInstaller{
   268  		client:   cl,
   269  		eventBus: testJetStreamEventBus,
   270  		config:   fakeConfig,
   271  		labels:   testLabels,
   272  		logger:   zaptest.NewLogger(t).Sugar(),
   273  	}
   274  	spec := i.buildJetStreamServiceSpec()
   275  	assert.Equal(t, 4, len(spec.Ports))
   276  	assert.Equal(t, corev1.ClusterIPNone, spec.ClusterIP)
   277  }
   278  
   279  func Test_JSBufferGetReplicas(t *testing.T) {
   280  	s := v1alpha1.JetStreamBus{}
   281  	assert.Equal(t, 3, s.GetReplicas())
   282  	five := int32(5)
   283  	s.Replicas = &five
   284  	assert.Equal(t, 5, s.GetReplicas())
   285  }