1
16
17 package create
18
19 import (
20 "testing"
21
22 restclient "k8s.io/client-go/rest"
23 cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
24
25 v1 "k8s.io/api/core/v1"
26 apiequality "k8s.io/apimachinery/pkg/api/equality"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/apimachinery/pkg/util/intstr"
29 "k8s.io/cli-runtime/pkg/genericiooptions"
30 )
31
32 func TestCreateServices(t *testing.T) {
33
34 tests := []struct {
35 name string
36 serviceType v1.ServiceType
37 tcp []string
38 clusterip string
39 externalName string
40 nodeport int
41 expected *v1.Service
42 expectErr bool
43 }{
44 {
45 name: "clusterip-ok",
46 tcp: []string{"456", "321:908"},
47 clusterip: "",
48 serviceType: v1.ServiceTypeClusterIP,
49 expected: &v1.Service{
50 ObjectMeta: metav1.ObjectMeta{
51 Name: "clusterip-ok",
52 Labels: map[string]string{"app": "clusterip-ok"},
53 },
54 Spec: v1.ServiceSpec{Type: "ClusterIP",
55 Ports: []v1.ServicePort{{Name: "456", Protocol: "TCP", Port: 456, TargetPort: intstr.IntOrString{Type: 0, IntVal: 456, StrVal: ""}, NodePort: 0},
56 {Name: "321-908", Protocol: "TCP", Port: 321, TargetPort: intstr.IntOrString{Type: 0, IntVal: 908, StrVal: ""}, NodePort: 0}},
57 Selector: map[string]string{"app": "clusterip-ok"},
58 ClusterIP: "", ExternalIPs: []string(nil), LoadBalancerIP: ""},
59 },
60 expectErr: false,
61 },
62 {
63 name: "clusterip-missing",
64 serviceType: v1.ServiceTypeClusterIP,
65 expectErr: true,
66 },
67 {
68 name: "clusterip-none-wrong-type",
69 tcp: []string{},
70 clusterip: "None",
71 serviceType: v1.ServiceTypeNodePort,
72 expectErr: true,
73 },
74 {
75 name: "clusterip-none-ok",
76 tcp: []string{},
77 clusterip: "None",
78 serviceType: v1.ServiceTypeClusterIP,
79 expected: &v1.Service{
80 ObjectMeta: metav1.ObjectMeta{
81 Name: "clusterip-none-ok",
82 Labels: map[string]string{"app": "clusterip-none-ok"},
83 },
84 Spec: v1.ServiceSpec{Type: "ClusterIP",
85 Ports: []v1.ServicePort{},
86 Selector: map[string]string{"app": "clusterip-none-ok"},
87 ClusterIP: "None", ExternalIPs: []string(nil), LoadBalancerIP: ""},
88 },
89 expectErr: false,
90 },
91 {
92 name: "clusterip-none-and-port-mapping",
93 tcp: []string{"456:9898"},
94 clusterip: "None",
95 serviceType: v1.ServiceTypeClusterIP,
96 expected: &v1.Service{
97 ObjectMeta: metav1.ObjectMeta{
98 Name: "clusterip-none-and-port-mapping",
99 Labels: map[string]string{"app": "clusterip-none-and-port-mapping"},
100 },
101 Spec: v1.ServiceSpec{Type: "ClusterIP",
102 Ports: []v1.ServicePort{{Name: "456-9898", Protocol: "TCP", Port: 456, TargetPort: intstr.IntOrString{Type: 0, IntVal: 9898, StrVal: ""}, NodePort: 0}},
103 Selector: map[string]string{"app": "clusterip-none-and-port-mapping"},
104 ClusterIP: "None", ExternalIPs: []string(nil), LoadBalancerIP: ""},
105 },
106 expectErr: false,
107 },
108 {
109 name: "loadbalancer-ok",
110 tcp: []string{"456:9898"},
111 clusterip: "",
112 serviceType: v1.ServiceTypeLoadBalancer,
113 expected: &v1.Service{
114 ObjectMeta: metav1.ObjectMeta{
115 Name: "loadbalancer-ok",
116 Labels: map[string]string{"app": "loadbalancer-ok"},
117 },
118 Spec: v1.ServiceSpec{Type: "LoadBalancer",
119 Ports: []v1.ServicePort{{Name: "456-9898", Protocol: "TCP", Port: 456, TargetPort: intstr.IntOrString{Type: 0, IntVal: 9898, StrVal: ""}, NodePort: 0}},
120 Selector: map[string]string{"app": "loadbalancer-ok"},
121 ClusterIP: "", ExternalIPs: []string(nil), LoadBalancerIP: ""},
122 },
123 expectErr: false,
124 },
125 {
126 name: "invalid-port",
127 tcp: []string{"65536"},
128 clusterip: "None",
129 serviceType: v1.ServiceTypeClusterIP,
130 expectErr: true,
131 },
132 {
133 name: "invalid-port-mapping",
134 tcp: []string{"8080:-abc"},
135 clusterip: "None",
136 serviceType: v1.ServiceTypeClusterIP,
137 expectErr: true,
138 },
139 {
140 expectErr: true,
141 },
142 {
143 name: "validate-ok",
144 serviceType: v1.ServiceTypeClusterIP,
145 tcp: []string{"123", "234:1234"},
146 clusterip: "",
147 expected: &v1.Service{
148 ObjectMeta: metav1.ObjectMeta{
149 Name: "validate-ok",
150 Labels: map[string]string{"app": "validate-ok"},
151 },
152 Spec: v1.ServiceSpec{Type: "ClusterIP",
153 Ports: []v1.ServicePort{
154 {Name: "123", Protocol: "TCP", Port: 123, TargetPort: intstr.IntOrString{Type: 0, IntVal: 123, StrVal: ""}, NodePort: 0},
155 {Name: "234-1234", Protocol: "TCP", Port: 234, TargetPort: intstr.IntOrString{Type: 0, IntVal: 1234, StrVal: ""}, NodePort: 0},
156 },
157 Selector: map[string]string{"app": "validate-ok"},
158 ClusterIP: "", ExternalIPs: []string(nil), LoadBalancerIP: ""},
159 },
160 expectErr: false,
161 },
162 {
163 name: "invalid-ClusterIPNone",
164 serviceType: v1.ServiceTypeNodePort,
165 tcp: []string{"123", "234:1234"},
166 clusterip: v1.ClusterIPNone,
167 expectErr: true,
168 },
169 {
170 name: "TCP-none",
171 serviceType: v1.ServiceTypeClusterIP,
172 clusterip: "",
173 expectErr: true,
174 },
175 {
176 name: "invalid-ExternalName",
177 serviceType: v1.ServiceTypeExternalName,
178 tcp: []string{"123", "234:1234"},
179 clusterip: "",
180 externalName: "@oi:test",
181 expectErr: true,
182 },
183 {
184 name: "externalName-ok",
185 serviceType: v1.ServiceTypeExternalName,
186 tcp: []string{"123", "234:1234"},
187 clusterip: "",
188 externalName: "www.externalname.com",
189 expected: &v1.Service{
190 ObjectMeta: metav1.ObjectMeta{
191 Name: "externalName-ok",
192 Labels: map[string]string{"app": "externalName-ok"},
193 },
194 Spec: v1.ServiceSpec{Type: "ExternalName",
195 Ports: []v1.ServicePort{
196 {Name: "123", Protocol: "TCP", Port: 123, TargetPort: intstr.IntOrString{Type: 0, IntVal: 123, StrVal: ""}, NodePort: 0},
197 {Name: "234-1234", Protocol: "TCP", Port: 234, TargetPort: intstr.IntOrString{Type: 0, IntVal: 1234, StrVal: ""}, NodePort: 0},
198 },
199 Selector: map[string]string{"app": "externalName-ok"},
200 ClusterIP: "", ExternalIPs: []string(nil), LoadBalancerIP: "", ExternalName: "www.externalname.com"},
201 },
202 expectErr: false,
203 },
204 {
205 name: "my-node-port-service-ok",
206 serviceType: v1.ServiceTypeNodePort,
207 tcp: []string{"443:https", "30000:8000"},
208 clusterip: "",
209 expected: &v1.Service{
210 ObjectMeta: metav1.ObjectMeta{
211 Name: "my-node-port-service-ok",
212 Labels: map[string]string{"app": "my-node-port-service-ok"},
213 },
214 Spec: v1.ServiceSpec{Type: "NodePort",
215 Ports: []v1.ServicePort{
216 {Name: "443-https", Protocol: "TCP", Port: 443, TargetPort: intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "https"}, NodePort: 0},
217 {Name: "30000-8000", Protocol: "TCP", Port: 30000, TargetPort: intstr.IntOrString{Type: 0, IntVal: 8000, StrVal: ""}, NodePort: 0},
218 },
219 Selector: map[string]string{"app": "my-node-port-service-ok"},
220 ClusterIP: "", ExternalIPs: []string(nil), LoadBalancerIP: ""},
221 },
222 expectErr: false,
223 },
224 {
225 name: "my-node-port-service-ok2",
226 serviceType: v1.ServiceTypeNodePort,
227 tcp: []string{"80:http"},
228 clusterip: "",
229 nodeport: 4444,
230 expected: &v1.Service{
231 ObjectMeta: metav1.ObjectMeta{
232 Name: "my-node-port-service-ok2",
233 Labels: map[string]string{"app": "my-node-port-service-ok2"},
234 },
235 Spec: v1.ServiceSpec{Type: "NodePort",
236 Ports: []v1.ServicePort{
237 {Name: "80-http", Protocol: "TCP", Port: 80, TargetPort: intstr.IntOrString{Type: 1, IntVal: 0, StrVal: "http"}, NodePort: 4444},
238 },
239 Selector: map[string]string{"app": "my-node-port-service-ok2"},
240 ClusterIP: "", ExternalIPs: []string(nil), LoadBalancerIP: ""},
241 },
242 expectErr: false,
243 },
244 }
245 for _, tc := range tests {
246 t.Run(tc.name, func(t *testing.T) {
247 options := ServiceOptions{
248 Name: tc.name,
249 Type: tc.serviceType,
250 TCP: tc.tcp,
251 ClusterIP: tc.clusterip,
252 NodePort: tc.nodeport,
253 ExternalName: tc.externalName,
254 }
255
256 var service *v1.Service
257
258 err := options.Validate()
259 if err == nil {
260 service, err = options.createService()
261 }
262 if tc.expectErr && err == nil {
263 t.Errorf("%s: expected an error, but createService passes.", tc.name)
264 }
265 if !tc.expectErr && err != nil {
266 t.Errorf("%s: unexpected error: %v", tc.name, err)
267 }
268 if !apiequality.Semantic.DeepEqual(service, tc.expected) {
269 t.Errorf("%s: expected:\n%#v\ngot:\n%#v", tc.name, tc.expected, service)
270 }
271 })
272 }
273 }
274
275 func TestCreateServiceWithNamespace(t *testing.T) {
276 svcName := "test-service"
277 ns := "test"
278 tf := cmdtesting.NewTestFactory().WithNamespace(ns)
279 defer tf.Cleanup()
280
281 tf.ClientConfigVal = &restclient.Config{}
282
283 ioStreams, _, buf, _ := genericiooptions.NewTestIOStreams()
284 cmd := NewCmdCreateServiceClusterIP(tf, ioStreams)
285 cmd.Flags().Set("dry-run", "client")
286 cmd.Flags().Set("output", "jsonpath={.metadata.namespace}")
287 cmd.Flags().Set("clusterip", "None")
288 cmd.Run(cmd, []string{svcName})
289 if buf.String() != ns {
290 t.Errorf("expected output: %s, but got: %s", ns, buf.String())
291 }
292 }
293
View as plain text