Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tests): Add initial unit tests #1

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
Expand Down Expand Up @@ -182,6 +183,7 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down Expand Up @@ -499,6 +501,8 @@ k8s.io/apimachinery v0.17.0 h1:xRBnuie9rXcPxUkDizUsGvPf1cnlZCFu210op7J7LJo=
k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
k8s.io/client-go v0.17.0 h1:8QOGvUGdqDMFrm9sD6IUFl256BcffynGoe80sxgTEDg=
k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k=
k8s.io/client-go v1.5.1 h1:XaX/lo2/u3/pmFau8HN+sB5C/b4dc4Dmm2eXjBH4p1E=
k8s.io/client-go v11.0.0+incompatible h1:LBbX2+lOwY9flffWlJM7f1Ct8V2SRNiMRDFeiwnJo9o=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
Expand Down
242 changes: 242 additions & 0 deletions pkg/controller/handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
package controller

import (
// "log"

"reflect"
"testing"
"time"

istionetworkingv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
istio "istio.io/client-go/pkg/clientset/versioned"
istiofake "istio.io/client-go/pkg/clientset/versioned/fake"
istioscheme "istio.io/client-go/pkg/clientset/versioned/scheme"
istioinformers "istio.io/client-go/pkg/informers/externalversions"
istionetworkinginformers "istio.io/client-go/pkg/informers/externalversions/networking/v1beta1"
corev1 "k8s.io/api/core/v1"
networkingv1beta1 "k8s.io/api/networking/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
kubeinformers "k8s.io/client-go/informers"
corev1informers "k8s.io/client-go/informers/core/v1"
networkinginformers "k8s.io/client-go/informers/networking/v1beta1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/kubernetes/scheme"
)

type system struct {
kubeclient kubernetes.Interface
istioclient istio.Interface

ingressesInformer networkinginformers.IngressInformer
servicesInformer corev1informers.ServiceInformer
virtualServicesInformer istionetworkinginformers.VirtualServiceInformer

controller *Controller
}

func setup(kubeObjects, istioObjects []runtime.Object) *system {
kubeclient := fake.NewSimpleClientset(kubeObjects...)
istioclient := istiofake.NewSimpleClientset(istioObjects...)

kubeInformerFactory := kubeinformers.NewSharedInformerFactory(kubeclient, time.Duration(0))
istioInformerFactory := istioinformers.NewSharedInformerFactory(istioclient, time.Duration(0))

ingressesInformer := kubeInformerFactory.Networking().V1beta1().Ingresses()
servicesInformer := kubeInformerFactory.Core().V1().Services()
virtualServicesInformer := istioInformerFactory.Networking().V1beta1().VirtualServices()

controller := NewController(
kubeclient, nil,
"cluster.local",
"default-gateway", "istio", 100,
ingressesInformer,
servicesInformer,
virtualServicesInformer)

return &system{
kubeclient: kubeclient,
istioclient: istioclient,
ingressesInformer: ingressesInformer,
servicesInformer: servicesInformer,
controller: controller,
virtualServicesInformer: virtualServicesInformer,
}
}

func TestGenerateVirtualServiceBasic(t *testing.T) {
// Setup test
var ingress string = `
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ing
namespace: test-ns
spec:
rules:
- host: example.ca
http:
paths:
- backend:
serviceName: test-svc
servicePort: 80
`

var vs string = `
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: test-ing
namespace: test-ns
spec:
gateways:
- istio-system/ingress
hosts:
- example.ca
http:
- match:
- authority:
exact: example.ca
route:
- destination:
host: test-svc.test-ns.svc.cluster.local
port:
number: 80
weight: 100
`

// Convert to objects
decode := scheme.Codecs.UniversalDeserializer().Decode
obj, _, err := decode([]byte(ingress), nil, nil)

if err != nil {
t.Fatalf("failed creating test object: %v", err)
}

test := obj.(*networkingv1beta1.Ingress)

decode = istioscheme.Codecs.UniversalDeserializer().Decode
obj, _, err = decode([]byte(vs), nil, nil)

if err != nil {
t.Fatalf("failed creating expected object: %v", err)
}

expected := obj.(*istionetworkingv1beta1.VirtualService)

// Generate VirtualService from Ingress
system := setup(nil, nil)
result, err := system.controller.generateVirtualService(test, []string{"istio-system/ingress"})
if err != nil {
t.Fatalf("got unexpected error converting ingress: %v", err)
}

// Compare generated VirtualService against expected
if result.Name != expected.Name {
t.Errorf("got %q for VirtualService.Name, but expected %q", result.Name, expected.Name)
}

if result.Namespace != expected.Namespace {
t.Errorf("got %q for VirtualService.Namespace, but expected %q", result.Namespace, expected.Namespace)
}

if !metav1.IsControlledBy(result, test) {
t.Errorf("VirtualService was not owned by the Ingress")
}

if !reflect.DeepEqual(result.Spec, expected.Spec) {
t.Errorf("got %v but expected %v", result.Spec, expected.Spec)
}
}

