Commit 163c3a6e authored by Geoff Simmons's avatar Geoff Simmons

Refactor the interface in template.go.

InitTemplates() takes a map of template paths to file paths, and
returns a map of parsed template to file paths.

Add WriteTemplate(), which takes a parsed template and a file path,
and generates VCL at the path from a spec and the template. Meant
for iteration on the map returned by InitTemplates().
parent ace00d98
...@@ -29,9 +29,9 @@ ...@@ -29,9 +29,9 @@
package vcl package vcl
import ( import (
"bytes"
"fmt" "fmt"
"path" "os"
"path/filepath"
"regexp" "regexp"
"text/template" "text/template"
) )
...@@ -41,25 +41,22 @@ var fMap = template.FuncMap{ ...@@ -41,25 +41,22 @@ var fMap = template.FuncMap{
"vclMangle": func(s string) string { return mangle(s) }, "vclMangle": func(s string) string { return mangle(s) },
} }
const ( var vclIllegal = regexp.MustCompile("[^[:word:]-]+")
tmplSrc = "backends.tmpl"
)
var (
tmpl *template.Template
vclIllegal = regexp.MustCompile("[^[:word:]-]+")
)
// InitTemplates initializes templates for VCL generation. // InitTemplates initializes templates for VCL generation.
func InitTemplates(tmplDir string) error { func InitTemplates(
var err error tmplMap map[string]string) (map[*template.Template]string, error) {
tmplPath := path.Join(tmplDir, tmplSrc)
tmpl, err = template.New(tmplSrc).Funcs(fMap).ParseFiles(tmplPath) tmpls2files := make(map[*template.Template]string, len(tmplMap))
if err != nil { for tmplPath, filePath := range tmplMap {
return err if tmpl, err := template.New(filepath.Base(tmplPath)).
Funcs(fMap).ParseFiles(tmplPath); err != nil {
return nil, err
} else {
tmpls2files[tmpl] = filePath
} }
return nil }
return tmpls2files, nil
} }
func replIllegal(ill []byte) []byte { func replIllegal(ill []byte) []byte {
...@@ -71,21 +68,24 @@ func replIllegal(ill []byte) []byte { ...@@ -71,21 +68,24 @@ func replIllegal(ill []byte) []byte {
return repl return repl
} }
// GetSrc returns the VCL generated to implement a Spec. // WriteTemplate generates a VCL file at path to implement spec, using
func (spec Spec) GetSrc() (string, error) { // the template.
var buf bytes.Buffer func (spec Spec) WriteTemplate(tmpl *template.Template, path string) error {
if err := tmpl.Execute(&buf, spec); err != nil { file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
return "", err if err != nil {
return err
}
if err = tmpl.Execute(file, spec); err != nil {
file.Close()
return err
} }
return buf.String(), nil return file.Close()
} }
func mangle(s string) string { func mangle(s string) string {
if s == "" { if s == "" {
return s return s
} }
prefixed := "vk8s_" + s mangled := vclIllegal.ReplaceAllFunc([]byte(s), replIllegal)
bytes := []byte(prefixed)
mangled := vclIllegal.ReplaceAllFunc(bytes, replIllegal)
return string(mangled) return string(mangled)
} }
...@@ -34,28 +34,50 @@ import ( ...@@ -34,28 +34,50 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"strings" "strings"
"testing" "testing"
"text/template"
"time" "time"
) )
func cmpGold(got []byte, goldfile string) (bool, error) { var (
goldpath := filepath.Join("testdata", goldfile) testdir string
gold, err := ioutil.ReadFile(goldpath) tmpdir string
)
func cmpGold(t *testing.T, gotPath string, goldfile string) bool {
goldPath := filepath.Join(testdir, "testdata", goldfile)
gold, err := ioutil.ReadFile(goldPath)
if err != nil {
t.Fatalf("Cannot read %s: %s", goldPath, err)
return false
}
got, err := ioutil.ReadFile(gotPath)
if err != nil { if err != nil {
return false, err t.Fatalf("Cannot read %s: %s", gotPath, err)
return false
} }
return bytes.Equal(got, gold), nil return bytes.Equal(got, gold)
} }
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
tmplDir := "" var err error
tmplEnv, exists := os.LookupEnv("TEMPLATE_DIR")
if !exists { _, filename, _, ok := runtime.Caller(0)
tmplDir = tmplEnv if !ok {
fmt.Println("Cannot get test directory")
os.Exit(-1)
}
testdir = filepath.Dir(filename)
tmpdir, err = ioutil.TempDir("", "k8s-vcl-reloader")
if err != nil {
fmt.Println("Cannot create tmp directory:", err)
os.Exit(-1)
} }
if err := InitTemplates(tmplDir); err != nil { tmpdir = filepath.Join(tmpdir, "vcl_test")
fmt.Printf("Cannot parse templates: %v\n", err) if err = os.Mkdir(tmpdir, 0755); err != nil {
fmt.Printf("Cannot make tmp directory %s: %s", tmpdir, err)
os.Exit(-1) os.Exit(-1)
} }
code := m.Run() code := m.Run()
...@@ -142,26 +164,33 @@ var testSpec = Spec{ ...@@ -142,26 +164,33 @@ var testSpec = Spec{
} }
func TestTemplate(t *testing.T) { func TestTemplate(t *testing.T) {
var buf bytes.Buffer var tmpl *template.Template
gold := "backends.golden" gold := "backends.golden"
if err := tmpl.Execute(&buf, testSpec); err != nil { tmplMap := make(map[string]string)
t.Fatal("Execute():", err) vclPath := filepath.Join(tmpdir, "backends.vcl")
} tmplMap[filepath.Join(testdir, "testdata", "backends.tmpl")] = vclPath
ok, err := cmpGold(buf.Bytes(), gold)
tmpl2file, err := InitTemplates(tmplMap);
if err != nil { if err != nil {
t.Fatalf("Reading %s: %v", gold, err) t.Fatal("InitTemplates():", err)
} }
if !ok { for t := range tmpl2file {
t.Errorf("Generated VCL does not match gold file: %s", gold) tmpl = t
if testing.Verbose() { }
t.Logf("Generated: %s", buf.String())
if err = testSpec.WriteTemplate(tmpl, vclPath); err != nil {
t.Fatal("WriteTemplate():", err)
} }
if !cmpGold(t, vclPath, gold) {
t.Errorf("Generated VCL at %s does not match gold file %s",
vclPath, filepath.Join("testdata", gold))
} }
} }
func TestFQVersion(t *testing.T) { func TestFQVersion(t *testing.T) {
fqVersion := testSpec.FQVersion() fqVersion := testSpec.FQVersion()
if !strings.HasPrefix(fqVersion, testSpec.Version + "-") { if !strings.HasPrefix(fqVersion, testSpec.Version+"-") {
t.Fatal("FQVersion(): does not begin with spec.Version + "+ t.Fatal("FQVersion(): does not begin with spec.Version + "+
"\"-\":", fqVersion) "\"-\":", fqVersion)
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment