diff --git a/cluster/cluster_test.go b/cluster/cluster_test.go new file mode 100644 index 00000000..e72c9bfd --- /dev/null +++ b/cluster/cluster_test.go @@ -0,0 +1,656 @@ +/* +Copyright 2021 RadonDB. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cluster + +import ( + "fmt" + "reflect" + "strconv" + "testing" + + . "bou.ke/monkey" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + mysqlv1alpha1 "github.com/radondb/radondb-mysql-kubernetes/api/v1alpha1" + "github.com/radondb/radondb-mysql-kubernetes/utils" +) + +var ( + mysqlCluster = mysqlv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sample", + }, + Spec: mysqlv1alpha1.ClusterSpec{ + MysqlVersion: "5.7", + }, + } + testCluster = Cluster{ + &mysqlCluster, + } +) + +func TestNew(t *testing.T) { + want := &Cluster{ + &mysqlCluster, + } + assert.Equal(t, want, New(&mysqlCluster)) +} + +func TestUnwrap(t *testing.T) { + assert.Equal(t, &mysqlCluster, testCluster.Unwrap()) +} + +func TestGetLabel(t *testing.T) { + //when the instance label exist + { + testMysqlCluster := mysqlCluster + testMysqlCluster.Annotations = map[string]string{ + "app.kubernetes.io/instance": "instance", + } + testCase := Cluster{ + &testMysqlCluster, + } + want := labels.Set{ + "mysql.radondb.com/cluster": "sample", + "app.kubernetes.io/name": "mysql", + "app.kubernetes.io/instance": "instance", + "app.kubernetes.io/version": "5.7.33", + "app.kubernetes.io/component": "database", + "app.kubernetes.io/managed-by": "mysql.radondb.com", + } + assert.Equal(t, want, testCase.GetLabels()) + } + //when the component label exist + { + testMysqlCluster := mysqlCluster + testMysqlCluster.Annotations = map[string]string{ + "app.kubernetes.io/component": "component", + } + testCase := Cluster{ + &testMysqlCluster, + } + want := labels.Set{ + "mysql.radondb.com/cluster": "sample", + "app.kubernetes.io/name": "mysql", + "app.kubernetes.io/instance": "sample", + "app.kubernetes.io/version": "5.7.33", + "app.kubernetes.io/component": "component", + "app.kubernetes.io/managed-by": "mysql.radondb.com", + } + assert.Equal(t, want, testCase.GetLabels()) + } + //when the part-of label exist + { + testMysqlCluster := mysqlCluster + testMysqlCluster.Annotations = map[string]string{ + "app.kubernetes.io/part-of": "part-of", + } + testCase := Cluster{ + &testMysqlCluster, + } + want := labels.Set{ + "mysql.radondb.com/cluster": "sample", + "app.kubernetes.io/name": "mysql", + "app.kubernetes.io/instance": "sample", + "app.kubernetes.io/version": "5.7.33", + "app.kubernetes.io/component": "database", + "app.kubernetes.io/managed-by": "mysql.radondb.com", + "app.kubernetes.io/part-of": "part-of", + } + assert.Equal(t, want, testCase.GetLabels()) + } +} + +func TestGetSelectorLabels(t *testing.T) { + want := labels.Set{ + "mysql.radondb.com/cluster": "sample", + "app.kubernetes.io/name": "mysql", + "app.kubernetes.io/managed-by": "mysql.radondb.com", + } + assert.Equal(t, want, testCluster.GetSelectorLabels()) +} + +func TestGetMySQLVersion(t *testing.T) { + //other 8.0 -> 5.7.33 + { + testMysqlCluster := mysqlCluster + testMysqlCluster.Spec.MysqlVersion = "8.0" + testCase := Cluster{ + &testMysqlCluster, + } + want := "5.7.33" + assert.Equal(t, want, testCase.GetMySQLVersion()) + } + //MySQLTagsToSemVer 5.7 -> 5.7.33 + { + testMysqlCluster := mysqlCluster + testMysqlCluster.Spec.MysqlVersion = "5.7" + testCase := Cluster{ + &testMysqlCluster, + } + want := "5.7.33" + assert.Equal(t, want, testCase.GetMySQLVersion()) + } + //MysqlImageVersions 5.7.33 -> 5.7.33 + { + testMysqlCluster := mysqlCluster + testMysqlCluster.Spec.MysqlVersion = "5.7.33" + testCase := Cluster{ + &testMysqlCluster, + } + want := "5.7.33" + assert.Equal(t, want, testCase.GetMySQLVersion()) + } +} + +func TestCreatePeers(t *testing.T) { + var replicas int32 = 2 + + { + testMysqlCluster := mysqlCluster + testMysqlCluster.ObjectMeta.Namespace = "default" + testMysqlCluster.Spec.Replicas = &replicas + testCase := Cluster{ + &testMysqlCluster, + } + want := "sample-mysql-0.sample-mysql.default:8801,sample-mysql-1.sample-mysql.default:8801" + assert.Equal(t, want, testCase.CreatePeers()) + } + { + replicas = 3 + testMysqlCluster := mysqlCluster + testMysqlCluster.ObjectMeta.Namespace = "default" + testMysqlCluster.Spec.Replicas = &replicas + testCase := Cluster{ + &testMysqlCluster, + } + want := "sample-mysql-0.sample-mysql.default:8801,sample-mysql-1.sample-mysql.default:8801,sample-mysql-2.sample-mysql.default:8801" + assert.Equal(t, want, testCase.CreatePeers()) + } + { + replicas = 666 + testMysqlCluster := mysqlCluster + testMysqlCluster.ObjectMeta.Namespace = "default" + testMysqlCluster.Spec.Replicas = &replicas + testCase := Cluster{ + &testMysqlCluster, + } + want := "" + for i := 0; i < 666; i++ { + if i > 0 { + want += "," + } + want += fmt.Sprintf("%s:%d", "sample-mysql-"+strconv.Itoa(i)+".sample-mysql.default", 8801) + } + + assert.Equal(t, want, testCase.CreatePeers()) + } + { + replicas = 0 + testMysqlCluster := mysqlCluster + testMysqlCluster.ObjectMeta.Namespace = "default" + testMysqlCluster.Spec.Replicas = &replicas + testCase := Cluster{ + &testMysqlCluster, + } + want := "" + assert.Equal(t, want, testCase.CreatePeers()) + } + { + replicas = -1 + testMysqlCluster := mysqlCluster + testMysqlCluster.ObjectMeta.Namespace = "default" + testMysqlCluster.Spec.Replicas = &replicas + testCase := Cluster{ + &testMysqlCluster, + } + want := "" + assert.Equal(t, want, testCase.CreatePeers()) + } +} + +func TestGetPodHostName(t *testing.T) { + testMysqlCluster := mysqlCluster + testMysqlCluster.ObjectMeta.Namespace = "default" + testCase := Cluster{ + &testMysqlCluster, + } + want0 := "sample-mysql-0.sample-mysql.default" + want1 := "sample-mysql-1.sample-mysql.default" + assert.Equal(t, want0, testCase.GetPodHostName(0)) + assert.Equal(t, want1, testCase.GetPodHostName(1)) +} + +func TestEnsureVolumes(t *testing.T) { + volume := []corev1.Volume{ + { + Name: utils.ConfVolumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: utils.LogsVolumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: utils.ConfMapVolumeName, + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "sample-mysql", + }, + }, + }, + }, + { + Name: utils.ScriptsVolumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: utils.XenonVolumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: utils.InitFileVolumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + } + //when disable Persistence + { + testMysql := mysqlCluster + testMysql.Spec.Persistence.Enabled = false + testCase := Cluster{ + &testMysql, + } + want := []corev1.Volume{ + { + Name: utils.DataVolumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + } + want = append(want, volume...) + assert.Equal(t, want, testCase.EnsureVolumes()) + } + //when enable tokudb + { + testMysql := mysqlCluster + testMysql.Spec.Persistence.Enabled = true + testMysql.Spec.MysqlOpts.InitTokuDB = true + testCase := Cluster{ + &testMysql, + } + want := []corev1.Volume{ + { + Name: utils.SysVolumeName, + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: "/sys/kernel/mm/transparent_hugepage", + }, + }, + }, + } + want = append(want, volume...) + assert.Equal(t, want, testCase.EnsureVolumes()) + } + //default(Persistence is turned on by default) + { + testMysql := mysqlCluster + testMysql.Spec.Persistence.Enabled = true + testCase := Cluster{ + &testMysql, + } + assert.Equal(t, volume, testCase.EnsureVolumes()) + } +} + +func TestEnsureVolumeClaimTemplates(t *testing.T) { + var scheme runtime.Scheme + //when disable persistence + { + result, err := testCluster.EnsureVolumeClaimTemplates(&scheme) + assert.Nil(t, result) + assert.Nil(t, err) + } + + //when enable persistence + { + var cluster *Cluster + storageClass := "ssd" + testMysql := mysqlv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sample", + Namespace: "default", + Labels: nil, + }, + Spec: mysqlv1alpha1.ClusterSpec{ + MysqlVersion: "5.7", + Persistence: mysqlv1alpha1.Persistence{ + AccessModes: nil, + StorageClass: &storageClass, + Enabled: true, + }, + }, + } + testCase := Cluster{ + &testMysql, + } + want := []corev1.PersistentVolumeClaim{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "data", + Namespace: "default", + Labels: nil, + }, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: nil, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.Quantity{}, + }, + }, + StorageClassName: &storageClass, + }, + }, + } + guard := PatchInstanceMethod(reflect.TypeOf(cluster), "GetLabels", func(*Cluster) labels.Set { + return nil + }) + guard1 := Patch(resource.MustParse, func(_ string) resource.Quantity { + return resource.Quantity{} + }) + guard2 := Patch(controllerutil.SetControllerReference, func(_ metav1.Object, _ metav1.Object, _ *runtime.Scheme) error { + return nil + }) + defer guard.Unpatch() + defer guard1.Unpatch() + defer guard2.Unpatch() + result, err := testCase.EnsureVolumeClaimTemplates(&scheme) + assert.Equal(t, want, result) + assert.Nil(t, err) + } + + //when the StorageClass is "-" + { + storageClass := "-" + testMysql := mysqlCluster + testMysql.Spec.Persistence.Enabled = true + testMysql.Spec.Persistence.Size = "10Gi" + testMysql.Spec.Persistence.StorageClass = &storageClass + testCase := Cluster{ + &testMysql, + } + guard := Patch(controllerutil.SetControllerReference, func(_ metav1.Object, _ metav1.Object, _ *runtime.Scheme) error { + return nil + }) + defer guard.Unpatch() + result, err := testCase.EnsureVolumeClaimTemplates(&scheme) + + assert.Equal(t, &storageClass, result[0].Spec.StorageClassName) + assert.Nil(t, err) + } + + //when SetControllerReference error + { + testMysql := mysqlCluster + testMysql.Spec.Persistence.Enabled = true + testMysql.Spec.Persistence.Size = "10Gi" + testCase := Cluster{ + &testMysql, + } + guard := Patch(controllerutil.SetControllerReference, func(_ metav1.Object, _ metav1.Object, _ *runtime.Scheme) error { + return fmt.Errorf("test") + }) + defer guard.Unpatch() + result, err := testCase.EnsureVolumeClaimTemplates(&scheme) + want := fmt.Errorf("failed setting controller reference: test") + assert.Nil(t, result) + assert.Equal(t, want, err) + } +} + +func TestGetNameForResource(t *testing.T) { + //statefulset configMap headlessSvc + { + want := "sample-mysql" + assert.Equal(t, want, testCluster.GetNameForResource(utils.StatefulSet)) + assert.Equal(t, want, testCluster.GetNameForResource(utils.ConfigMap)) + assert.Equal(t, want, testCluster.GetNameForResource(utils.HeadlessSVC)) + } + //leaderSvc + { + want := "sample-leader" + assert.Equal(t, want, testCluster.GetNameForResource(utils.LeaderService)) + } + //folloerSvc + { + want := "sample-follower" + assert.Equal(t, want, testCluster.GetNameForResource(utils.FollowerService)) + } + //secret + { + want := "sample-secret" + assert.Equal(t, want, testCluster.GetNameForResource(utils.Secret)) + } + //others + { + want := "sample" + assert.Equal(t, want, testCluster.GetNameForResource("others")) + } +} + +func TestEnsureMysqlConf(t *testing.T) { + var ( + gb int64 = 1 << 30 + mb int64 = 1 << 20 + wantSize, wantInstance string + ) + + requestsMemory := resource.NewQuantity(gb, resource.BinarySI) + LimitCpucorev1s := resource.NewQuantity(1, resource.DecimalSI) + testMysql := mysqlCluster + testMysql.Spec = mysqlv1alpha1.ClusterSpec{ + PodSpec: mysqlv1alpha1.PodSpec{ + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + "cpu": *LimitCpucorev1s, + }, + }, + }, + MysqlOpts: mysqlv1alpha1.MysqlOpts{ + MysqlConf: mysqlv1alpha1.MysqlConf{}, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + "memory": *requestsMemory, + }, + }, + }, + } + //cpu 1 corev1s,memory 1 gb,innodb_buffer_pool_size not set + { + testMysqlCase := testMysql + testCase := Cluster{ + &testMysqlCase, + } + testCase.EnsureMysqlConf() + wantSize = strconv.FormatUint(uint64(0.45*float64(gb)), 10) + wantInstance = strconv.Itoa(int(1)) + assert.Equal(t, wantSize, testCase.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"]) + assert.Equal(t, wantInstance, testCase.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_instances"]) + } + //cpu 1 corev1s,memory 1 gb,innodb_buffer_pool_size 600 mb + { + guard := Patch(sizeToBytes, func(s string) (uint64, error) { + return uint64(600 * mb), nil + }) + defer guard.Unpatch() + + testMysqlCase := testMysql + testMysqlCase.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"] = strconv.FormatUint(uint64(600*mb), 10) + testCase := Cluster{ + &testMysqlCase, + } + testCase.EnsureMysqlConf() + wantSize := strconv.FormatUint(uint64(600*float64(mb)), 10) + wantInstance := strconv.Itoa(int(1)) + assert.Equal(t, wantSize, testCase.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"]) + assert.Equal(t, wantInstance, testCase.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_instances"]) + } + //cpu 1 corev1s,memory 2 gb,innodb_buffer_pool_size 1.7 gb + { + guard := Patch(sizeToBytes, func(s string) (uint64, error) { + return uint64(1700 * mb), nil + }) + defer guard.Unpatch() + + memoryCase := resource.NewQuantity(2*gb, resource.BinarySI) + testMysqlCase := testMysql + testMysqlCase.Spec.MysqlOpts.Resources.Requests["memory"] = *memoryCase + testMysqlCase.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"] = strconv.FormatUint(uint64(1.7*float64(gb)), 10) + testCase := Cluster{ + &testMysqlCase, + } + testCase.EnsureMysqlConf() + wantSize := strconv.FormatUint(uint64(1.6*float64(gb)), 10) + wantInstance := strconv.Itoa(int(1)) + assert.Equal(t, wantSize, testCase.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"]) + assert.Equal(t, wantInstance, testCase.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_instances"]) + } + //cpu 1 corev1s,memory 2 gb,innodb_buffer_pool_size 1.7 gb, sizeToBytes error + { + guard := Patch(sizeToBytes, func(s string) (uint64, error) { + return uint64(1700 * mb), fmt.Errorf("error") + }) + defer guard.Unpatch() + memoryCase := resource.NewQuantity(2*gb, resource.BinarySI) + testMysqlCase := testMysql + testMysqlCase.Spec.MysqlOpts.Resources.Requests["memory"] = *memoryCase + testMysqlCase.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"] = strconv.FormatUint(uint64(1.7*float64(gb)), 10) + testCase := Cluster{ + &testMysqlCase, + } + testCase.EnsureMysqlConf() + wantSize := strconv.FormatUint(uint64(1.2*float64(gb)), 10) + wantInstance := strconv.Itoa(int(1)) + assert.Equal(t, wantSize, testCase.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"]) + assert.Equal(t, wantInstance, testCase.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_instances"]) + } + //cpu 8 corev1s,memory 16 gb,innodb_buffer_pool_size 2 gb + { + guard := Patch(sizeToBytes, func(s string) (uint64, error) { + return uint64(2 * gb), nil + }) + defer guard.Unpatch() + + memoryCase := resource.NewQuantity(16*gb, resource.BinarySI) + limitCpucorev1sCase := resource.NewQuantity(4, resource.DecimalSI) + testMysqlCase := testMysql + testMysqlCase.Spec.PodSpec.Resources.Limits["cpu"] = *limitCpucorev1sCase + testMysqlCase.Spec.MysqlOpts.Resources.Requests["memory"] = *memoryCase + testCase := Cluster{ + &testMysqlCase, + } + testCase.EnsureMysqlConf() + wantSize := strconv.FormatUint(uint64(2*float64(gb)), 10) + wantInstance := strconv.Itoa(int(2)) + assert.Equal(t, wantSize, testCase.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"]) + assert.Equal(t, wantInstance, testCase.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_instances"]) + } +} + +func TestSizeToBytes(t *testing.T) { + var ( + gb int64 = 1 << 30 + mb int64 = 1 << 20 + kb int64 = 1 << 10 + ) + //kb + { + testCase := "1000k" + want := uint64(1000 * kb) + result, err := sizeToBytes(testCase) + assert.Equal(t, want, result) + assert.Nil(t, err) + } + //mb + { + testCase := "1000m" + want := uint64(1000 * mb) + result, err := sizeToBytes(testCase) + assert.Equal(t, want, result) + assert.Nil(t, err) + } + //gb + { + testCase := "1000g" + want := uint64(1000 * gb) + result, err := sizeToBytes(testCase) + assert.Equal(t, want, result) + assert.Nil(t, err) + } + //others + { + testCase := "1000a" + want := uint64(0) + wantError := fmt.Errorf("'1000A' format error, must be a positive integer with a unit of measurement like K, M or G") + result, err := sizeToBytes(testCase) + assert.Equal(t, want, result) + assert.Equal(t, wantError, err) + } + //it will return the result of ParseUint() when the parameter without unit + { + guard := Patch(strconv.ParseUint, func(s string, base int, bitSize int) (uint64, error) { + return uint64(666), nil + }) + defer guard.Unpatch() + + testCase := "1000" + want := uint64(666) + result, err := sizeToBytes(testCase) + assert.Equal(t, want, result) + assert.Nil(t, err) + } + //ParseUint error + { + guard := Patch(strconv.ParseUint, func(s string, base int, bitSize int) (uint64, error) { + return uint64(777), fmt.Errorf("error") + }) + defer guard.Unpatch() + + testCase := "1000k" + want := uint64(0) + result, err := sizeToBytes(testCase) + assert.Equal(t, want, result) + assert.Equal(t, err, fmt.Errorf("error")) + } +} diff --git a/cluster/container/auditlog_test.go b/cluster/container/auditlog_test.go new file mode 100644 index 00000000..c1d08525 --- /dev/null +++ b/cluster/container/auditlog_test.go @@ -0,0 +1,95 @@ +/* +Copyright 2021 RadonDB. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package container + +import ( + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + + mysqlv1alpha1 "github.com/radondb/radondb-mysql-kubernetes/api/v1alpha1" + "github.com/radondb/radondb-mysql-kubernetes/cluster" +) + +var ( + auditlogMysqlCluster = mysqlv1alpha1.Cluster{ + Spec: mysqlv1alpha1.ClusterSpec{ + PodSpec: mysqlv1alpha1.PodSpec{ + BusyboxImage: "busybox", + Resources: corev1.ResourceRequirements{ + Limits: nil, + Requests: nil, + }, + }, + }, + } + testAuditlogCluster = cluster.Cluster{ + Cluster: &auditlogMysqlCluster, + } + auditLogCase = EnsureContainer("auditlog", &testAuditlogCluster) + auditlogCommand = []string{"tail", "-f", "/var/log/mysql" + "/mysql-audit.log"} + auditlogVolumeMounts = []corev1.VolumeMount{ + { + Name: "logs", + MountPath: "/var/log/mysql", + }, + } +) + +func TestGetAuditlogName(t *testing.T) { + assert.Equal(t, "auditlog", auditLogCase.Name) +} + +func TestGetAuditlogImage(t *testing.T) { + assert.Equal(t, "busybox", auditLogCase.Image) +} + +func TestGetAuditlogCommand(t *testing.T) { + assert.Equal(t, auditlogCommand, auditLogCase.Command) +} + +func TestGetAuditlogEnvVar(t *testing.T) { + assert.Nil(t, auditLogCase.Env) +} + +func TestGetAuditlogLifecycle(t *testing.T) { + assert.Nil(t, auditLogCase.Lifecycle) +} + +func TestGetAuditlogResources(t *testing.T) { + assert.Equal(t, corev1.ResourceRequirements{ + Limits: nil, + Requests: nil, + }, auditLogCase.Resources) +} + +func TestGetAuditlogPorts(t *testing.T) { + assert.Nil(t, auditLogCase.Ports) +} + +func TestGetAuditlogLivenessProbe(t *testing.T) { + assert.Nil(t, auditLogCase.LivenessProbe) +} + +func TestGetAuditlogReadinessProbe(t *testing.T) { + assert.Nil(t, auditLogCase.ReadinessProbe) +} + +func TestGetAuditlogVolumeMounts(t *testing.T) { + assert.Equal(t, auditlogVolumeMounts, auditLogCase.VolumeMounts) +} diff --git a/cluster/container/init_mysql_test.go b/cluster/container/init_mysql_test.go new file mode 100644 index 00000000..8510a707 --- /dev/null +++ b/cluster/container/init_mysql_test.go @@ -0,0 +1,201 @@ +/* +Copyright 2021 RadonDB. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package container + +import ( + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + mysqlv1alpha1 "github.com/radondb/radondb-mysql-kubernetes/api/v1alpha1" + "github.com/radondb/radondb-mysql-kubernetes/cluster" + "github.com/radondb/radondb-mysql-kubernetes/utils" +) + +var ( + initMysqlMysqlCluster = mysqlv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sample", + }, + Spec: mysqlv1alpha1.ClusterSpec{ + PodSpec: mysqlv1alpha1.PodSpec{ + Resources: corev1.ResourceRequirements{ + Limits: nil, + Requests: nil, + }, + }, + MysqlVersion: "5.7", + MysqlOpts: mysqlv1alpha1.MysqlOpts{ + InitTokuDB: false, + }, + }, + } + testInitMysqlCluster = cluster.Cluster{ + Cluster: &initMysqlMysqlCluster, + } + initMysqlVolumeMounts = []corev1.VolumeMount{ + { + Name: utils.ConfVolumeName, + MountPath: utils.ConfVolumeMountPath, + }, + { + Name: utils.ConfMapVolumeName, + MountPath: utils.MyCnfMountPath, + SubPath: "my.cnf", + }, + { + Name: utils.DataVolumeName, + MountPath: utils.DataVolumeMountPath, + }, + { + Name: utils.LogsVolumeName, + MountPath: utils.LogsVolumeMountPath, + }, + { + Name: utils.InitFileVolumeName, + MountPath: utils.InitFileVolumeMountPath, + }, + } + optFalse = false + optTrue = true + sctName = "sample-secret" + initMysqlEnvs = []corev1.EnvVar{ + { + Name: "MYSQL_ALLOW_EMPTY_PASSWORD", + Value: "yes", + }, + { + Name: "MYSQL_ROOT_HOST", + Value: "127.0.0.1", + }, + { + Name: "MYSQL_INIT_ONLY", + Value: "1", + }, + { + Name: "MYSQL_ROOT_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: sctName, + }, + Key: "root-password", + Optional: &optFalse, + }, + }, + }, + { + Name: "MYSQL_DATABASE", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: sctName, + }, + Key: "mysql-database", + Optional: &optTrue, + }, + }, + }, + { + Name: "MYSQL_USER", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: sctName, + }, + Key: "mysql-user", + Optional: &optTrue, + }, + }, + }, + { + Name: "MYSQL_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: sctName, + }, + Key: "mysql-password", + Optional: &optTrue, + }, + }, + }, + } + initMysqlCase = EnsureContainer("init-mysql", &testInitMysqlCluster) +) + +func TestGetInitMysqlName(t *testing.T) { + assert.Equal(t, "init-mysql", initMysqlCase.Name) +} + +func TestGetInitMysqlImage(t *testing.T) { + assert.Equal(t, "percona/percona-server:5.7.33", initMysqlCase.Image) +} + +func TestGetInitMysqlCommand(t *testing.T) { + assert.Nil(t, initMysqlCase.Command) +} + +func TestGetInitMysqlEnvVar(t *testing.T) { + //base env + { + assert.Equal(t, initMysqlEnvs, initMysqlCase.Env) + } + //initTokuDB + { + testToKuDBMysqlCluster := initMysqlMysqlCluster + testToKuDBMysqlCluster.Spec.MysqlOpts.InitTokuDB = true + testTokuDBCluster := cluster.Cluster{ + Cluster: &testToKuDBMysqlCluster, + } + tokudbCase := EnsureContainer("init-mysql", &testTokuDBCluster) + testEnv := append(initMysqlEnvs, corev1.EnvVar{ + Name: "INIT_TOKUDB", + Value: "1", + }) + assert.Equal(t, testEnv, tokudbCase.Env) + } +} + +func TestGetInitMysqlLifecycle(t *testing.T) { + assert.Nil(t, initMysqlCase.Lifecycle) +} + +func TestGetInitMysqlResources(t *testing.T) { + assert.Equal(t, corev1.ResourceRequirements{ + Limits: nil, + Requests: nil, + }, initMysqlCase.Resources) +} + +func TestGetInitMysqlPorts(t *testing.T) { + assert.Nil(t, initMysqlCase.Ports) +} + +func TestGetInitMysqlLivenessProbe(t *testing.T) { + assert.Nil(t, initMysqlCase.LivenessProbe) +} + +func TestGetInitMysqlReadinessProbe(t *testing.T) { + assert.Nil(t, initMysqlCase.ReadinessProbe) +} + +func TestGetInitMysqlVolumeMounts(t *testing.T) { + assert.Equal(t, initMysqlVolumeMounts, initMysqlCase.VolumeMounts) +} diff --git a/cluster/container/init_sidecar_test.go b/cluster/container/init_sidecar_test.go new file mode 100644 index 00000000..fff66d09 --- /dev/null +++ b/cluster/container/init_sidecar_test.go @@ -0,0 +1,301 @@ +/* +Copyright 2021 RadonDB. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package container + +import ( + "strconv" + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + mysqlv1alpha1 "github.com/radondb/radondb-mysql-kubernetes/api/v1alpha1" + "github.com/radondb/radondb-mysql-kubernetes/cluster" + "github.com/radondb/radondb-mysql-kubernetes/utils" +) + +var ( + defeatCount int32 = 1 + electionTimeout int32 = 5 + initSidecarMysqlCluster = mysqlv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sample", + }, + Spec: mysqlv1alpha1.ClusterSpec{ + PodSpec: mysqlv1alpha1.PodSpec{ + SidecarImage: "sidecar image", + Resources: corev1.ResourceRequirements{ + Limits: nil, + Requests: nil, + }, + }, + XenonOpts: mysqlv1alpha1.XenonOpts{ + AdmitDefeatHearbeatCount: &defeatCount, + ElectionTimeout: &electionTimeout, + }, + MetricsOpts: mysqlv1alpha1.MetricsOpts{ + Enabled: false, + }, + MysqlOpts: mysqlv1alpha1.MysqlOpts{ + InitTokuDB: false, + }, + Persistence: mysqlv1alpha1.Persistence{ + Enabled: false, + }, + }, + } + testInitSidecarCluster = cluster.Cluster{ + Cluster: &initSidecarMysqlCluster, + } + defaultInitSidecarEnvs = []corev1.EnvVar{ + { + Name: "POD_HOSTNAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "metadata.name", + }, + }, + }, + { + Name: "NAMESPACE", + Value: testInitSidecarCluster.Namespace, + }, + { + Name: "SERVICE_NAME", + Value: "sample-mysql", + }, + { + Name: "ADMIT_DEFEAT_HEARBEAT_COUNT", + Value: strconv.Itoa(int(*testInitSidecarCluster.Spec.XenonOpts.AdmitDefeatHearbeatCount)), + }, + { + Name: "ELECTION_TIMEOUT", + Value: strconv.Itoa(int(*testInitSidecarCluster.Spec.XenonOpts.ElectionTimeout)), + }, + { + Name: "MY_MYSQL_VERSION", + Value: "5.7.33", + }, + { + Name: "MYSQL_ROOT_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: sctName, + }, + Key: "root-password", + Optional: &optFalse, + }, + }, + }, + { + Name: "MYSQL_REPL_USER", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: sctName, + }, + Key: "replication-user", + Optional: &optTrue, + }, + }, + }, + { + Name: "MYSQL_REPL_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: sctName, + }, + Key: "replication-password", + Optional: &optTrue, + }, + }, + }, + { + Name: "METRICS_USER", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: sctName, + }, + Key: "metrics-user", + Optional: &optTrue, + }, + }, + }, + { + Name: "METRICS_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: sctName, + }, + Key: "metrics-password", + Optional: &optTrue, + }, + }, + }, + { + Name: "OPERATOR_USER", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: sctName, + }, + Key: "operator-user", + Optional: &optTrue, + }, + }, + }, + { + Name: "OPERATOR_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: sctName, + }, + Key: "operator-password", + Optional: &optTrue, + }, + }, + }, + } + defaultInitsidecarVolumeMounts = []corev1.VolumeMount{ + { + Name: utils.ConfVolumeName, + MountPath: utils.ConfVolumeMountPath, + }, + { + Name: utils.ConfMapVolumeName, + MountPath: utils.ConfMapVolumeMountPath, + }, + { + Name: utils.ScriptsVolumeName, + MountPath: utils.ScriptsVolumeMountPath, + }, + { + Name: utils.XenonVolumeName, + MountPath: utils.XenonVolumeMountPath, + }, + { + Name: utils.InitFileVolumeName, + MountPath: utils.InitFileVolumeMountPath, + }, + } + initSidecarCase = EnsureContainer("init-sidecar", &testInitSidecarCluster) +) + +func TestGetInitSidecarName(t *testing.T) { + assert.Equal(t, "init-sidecar", initSidecarCase.Name) +} + +func TestGetInitSidecarImage(t *testing.T) { + assert.Equal(t, "sidecar image", initSidecarCase.Image) +} + +func TestGetInitSidecarCommand(t *testing.T) { + command := []string{"sidecar", "init"} + assert.Equal(t, command, initSidecarCase.Command) +} + +func TestGetInitSidecarEnvVar(t *testing.T) { + //default + { + assert.Equal(t, defaultInitSidecarEnvs, initSidecarCase.Env) + } + //initTokuDB + { + testToKuDBMysqlCluster := initSidecarMysqlCluster + testToKuDBMysqlCluster.Spec.MysqlOpts.InitTokuDB = true + testTokuDBCluster := cluster.Cluster{ + Cluster: &testToKuDBMysqlCluster, + } + tokudbCase := EnsureContainer("init-sidecar", &testTokuDBCluster) + testTokuDBEnv := make([]corev1.EnvVar, 13) + copy(testTokuDBEnv, defaultInitSidecarEnvs) + testTokuDBEnv = append(testTokuDBEnv, corev1.EnvVar{ + Name: "INIT_TOKUDB", + Value: "1", + }) + assert.Equal(t, testTokuDBEnv, tokudbCase.Env) + } +} + +func TestGetInitSidecarLifecycle(t *testing.T) { + assert.Nil(t, initSidecarCase.Lifecycle) +} + +func TestGetInitSidecarResources(t *testing.T) { + assert.Equal(t, corev1.ResourceRequirements{ + Limits: nil, + Requests: nil, + }, initSidecarCase.Resources) +} + +func TestGetInitSidecarPorts(t *testing.T) { + assert.Nil(t, initSidecarCase.Ports) +} + +func TestGetInitSidecarLivenessProbe(t *testing.T) { + assert.Nil(t, initSidecarCase.LivenessProbe) +} + +func TestGetInitSidecarReadinessProbe(t *testing.T) { + assert.Nil(t, initSidecarCase.ReadinessProbe) +} + +func TestGetInitSidecarVolumeMounts(t *testing.T) { + //default + { + assert.Equal(t, defaultInitsidecarVolumeMounts, initSidecarCase.VolumeMounts) + } + //init tokudb + { + testToKuDBMysqlCluster := initSidecarMysqlCluster + testToKuDBMysqlCluster.Spec.MysqlOpts.InitTokuDB = true + testTokuDBCluster := cluster.Cluster{ + Cluster: &testToKuDBMysqlCluster, + } + tokudbCase := EnsureContainer("init-sidecar", &testTokuDBCluster) + tokuDBVolumeMounts := make([]corev1.VolumeMount, 5, 6) + copy(tokuDBVolumeMounts, defaultInitsidecarVolumeMounts) + tokuDBVolumeMounts = append(tokuDBVolumeMounts, corev1.VolumeMount{ + Name: utils.SysVolumeName, + MountPath: utils.SysVolumeMountPath, + }) + assert.Equal(t, tokuDBVolumeMounts, tokudbCase.VolumeMounts) + } + //enable persistence + { + testPersistenceMysqlCluster := initSidecarMysqlCluster + testPersistenceMysqlCluster.Spec.Persistence.Enabled = true + testPersistenceCluster := cluster.Cluster{ + Cluster: &testPersistenceMysqlCluster, + } + persistenceCase := EnsureContainer("init-sidecar", &testPersistenceCluster) + persistenceVolumeMounts := make([]corev1.VolumeMount, 5, 6) + copy(persistenceVolumeMounts, defaultInitsidecarVolumeMounts) + persistenceVolumeMounts = append(persistenceVolumeMounts, corev1.VolumeMount{ + Name: utils.DataVolumeName, + MountPath: utils.DataVolumeMountPath, + }) + assert.Equal(t, persistenceVolumeMounts, persistenceCase.VolumeMounts) + } +} diff --git a/cluster/container/metrics_test.go b/cluster/container/metrics_test.go new file mode 100644 index 00000000..abbd8001 --- /dev/null +++ b/cluster/container/metrics_test.go @@ -0,0 +1,150 @@ +/* +Copyright 2021 RadonDB. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package container + +import ( + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + + mysqlv1alpha1 "github.com/radondb/radondb-mysql-kubernetes/api/v1alpha1" + "github.com/radondb/radondb-mysql-kubernetes/cluster" +) + +var ( + metricsMysqlCluster = mysqlv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sample", + }, + Spec: mysqlv1alpha1.ClusterSpec{ + PodSpec: mysqlv1alpha1.PodSpec{ + Resources: corev1.ResourceRequirements{ + Limits: nil, + Requests: nil, + }, + }, + MetricsOpts: mysqlv1alpha1.MetricsOpts{ + Image: "metrics-image", + }, + }, + } + testMetricsCluster = cluster.Cluster{ + Cluster: &metricsMysqlCluster, + } + metricsCase = EnsureContainer("metrics", &testMetricsCluster) +) + +func TestGetMetricsName(t *testing.T) { + assert.Equal(t, "metrics", metricsCase.Name) +} + +func TestGetMetricsImage(t *testing.T) { + assert.Equal(t, "metrics-image", metricsCase.Image) +} + +func TestGetMetricsCommand(t *testing.T) { + assert.Nil(t, metricsCase.Command) +} + +func TestGetMetricsEnvVar(t *testing.T) { + { + optTrue := true + env := []corev1.EnvVar{ + { + Name: "DATA_SOURCE_NAME", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "sample-secret", + }, + Key: "data-source", + Optional: &optTrue, + }, + }, + }, + } + assert.Equal(t, env, metricsCase.Env) + } +} + +func TestGetMetricsLifecycle(t *testing.T) { + assert.Nil(t, metricsCase.Lifecycle) +} + +func TestGetMetricsResources(t *testing.T) { + assert.Equal(t, corev1.ResourceRequirements{ + Limits: nil, + Requests: nil, + }, metricsCase.Resources) +} + +func TestGetMetricsPorts(t *testing.T) { + port := []corev1.ContainerPort{ + { + Name: "metrics", + ContainerPort: 9104, + }, + } + assert.Equal(t, port, metricsCase.Ports) +} + +func TestGetMetricsLivenessProbe(t *testing.T) { + livenessProbe := &corev1.Probe{ + Handler: corev1.Handler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/", + Port: intstr.IntOrString{ + Type: 0, + IntVal: int32(9104), + }, + }, + }, + InitialDelaySeconds: 15, + TimeoutSeconds: 5, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + } + assert.Equal(t, livenessProbe, metricsCase.LivenessProbe) +} + +func TestGetMetricsReadinessProbe(t *testing.T) { + readinessProbe := &corev1.Probe{ + Handler: corev1.Handler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/", + Port: intstr.IntOrString{ + Type: 0, + IntVal: int32(9104), + }, + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + } + assert.Equal(t, readinessProbe, metricsCase.ReadinessProbe) +} + +func TestGetMetricsVolumeMounts(t *testing.T) { + assert.Nil(t, metricsCase.VolumeMounts) +} diff --git a/cluster/container/mysql_test.go b/cluster/container/mysql_test.go new file mode 100644 index 00000000..d0b0f92d --- /dev/null +++ b/cluster/container/mysql_test.go @@ -0,0 +1,159 @@ +/* +Copyright 2021 RadonDB. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package container + +import ( + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + + mysqlv1alpha1 "github.com/radondb/radondb-mysql-kubernetes/api/v1alpha1" + "github.com/radondb/radondb-mysql-kubernetes/cluster" +) + +var ( + mysqlMysqlCluster = mysqlv1alpha1.Cluster{ + Spec: mysqlv1alpha1.ClusterSpec{ + PodSpec: mysqlv1alpha1.PodSpec{ + Resources: corev1.ResourceRequirements{ + Limits: nil, + Requests: nil, + }, + }, + MysqlVersion: "5.7", + MysqlOpts: mysqlv1alpha1.MysqlOpts{ + InitTokuDB: false, + }, + }, + } + testMysqlCluster = cluster.Cluster{ + Cluster: &mysqlMysqlCluster, + } + mysqlCase = EnsureContainer("mysql", &testMysqlCluster) +) + +func TestGetMysqlName(t *testing.T) { + assert.Equal(t, "mysql", mysqlCase.Name) +} + +func TestGetMysqlImage(t *testing.T) { + assert.Equal(t, "percona/percona-server:5.7.33", mysqlCase.Image) +} + +func TestGetMysqlCommand(t *testing.T) { + assert.Nil(t, mysqlCase.Command) +} + +func TestGetMysqlEnvVar(t *testing.T) { + //base env + { + assert.Nil(t, mysqlCase.Env) + } + //initTokuDB + { + volumeMounts := []corev1.EnvVar{ + { + Name: "INIT_TOKUDB", + Value: "1", + }, + } + mysqlCluster := mysqlMysqlCluster + mysqlCluster.Spec.MysqlOpts.InitTokuDB = true + testCluster := cluster.Cluster{ + Cluster: &mysqlCluster, + } + mysqlCase = EnsureContainer("mysql", &testCluster) + assert.Equal(t, volumeMounts, mysqlCase.Env) + } +} + +func TestGetMysqlLifecycle(t *testing.T) { + assert.Nil(t, mysqlCase.Lifecycle) +} + +func TestGetMysqlResources(t *testing.T) { + assert.Equal(t, corev1.ResourceRequirements{ + Limits: nil, + Requests: nil, + }, mysqlCase.Resources) +} + +func TestGetMysqlPorts(t *testing.T) { + port := []corev1.ContainerPort{ + { + Name: "mysql", + ContainerPort: 3306, + }, + } + assert.Equal(t, port, mysqlCase.Ports) +} + +func TestGetMysqlLivenessProbe(t *testing.T) { + livenessProbe := &corev1.Probe{ + Handler: corev1.Handler{ + Exec: &corev1.ExecAction{ + Command: []string{"sh", "-c", "mysqladmin ping -uroot -p${MYSQL_ROOT_PASSWORD}"}, + }, + }, + InitialDelaySeconds: 30, + TimeoutSeconds: 5, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + } + assert.Equal(t, livenessProbe, mysqlCase.LivenessProbe) +} + +func TestGetMysqlReadinessProbe(t *testing.T) { + readinessProbe := &corev1.Probe{ + Handler: corev1.Handler{ + Exec: &corev1.ExecAction{ + Command: []string{"sh", "-c", `mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "SELECT 1"`}, + }, + }, + InitialDelaySeconds: 10, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + } + assert.Equal(t, readinessProbe, mysqlCase.ReadinessProbe) +} + +func TestGetMysqlVolumeMounts(t *testing.T) { + volumeMounts := []corev1.VolumeMount{ + { + Name: "conf", + MountPath: "/etc/mysql/conf.d", + }, + { + Name: "config-map", + MountPath: "/etc/mysql/my.cnf", + SubPath: "my.cnf", + }, + { + Name: "data", + MountPath: "/var/lib/mysql", + }, + { + Name: "logs", + MountPath: "/var/log/mysql", + }, + } + assert.Equal(t, volumeMounts, mysqlCase.VolumeMounts) +} diff --git a/cluster/container/slowlog_test.go b/cluster/container/slowlog_test.go new file mode 100644 index 00000000..3c273306 --- /dev/null +++ b/cluster/container/slowlog_test.go @@ -0,0 +1,95 @@ +/* +Copyright 2021 RadonDB. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package container + +import ( + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + + mysqlv1alpha1 "github.com/radondb/radondb-mysql-kubernetes/api/v1alpha1" + "github.com/radondb/radondb-mysql-kubernetes/cluster" +) + +var ( + slowlogMysqlCluster = mysqlv1alpha1.Cluster{ + Spec: mysqlv1alpha1.ClusterSpec{ + PodSpec: mysqlv1alpha1.PodSpec{ + SidecarImage: "sidecar image", + Resources: corev1.ResourceRequirements{ + Limits: nil, + Requests: nil, + }, + }, + }, + } + testSlowlogCluster = cluster.Cluster{ + Cluster: &slowlogMysqlCluster, + } + slowlogCase = EnsureContainer("slowlog", &testSlowlogCluster) +) + +func TestGetSlowlogName(t *testing.T) { + assert.Equal(t, "slowlog", slowlogCase.Name) +} + +func TestGetSlowlogImage(t *testing.T) { + assert.Equal(t, "sidecar image", slowlogCase.Image) +} + +func TestGetSlowlogCommand(t *testing.T) { + command := []string{"tail", "-f", "/var/log/mysql" + "/mysql-slow.log"} + assert.Equal(t, command, slowlogCase.Command) +} + +func TestGetSlowlogEnvVar(t *testing.T) { + assert.Nil(t, slowlogCase.Env) +} + +func TestGetSlowlogLifecycle(t *testing.T) { + assert.Nil(t, slowlogCase.Lifecycle) +} + +func TestGetSlowlogResources(t *testing.T) { + assert.Equal(t, corev1.ResourceRequirements{ + Limits: nil, + Requests: nil, + }, slowlogCase.Resources) +} + +func TestGetSlowlogPorts(t *testing.T) { + assert.Nil(t, slowlogCase.Ports) +} + +func TestGetSlowlogLivenessProbe(t *testing.T) { + assert.Nil(t, slowlogCase.LivenessProbe) +} + +func TestGetSlowlogReadinessProbe(t *testing.T) { + assert.Nil(t, slowlogCase.ReadinessProbe) +} + +func TestGetSlowlogVolumeMounts(t *testing.T) { + volumeMounts := []corev1.VolumeMount{ + { + Name: "logs", + MountPath: "/var/log/mysql", + }, + } + assert.Equal(t, volumeMounts, slowlogCase.VolumeMounts) +} diff --git a/cluster/container/xenon_test.go b/cluster/container/xenon_test.go new file mode 100644 index 00000000..cd049f96 --- /dev/null +++ b/cluster/container/xenon_test.go @@ -0,0 +1,146 @@ +/* +Copyright 2021 RadonDB. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package container + +import ( + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + mysqlv1alpha1 "github.com/radondb/radondb-mysql-kubernetes/api/v1alpha1" + "github.com/radondb/radondb-mysql-kubernetes/cluster" +) + +var ( + xenonReplicas int32 = 1 + xenonMysqlCluster = mysqlv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sample", + Namespace: "default", + }, + Spec: mysqlv1alpha1.ClusterSpec{ + PodSpec: mysqlv1alpha1.PodSpec{ + Resources: corev1.ResourceRequirements{ + Limits: nil, + Requests: nil, + }, + }, + XenonOpts: mysqlv1alpha1.XenonOpts{ + Image: "xenon image", + }, + Replicas: &xenonReplicas, + }, + } + testXenonCluster = cluster.Cluster{ + Cluster: &xenonMysqlCluster, + } + xenonCase = EnsureContainer("xenon", &testXenonCluster) +) + +func TestGetXenonName(t *testing.T) { + assert.Equal(t, "xenon", xenonCase.Name) +} + +func TestGetXenonImage(t *testing.T) { + assert.Equal(t, "xenon image", xenonCase.Image) +} + +func TestGetXenonCommand(t *testing.T) { + assert.Nil(t, xenonCase.Command) +} + +func TestGetXenonEnvVar(t *testing.T) { + assert.Nil(t, xenonCase.Env) +} + +func TestGetXenonLifecycle(t *testing.T) { + lifecycle := &corev1.Lifecycle{ + PostStart: &corev1.Handler{ + Exec: &corev1.ExecAction{ + Command: []string{"sh", "-c", + "until (xenoncli xenon ping && xenoncli cluster add sample-mysql-0.sample-mysql.default:8801) > /dev/null 2>&1; do sleep 2; done", + }, + }, + }, + } + assert.Equal(t, lifecycle, xenonCase.Lifecycle) +} + +func TestGetXenonResources(t *testing.T) { + assert.Equal(t, corev1.ResourceRequirements{ + Limits: nil, + Requests: nil, + }, xenonCase.Resources) +} + +func TestGetXenonPorts(t *testing.T) { + port := []corev1.ContainerPort{ + { + Name: "xenon", + ContainerPort: 8801, + }, + } + assert.Equal(t, port, xenonCase.Ports) +} + +func TestGetXenonLivenessProbe(t *testing.T) { + livenessProbe := &corev1.Probe{ + Handler: corev1.Handler{ + Exec: &corev1.ExecAction{ + Command: []string{"pgrep", "xenon"}, + }, + }, + InitialDelaySeconds: 30, + TimeoutSeconds: 5, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + } + assert.Equal(t, livenessProbe, xenonCase.LivenessProbe) +} + +func TestGetXenonReadinessProbe(t *testing.T) { + readinessProbe := &corev1.Probe{ + Handler: corev1.Handler{ + Exec: &corev1.ExecAction{ + Command: []string{"sh", "-c", "xenoncli xenon ping"}, + }, + }, + InitialDelaySeconds: 10, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + } + assert.Equal(t, readinessProbe, xenonCase.ReadinessProbe) +} + +func TestGetXenonVolumeMounts(t *testing.T) { + volumeMounts := []corev1.VolumeMount{ + { + Name: "scripts", + MountPath: "/scripts", + }, + { + Name: "xenon", + MountPath: "/etc/xenon", + }, + } + assert.Equal(t, volumeMounts, xenonCase.VolumeMounts) +} diff --git a/go.mod b/go.mod index ba31fc67..3700a612 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/radondb/radondb-mysql-kubernetes go 1.16 require ( + bou.ke/monkey v1.0.2 github.com/blang/semver v3.5.1+incompatible github.com/go-ini/ini v1.62.0 github.com/go-sql-driver/mysql v1.6.0 @@ -11,6 +12,7 @@ require ( github.com/onsi/gomega v1.10.5 github.com/presslabs/controller-util v0.3.0-alpha.2 github.com/spf13/cobra v1.1.1 + github.com/stretchr/testify v1.6.1 k8s.io/api v0.20.4 k8s.io/apimachinery v0.20.4 k8s.io/client-go v0.20.4 diff --git a/go.sum b/go.sum index d1d18c23..95ac40d3 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +bou.ke/monkey v1.0.2 h1:kWcnsrCNUatbxncxR/ThdYqbytgOIArtYWqcQLQzKLI= +bou.ke/monkey v1.0.2/go.mod h1:OqickVX3tNx6t33n1xvtTtu85YN5s6cKwVug+oHMaIA= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -714,6 +716,7 @@ k8s.io/api v0.20.2 h1:y/HR22XDZY3pniu9hIFDLpUCPq2w5eQ6aV/VFQ7uJMw= k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8= k8s.io/api v0.20.4 h1:xZjKidCirayzX6tHONRQyTNDVIR55TYVqgATqo6ZULY= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= +k8s.io/api v0.21.2 h1:vz7DqmRsXTCSa6pNxXwQ1IYeAZgdIsua+DZU+o+SX3Y= k8s.io/apiextensions-apiserver v0.20.1 h1:ZrXQeslal+6zKM/HjDXLzThlz/vPSxrfK3OqL8txgVQ= k8s.io/apiextensions-apiserver v0.20.1/go.mod h1:ntnrZV+6a3dB504qwC5PN/Yg9PBiDNt1EVqbW2kORVk= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=