func TestNodeFunc_missingData(t *testing.T) { d, err := dep.ParseCatalogNode("@non-existing") if err != nil { t.Fatal(err) } brain := NewBrain() used := make(map[string]dep.Dependency) missing := make(map[string]dep.Dependency) f := nodeFunc(brain, used, missing) result, err := f("@non-existing") if err != nil { t.Fatal(err) } if result != nil { t.Errorf("expected %q to be nil", result) } if _, ok := used[d.HashCode()]; !ok { t.Errorf("expected dep to be used") } if _, ok := missing[d.HashCode()]; !ok { t.Errorf("expected dep to be missing") } }
// nodeFunc returns or accumulates catalog node dependency. func nodeFunc(brain *Brain, used, missing map[string]dep.Dependency) func(...string) (*dep.NodeDetail, error) { return func(s ...string) (*dep.NodeDetail, error) { d, err := dep.ParseCatalogNode(s...) if err != nil { return nil, err } addDependency(used, d) if value, ok := brain.Recall(d); ok { return value.(*dep.NodeDetail), nil } addDependency(missing, d) return nil, nil } }
func TestNodeFunc_hasData(t *testing.T) { d, err := dep.ParseCatalogNode("@existing") if err != nil { t.Fatal(err) } data := &dep.NodeDetail{ Node: &dep.Node{Node: "a"}, Services: make(dep.NodeServiceList, 0), } brain := NewBrain() brain.Remember(d, data) used := make(map[string]dep.Dependency) missing := make(map[string]dep.Dependency) f := nodeFunc(brain, used, missing) result, err := f("@existing") if err != nil { t.Fatal(err) } expected := data if !reflect.DeepEqual(result, expected) { t.Errorf("expected %q to be %q", result, expected) } if len(missing) != 0 { t.Errorf("expected missing to have 0 elements, but had %d", len(missing)) } if _, ok := used[d.HashCode()]; !ok { t.Errorf("expected dep to be used") } }
func TestExecute_renders(t *testing.T) { // Stub out the time. now = func() time.Time { return time.Unix(0, 0).UTC() } in := test.CreateTempfile([]byte(` API Functions ------------- datacenters:{{ range datacenters }} {{.}}{{ end }} file: {{ file "/path/to/file" }} key: {{ key "config/redis/maxconns" }} key_or_default (exists): {{ key_or_default "config/redis/minconns" "100" }} key_or_default (missing): {{ key_or_default "config/redis/maxconns" "200" }} ls:{{ range ls "config/redis" }} {{.Key}}={{.Value}}{{ end }} node:{{ with node }} {{.Node.Node}}{{ range .Services}} {{.Service}}{{ end }}{{ end }} nodes:{{ range nodes }} {{.Node}}{{ end }} service:{{ range service "webapp" }} {{.Address}}{{ end }} service (any):{{ range service "webapp" "any" }} {{.Address}}{{ end }} service (tag.Contains):{{ range service "webapp" }}{{ if .Tags.Contains "production" }} {{.Node}}{{ end }}{{ end }} services:{{ range services }} {{.Name}}{{ end }} tree:{{ range tree "config/redis" }} {{.Key}}={{.Value}}{{ end }} vault: {{ with vault "secret/foo/bar" }}{{.Data.zip}}{{ end }} Helper Functions ---------------- byKey:{{ range $key, $pairs := tree "config/redis" | byKey }} {{$key}}:{{ range $pairs }} {{.Key}}={{.Value}}{{ end }}{{ end }} byTag (health service):{{ range $tag, $services := service "webapp" | byTag }} {{$tag}}:{{ range $services }} {{.Address}}{{ end }}{{ end }} byTag (catalog services):{{ range $tag, $services := services | byTag }} {{$tag}}:{{ range $services }} {{.Name}}{{ end }}{{ end }} contains:{{ range service "webapp" }}{{ if .Tags | contains "production" }} {{.Node}}{{ end }}{{ end }} env: {{ env "foo" }} explode:{{ range $k, $v := tree "config/redis" | explode }} {{$k}}{{$v}}{{ end }} in:{{ range service "webapp" }}{{ if in .Tags "production" }} {{.Node}}{{ end }}{{ end }} loop:{{ range loop 3 }} test{{ end }} loop(i):{{ range $i := loop 5 8 }} test{{$i}}{{ end }} join: {{ "a,b,c" | split "," | join ";" }} parseBool: {{"true" | parseBool}} parseFloat: {{"1.2" | parseFloat}} parseInt: {{"-1" | parseInt}} parseJSON (string):{{ range $key, $value := "{\"foo\": \"bar\"}" | parseJSON }} {{$key}}={{$value}}{{ end }} parseJSON (file):{{ range $key, $value := file "/path/to/json/file" | parseJSON }} {{$key}}={{$value}}{{ end }} parseJSON (env):{{ range $key, $value := env "json" | parseJSON }} {{$key}}={{$value}}{{ end }} parseUint: {{"1" | parseUint}} plugin: {{ file "/path/to/json/file" | plugin "echo" }} timestamp: {{ timestamp }} timestamp (formatted): {{ timestamp "2006-01-02" }} regexMatch: {{ file "/path/to/file" | regexMatch ".*[cont][a-z]+" }} regexMatch: {{ file "/path/to/file" | regexMatch "v[0-9]*" }} regexReplaceAll: {{ file "/path/to/file" | regexReplaceAll "\\w" "x" }} replaceAll: {{ file "/path/to/file" | replaceAll "some" "this" }} split:{{ range "a,b,c" | split "," }} {{.}}{{end}} toLower: {{ file "/path/to/file" | toLower }} toJSON: {{ tree "config/redis" | explode | toJSON }} toJSONPretty: {{ tree "config/redis" | explode | toJSONPretty }} toTitle: {{ file "/path/to/file" | toTitle }} toUpper: {{ file "/path/to/file" | toUpper }} toYAML: {{ tree "config/redis" | explode | toYAML }} Math Functions -------------- add:{{ 2 | add 2 }} subtract:{{ 2 | subtract 2 }} multiply:{{ 2 | multiply 2 }} divide:{{ 2 | divide 2 }} `), t) defer test.DeleteTempfile(in, t) tmpl, err := NewTemplate(in.Name()) if err != nil { t.Fatal(err) } brain := NewBrain() var d dep.Dependency d, err = dep.ParseDatacenters() if err != nil { t.Fatal(err) } brain.Remember(d, []string{"dc1", "dc2"}) d, err = dep.ParseFile("/path/to/file") if err != nil { t.Fatal(err) } brain.Remember(d, "some content") d, err = dep.ParseStoreKey("config/redis/maxconns") if err != nil { t.Fatal(err) } brain.Remember(d, "5") d, err = dep.ParseStoreKey("config/redis/minconns") if err != nil { t.Fatal(err) } d.(*dep.StoreKey).SetDefault("100") brain.Remember(d, "150") d, err = dep.ParseStoreKey("config/redis/maxconns") if err != nil { t.Fatal(err) } d.(*dep.StoreKey).SetDefault("200") d, err = dep.ParseStoreKeyPrefix("config/redis") if err != nil { t.Fatal(err) } brain.Remember(d, []*dep.KeyPair{ &dep.KeyPair{Key: "", Value: ""}, &dep.KeyPair{Key: "admin/port", Value: "1134"}, &dep.KeyPair{Key: "maxconns", Value: "5"}, &dep.KeyPair{Key: "minconns", Value: "2"}, }) d, err = dep.ParseCatalogNode() if err != nil { t.Fatal(err) } brain.Remember(d, &dep.NodeDetail{ Node: &dep.Node{Node: "node1"}, Services: dep.NodeServiceList([]*dep.NodeService{ &dep.NodeService{ Service: "service1", }, }), }) d, err = dep.ParseCatalogNodes("") if err != nil { t.Fatal(err) } brain.Remember(d, []*dep.Node{ &dep.Node{Node: "node1"}, &dep.Node{Node: "node2"}, }) d, err = dep.ParseHealthServices("webapp") if err != nil { t.Fatal(err) } brain.Remember(d, []*dep.HealthService{ &dep.HealthService{ Node: "node1", Address: "1.2.3.4", Tags: []string{"release"}, }, &dep.HealthService{ Node: "node2", Address: "5.6.7.8", Tags: []string{"release", "production"}, }, &dep.HealthService{ Node: "node3", Address: "9.10.11.12", Tags: []string{"production"}, }, }) d, err = dep.ParseHealthServices("webapp", "any") if err != nil { t.Fatal(err) } brain.Remember(d, []*dep.HealthService{ &dep.HealthService{Node: "node1", Address: "1.2.3.4"}, &dep.HealthService{Node: "node2", Address: "5.6.7.8"}, }) d, err = dep.ParseCatalogServices("") if err != nil { t.Fatal(err) } brain.Remember(d, []*dep.CatalogService{ &dep.CatalogService{ Name: "service1", Tags: []string{"production"}, }, &dep.CatalogService{ Name: "service2", Tags: []string{"release", "production"}, }, }) d, err = dep.ParseVaultSecret("secret/foo/bar") if err != nil { t.Fatal(err) } brain.Remember(d, &dep.Secret{ LeaseID: "abcd1234", LeaseDuration: 120, Renewable: true, Data: map[string]interface{}{"zip": "zap"}, }) if err := os.Setenv("foo", "bar"); err != nil { t.Fatal(err) } d, err = dep.ParseFile("/path/to/json/file") if err != nil { t.Fatal(err) } brain.Remember(d, `{"foo": "bar"}`) if err := os.Setenv("json", `{"foo": "bar"}`); err != nil { t.Fatal(err) } _, _, result, err := tmpl.Execute(brain) if err != nil { t.Fatal(err) } expected := []byte(` API Functions ------------- datacenters: dc1 dc2 file: some content key: 5 key_or_default (exists): 150 key_or_default (missing): 200 ls: maxconns=5 minconns=2 node: node1 service1 nodes: node1 node2 service: 1.2.3.4 5.6.7.8 9.10.11.12 service (any): 1.2.3.4 5.6.7.8 service (tag.Contains): node2 node3 services: service1 service2 tree: admin/port=1134 maxconns=5 minconns=2 vault: zap Helper Functions ---------------- byKey: admin: port=1134 byTag (health service): production: 5.6.7.8 9.10.11.12 release: 1.2.3.4 5.6.7.8 byTag (catalog services): production: service1 service2 release: service2 contains: node2 node3 env: bar explode: adminmap[port:1134] maxconns5 minconns2 in: node2 node3 loop: test test test loop(i): test5 test6 test7 join: a;b;c parseBool: true parseFloat: 1.2 parseInt: -1 parseJSON (string): foo=bar parseJSON (file): foo=bar parseJSON (env): foo=bar parseUint: 1 plugin: {"foo": "bar"} timestamp: 1970-01-01T00:00:00Z timestamp (formatted): 1970-01-01 regexMatch: true regexMatch: false regexReplaceAll: xxxx xxxxxxx replaceAll: this content split: a b c toLower: some content toJSON: {"admin":{"port":"1134"},"maxconns":"5","minconns":"2"} toJSONPretty: { "admin": { "port": "1134" }, "maxconns": "5", "minconns": "2" } toTitle: Some Content toUpper: SOME CONTENT toYAML: admin: port: "1134" maxconns: "5" minconns: "2" Math Functions -------------- add:4 subtract:0 multiply:4 divide:1 `) if !bytes.Equal(result, expected) { t.Errorf("expected %s to be %s", result, expected) } }