github.com/danielqsj/helm@v2.0.0-alpha.4.0.20160908204436-976e0ba5199b+incompatible/pkg/kube/client_test.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors All rights reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package kube 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "io" 23 "io/ioutil" 24 "net/http" 25 "strings" 26 "testing" 27 28 "k8s.io/kubernetes/pkg/api/meta" 29 "k8s.io/kubernetes/pkg/api/testapi" 30 "k8s.io/kubernetes/pkg/api/unversioned" 31 api "k8s.io/kubernetes/pkg/api/v1" 32 "k8s.io/kubernetes/pkg/client/unversioned/fake" 33 "k8s.io/kubernetes/pkg/kubectl/resource" 34 "k8s.io/kubernetes/pkg/runtime" 35 ) 36 37 func TestUpdateResource(t *testing.T) { 38 39 tests := []struct { 40 name string 41 namespace string 42 modified *resource.Info 43 currentObj runtime.Object 44 err bool 45 errMessage string 46 }{ 47 { 48 name: "no changes when updating resources", 49 modified: createFakeInfo("nginx", nil), 50 currentObj: createFakePod("nginx", nil), 51 err: true, 52 errMessage: "Looks like there are no changes for nginx", 53 }, 54 //{ 55 //name: "valid update input", 56 //modified: createFakeInfo("nginx", map[string]string{"app": "nginx"}), 57 //currentObj: createFakePod("nginx", nil), 58 //}, 59 } 60 61 for _, tt := range tests { 62 err := updateResource(tt.modified, tt.currentObj) 63 if err != nil && err.Error() != tt.errMessage { 64 t.Errorf("%q. expected error message: %v, got %v", tt.name, tt.errMessage, err) 65 } 66 } 67 } 68 69 func TestPerform(t *testing.T) { 70 tests := []struct { 71 name string 72 namespace string 73 reader io.Reader 74 count int 75 err bool 76 errMessage string 77 }{ 78 { 79 name: "Valid input", 80 namespace: "test", 81 reader: strings.NewReader(guestbookManifest), 82 count: 6, 83 }, { 84 name: "Empty manifests", 85 namespace: "test", 86 reader: strings.NewReader(""), 87 err: true, 88 errMessage: "no objects passed to create", 89 }, 90 } 91 92 for _, tt := range tests { 93 results := []*resource.Info{} 94 95 fn := func(info *resource.Info) error { 96 results = append(results, info) 97 98 if info.Namespace != tt.namespace { 99 t.Errorf("%q. expected namespace to be '%s', got %s", tt.name, tt.namespace, info.Namespace) 100 } 101 return nil 102 } 103 104 c := New(nil) 105 c.ClientForMapping = func(mapping *meta.RESTMapping) (resource.RESTClient, error) { 106 return &fake.RESTClient{}, nil 107 } 108 109 err := perform(c, tt.namespace, tt.reader, fn) 110 if (err != nil) != tt.err { 111 t.Errorf("%q. expected error: %v, got %v", tt.name, tt.err, err) 112 } 113 if err != nil && err.Error() != tt.errMessage { 114 t.Errorf("%q. expected error message: %v, got %v", tt.name, tt.errMessage, err) 115 } 116 117 if len(results) != tt.count { 118 t.Errorf("%q. expected %d result objects, got %d", tt.name, tt.count, len(results)) 119 } 120 } 121 } 122 123 func TestReal(t *testing.T) { 124 t.Skip("This is a live test, comment this line to run") 125 if err := New(nil).Create("test", strings.NewReader(guestbookManifest)); err != nil { 126 t.Fatal(err) 127 } 128 129 testSvcEndpointManifest := testServiceManifest + "\n---\n" + testEndpointManifest 130 c := New(nil) 131 if err := c.Create("test-delete", strings.NewReader(testSvcEndpointManifest)); err != nil { 132 t.Fatal(err) 133 } 134 135 if err := c.Delete("test-delete", strings.NewReader(testEndpointManifest)); err != nil { 136 t.Fatal(err) 137 } 138 139 // ensures that delete does not fail if a resource is not found 140 if err := c.Delete("test-delete", strings.NewReader(testSvcEndpointManifest)); err != nil { 141 t.Fatal(err) 142 } 143 } 144 145 const testServiceManifest = ` 146 kind: Service 147 apiVersion: v1 148 metadata: 149 name: my-service 150 spec: 151 selector: 152 app: myapp 153 ports: 154 - port: 80 155 protocol: TCP 156 targetPort: 9376 157 ` 158 159 const testEndpointManifest = ` 160 kind: Endpoints 161 apiVersion: v1 162 metadata: 163 name: my-service 164 subsets: 165 - addresses: 166 - ip: "1.2.3.4" 167 ports: 168 - port: 9376 169 ` 170 171 const guestbookManifest = ` 172 apiVersion: v1 173 kind: Service 174 metadata: 175 name: redis-master 176 labels: 177 app: redis 178 tier: backend 179 role: master 180 spec: 181 ports: 182 - port: 6379 183 targetPort: 6379 184 selector: 185 app: redis 186 tier: backend 187 role: master 188 --- 189 apiVersion: extensions/v1beta1 190 kind: Deployment 191 metadata: 192 name: redis-master 193 spec: 194 replicas: 1 195 template: 196 metadata: 197 labels: 198 app: redis 199 role: master 200 tier: backend 201 spec: 202 containers: 203 - name: master 204 image: gcr.io/google_containers/redis:e2e # or just image: redis 205 resources: 206 requests: 207 cpu: 100m 208 memory: 100Mi 209 ports: 210 - containerPort: 6379 211 --- 212 apiVersion: v1 213 kind: Service 214 metadata: 215 name: redis-slave 216 labels: 217 app: redis 218 tier: backend 219 role: slave 220 spec: 221 ports: 222 # the port that this service should serve on 223 - port: 6379 224 selector: 225 app: redis 226 tier: backend 227 role: slave 228 --- 229 apiVersion: extensions/v1beta1 230 kind: Deployment 231 metadata: 232 name: redis-slave 233 spec: 234 replicas: 2 235 template: 236 metadata: 237 labels: 238 app: redis 239 role: slave 240 tier: backend 241 spec: 242 containers: 243 - name: slave 244 image: gcr.io/google_samples/gb-redisslave:v1 245 resources: 246 requests: 247 cpu: 100m 248 memory: 100Mi 249 env: 250 - name: GET_HOSTS_FROM 251 value: dns 252 ports: 253 - containerPort: 6379 254 --- 255 apiVersion: v1 256 kind: Service 257 metadata: 258 name: frontend 259 labels: 260 app: guestbook 261 tier: frontend 262 spec: 263 ports: 264 - port: 80 265 selector: 266 app: guestbook 267 tier: frontend 268 --- 269 apiVersion: extensions/v1beta1 270 kind: Deployment 271 metadata: 272 name: frontend 273 spec: 274 replicas: 3 275 template: 276 metadata: 277 labels: 278 app: guestbook 279 tier: frontend 280 spec: 281 containers: 282 - name: php-redis 283 image: gcr.io/google-samples/gb-frontend:v4 284 resources: 285 requests: 286 cpu: 100m 287 memory: 100Mi 288 env: 289 - name: GET_HOSTS_FROM 290 value: dns 291 ports: 292 - containerPort: 80 293 ` 294 295 func createFakePod(name string, labels map[string]string) runtime.Object { 296 objectMeta := createObjectMeta(name, labels) 297 298 object := &api.Pod{ 299 ObjectMeta: objectMeta, 300 } 301 302 return object 303 } 304 305 func createFakeInfo(name string, labels map[string]string) *resource.Info { 306 pod := createFakePod(name, labels) 307 marshaledObj, _ := json.Marshal(pod) 308 309 mapping := &meta.RESTMapping{ 310 Resource: name, 311 Scope: meta.RESTScopeNamespace, 312 GroupVersionKind: unversioned.GroupVersionKind{ 313 Kind: "Pod", 314 Version: "v1", 315 }} 316 317 client := &fake.RESTClient{ 318 Codec: testapi.Default.Codec(), 319 Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { 320 header := http.Header{} 321 header.Set("Content-Type", runtime.ContentTypeJSON) 322 return &http.Response{ 323 StatusCode: 200, 324 Header: header, 325 Body: ioutil.NopCloser(bytes.NewReader(marshaledObj)), 326 }, nil 327 })} 328 info := resource.NewInfo(client, mapping, "default", "nginx", false) 329 330 info.Object = pod 331 332 return info 333 } 334 335 func createObjectMeta(name string, labels map[string]string) api.ObjectMeta { 336 objectMeta := api.ObjectMeta{Name: name, Namespace: "default"} 337 338 if labels != nil { 339 objectMeta.Labels = labels 340 } 341 342 return objectMeta 343 }