blob: f57f0eedc9367588ddaa227564c9abc786d4e015 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 resource
import (
dv1 "github.com/apache/doris-operator/api/disaggregated/v1"
v1 "github.com/apache/doris-operator/api/doris/v1"
corev1 "k8s.io/api/core/v1"
kr "k8s.io/apimachinery/pkg/api/resource"
"k8s.io/utils/pointer"
"testing"
)
func Test_NewPodTemplateSpec(t *testing.T) {
for _, ct := range []v1.ComponentType{"fe", "be", "cn", "broker"} {
config := map[string]interface{}{}
pt := NewPodTemplateSpec(dcr, config, ct)
t.Log(pt)
}
}
func Test_NewContainerWithCommonSpec(t *testing.T) {
cs := &dv1.CommonSpec{
Replicas: pointer.Int32(1),
Image: "selectdb/doris.be-ubuntu:latest",
ContainerSecurityContext: &corev1.SecurityContext{},
ResourceRequirements: corev1.ResourceRequirements{
Requests: map[corev1.ResourceName]kr.Quantity{
"cpu": kr.MustParse("4"),
"memory": kr.MustParse("8Gi"),
},
},
}
c := NewContainerWithCommonSpec(cs)
t.Log(c)
}
func Test_NewPodTemplateSpecWithCommonSpec(t *testing.T) {
tm := make(map[dv1.DisaggregatedComponentType]*dv1.CommonSpec)
ccs := &dv1.CommonSpec{
Replicas: pointer.Int32(1),
Image: "selectdb/doris.be-ubuntu:latest",
ResourceRequirements: corev1.ResourceRequirements{
Requests: map[corev1.ResourceName]kr.Quantity{
"cpu": kr.MustParse("4"),
"memory": kr.MustParse("8Gi"),
},
},
SystemInitialization: &dv1.SystemInitialization{
InitImage: "selectdb/doris.alpine:latest",
},
PersistentVolume: &dv1.PersistentVolume{
MountPaths: []string{"/opt/apache-doris/be/storage"},
LogNotStore: true,
Annotations: map[string]string{
"name": "test",
"namespace": "default",
},
PersistentVolumeClaimSpec: corev1.PersistentVolumeClaimSpec{
Resources: corev1.VolumeResourceRequirements{
Requests: map[corev1.ResourceName]kr.Quantity{
"storage": kr.MustParse("200Gi"),
},
},
AccessModes: []corev1.PersistentVolumeAccessMode{"ReadAndWriteOnce"},
},
},
}
tm[dv1.DisaggregatedBE] = ccs
fcs := &dv1.CommonSpec{
Replicas: pointer.Int32(1),
Image: "selectdb/doris.fe-ubuntu:latest",
ResourceRequirements: corev1.ResourceRequirements{
Requests: map[corev1.ResourceName]kr.Quantity{
"cpu": kr.MustParse("4"),
"memory": kr.MustParse("8Gi"),
},
},
PersistentVolume: &dv1.PersistentVolume{
MountPaths: []string{"/opt/apache-doris/fe/doris-meta"},
LogNotStore: false,
Annotations: map[string]string{
"name": "test",
"namespace": "default",
},
PersistentVolumeClaimSpec: corev1.PersistentVolumeClaimSpec{
Resources: corev1.VolumeResourceRequirements{
Requests: map[corev1.ResourceName]kr.Quantity{
"storage": kr.MustParse("200Gi"),
},
},
AccessModes: []corev1.PersistentVolumeAccessMode{"ReadAndWriteOnce"},
},
},
}
tm[dv1.DisaggregatedFE] = fcs
mcs := &dv1.CommonSpec{
Replicas: pointer.Int32(1),
Image: "selectdb/doris.ms-ubuntu:latest",
ResourceRequirements: corev1.ResourceRequirements{
Requests: map[corev1.ResourceName]kr.Quantity{
"cpu": kr.MustParse("4"),
"memory": kr.MustParse("8Gi"),
},
},
}
tm[dv1.DisaggregatedMS] = mcs
for dct, cs := range tm {
pts := NewPodTemplateSpecWithCommonSpec(false, cs, dct)
t.Log(pts)
}
}
func Test_NewBaseMainContainer(t *testing.T) {
for _, dct := range []v1.ComponentType{v1.Component_FE, v1.Component_BE, v1.Component_CN, v1.Component_Broker} {
c := NewBaseMainContainer(dcr, cm, dct)
t.Log(c)
}
}
func Test_NewBaseMainContainer_ImagePullPolicy(t *testing.T) {
// Unset keeps the previous behaviour, so existing clusters are unaffected by the new field.
for _, dct := range []v1.ComponentType{v1.Component_FE, v1.Component_BE, v1.Component_CN, v1.Component_Broker} {
c := NewBaseMainContainer(dcr, cm, dct)
if c.ImagePullPolicy != corev1.PullIfNotPresent {
t.Errorf("%s: default imagePullPolicy = %q, want %q", dct, c.ImagePullPolicy, corev1.PullIfNotPresent)
}
}
always := dcr.DeepCopy()
always.Spec.FeSpec.ImagePullPolicy = corev1.PullAlways
c := NewBaseMainContainer(always, cm, v1.Component_FE)
if c.ImagePullPolicy != corev1.PullAlways {
t.Errorf("imagePullPolicy = %q, want %q", c.ImagePullPolicy, corev1.PullAlways)
}
}
func Test_LifeCycleWithPreStopScript(t *testing.T) {
lcs := []*corev1.Lifecycle{nil, {}}
for i, _ := range lcs {
lc := LifeCycleWithPreStopScript(lcs[i], "/opt/apache-doris/prestop.sh")
if lc.PreStop == nil {
t.Errorf("build lifeCycleWithPreStopScript failed. %d", i)
}
}
}
func Test_AddTerminationGracePeriodSeconds_Default(t *testing.T) {
pts := &corev1.PodTemplateSpec{}
AddTerminationGracePeriodSeconds(pts, map[string]interface{}{}, DEFAULT_BE_TERMINATION_GRACE_PERIOD_SECONDS)
if pts.Spec.TerminationGracePeriodSeconds == nil {
t.Fatalf("expected terminationGracePeriodSeconds")
}
if *pts.Spec.TerminationGracePeriodSeconds != DEFAULT_BE_TERMINATION_GRACE_PERIOD_SECONDS {
t.Errorf("expected default terminationGracePeriodSeconds=%d, got %d", DEFAULT_BE_TERMINATION_GRACE_PERIOD_SECONDS, *pts.Spec.TerminationGracePeriodSeconds)
}
}
func Test_AddTerminationGracePeriodSeconds_ConfigOverride(t *testing.T) {
pts := &corev1.PodTemplateSpec{}
AddTerminationGracePeriodSeconds(pts, map[string]interface{}{GRACE_SHUTDOWN_WAIT_SECONDS: "60"}, DEFAULT_BE_TERMINATION_GRACE_PERIOD_SECONDS)
if pts.Spec.TerminationGracePeriodSeconds == nil {
t.Fatalf("expected terminationGracePeriodSeconds")
}
if *pts.Spec.TerminationGracePeriodSeconds != 60 {
t.Errorf("expected configured terminationGracePeriodSeconds=60, got %d", *pts.Spec.TerminationGracePeriodSeconds)
}
}
func Test_BuildDisaggregatedProbe(t *testing.T) {
c := &corev1.Container{}
cs := &dv1.CommonSpec{
StartTimeout: 600,
LiveTimeout: 30,
}
BuildDisaggregatedProbe(c, cs, dv1.DisaggregatedBE)
if c.StartupProbe == nil {
t.Errorf("startupProbe not build")
}
fts := 600 / 5
if c.StartupProbe.FailureThreshold != int32(fts) {
t.Errorf("startupProbe failureThreshold build failed.")
}
if c.LivenessProbe.TimeoutSeconds != int32(30) {
t.Errorf("livenessProbe TimeoutSeconds build failed.")
}
}
func Test_ReadinessProbePolicy_NilPolicy(t *testing.T) {
// nil policy should produce original defaults
probe := readinessProbe(8040, HEALTH_API_PATH, nil, HttpGet, nil)
if probe.PeriodSeconds != 5 {
t.Errorf("expected PeriodSeconds=5, got %d", probe.PeriodSeconds)
}
if probe.FailureThreshold != 3 {
t.Errorf("expected FailureThreshold=3, got %d", probe.FailureThreshold)
}
if probe.TimeoutSeconds != 0 {
t.Errorf("expected TimeoutSeconds=0 (k8s default), got %d", probe.TimeoutSeconds)
}
}
func Test_ReadinessProbePolicy_WithPolicy(t *testing.T) {
policy := &v1.ReadinessProbePolicy{
TimeoutSeconds: 5,
FailureThreshold: 5,
PeriodSeconds: 10,
}
probe := readinessProbe(8040, HEALTH_API_PATH, nil, HttpGet, policy)
if probe.PeriodSeconds != 10 {
t.Errorf("expected PeriodSeconds=10, got %d", probe.PeriodSeconds)
}
if probe.FailureThreshold != 5 {
t.Errorf("expected FailureThreshold=5, got %d", probe.FailureThreshold)
}
if probe.TimeoutSeconds != 5 {
t.Errorf("expected TimeoutSeconds=5, got %d", probe.TimeoutSeconds)
}
}
func Test_ReadinessProbePolicy_PartialOverride(t *testing.T) {
// only set TimeoutSeconds, others should keep defaults
policy := &v1.ReadinessProbePolicy{
TimeoutSeconds: 5,
}
probe := readinessProbe(8040, HEALTH_API_PATH, nil, HttpGet, policy)
if probe.PeriodSeconds != 5 {
t.Errorf("expected default PeriodSeconds=5, got %d", probe.PeriodSeconds)
}
if probe.FailureThreshold != 3 {
t.Errorf("expected default FailureThreshold=3, got %d", probe.FailureThreshold)
}
if probe.TimeoutSeconds != 5 {
t.Errorf("expected TimeoutSeconds=5, got %d", probe.TimeoutSeconds)
}
}
func Test_BuildDisaggregatedProbe_NilCommonSpec(t *testing.T) {
c := &corev1.Container{}
BuildDisaggregatedProbe(c, nil, dv1.DisaggregatedBE)
if c.ReadinessProbe != nil {
t.Errorf("expected nil ReadinessProbe when cs is nil")
}
}
func Test_BuildDisaggregatedProbe_ReadinessProbePolicy_PartialOverride(t *testing.T) {
c := &corev1.Container{}
cs := &dv1.CommonSpec{
StartTimeout: 600,
LiveTimeout: 30,
ReadinessProbePolicy: &dv1.ReadinessProbePolicy{
TimeoutSeconds: 8,
},
}
BuildDisaggregatedProbe(c, cs, dv1.DisaggregatedBE)
if c.ReadinessProbe.PeriodSeconds != 5 {
t.Errorf("expected default PeriodSeconds=5, got %d", c.ReadinessProbe.PeriodSeconds)
}
if c.ReadinessProbe.FailureThreshold != 3 {
t.Errorf("expected default FailureThreshold=3, got %d", c.ReadinessProbe.FailureThreshold)
}
if c.ReadinessProbe.TimeoutSeconds != 8 {
t.Errorf("expected TimeoutSeconds=8, got %d", c.ReadinessProbe.TimeoutSeconds)
}
}
func Test_BuildDisaggregatedProbe_ReadinessProbePolicy_Nil(t *testing.T) {
c := &corev1.Container{}
cs := &dv1.CommonSpec{
StartTimeout: 600,
LiveTimeout: 30,
}
BuildDisaggregatedProbe(c, cs, dv1.DisaggregatedBE)
if c.ReadinessProbe.PeriodSeconds != 5 {
t.Errorf("expected default PeriodSeconds=5, got %d", c.ReadinessProbe.PeriodSeconds)
}
if c.ReadinessProbe.FailureThreshold != 3 {
t.Errorf("expected default FailureThreshold=3, got %d", c.ReadinessProbe.FailureThreshold)
}
}
func Test_BuildDisaggregatedProbe_ReadinessProbePolicy_WithPolicy(t *testing.T) {
c := &corev1.Container{}
cs := &dv1.CommonSpec{
StartTimeout: 600,
LiveTimeout: 30,
ReadinessProbePolicy: &dv1.ReadinessProbePolicy{
TimeoutSeconds: 10,
FailureThreshold: 6,
PeriodSeconds: 15,
},
}
BuildDisaggregatedProbe(c, cs, dv1.DisaggregatedBE)
if c.ReadinessProbe.PeriodSeconds != 15 {
t.Errorf("expected PeriodSeconds=15, got %d", c.ReadinessProbe.PeriodSeconds)
}
if c.ReadinessProbe.FailureThreshold != 6 {
t.Errorf("expected FailureThreshold=6, got %d", c.ReadinessProbe.FailureThreshold)
}
if c.ReadinessProbe.TimeoutSeconds != 10 {
t.Errorf("expected TimeoutSeconds=10, got %d", c.ReadinessProbe.TimeoutSeconds)
}
}