github.com/felipejfc/helm@v2.1.2+incompatible/pkg/chartutil/values_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 chartutil 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "fmt" 23 "testing" 24 "text/template" 25 26 "github.com/golang/protobuf/ptypes/any" 27 "k8s.io/helm/pkg/proto/hapi/chart" 28 "k8s.io/helm/pkg/timeconv" 29 ) 30 31 func TestReadValues(t *testing.T) { 32 doc := `# Test YAML parse 33 poet: "Coleridge" 34 title: "Rime of the Ancient Mariner" 35 stanza: 36 - "at" 37 - "length" 38 - "did" 39 - cross 40 - an 41 - Albatross 42 43 mariner: 44 with: "crossbow" 45 shot: "ALBATROSS" 46 47 water: 48 water: 49 where: "everywhere" 50 nor: "any drop to drink" 51 ` 52 53 data, err := ReadValues([]byte(doc)) 54 if err != nil { 55 t.Fatalf("Error parsing bytes: %s", err) 56 } 57 matchValues(t, data) 58 59 tests := []string{`poet: "Coleridge"`, "# Just a comment", ""} 60 61 for _, tt := range tests { 62 data, err = ReadValues([]byte(tt)) 63 if err != nil { 64 t.Fatalf("Error parsing bytes (%s): %s", tt, err) 65 } 66 if data == nil { 67 t.Errorf(`YAML string "%s" gave a nil map`, tt) 68 } 69 } 70 } 71 72 func TestToRenderValues(t *testing.T) { 73 74 chartValues := ` 75 name: al Rashid 76 where: 77 city: Basrah 78 title: caliph 79 ` 80 overideValues := ` 81 name: Haroun 82 where: 83 city: Baghdad 84 date: 809 CE 85 ` 86 87 c := &chart.Chart{ 88 Metadata: &chart.Metadata{Name: "test"}, 89 Templates: []*chart.Template{}, 90 Values: &chart.Config{Raw: chartValues}, 91 Dependencies: []*chart.Chart{ 92 { 93 Metadata: &chart.Metadata{Name: "where"}, 94 Values: &chart.Config{Raw: ""}, 95 }, 96 }, 97 Files: []*any.Any{ 98 {TypeUrl: "scheherazade/shahryar.txt", Value: []byte("1,001 Nights")}, 99 }, 100 } 101 v := &chart.Config{Raw: overideValues} 102 103 o := ReleaseOptions{ 104 Name: "Seven Voyages", 105 Time: timeconv.Now(), 106 Namespace: "al Basrah", 107 } 108 109 res, err := ToRenderValues(c, v, o) 110 if err != nil { 111 t.Fatal(err) 112 } 113 114 // Ensure that the top-level values are all set. 115 if name := res["Chart"].(*chart.Metadata).Name; name != "test" { 116 t.Errorf("Expected chart name 'test', got %q", name) 117 } 118 if name := res["Release"].(map[string]interface{})["Name"]; fmt.Sprint(name) != "Seven Voyages" { 119 t.Errorf("Expected release name 'Seven Voyages', got %q", name) 120 } 121 if data := res["Files"].(Files)["scheherazade/shahryar.txt"]; string(data) != "1,001 Nights" { 122 t.Errorf("Expected file '1,001 Nights', got %q", string(data)) 123 } 124 125 var vals Values 126 vals = res["Values"].(Values) 127 128 if vals["name"] != "Haroun" { 129 t.Errorf("Expected 'Haroun', got %q (%v)", vals["name"], vals) 130 } 131 where := vals["where"].(map[string]interface{}) 132 expects := map[string]string{ 133 "city": "Baghdad", 134 "date": "809 CE", 135 "title": "caliph", 136 } 137 for field, expect := range expects { 138 if got := where[field]; got != expect { 139 t.Errorf("Expected %q, got %q (%v)", expect, got, where) 140 } 141 } 142 } 143 144 func TestReadValuesFile(t *testing.T) { 145 data, err := ReadValuesFile("./testdata/coleridge.yaml") 146 if err != nil { 147 t.Fatalf("Error reading YAML file: %s", err) 148 } 149 matchValues(t, data) 150 } 151 152 func ExampleValues() { 153 doc := ` 154 title: "Moby Dick" 155 chapter: 156 one: 157 title: "Loomings" 158 two: 159 title: "The Carpet-Bag" 160 three: 161 title: "The Spouter Inn" 162 ` 163 d, err := ReadValues([]byte(doc)) 164 if err != nil { 165 panic(err) 166 } 167 ch1, err := d.Table("chapter.one") 168 if err != nil { 169 panic("could not find chapter one") 170 } 171 fmt.Print(ch1["title"]) 172 // Output: 173 // Loomings 174 } 175 176 func TestTable(t *testing.T) { 177 doc := ` 178 title: "Moby Dick" 179 chapter: 180 one: 181 title: "Loomings" 182 two: 183 title: "The Carpet-Bag" 184 three: 185 title: "The Spouter Inn" 186 ` 187 d, err := ReadValues([]byte(doc)) 188 if err != nil { 189 t.Fatalf("Failed to parse the White Whale: %s", err) 190 } 191 192 if _, err := d.Table("title"); err == nil { 193 t.Fatalf("Title is not a table.") 194 } 195 196 if _, err := d.Table("chapter"); err != nil { 197 t.Fatalf("Failed to get the chapter table: %s\n%v", err, d) 198 } 199 200 if v, err := d.Table("chapter.one"); err != nil { 201 t.Errorf("Failed to get chapter.one: %s", err) 202 } else if v["title"] != "Loomings" { 203 t.Errorf("Unexpected title: %s", v["title"]) 204 } 205 206 if _, err := d.Table("chapter.three"); err != nil { 207 t.Errorf("Chapter three is missing: %s\n%v", err, d) 208 } 209 210 if _, err := d.Table("chapter.OneHundredThirtySix"); err == nil { 211 t.Errorf("I think you mean 'Epilogue'") 212 } 213 } 214 215 func matchValues(t *testing.T, data map[string]interface{}) { 216 if data["poet"] != "Coleridge" { 217 t.Errorf("Unexpected poet: %s", data["poet"]) 218 } 219 220 if o, err := ttpl("{{len .stanza}}", data); err != nil { 221 t.Errorf("len stanza: %s", err) 222 } else if o != "6" { 223 t.Errorf("Expected 6, got %s", o) 224 } 225 226 if o, err := ttpl("{{.mariner.shot}}", data); err != nil { 227 t.Errorf(".mariner.shot: %s", err) 228 } else if o != "ALBATROSS" { 229 t.Errorf("Expected that mariner shot ALBATROSS") 230 } 231 232 if o, err := ttpl("{{.water.water.where}}", data); err != nil { 233 t.Errorf(".water.water.where: %s", err) 234 } else if o != "everywhere" { 235 t.Errorf("Expected water water everywhere") 236 } 237 } 238 239 func ttpl(tpl string, v map[string]interface{}) (string, error) { 240 var b bytes.Buffer 241 tt := template.Must(template.New("t").Parse(tpl)) 242 if err := tt.Execute(&b, v); err != nil { 243 return "", err 244 } 245 return b.String(), nil 246 } 247 248 var testCoalesceValuesYaml = ` 249 top: yup 250 251 global: 252 name: Ishmael 253 subject: Queequeg 254 nested: 255 boat: true 256 257 pequod: 258 global: 259 name: Stinky 260 harpooner: Tashtego 261 nested: 262 boat: false 263 sail: true 264 ahab: 265 scope: whale 266 ` 267 268 func TestCoalesceValues(t *testing.T) { 269 tchart := "testdata/moby" 270 c, err := LoadDir(tchart) 271 if err != nil { 272 t.Fatal(err) 273 } 274 275 tvals := &chart.Config{Raw: testCoalesceValuesYaml} 276 277 v, err := CoalesceValues(c, tvals) 278 if err != nil { 279 t.Fatal(err) 280 } 281 j, _ := json.MarshalIndent(v, "", " ") 282 t.Logf("Coalesced Values: %s", string(j)) 283 284 tests := []struct { 285 tpl string 286 expect string 287 }{ 288 {"{{.top}}", "yup"}, 289 {"{{.name}}", "moby"}, 290 {"{{.global.name}}", "Ishmael"}, 291 {"{{.global.subject}}", "Queequeg"}, 292 {"{{.global.harpooner}}", "<no value>"}, 293 {"{{.pequod.name}}", "pequod"}, 294 {"{{.pequod.ahab.name}}", "ahab"}, 295 {"{{.pequod.ahab.scope}}", "whale"}, 296 {"{{.pequod.ahab.global.name}}", "Ishmael"}, 297 {"{{.pequod.ahab.global.subject}}", "Queequeg"}, 298 {"{{.pequod.ahab.global.harpooner}}", "Tashtego"}, 299 {"{{.pequod.global.name}}", "Ishmael"}, 300 {"{{.pequod.global.subject}}", "Queequeg"}, 301 {"{{.spouter.global.name}}", "Ishmael"}, 302 {"{{.spouter.global.harpooner}}", "<no value>"}, 303 304 {"{{.global.nested.boat}}", "true"}, 305 {"{{.pequod.global.nested.boat}}", "true"}, 306 {"{{.spouter.global.nested.boat}}", "true"}, 307 {"{{.pequod.global.nested.sail}}", "true"}, 308 {"{{.spouter.global.nested.sail}}", "<no value>"}, 309 } 310 311 for _, tt := range tests { 312 if o, err := ttpl(tt.tpl, v); err != nil || o != tt.expect { 313 t.Errorf("Expected %q to expand to %q, got %q", tt.tpl, tt.expect, o) 314 } 315 } 316 } 317 318 func TestCoalesceTables(t *testing.T) { 319 dst := map[string]interface{}{ 320 "name": "Ishmael", 321 "address": map[string]interface{}{ 322 "street": "123 Spouter Inn Ct.", 323 "city": "Nantucket", 324 }, 325 "details": map[string]interface{}{ 326 "friends": []string{"Tashtego"}, 327 }, 328 "boat": "pequod", 329 } 330 src := map[string]interface{}{ 331 "occupation": "whaler", 332 "address": map[string]interface{}{ 333 "state": "MA", 334 "street": "234 Spouter Inn Ct.", 335 }, 336 "details": "empty", 337 "boat": map[string]interface{}{ 338 "mast": true, 339 }, 340 } 341 342 // What we expect is that anything in dst overrides anything in src, but that 343 // otherwise the values are coalesced. 344 coalesceTables(dst, src) 345 346 if dst["name"] != "Ishmael" { 347 t.Errorf("Unexpected name: %s", dst["name"]) 348 } 349 if dst["occupation"] != "whaler" { 350 t.Errorf("Unexpected occupation: %s", dst["occupation"]) 351 } 352 353 addr, ok := dst["address"].(map[string]interface{}) 354 if !ok { 355 t.Fatal("Address went away.") 356 } 357 358 if addr["street"].(string) != "123 Spouter Inn Ct." { 359 t.Errorf("Unexpected address: %v", addr["street"]) 360 } 361 362 if addr["city"].(string) != "Nantucket" { 363 t.Errorf("Unexpected city: %v", addr["city"]) 364 } 365 366 if addr["state"].(string) != "MA" { 367 t.Errorf("Unexpected state: %v", addr["state"]) 368 } 369 370 if det, ok := dst["details"].(map[string]interface{}); !ok { 371 t.Fatalf("Details is the wrong type: %v", dst["details"]) 372 } else if _, ok := det["friends"]; !ok { 373 t.Error("Could not find your friends. Maybe you don't have any. :-(") 374 } 375 376 if dst["boat"].(string) != "pequod" { 377 t.Errorf("Expected boat string, got %v", dst["boat"]) 378 } 379 }