blob: 96aa88adf0370255c731b80a26e10581ede4d59d [file] [log] [blame]
// Copyright Istio 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 validate
import (
"fmt"
"os"
"path/filepath"
"testing"
)
import (
"sigs.k8s.io/yaml"
)
import (
"github.com/apache/dubbo-go-pixiu/operator/pkg/helm"
"github.com/apache/dubbo-go-pixiu/operator/pkg/object"
"github.com/apache/dubbo-go-pixiu/operator/pkg/util"
"github.com/apache/dubbo-go-pixiu/pkg/test/env"
)
var repoRootDir string
func init() {
repoRootDir = env.IstioSrc
}
func TestValidateValues(t *testing.T) {
tests := []struct {
desc string
yamlStr string
wantErrs util.Errors
}{
{
desc: "nil success",
},
{
desc: "StarIPRange",
yamlStr: `
global:
proxy:
includeIPRanges: "*"
excludeIPRanges: "*"
`,
},
{
desc: "ProxyConfig",
yamlStr: `
global:
podDNSSearchNamespaces:
- "my-namespace"
proxy:
includeIPRanges: "1.1.0.0/16,2.2.0.0/16"
excludeIPRanges: "3.3.0.0/16,4.4.0.0/16"
excludeInboundPorts: "333,444"
clusterDomain: "my.domain"
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 30"]
`,
},
{
desc: "CNIConfig",
yamlStr: `
cni:
cniBinDir: "/var/lib/cni/bin"
cniConfDir: "/var/run/multus/cni/net.d"
`,
},
{
desc: "BadIPRange",
yamlStr: `
global:
proxy:
includeIPRanges: "1.1.0.256/16,2.2.0.257/16"
excludeIPRanges: "3.3.0.0/33,4.4.0.0/34"
`,
wantErrs: makeErrors([]string{
`global.proxy.excludeIPRanges invalid CIDR address: 3.3.0.0/33`,
`global.proxy.excludeIPRanges invalid CIDR address: 4.4.0.0/34`,
`global.proxy.includeIPRanges invalid CIDR address: 1.1.0.256/16`,
`global.proxy.includeIPRanges invalid CIDR address: 2.2.0.257/16`,
}),
},
{
desc: "BadIPMalformed",
yamlStr: `
global:
proxy:
includeIPRanges: "1.2.3/16,1.2.3.x/16"
`,
wantErrs: makeErrors([]string{
`global.proxy.includeIPRanges invalid CIDR address: 1.2.3/16`,
`global.proxy.includeIPRanges invalid CIDR address: 1.2.3.x/16`,
}),
},
{
desc: "BadIPWithStar",
yamlStr: `
global:
proxy:
includeIPRanges: "*,1.1.0.0/16,2.2.0.0/16"
`,
wantErrs: makeErrors([]string{`global.proxy.includeIPRanges invalid CIDR address: *`}),
},
{
desc: "BadPortRange",
yamlStr: `
global:
proxy:
excludeInboundPorts: "-1,444"
`,
wantErrs: makeErrors([]string{`value global.proxy.excludeInboundPorts:-1 falls outside range [0, 65535]`}),
},
{
desc: "BadPortMalformed",
yamlStr: `
global:
proxy:
excludeInboundPorts: "111,222x"
`,
wantErrs: makeErrors([]string{`global.proxy.excludeInboundPorts : strconv.ParseInt: parsing "222x": invalid syntax`}),
},
{
desc: "unknown field",
yamlStr: `
global:
proxy:
foo: "bar"
`,
wantErrs: makeErrors([]string{`unknown field "foo" in v1alpha1.ProxyConfig`}),
},
{
desc: "unknown cni field",
yamlStr: `
cni:
foo: "bar"
`,
wantErrs: makeErrors([]string{`unknown field "foo" in v1alpha1.CNIConfig`}),
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
root := make(map[string]interface{})
err := yaml.Unmarshal([]byte(tt.yamlStr), &root)
if err != nil {
t.Fatalf("yaml.Unmarshal(%s): got error %s", tt.desc, err)
}
errs := CheckValues(util.MustStruct(root))
if gotErr, wantErr := errs, tt.wantErrs; !util.EqualErrors(gotErr, wantErr) {
t.Errorf("CheckValues(%s)(%v): gotErr:%s, wantErr:%s", tt.desc, tt.yamlStr, gotErr, wantErr)
}
})
}
}
func TestValidateValuesFromProfile(t *testing.T) {
tests := []struct {
profile string
wantErrs util.Errors
}{
{
profile: "default",
},
{
profile: "demo",
},
{
profile: "minimal",
},
}
for _, tt := range tests {
t.Run(tt.profile, func(t *testing.T) {
pf, err := helm.ReadProfileYAML(tt.profile, filepath.Join(env.IstioSrc, "manifests"))
if err != nil {
t.Fatalf("fail to read profile: %s", tt.profile)
}
val, _, err := object.ParseK8SYAMLToIstioOperator(pf)
if err != nil {
t.Fatalf(" fail to parse profile to ISCP: (%s), got error %s", tt.profile, err)
}
errs := CheckValues(val.Spec.Values)
if gotErr, wantErr := errs, tt.wantErrs; !util.EqualErrors(gotErr, wantErr) {
t.Errorf("CheckValues of (%v): gotErr:%s, wantErr:%s", tt.profile, gotErr, wantErr)
}
})
}
}
func TestValidateValuesFromValuesYAMLs(t *testing.T) {
valuesYAML := ""
var allFiles []string
manifestDir := filepath.Join(repoRootDir, "manifests/charts")
for _, sd := range []string{"base", "gateways", "istio-cni", "istio-control"} {
dir := filepath.Join(manifestDir, sd)
files, err := util.FindFiles(dir, yamlFileFilter)
if err != nil {
t.Fatalf(err.Error())
}
allFiles = append(allFiles, files...)
}
for _, f := range allFiles {
b, err := os.ReadFile(f)
if err != nil {
t.Fatal(err.Error())
}
valuesYAML, err = util.OverlayYAML(valuesYAML, string(b))
if err != nil {
t.Fatal(err.Error())
}
valuesTree := make(map[string]interface{})
if err := yaml.Unmarshal([]byte(valuesYAML), &valuesTree); err != nil {
t.Fatal(err.Error())
}
if err := CheckValues(util.MustStruct(valuesTree)); err != nil {
t.Fatalf("file %s failed validation with: %s", f, err)
}
}
}
func makeErrors(estr []string) util.Errors {
var errs util.Errors
for _, s := range estr {
errs = util.AppendErr(errs, fmt.Errorf("%s", s))
}
return errs
}
func yamlFileFilter(path string) bool {
return filepath.Base(path) == "values.yaml"
}