mirror of
https://github.com/hanzo-ml/kserve.git
synced 2026-10-30 20:53:49 +00:00
728 lines
26 KiB
Go
728 lines
26 KiB
Go
/*
|
|
Copyright 2022 The KServe Authors.
|
|
|
|
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 v1beta1
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/onsi/gomega"
|
|
corev1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
fakeclientset "k8s.io/client-go/kubernetes/fake"
|
|
|
|
"github.com/kserve/kserve/pkg/constants"
|
|
)
|
|
|
|
var (
|
|
KserveIngressGateway = "kserve/kserve-ingress-gateway"
|
|
KnativeIngressGateway = "knative-serving/knative-ingress-gateway"
|
|
KnativeLocalGatewayService = "test-destination"
|
|
KnativeLocalGateway = "knative-serving/knative-local-gateway"
|
|
LocalGatewayService = "knative-local-gateway.istio-system.svc.cluster.local"
|
|
UrlScheme = "https"
|
|
IngressDomain = "example.com"
|
|
AdditionalDomain = "additional-example.com"
|
|
AdditionalDomainExtra = "additional-example-extra.com"
|
|
IngressConfigData = fmt.Sprintf(`{
|
|
"kserveIngressGateway" : "%s",
|
|
"ingressGateway" : "%s",
|
|
"knativeLocalGatewayService" : "%s",
|
|
"localGateway" : "%s",
|
|
"localGatewayService" : "%s",
|
|
"ingressDomain": "%s",
|
|
"urlScheme": "https",
|
|
"additionalIngressDomains": ["%s","%s"]
|
|
}`, KserveIngressGateway, KnativeIngressGateway, KnativeLocalGatewayService, KnativeLocalGateway, LocalGatewayService, IngressDomain,
|
|
AdditionalDomain, AdditionalDomainExtra)
|
|
ServiceConfigData = fmt.Sprintf(`{
|
|
"serviceClusterIPNone" : %t
|
|
}`, true)
|
|
|
|
ISCVWithData = fmt.Sprintf(`{
|
|
"serviceAnnotationDisallowedList": ["%s","%s"],
|
|
"serviceLabelDisallowedList": ["%s","%s"]
|
|
}`, "my.custom.annotation/1", "my.custom.annotation/2",
|
|
"my.custom.label.1", "my.custom.label.2")
|
|
|
|
ISCVNoData = fmt.Sprintf(`{
|
|
"serviceAnnotationDisallowedList": %s,
|
|
"serviceLabelDisallowedList": %s
|
|
}`, []string{}, []string{})
|
|
|
|
MultiNodeConfigData = `{
|
|
"customGPUResourceTypeList": [
|
|
"custom.com/gpu-1",
|
|
"custom.com/gpu-2"
|
|
]
|
|
}`
|
|
MultiNodeConfigNoData = `{}`
|
|
)
|
|
|
|
func TestNewInferenceServiceConfig(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
clientset := fakeclientset.NewSimpleClientset(&corev1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace},
|
|
})
|
|
isvcConfigMap, err := GetInferenceServiceConfigMap(t.Context(), clientset)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
isvcConfig, err := NewInferenceServicesConfig(isvcConfigMap)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(isvcConfig).ShouldNot(gomega.BeNil())
|
|
}
|
|
|
|
func TestNewMultiNodeConfigWithNoData(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
clientset := fakeclientset.NewSimpleClientset(&corev1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace},
|
|
Data: map[string]string{
|
|
MultiNodeConfigKeyName: MultiNodeConfigNoData,
|
|
},
|
|
})
|
|
|
|
configMap, err := GetInferenceServiceConfigMap(t.Context(), clientset)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
|
|
multiNodeCfg, err := NewMultiNodeConfig(configMap)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(multiNodeCfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(multiNodeCfg.CustomGPUResourceTypeList).To(gomega.Equal([]string{}))
|
|
g.Expect(constants.DefaultGPUResourceTypeList).To(gomega.Equal([]string{"nvidia.com/gpu", "amd.com/gpu", "intel.com/gpu", "habana.ai/gaudi"}))
|
|
}
|
|
|
|
func TestNewMultiNodeConfigWithoutData(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
clientset := fakeclientset.NewSimpleClientset(&corev1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace},
|
|
Data: map[string]string{},
|
|
})
|
|
|
|
configMap, err := GetInferenceServiceConfigMap(t.Context(), clientset)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
|
|
multiNodeCfg, err := NewMultiNodeConfig(configMap)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(multiNodeCfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(multiNodeCfg.CustomGPUResourceTypeList).To(gomega.Equal([]string{}))
|
|
g.Expect(constants.DefaultGPUResourceTypeList).To(gomega.Equal([]string{"nvidia.com/gpu", "amd.com/gpu", "intel.com/gpu", "habana.ai/gaudi"}))
|
|
}
|
|
|
|
func TestNewMultiNodeConfigWithData(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
clientset := fakeclientset.NewSimpleClientset(&corev1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace},
|
|
Data: map[string]string{
|
|
MultiNodeConfigKeyName: MultiNodeConfigData,
|
|
},
|
|
})
|
|
|
|
configMap, err := GetInferenceServiceConfigMap(t.Context(), clientset)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
|
|
multiNodeCfg, err := NewMultiNodeConfig(configMap)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(multiNodeCfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(multiNodeCfg.CustomGPUResourceTypeList).To(gomega.Equal([]string{"custom.com/gpu-1", "custom.com/gpu-2"}))
|
|
g.Expect(constants.DefaultGPUResourceTypeList).To(gomega.Equal([]string{"nvidia.com/gpu", "amd.com/gpu", "intel.com/gpu", "habana.ai/gaudi", "custom.com/gpu-1", "custom.com/gpu-2"}))
|
|
}
|
|
|
|
func TestNewIngressConfig(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
clientset := fakeclientset.NewSimpleClientset(&corev1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace},
|
|
Data: map[string]string{
|
|
IngressConfigKeyName: IngressConfigData,
|
|
},
|
|
})
|
|
configMap, err := GetInferenceServiceConfigMap(t.Context(), clientset)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
ingressCfg, err := NewIngressConfig(configMap)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(ingressCfg).ShouldNot(gomega.BeNil())
|
|
|
|
g.Expect(ingressCfg.IngressGateway).To(gomega.Equal(KnativeIngressGateway))
|
|
g.Expect(ingressCfg.KnativeLocalGatewayService).To(gomega.Equal(KnativeLocalGatewayService))
|
|
g.Expect(ingressCfg.LocalGateway).To(gomega.Equal(KnativeLocalGateway))
|
|
g.Expect(ingressCfg.LocalGatewayServiceName).To(gomega.Equal(LocalGatewayService))
|
|
g.Expect(ingressCfg.UrlScheme).To(gomega.Equal(UrlScheme))
|
|
g.Expect(ingressCfg.IngressDomain).To(gomega.Equal(IngressDomain))
|
|
g.Expect(*ingressCfg.AdditionalIngressDomains).To(gomega.Equal([]string{AdditionalDomain, AdditionalDomainExtra}))
|
|
}
|
|
|
|
func TestNewIngressConfigDefaultKnativeService(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
clientset := fakeclientset.NewSimpleClientset(&corev1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace},
|
|
Data: map[string]string{
|
|
IngressConfigKeyName: fmt.Sprintf(`{
|
|
"kserveIngressGateway" : "%s",
|
|
"ingressGateway" : "%s",
|
|
"localGateway" : "%s",
|
|
"localGatewayService" : "%s",
|
|
"ingressDomain": "%s",
|
|
"urlScheme": "https",
|
|
"additionalIngressDomains": ["%s","%s"]
|
|
}`, KserveIngressGateway, KnativeIngressGateway, KnativeLocalGateway, LocalGatewayService, IngressDomain,
|
|
AdditionalDomain, AdditionalDomainExtra),
|
|
},
|
|
})
|
|
configMap, err := GetInferenceServiceConfigMap(t.Context(), clientset)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
ingressCfg, err := NewIngressConfig(configMap)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(ingressCfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(ingressCfg.KnativeLocalGatewayService).To(gomega.Equal(LocalGatewayService))
|
|
}
|
|
|
|
func TestNewDeployConfig(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
clientset := fakeclientset.NewSimpleClientset(&corev1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace},
|
|
})
|
|
isvcConfigMap, err := GetInferenceServiceConfigMap(t.Context(), clientset)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
deployConfig, err := NewDeployConfig(isvcConfigMap)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(deployConfig).ShouldNot(gomega.BeNil())
|
|
}
|
|
|
|
func TestNewServiceConfig(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
// nothing declared
|
|
empty := fakeclientset.NewSimpleClientset(&corev1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace},
|
|
})
|
|
isvcConfigMap, err := GetInferenceServiceConfigMap(t.Context(), empty)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
emp, err := NewServiceConfig(isvcConfigMap)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(emp).ShouldNot(gomega.BeNil())
|
|
|
|
// with value
|
|
withTrue := fakeclientset.NewSimpleClientset(&corev1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace},
|
|
Data: map[string]string{
|
|
ServiceConfigName: ServiceConfigData,
|
|
},
|
|
})
|
|
isvcConfigMap, err = GetInferenceServiceConfigMap(t.Context(), withTrue)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
wt, err := NewServiceConfig(isvcConfigMap)
|
|
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(wt).ShouldNot(gomega.BeNil())
|
|
g.Expect(wt.ServiceClusterIPNone).Should(gomega.BeTrue())
|
|
|
|
// no value, should be nil
|
|
noValue := fakeclientset.NewSimpleClientset(&corev1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace},
|
|
Data: map[string]string{
|
|
ServiceConfigName: `{}`,
|
|
},
|
|
})
|
|
isvcConfigMap, err = GetInferenceServiceConfigMap(t.Context(), noValue)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
nv, err := NewServiceConfig(isvcConfigMap)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(nv).ShouldNot(gomega.BeNil())
|
|
g.Expect(nv.ServiceClusterIPNone).Should(gomega.BeFalse())
|
|
}
|
|
|
|
func TestInferenceServiceDisallowedLists(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
clientset := fakeclientset.NewSimpleClientset(&corev1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace},
|
|
Data: map[string]string{
|
|
InferenceServiceConfigKeyName: ISCVWithData,
|
|
},
|
|
})
|
|
isvcConfigMap, err := GetInferenceServiceConfigMap(t.Context(), clientset)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
isvcConfigWithData, err := NewInferenceServicesConfig(isvcConfigMap)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(isvcConfigWithData).ShouldNot(gomega.BeNil())
|
|
|
|
//nolint:gocritic
|
|
annotations := append(constants.ServiceAnnotationDisallowedList, []string{"my.custom.annotation/1", "my.custom.annotation/2"}...)
|
|
g.Expect(isvcConfigWithData.ServiceAnnotationDisallowedList).To(gomega.Equal(annotations))
|
|
//nolint:gocritic
|
|
labels := append(constants.RevisionTemplateLabelDisallowedList, []string{"my.custom.label.1", "my.custom.label.2"}...)
|
|
g.Expect(isvcConfigWithData.ServiceLabelDisallowedList).To(gomega.Equal(labels))
|
|
|
|
// with no data
|
|
clientsetWithoutData := fakeclientset.NewSimpleClientset(&corev1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{Name: constants.InferenceServiceConfigMapName, Namespace: constants.KServeNamespace},
|
|
Data: map[string]string{
|
|
InferenceServiceConfigKeyName: ISCVNoData,
|
|
},
|
|
})
|
|
isvcConfigMap, err = GetInferenceServiceConfigMap(t.Context(), clientsetWithoutData)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
isvcConfigWithoutData, err := NewInferenceServicesConfig(isvcConfigMap)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(isvcConfigWithoutData).ShouldNot(gomega.BeNil())
|
|
g.Expect(isvcConfigWithoutData.ServiceAnnotationDisallowedList).To(gomega.Equal(constants.ServiceAnnotationDisallowedList))
|
|
g.Expect(isvcConfigWithoutData.ServiceLabelDisallowedList).To(gomega.Equal(constants.RevisionTemplateLabelDisallowedList))
|
|
}
|
|
|
|
func TestValidateIngressGateway(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
|
|
tests := []struct {
|
|
name string
|
|
ingressConfig *IngressConfig
|
|
expectedError string
|
|
}{
|
|
{
|
|
name: "valid ingress gateway",
|
|
ingressConfig: &IngressConfig{
|
|
KserveIngressGateway: "kserve/kserve-ingress-gateway",
|
|
},
|
|
expectedError: "",
|
|
},
|
|
{
|
|
name: "missing kserveIngressGateway",
|
|
ingressConfig: &IngressConfig{
|
|
KserveIngressGateway: "",
|
|
},
|
|
expectedError: ErrKserveIngressGatewayRequired,
|
|
},
|
|
{
|
|
name: "invalid format for kserveIngressGateway",
|
|
ingressConfig: &IngressConfig{
|
|
KserveIngressGateway: "invalid-format",
|
|
},
|
|
expectedError: ErrInvalidKserveIngressGatewayFormat,
|
|
},
|
|
{
|
|
name: "invalid namespace in kserveIngressGateway",
|
|
ingressConfig: &IngressConfig{
|
|
KserveIngressGateway: "invalid_namespace/kserve-ingress-gateway",
|
|
},
|
|
expectedError: ErrInvalidKserveIngressGatewayNamespace,
|
|
},
|
|
{
|
|
name: "invalid name in kserveIngressGateway",
|
|
ingressConfig: &IngressConfig{
|
|
KserveIngressGateway: "kserve/invalid_name",
|
|
},
|
|
expectedError: ErrInvalidKserveIngressGatewayName,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := validateIngressGateway(tt.ingressConfig)
|
|
if tt.expectedError == "" {
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
} else {
|
|
g.Expect(err).Should(gomega.HaveOccurred())
|
|
g.Expect(err.Error()).Should(gomega.ContainSubstring(tt.expectedError))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewOtelCollectorConfig(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
|
|
t.Run("returns default config when otel config is missing", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{},
|
|
}
|
|
cfg, err := NewOtelCollectorConfig(cm)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(cfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(cfg.ScrapeInterval).To(gomega.BeEmpty())
|
|
g.Expect(cfg.MetricReceiverEndpoint).To(gomega.BeEmpty())
|
|
g.Expect(cfg.MetricScalerEndpoint).To(gomega.BeEmpty())
|
|
})
|
|
|
|
t.Run("returns config when otel config is present", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
OtelCollectorConfigName: `{
|
|
"scrapeInterval": "30s",
|
|
"metricReceiverEndpoint": "localhost:4317",
|
|
"metricScalerEndpoint": "localhost:8080"
|
|
}`,
|
|
},
|
|
}
|
|
cfg, err := NewOtelCollectorConfig(cm)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(cfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(cfg.ScrapeInterval).To(gomega.Equal("30s"))
|
|
g.Expect(cfg.MetricReceiverEndpoint).To(gomega.Equal("localhost:4317"))
|
|
g.Expect(cfg.MetricScalerEndpoint).To(gomega.Equal("localhost:8080"))
|
|
})
|
|
|
|
t.Run("returns error on invalid otel config json", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
OtelCollectorConfigName: `invalid-json`,
|
|
},
|
|
}
|
|
cfg, err := NewOtelCollectorConfig(cm)
|
|
g.Expect(err).Should(gomega.HaveOccurred())
|
|
g.Expect(cfg).To(gomega.BeNil())
|
|
})
|
|
}
|
|
|
|
func TestNewDeployConfig_WithValidConfig(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
validModes := []string{
|
|
string(constants.Knative),
|
|
string(constants.Standard),
|
|
string(constants.ModelMeshDeployment),
|
|
}
|
|
for _, mode := range validModes {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
DeployConfigName: fmt.Sprintf(`{"defaultDeploymentMode":"%s"}`, mode),
|
|
},
|
|
}
|
|
cfg, err := NewDeployConfig(cm)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(cfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(cfg.DefaultDeploymentMode).To(gomega.Equal(mode))
|
|
}
|
|
}
|
|
|
|
func TestNewDeployConfig_MissingDefaultDeploymentMode(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
DeployConfigName: `{}`,
|
|
},
|
|
}
|
|
cfg, err := NewDeployConfig(cm)
|
|
g.Expect(err).Should(gomega.HaveOccurred())
|
|
g.Expect(cfg).To(gomega.BeNil())
|
|
g.Expect(err.Error()).To(gomega.ContainSubstring("defaultDeploymentMode is required"))
|
|
}
|
|
|
|
func TestNewDeployConfig_InvalidDeploymentMode(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
DeployConfigName: `{"defaultDeploymentMode":"invalid-mode"}`,
|
|
},
|
|
}
|
|
cfg, err := NewDeployConfig(cm)
|
|
g.Expect(err).Should(gomega.HaveOccurred())
|
|
g.Expect(cfg).To(gomega.BeNil())
|
|
g.Expect(err.Error()).To(gomega.ContainSubstring("invalid deployment mode"))
|
|
}
|
|
|
|
func TestNewDeployConfig_LegacyDeploymentMode(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
validModes := []string{
|
|
string(constants.LegacyRawDeployment),
|
|
string(constants.LegacyServerless),
|
|
}
|
|
expected := []string{
|
|
string(constants.Standard),
|
|
string(constants.Knative),
|
|
}
|
|
for i, mode := range validModes {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
DeployConfigName: fmt.Sprintf(`{"defaultDeploymentMode":"%s"}`, mode),
|
|
},
|
|
}
|
|
cfg, err := NewDeployConfig(cm)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(cfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(cfg.DefaultDeploymentMode).To(gomega.Equal(expected[i]))
|
|
}
|
|
}
|
|
|
|
func TestNewDeployConfig_InvalidJSON(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
DeployConfigName: `invalid-json`,
|
|
},
|
|
}
|
|
cfg, err := NewDeployConfig(cm)
|
|
g.Expect(err).Should(gomega.HaveOccurred())
|
|
g.Expect(cfg).To(gomega.BeNil())
|
|
g.Expect(err.Error()).To(gomega.ContainSubstring("unable to parse deploy config json"))
|
|
}
|
|
|
|
func TestNewDeployConfig_EmptyConfigMap(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{},
|
|
}
|
|
cfg, err := NewDeployConfig(cm)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(cfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(cfg.DefaultDeploymentMode).To(gomega.BeEmpty())
|
|
}
|
|
|
|
func TestNewLocalModelConfig(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
|
|
t.Run("returns default config when localModel config is missing", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{},
|
|
}
|
|
cfg, err := NewLocalModelConfig(cm)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(cfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(cfg.Enabled).To(gomega.BeFalse())
|
|
g.Expect(cfg.JobNamespace).To(gomega.BeEmpty())
|
|
})
|
|
|
|
t.Run("returns config when localModel config is present", func(t *testing.T) {
|
|
fsGroup := int64(1000)
|
|
jobTTL := int32(3600)
|
|
reconFreq := int64(60)
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
LocalModelConfigName: fmt.Sprintf(`{
|
|
"enabled": true,
|
|
"jobNamespace": "test-ns",
|
|
"defaultJobImage": "test-image",
|
|
"fsGroup": %d,
|
|
"jobTTLSecondsAfterFinished": %d,
|
|
"reconcilationFrequencyInSecs": %d,
|
|
"disableVolumeManagement": true
|
|
}`, fsGroup, jobTTL, reconFreq),
|
|
},
|
|
}
|
|
cfg, err := NewLocalModelConfig(cm)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(cfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(cfg.Enabled).To(gomega.BeTrue())
|
|
g.Expect(cfg.JobNamespace).To(gomega.Equal("test-ns"))
|
|
g.Expect(cfg.DefaultJobImage).To(gomega.Equal("test-image"))
|
|
g.Expect(cfg.FSGroup).ToNot(gomega.BeNil())
|
|
g.Expect(*cfg.FSGroup).To(gomega.Equal(fsGroup))
|
|
g.Expect(cfg.JobTTLSecondsAfterFinished).ToNot(gomega.BeNil())
|
|
g.Expect(*cfg.JobTTLSecondsAfterFinished).To(gomega.Equal(jobTTL))
|
|
g.Expect(cfg.ReconcilationFrequencyInSecs).ToNot(gomega.BeNil())
|
|
g.Expect(*cfg.ReconcilationFrequencyInSecs).To(gomega.Equal(reconFreq))
|
|
g.Expect(cfg.DisableVolumeManagement).To(gomega.BeTrue())
|
|
})
|
|
|
|
t.Run("returns error on invalid localModel config json", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
LocalModelConfigName: `invalid-json`,
|
|
},
|
|
}
|
|
cfg, err := NewLocalModelConfig(cm)
|
|
g.Expect(err).Should(gomega.HaveOccurred())
|
|
g.Expect(cfg).To(gomega.BeNil())
|
|
})
|
|
}
|
|
|
|
func TestNewSecurityConfig(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
|
|
t.Run("returns default config when security config is missing", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{},
|
|
}
|
|
cfg, err := NewSecurityConfig(cm)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(cfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(cfg.AutoMountServiceAccountToken).To(gomega.BeFalse())
|
|
})
|
|
|
|
t.Run("returns config when security config is present", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
SecurityConfigName: `{"autoMountServiceAccountToken": true}`,
|
|
},
|
|
}
|
|
cfg, err := NewSecurityConfig(cm)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(cfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(cfg.AutoMountServiceAccountToken).To(gomega.BeTrue())
|
|
})
|
|
|
|
t.Run("returns error on invalid security config json", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
SecurityConfigName: `invalid-json`,
|
|
},
|
|
}
|
|
cfg, err := NewSecurityConfig(cm)
|
|
g.Expect(err).Should(gomega.HaveOccurred())
|
|
g.Expect(cfg).To(gomega.BeNil())
|
|
})
|
|
}
|
|
|
|
func TestNewIngressConfig_Validation(t *testing.T) {
|
|
g := gomega.NewGomegaWithT(t)
|
|
|
|
t.Run("returns error on invalid ingress config json", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
IngressConfigKeyName: `invalid-json`,
|
|
},
|
|
}
|
|
cfg, err := NewIngressConfig(cm)
|
|
g.Expect(err).Should(gomega.HaveOccurred())
|
|
g.Expect(cfg).To(gomega.BeNil())
|
|
})
|
|
|
|
t.Run("returns error if ingressGateway is missing", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
IngressConfigKeyName: `{
|
|
"kserveIngressGateway": "kserve/kserve-ingress-gateway"
|
|
}`,
|
|
},
|
|
}
|
|
cfg, err := NewIngressConfig(cm)
|
|
g.Expect(err).Should(gomega.HaveOccurred())
|
|
g.Expect(cfg).To(gomega.BeNil())
|
|
g.Expect(err.Error()).To(gomega.ContainSubstring("ingressGateway is required"))
|
|
})
|
|
|
|
t.Run("returns error if pathTemplate is invalid template", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
IngressConfigKeyName: `{
|
|
"kserveIngressGateway": "kserve/kserve-ingress-gateway",
|
|
"ingressGateway": "knative-serving/knative-ingress-gateway",
|
|
"pathTemplate": "{{ .Name }"
|
|
}`,
|
|
},
|
|
}
|
|
cfg, err := NewIngressConfig(cm)
|
|
g.Expect(err).Should(gomega.HaveOccurred())
|
|
g.Expect(cfg).To(gomega.BeNil())
|
|
g.Expect(err.Error()).To(gomega.ContainSubstring("unable to parse pathTemplate"))
|
|
})
|
|
|
|
t.Run("returns error if pathTemplate is set but ingressDomain is missing", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
IngressConfigKeyName: `{
|
|
"kserveIngressGateway": "kserve/kserve-ingress-gateway",
|
|
"ingressGateway": "knative-serving/knative-ingress-gateway",
|
|
"pathTemplate": "/foo/bar"
|
|
}`,
|
|
},
|
|
}
|
|
cfg, err := NewIngressConfig(cm)
|
|
g.Expect(err).Should(gomega.HaveOccurred())
|
|
g.Expect(cfg).To(gomega.BeNil())
|
|
g.Expect(err.Error()).To(gomega.ContainSubstring("ingressDomain is required if pathTemplate is given"))
|
|
})
|
|
|
|
t.Run("returns error if EnableGatewayAPI is true and kserveIngressGateway is missing", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
IngressConfigKeyName: `{
|
|
"enableGatewayApi": true,
|
|
"ingressGateway": "knative-serving/knative-ingress-gateway"
|
|
}`,
|
|
},
|
|
}
|
|
cfg, err := NewIngressConfig(cm)
|
|
g.Expect(err).Should(gomega.HaveOccurred())
|
|
g.Expect(cfg).To(gomega.BeNil())
|
|
g.Expect(err.Error()).To(gomega.ContainSubstring("kserveIngressGateway is required"))
|
|
})
|
|
|
|
t.Run("returns error if EnableGatewayAPI is true and kserveIngressGateway is invalid", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
IngressConfigKeyName: `{
|
|
"enableGatewayApi": true,
|
|
"kserveIngressGateway": "invalid-format",
|
|
"ingressGateway": "knative-serving/knative-ingress-gateway"
|
|
}`,
|
|
},
|
|
}
|
|
cfg, err := NewIngressConfig(cm)
|
|
g.Expect(err).Should(gomega.HaveOccurred())
|
|
g.Expect(cfg).To(gomega.BeNil())
|
|
g.Expect(err.Error()).To(gomega.ContainSubstring("should be in the format"))
|
|
})
|
|
|
|
t.Run("returns config with defaults when config map is empty", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{},
|
|
}
|
|
cfg, err := NewIngressConfig(cm)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(cfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(cfg.DomainTemplate).To(gomega.Equal(DefaultDomainTemplate))
|
|
g.Expect(cfg.IngressDomain).To(gomega.Equal(DefaultIngressDomain))
|
|
g.Expect(cfg.UrlScheme).To(gomega.Equal(DefaultUrlScheme))
|
|
})
|
|
|
|
t.Run("sets KnativeLocalGatewayService from LocalGatewayServiceName if missing", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
IngressConfigKeyName: `{
|
|
"kserveIngressGateway": "kserve/kserve-ingress-gateway",
|
|
"ingressGateway": "knative-serving/knative-ingress-gateway",
|
|
"localGatewayService": "my-local-gateway-service"
|
|
}`,
|
|
},
|
|
}
|
|
cfg, err := NewIngressConfig(cm)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(cfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(cfg.KnativeLocalGatewayService).To(gomega.Equal("my-local-gateway-service"))
|
|
})
|
|
|
|
t.Run("returns error if pathTemplate is valid but ingressDomain is empty", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
IngressConfigKeyName: `{
|
|
"kserveIngressGateway": "kserve/kserve-ingress-gateway",
|
|
"ingressGateway": "knative-serving/knative-ingress-gateway",
|
|
"pathTemplate": "/foo/bar"
|
|
}`,
|
|
},
|
|
}
|
|
cfg, err := NewIngressConfig(cm)
|
|
g.Expect(err).Should(gomega.HaveOccurred())
|
|
g.Expect(cfg).To(gomega.BeNil())
|
|
g.Expect(err.Error()).To(gomega.ContainSubstring("ingressDomain is required if pathTemplate is given"))
|
|
})
|
|
|
|
t.Run("returns config when all required fields are present", func(t *testing.T) {
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
IngressConfigKeyName: `{
|
|
"kserveIngressGateway": "kserve/kserve-ingress-gateway",
|
|
"ingressGateway": "knative-serving/knative-ingress-gateway",
|
|
"ingressDomain": "mydomain.com",
|
|
"urlScheme": "https"
|
|
}`,
|
|
},
|
|
}
|
|
cfg, err := NewIngressConfig(cm)
|
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
g.Expect(cfg).ShouldNot(gomega.BeNil())
|
|
g.Expect(cfg.KserveIngressGateway).To(gomega.Equal("kserve/kserve-ingress-gateway"))
|
|
g.Expect(cfg.IngressGateway).To(gomega.Equal("knative-serving/knative-ingress-gateway"))
|
|
g.Expect(cfg.IngressDomain).To(gomega.Equal("mydomain.com"))
|
|
g.Expect(cfg.UrlScheme).To(gomega.Equal("https"))
|
|
})
|
|
}
|