1// Copyright 2019 Istio Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package rt_test
16
17import (
18	"fmt"
19	"testing"
20
21	"github.com/gogo/protobuf/proto"
22	. "github.com/onsi/gomega"
23	"k8s.io/api/extensions/v1beta1"
24
25	"istio.io/istio/pkg/config/schema/resource"
26
27	appsV1 "k8s.io/api/apps/v1"
28	coreV1 "k8s.io/api/core/v1"
29	metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30
31	"istio.io/istio/galley/pkg/config/source/kube/rt"
32	"istio.io/istio/galley/pkg/config/testing/data"
33	"istio.io/istio/galley/pkg/config/testing/k8smeta"
34)
35
36func TestParse(t *testing.T) {
37	t.Run("Endpoints", func(t *testing.T) {
38		g := NewGomegaWithT(t)
39		input := data.GetEndpoints()
40
41		objMeta, objResource := parse(t, []byte(input), "", "Endpoints", "v1")
42
43		// Just validate a couple of things...
44		_, ok := objResource.(*coreV1.Endpoints)
45		if !ok {
46			t.Fatal("failed casting item to Endpoints")
47		}
48		g.Expect(objMeta.GetName()).To(Equal("kube-dns"))
49	})
50
51	t.Run("Namespace", func(t *testing.T) {
52		g := NewGomegaWithT(t)
53		input := data.GetNamespace()
54
55		objMeta, objResource := parse(t, []byte(input), "", "Namespace", "v1")
56
57		// Just validate a couple of things...
58		_, ok := objResource.(*coreV1.NamespaceSpec)
59		if !ok {
60			t.Fatal("failed casting item to Namespace")
61		}
62		g.Expect(objMeta.GetName()).To(Equal("somens"))
63	})
64
65	t.Run("Ingress", func(t *testing.T) {
66		g := NewGomegaWithT(t)
67		input := data.GetIngress()
68
69		objMeta, objResource := parse(t, []byte(input), "extensions", "Ingress", "v1beta1")
70
71		// Just validate a couple of things...
72		_, ok := objResource.(*v1beta1.IngressSpec)
73		if !ok {
74			t.Fatal("failed casting item to IngressSpec")
75		}
76		g.Expect(objMeta.GetName()).To(Equal("secured-ingress"))
77	})
78
79	t.Run("Node", func(t *testing.T) {
80		g := NewGomegaWithT(t)
81		input := data.GetNode()
82
83		objMeta, objResource := parse(t, []byte(input), "", "Node", "v1")
84
85		// Just validate a couple of things...
86		_, ok := objResource.(*coreV1.NodeSpec)
87		if !ok {
88			t.Fatal("failed casting item to NodeSpec")
89		}
90		g.Expect(objMeta.GetName()).To(Equal("gke-istio-test-default-pool-866a0405-420r"))
91	})
92
93	t.Run("Pod", func(t *testing.T) {
94		g := NewGomegaWithT(t)
95		input := data.GetPod()
96
97		objMeta, objResource := parse(t, []byte(input), "", "Pod", "v1")
98
99		// Just validate a couple of things...
100		_, ok := objResource.(*coreV1.Pod)
101		if !ok {
102			t.Fatal("failed casting item to Pod")
103		}
104		g.Expect(objMeta.GetName()).To(Equal("kube-dns-548976df6c-d9kkv"))
105	})
106
107	t.Run("Service", func(t *testing.T) {
108		g := NewGomegaWithT(t)
109		input := data.GetService()
110
111		objMeta, objResource := parse(t, []byte(input), "", "Service", "v1")
112
113		// Just validate a couple of things...
114		_, ok := objResource.(*coreV1.ServiceSpec)
115		if !ok {
116			t.Fatal("failed casting item to ServiceSpec")
117		}
118		g.Expect(objMeta.GetName()).To(Equal("kube-dns"))
119	})
120
121	t.Run("Deployment", func(t *testing.T) {
122		g := NewGomegaWithT(t)
123		input := data.GetDeployment()
124
125		objMeta, objResource := parse(t, []byte(input), "apps", "Deployment", "v1")
126
127		// Just validate a couple of things...
128		_, ok := objResource.(*appsV1.Deployment)
129		if !ok {
130			t.Fatal("failed casting item to Deployment")
131		}
132		g.Expect(objMeta.GetName()).To(Equal("httpbin"))
133	})
134
135}
136
137func TestExtractObject(t *testing.T) {
138	for _, r := range k8smeta.MustGet().KubeCollections().All() {
139		a := rt.DefaultProvider().GetAdapter(r.Resource())
140
141		t.Run(r.Resource().Kind(), func(t *testing.T) {
142			t.Run("WrongTypeShouldReturnNil", func(t *testing.T) {
143				out := a.ExtractObject(struct{}{})
144				g := NewGomegaWithT(t)
145				g.Expect(out).To(BeNil())
146			})
147
148			t.Run("Success", func(t *testing.T) {
149				out := a.ExtractObject(empty(r.Resource().Kind()))
150				g := NewGomegaWithT(t)
151				g.Expect(out).ToNot(BeNil())
152			})
153		})
154	}
155}
156
157func TestExtractResource(t *testing.T) {
158	for _, r := range k8smeta.MustGet().KubeCollections().All() {
159		a := rt.DefaultProvider().GetAdapter(r.Resource())
160
161		t.Run(r.Resource().Kind(), func(t *testing.T) {
162			t.Run("WrongTypeShouldReturnNil", func(t *testing.T) {
163				_, err := a.ExtractResource(struct{}{})
164				g := NewGomegaWithT(t)
165				g.Expect(err).NotTo(BeNil())
166			})
167
168			t.Run("Success", func(t *testing.T) {
169				out, err := a.ExtractResource(empty(r.Resource().Kind()))
170				g := NewGomegaWithT(t)
171				g.Expect(err).To(BeNil())
172				g.Expect(out).ToNot(BeNil())
173			})
174		})
175	}
176}
177
178func parse(t *testing.T, input []byte, group, kind, version string) (metaV1.Object, proto.Message) {
179	t.Helper()
180	g := NewGomegaWithT(t)
181
182	pr := rt.DefaultProvider()
183	a := pr.GetAdapter(k8smeta.MustGet().KubeCollections().MustFindByGroupVersionKind(resource.GroupVersionKind{
184		Group:   group,
185		Version: version,
186		Kind:    kind,
187	}).Resource())
188	obj, err := a.ParseJSON(input)
189	g.Expect(err).To(BeNil())
190
191	p, err := a.ExtractResource(obj)
192	g.Expect(err).To(BeNil())
193
194	return a.ExtractObject(obj), p
195}
196
197func empty(kind string) metaV1.Object {
198	switch kind {
199	case "Node":
200		return &coreV1.Node{}
201	case "Service":
202		return &coreV1.Service{}
203	case "Pod":
204		return &coreV1.Pod{}
205	case "Endpoints":
206		return &coreV1.Endpoints{}
207	case "Namespace":
208		return &coreV1.Namespace{}
209	case "Ingress":
210		return &v1beta1.Ingress{}
211	case "Deployment":
212		return &appsV1.Deployment{}
213	default:
214		panic(fmt.Sprintf("unsupported kind: %v", kind))
215	}
216}
217