blob: 8106ebf67a18b7bd9e661981fa3f04f4ce4b7ea2 [file] [log] [blame]
// 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 translation
import (
"context"
"fmt"
"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"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/tools/cache"
"github.com/apache/apisix-ingress-controller/pkg/id"
configv2alpha1 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1"
fakeapisix "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/fake"
apisixinformers "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/informers/externalversions"
)
func TestRouteMatchExpr(t *testing.T) {
tr := &translator{}
value1 := "text/plain"
value2 := "gzip"
value3 := "13"
value4 := ".*\\.php"
exprs := []configv2alpha1.ApisixRouteHTTPMatchExpr{
{
Subject: configv2alpha1.ApisixRouteHTTPMatchExprSubject{
Scope: configv2alpha1.ScopeHeader,
Name: "Content-Type",
},
Op: configv2alpha1.OpEqual,
Value: &value1,
},
{
Subject: configv2alpha1.ApisixRouteHTTPMatchExprSubject{
Scope: configv2alpha1.ScopeHeader,
Name: "Content-Encoding",
},
Op: configv2alpha1.OpNotEqual,
Value: &value2,
},
{
Subject: configv2alpha1.ApisixRouteHTTPMatchExprSubject{
Scope: configv2alpha1.ScopeQuery,
Name: "ID",
},
Op: configv2alpha1.OpGreaterThan,
Value: &value3,
},
{
Subject: configv2alpha1.ApisixRouteHTTPMatchExprSubject{
Scope: configv2alpha1.ScopeQuery,
Name: "ID",
},
Op: configv2alpha1.OpLessThan,
Value: &value3,
},
{
Subject: configv2alpha1.ApisixRouteHTTPMatchExprSubject{
Scope: configv2alpha1.ScopeQuery,
Name: "ID",
},
Op: configv2alpha1.OpRegexMatch,
Value: &value4,
},
{
Subject: configv2alpha1.ApisixRouteHTTPMatchExprSubject{
Scope: configv2alpha1.ScopeQuery,
Name: "ID",
},
Op: configv2alpha1.OpRegexMatchCaseInsensitive,
Value: &value4,
},
{
Subject: configv2alpha1.ApisixRouteHTTPMatchExprSubject{
Scope: configv2alpha1.ScopeQuery,
Name: "ID",
},
Op: configv2alpha1.OpRegexNotMatch,
Value: &value4,
},
{
Subject: configv2alpha1.ApisixRouteHTTPMatchExprSubject{
Scope: configv2alpha1.ScopeQuery,
Name: "ID",
},
Op: configv2alpha1.OpRegexNotMatchCaseInsensitive,
Value: &value4,
},
{
Subject: configv2alpha1.ApisixRouteHTTPMatchExprSubject{
Scope: configv2alpha1.ScopeCookie,
Name: "domain",
},
Op: configv2alpha1.OpIn,
Set: []string{
"a.com",
"b.com",
},
},
{
Subject: configv2alpha1.ApisixRouteHTTPMatchExprSubject{
Scope: configv2alpha1.ScopeCookie,
Name: "X-Foo",
},
Op: configv2alpha1.OpIn,
Set: []string{
"foo.com",
},
},
}
results, err := tr.translateRouteMatchExprs(exprs)
assert.Nil(t, err)
assert.Len(t, results, 10)
assert.Len(t, results[0], 3)
assert.Equal(t, results[0][0].StrVal, "http_content_type")
assert.Equal(t, results[0][1].StrVal, "==")
assert.Equal(t, results[0][2].StrVal, "text/plain")
assert.Len(t, results[1], 3)
assert.Equal(t, results[1][0].StrVal, "http_content_encoding")
assert.Equal(t, results[1][1].StrVal, "~=")
assert.Equal(t, results[1][2].StrVal, "gzip")
assert.Len(t, results[2], 3)
assert.Equal(t, results[2][0].StrVal, "arg_id")
assert.Equal(t, results[2][1].StrVal, ">")
assert.Equal(t, results[2][2].StrVal, "13")
assert.Len(t, results[3], 3)
assert.Equal(t, results[3][0].StrVal, "arg_id")
assert.Equal(t, results[3][1].StrVal, "<")
assert.Equal(t, results[3][2].StrVal, "13")
assert.Len(t, results[4], 3)
assert.Equal(t, results[4][0].StrVal, "arg_id")
assert.Equal(t, results[4][1].StrVal, "~~")
assert.Equal(t, results[4][2].StrVal, ".*\\.php")
assert.Len(t, results[5], 3)
assert.Equal(t, results[5][0].StrVal, "arg_id")
assert.Equal(t, results[5][1].StrVal, "~*")
assert.Equal(t, results[5][2].StrVal, ".*\\.php")
assert.Len(t, results[6], 4)
assert.Equal(t, results[6][0].StrVal, "arg_id")
assert.Equal(t, results[6][1].StrVal, "!")
assert.Equal(t, results[6][2].StrVal, "~~")
assert.Equal(t, results[6][3].StrVal, ".*\\.php")
assert.Len(t, results[7], 4)
assert.Equal(t, results[7][0].StrVal, "arg_id")
assert.Equal(t, results[7][1].StrVal, "!")
assert.Equal(t, results[7][2].StrVal, "~*")
assert.Equal(t, results[7][3].StrVal, ".*\\.php")
assert.Len(t, results[8], 3)
assert.Equal(t, results[8][0].StrVal, "cookie_domain")
assert.Equal(t, results[8][1].StrVal, "in")
assert.Equal(t, results[8][2].SliceVal, []string{"a.com", "b.com"})
assert.Len(t, results[9], 3)
assert.Equal(t, results[9][0].StrVal, "cookie_X-Foo")
assert.Equal(t, results[9][1].StrVal, "in")
assert.Equal(t, results[9][2].SliceVal, []string{"foo.com"})
}
func TestTranslateApisixRouteV2alpha1WithDuplicatedName(t *testing.T) {
svc := &corev1.Service{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: "svc",
Namespace: "test",
},
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{
Name: "port1",
Port: 80,
TargetPort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 9080,
},
},
{
Name: "port2",
Port: 443,
TargetPort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 9443,
},
},
},
},
}
endpoints := &corev1.Endpoints{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: "svc",
Namespace: "test",
},
Subsets: []corev1.EndpointSubset{
{
Ports: []corev1.EndpointPort{
{
Name: "port1",
Port: 9080,
},
{
Name: "port2",
Port: 9443,
},
},
Addresses: []corev1.EndpointAddress{
{IP: "192.168.1.1"},
{IP: "192.168.1.2"},
},
},
},
}
client := fake.NewSimpleClientset()
informersFactory := informers.NewSharedInformerFactory(client, 0)
svcInformer := informersFactory.Core().V1().Services().Informer()
svcLister := informersFactory.Core().V1().Services().Lister()
epInformer := informersFactory.Core().V1().Endpoints().Informer()
epLister := informersFactory.Core().V1().Endpoints().Lister()
apisixClient := fakeapisix.NewSimpleClientset()
apisixInformersFactory := apisixinformers.NewSharedInformerFactory(apisixClient, 0)
_, err := client.CoreV1().Endpoints("test").Create(context.Background(), endpoints, metav1.CreateOptions{})
assert.Nil(t, err)
_, err = client.CoreV1().Services("test").Create(context.Background(), svc, metav1.CreateOptions{})
assert.Nil(t, err)
tr := &translator{
&TranslatorOptions{
EndpointsLister: epLister,
ServiceLister: svcLister,
ApisixUpstreamLister: apisixInformersFactory.Apisix().V1().ApisixUpstreams().Lister(),
},
}
processCh := make(chan struct{})
svcInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
processCh <- struct{}{}
},
})
epInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
processCh <- struct{}{}
},
})
stopCh := make(chan struct{})
defer close(stopCh)
go svcInformer.Run(stopCh)
go epInformer.Run(stopCh)
cache.WaitForCacheSync(stopCh, svcInformer.HasSynced)
<-processCh
<-processCh
ar := &configv2alpha1.ApisixRoute{
ObjectMeta: metav1.ObjectMeta{
Name: "ar",
Namespace: "test",
},
Spec: &configv2alpha1.ApisixRouteSpec{
HTTP: []*configv2alpha1.ApisixRouteHTTP{
{
Name: "rule1",
Match: &configv2alpha1.ApisixRouteHTTPMatch{
Paths: []string{
"/*",
},
},
Backend: &configv2alpha1.ApisixRouteHTTPBackend{
ServiceName: "svc",
ServicePort: intstr.IntOrString{
IntVal: 80,
},
},
},
{
Name: "rule1",
Match: &configv2alpha1.ApisixRouteHTTPMatch{
Paths: []string{
"/*",
},
},
Backend: &configv2alpha1.ApisixRouteHTTPBackend{
ServiceName: "svc",
ServicePort: intstr.IntOrString{
IntVal: 80,
},
},
},
},
},
}
_, err = tr.TranslateRouteV2alpha1(ar)
assert.Equal(t, err.Error(), "duplicated route rule name")
}
func TestTranslateApisixRouteV2alpha1NotStrictly(t *testing.T) {
tr := &translator{
&TranslatorOptions{},
}
ar := &configv2alpha1.ApisixRoute{
ObjectMeta: metav1.ObjectMeta{
Name: "ar",
Namespace: "test",
},
Spec: &configv2alpha1.ApisixRouteSpec{
HTTP: []*configv2alpha1.ApisixRouteHTTP{
{
Name: "rule1",
Match: &configv2alpha1.ApisixRouteHTTPMatch{
Paths: []string{
"/*",
},
},
Backend: &configv2alpha1.ApisixRouteHTTPBackend{
ServiceName: "svc1",
ServicePort: intstr.IntOrString{
IntVal: 81,
},
},
},
{
Name: "rule2",
Match: &configv2alpha1.ApisixRouteHTTPMatch{
Paths: []string{
"/*",
},
},
Backend: &configv2alpha1.ApisixRouteHTTPBackend{
ServiceName: "svc2",
ServicePort: intstr.IntOrString{
IntVal: 82,
},
},
},
},
},
}
tx, err := tr.TranslateRouteV2alpha1NotStrictly(ar)
fmt.Println(tx)
assert.NoError(t, err, "translateRoute not strictly should be no error")
assert.Equal(t, len(tx.Routes), 2, "There should be 2 routes")
assert.Equal(t, len(tx.Upstreams), 2, "There should be 2 upstreams")
assert.Equal(t, tx.Routes[0].Name, "test_ar_rule1", "route1 name error")
assert.Equal(t, tx.Routes[1].Name, "test_ar_rule2", "route2 name error")
assert.Equal(t, tx.Upstreams[0].Name, "test_svc1_81", "upstream1 name error")
assert.Equal(t, tx.Upstreams[1].Name, "test_svc2_82", "upstream2 name error")
assert.Equal(t, tx.Routes[0].ID, id.GenID("test_ar_rule1"), "route1 id error")
assert.Equal(t, tx.Routes[1].ID, id.GenID("test_ar_rule2"), "route2 id error")
assert.Equal(t, tx.Upstreams[0].ID, id.GenID("test_svc1_81"), "upstream1 id error")
assert.Equal(t, tx.Upstreams[1].ID, id.GenID("test_svc2_82"), "upstream2 id error")
}