func TestGenerateVirtualServiceServicePortName(t *testing.T) {
// Setup test
var service string = `
apiVersion: v1
kind: Service
metadata:
name: test-svc
namespace: test-ns
spec:
ports:
- name: http
port: 80
`
var ingress string = `
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ing
namespace: test-ns
spec:
rules:
- host: example.ca
http:
paths:
- backend:
serviceName: test-svc
servicePort: http
`

var vs string = `
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: test-ing
namespace: test-ns
spec:
gateways:
- istio-system/ingress
hosts:
- example.ca
http:
- match:
- authority:
exact: example.ca
route:
- destination:
host: test-svc.test-ns.svc.cluster.local
port:
number: 80
weight: 100
`
// Convert to objects
decode := scheme.Codecs.UniversalDeserializer().Decode

obj, _, err := decode([]byte(service), nil, nil)
if err != nil {
t.Fatalf("failed creating service object: %v", err)
}
svc := obj.(*corev1.Service)

obj, _, err = decode([]byte(ingress), nil, nil)
if err != nil {
t.Fatalf("failed creating test object: %v", err)
}
test := obj.(*networkingv1beta1.Ingress)

decode = istioscheme.Codecs.UniversalDeserializer().Decode
obj, _, err = decode([]byte(vs), nil, nil)

if err != nil {
t.Fatalf("failed creating expected object: %v", err)
}

expected := obj.(*istionetworkingv1beta1.VirtualService)

// Register service
system := setup([]runtime.Object{svc}, nil)
system.servicesInformer.Informer().GetIndexer().Add(svc)

// Generate VirtualService from Ingress
result, err := system.controller.generateVirtualService(test, []string{"istio-system/ingress"})
if err != nil {
t.Fatalf("got unexpected error converting ingress: %v", err)
}

// Compare generated VirtualService against expected
if !reflect.DeepEqual(result.Spec, expected.Spec) {
t.Errorf("got %v but expected %v", result.Spec, expected.Spec)
}
}
48 changes: 48 additions & 0 deletions pkg/controller/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package controller

import (
"testing"
)

func TestStringInArray(t *testing.T) {
tests := []struct {
str string
arr []string
expected bool
}{
{"a", []string{"a", "b", "c"}, true},
{"d", []string{"a", "b", "c"}, false},
{"alpha", []string{"alpha", "bravo", "charlie"}, true},
{"alpha", []string{}, false},
{"", []string{"one", "two", "three", "four", "five"}, false},
{"", []string{"one", "two", "", "four", "five"}, true},
}

for _, test := range tests {
result := stringInArray(test.str, test.arr)
if result != test.expected {
t.Errorf("got %t for %q in %q, expected %t", result, test.str, test.arr, test.expected)
}
}
}

func TestStringArrayEquals(t *testing.T) {
tests := []struct {
a []string
b []string
expected bool
}{
{[]string{"a", "b", "c"}, []string{"a", "b", "c"}, true},
{[]string{"a", "b", "c"}, []string{"a", "c", "b"}, false},
{[]string{}, []string{}, true},
{[]string{"a"}, []string{}, false},
{[]string{}, []string{"a"}, false},
}

for _, test := range tests {
result := stringArrayEquals(test.a, test.b)
if result != test.expected {
t.Errorf("got %t for %q equals %q, expected %t", result, test.a, test.b, test.expected)
}
}
}