blob: 3c2381a977937a2c693e188535b94d1de551b008 [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 xds
import (
"fmt"
"strconv"
"testing"
)
import (
model "github.com/apache/dubbo-go-pixiu/pilot/pkg/model"
"github.com/apache/dubbo-go-pixiu/pkg/config"
"github.com/apache/dubbo-go-pixiu/pkg/config/schema/gvk"
"github.com/apache/dubbo-go-pixiu/pkg/spiffe"
)
func TestProxyNeedsPush(t *testing.T) {
const (
invalidKind = "INVALID_KIND"
svcName = "svc1.com"
drName = "dr1"
vsName = "vs1"
scName = "sc1"
nsName = "ns1"
nsRoot = "rootns"
generalName = "name1"
invalidNameSuffix = "invalid"
)
type Case struct {
name string
proxy *model.Proxy
configs map[model.ConfigKey]struct{}
want bool
}
sidecar := &model.Proxy{
Type: model.SidecarProxy, IPAddresses: []string{"127.0.0.1"}, Metadata: &model.NodeMetadata{},
SidecarScope: &model.SidecarScope{Name: generalName, Namespace: nsName, RootNamespace: nsRoot},
}
gateway := &model.Proxy{Type: model.Router}
sidecarScopeKindNames := map[config.GroupVersionKind]string{
gvk.ServiceEntry: svcName, gvk.VirtualService: vsName, gvk.DestinationRule: drName, gvk.Sidecar: scName,
}
for kind, name := range sidecarScopeKindNames {
sidecar.SidecarScope.AddConfigDependencies(model.ConfigKey{Kind: kind, Name: name, Namespace: nsName})
}
for kind, types := range configKindAffectedProxyTypes {
for _, nodeType := range types {
if nodeType == model.SidecarProxy {
sidecar.SidecarScope.AddConfigDependencies(model.ConfigKey{
Kind: kind,
Name: generalName,
Namespace: nsName,
})
}
}
}
cases := []Case{
{"no namespace or configs", sidecar, nil, true},
{"gateway config for sidecar", sidecar, map[model.ConfigKey]struct{}{
{
Kind: gvk.Gateway,
Name: generalName, Namespace: nsName,
}: {},
}, false},
{"gateway config for gateway", gateway, map[model.ConfigKey]struct{}{
{
Kind: gvk.Gateway,
Name: generalName, Namespace: nsName,
}: {},
}, true},
{"sidecar config for gateway", gateway, map[model.ConfigKey]struct{}{
{
Kind: gvk.Sidecar,
Name: scName, Namespace: nsName,
}: {},
}, false},
{
"invalid config for sidecar", sidecar,
map[model.ConfigKey]struct{}{
{
Kind: config.GroupVersionKind{Kind: invalidKind}, Name: generalName, Namespace: nsName,
}: {},
},
true,
},
{"mixture matched and unmatched config for sidecar", sidecar, map[model.ConfigKey]struct{}{
{Kind: gvk.DestinationRule, Name: drName, Namespace: nsName}: {},
{Kind: gvk.ServiceEntry, Name: svcName + invalidNameSuffix, Namespace: nsName}: {},
}, true},
{"mixture unmatched and unmatched config for sidecar", sidecar, map[model.ConfigKey]struct{}{
{Kind: gvk.DestinationRule, Name: drName + invalidNameSuffix, Namespace: nsName}: {},
{Kind: gvk.ServiceEntry, Name: svcName + invalidNameSuffix, Namespace: nsName}: {},
}, false},
{"empty configsUpdated for sidecar", sidecar, nil, true},
}
for kind, name := range sidecarScopeKindNames {
cases = append(cases, Case{ // valid name
name: fmt.Sprintf("%s config for sidecar", kind.Kind),
proxy: sidecar,
configs: map[model.ConfigKey]struct{}{{Kind: kind, Name: name, Namespace: nsName}: {}},
want: true,
}, Case{ // invalid name
name: fmt.Sprintf("%s unmatched config for sidecar", kind.Kind),
proxy: sidecar,
configs: map[model.ConfigKey]struct{}{{Kind: kind, Name: name + invalidNameSuffix, Namespace: nsName}: {}},
want: false,
})
}
sidecarNamespaceScopeTypes := []config.GroupVersionKind{
gvk.EnvoyFilter, gvk.AuthorizationPolicy, gvk.RequestAuthentication,
}
for _, kind := range sidecarNamespaceScopeTypes {
cases = append(cases,
Case{
name: fmt.Sprintf("%s config for sidecar in same namespace", kind.Kind),
proxy: sidecar,
configs: map[model.ConfigKey]struct{}{{Kind: kind, Name: generalName, Namespace: nsName}: {}},
want: true,
},
Case{
name: fmt.Sprintf("%s config for sidecar in different namespace", kind.Kind),
proxy: sidecar,
configs: map[model.ConfigKey]struct{}{{Kind: kind, Name: generalName, Namespace: "invalid-namespace"}: {}},
want: false,
},
)
}
// tests for kind-affect-proxy.
for kind, types := range configKindAffectedProxyTypes {
for _, nodeType := range model.NodeTypes {
affected := false
for _, affectedType := range types {
if nodeType == affectedType {
affected = true
break
}
}
if !affected {
proxy := gateway
if nodeType == model.SidecarProxy {
proxy = sidecar
}
cases = append(cases, Case{
name: fmt.Sprintf("kind %s not affect %s", kind, nodeType),
proxy: proxy,
configs: map[model.ConfigKey]struct{}{
{Kind: kind, Name: generalName + invalidNameSuffix, Namespace: nsName}: {},
},
want: false,
})
}
}
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
got := DefaultProxyNeedsPush(tt.proxy, &model.PushRequest{ConfigsUpdated: tt.configs})
if got != tt.want {
t.Fatalf("Got needs push = %v, expected %v", got, tt.want)
}
})
}
}
func BenchmarkListEquals(b *testing.B) {
size := 100
var l []string
for i := 0; i < size; i++ {
l = append(l, strconv.Itoa(i))
}
var equal []string
for i := 0; i < size; i++ {
equal = append(equal, strconv.Itoa(i))
}
var notEqual []string
for i := 0; i < size; i++ {
notEqual = append(notEqual, strconv.Itoa(i))
}
notEqual[size-1] = "z"
for n := 0; n < b.N; n++ {
listEqualUnordered(l, equal)
listEqualUnordered(l, notEqual)
}
}
func TestCheckConnectionIdentity(t *testing.T) {
cases := []struct {
name string
identity []string
sa string
namespace string
success bool
}{
{
name: "single match",
identity: []string{spiffe.Identity{TrustDomain: "cluster.local", Namespace: "namespace", ServiceAccount: "serviceaccount"}.String()},
sa: "serviceaccount",
namespace: "namespace",
success: true,
},
{
name: "second match",
identity: []string{
spiffe.Identity{TrustDomain: "cluster.local", Namespace: "bad", ServiceAccount: "serviceaccount"}.String(),
spiffe.Identity{TrustDomain: "cluster.local", Namespace: "namespace", ServiceAccount: "serviceaccount"}.String(),
},
sa: "serviceaccount",
namespace: "namespace",
success: true,
},
{
name: "no match namespace",
identity: []string{
spiffe.Identity{TrustDomain: "cluster.local", Namespace: "bad", ServiceAccount: "serviceaccount"}.String(),
},
sa: "serviceaccount",
namespace: "namespace",
success: false,
},
{
name: "no match service account",
identity: []string{
spiffe.Identity{TrustDomain: "cluster.local", Namespace: "namespace", ServiceAccount: "bad"}.String(),
},
sa: "serviceaccount",
namespace: "namespace",
success: false,
},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
proxy := &model.Proxy{ConfigNamespace: tt.namespace, Metadata: &model.NodeMetadata{ServiceAccount: tt.sa}}
if _, err := checkConnectionIdentity(proxy, tt.identity); (err == nil) != tt.success {
t.Fatalf("expected success=%v, got err=%v", tt.success, err)
}
})
}
}