mirror of
https://github.com/helmfile/helmfile.git
synced 2026-09-30 19:32:27 +02:00
Introduce Helmfile's own filesystem abstraction to correctly unit test some components (#307)
Use abstracted FS Signed-off-by: Arkaitz Jimenez <arkaitzj@gmail.com> Signed-off-by: Arkaitz Jimenez <arkaitzj@gmail.com>
This commit is contained in:
+6
-9
@@ -1,12 +1,13 @@
|
||||
package tmpl
|
||||
|
||||
import "io/fs"
|
||||
import (
|
||||
"github.com/helmfile/helmfile/pkg/filesystem"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
preRender bool
|
||||
basePath string
|
||||
readFile func(string) ([]byte, error)
|
||||
readDir func(string) ([]fs.DirEntry, error)
|
||||
fs *filesystem.FileSystem
|
||||
}
|
||||
|
||||
// SetBasePath sets the base path for the template
|
||||
@@ -14,10 +15,6 @@ func (c *Context) SetBasePath(path string) {
|
||||
c.basePath = path
|
||||
}
|
||||
|
||||
func (c *Context) SetReadFile(f func(string) ([]byte, error)) {
|
||||
c.readFile = f
|
||||
}
|
||||
|
||||
func (c *Context) SetReadDir(f func(string) ([]fs.DirEntry, error)) {
|
||||
c.readDir = f
|
||||
func (c *Context) SetFileSystem(fs *filesystem.FileSystem) {
|
||||
c.fs = fs
|
||||
}
|
||||
|
||||
@@ -220,11 +220,11 @@ func (c *Context) ReadFile(filename string) (string, error) {
|
||||
path = filepath.Join(c.basePath, filename)
|
||||
}
|
||||
|
||||
if c.readFile == nil {
|
||||
if c.fs.ReadFile == nil {
|
||||
return "", fmt.Errorf("readFile is not implemented")
|
||||
}
|
||||
|
||||
bytes, err := c.readFile(path)
|
||||
bytes, err := c.fs.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -239,7 +239,7 @@ func (c *Context) ReadDir(path string) ([]string, error) {
|
||||
contextPath = filepath.Join(c.basePath, path)
|
||||
}
|
||||
|
||||
entries, err := c.readDir(contextPath)
|
||||
entries, err := c.fs.ReadDir(contextPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ReadDir %q: %w", contextPath, err)
|
||||
}
|
||||
@@ -262,7 +262,7 @@ func (c *Context) ReadDirEntries(path string) ([]fs.DirEntry, error) {
|
||||
} else {
|
||||
contextPath = filepath.Join(c.basePath, path)
|
||||
}
|
||||
entries, err := c.readDir(contextPath)
|
||||
entries, err := c.fs.ReadDir(contextPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ReadDirEntries %q: %w", contextPath, err)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/helmfile/helmfile/pkg/filesystem"
|
||||
)
|
||||
|
||||
func TestCreateFuncMap(t *testing.T) {
|
||||
@@ -62,17 +64,23 @@ func TestCreateFuncMap_SkipInsecureTemplateFunctions(t *testing.T) {
|
||||
skipInsecureTemplateFunctions = currentVal
|
||||
}
|
||||
|
||||
func newFSExpecting(expectedFilename string, expected string) *filesystem.FileSystem {
|
||||
return filesystem.FromFileSystem(filesystem.FileSystem{
|
||||
ReadFile: func(filename string) ([]byte, error) {
|
||||
if filename != expectedFilename {
|
||||
return nil, fmt.Errorf("unexpected filename: expected=%v, actual=%s", expectedFilename, filename)
|
||||
}
|
||||
return []byte(expected), nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestReadFile(t *testing.T) {
|
||||
expected := `foo:
|
||||
bar: BAR
|
||||
`
|
||||
expectedFilename := "values.yaml"
|
||||
ctx := &Context{basePath: ".", readFile: func(filename string) ([]byte, error) {
|
||||
if filename != expectedFilename {
|
||||
return nil, fmt.Errorf("unexpected filename: expected=%v, actual=%s", expectedFilename, filename)
|
||||
}
|
||||
return []byte(expected), nil
|
||||
}}
|
||||
ctx := &Context{basePath: ".", fs: newFSExpecting(expectedFilename, expected)}
|
||||
actual, err := ctx.ReadFile(expectedFilename)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expected, actual)
|
||||
@@ -125,12 +133,12 @@ func TestReadDir(t *testing.T) {
|
||||
}
|
||||
|
||||
expectedDirname := "sampleDirectory"
|
||||
ctx := &Context{basePath: ".", readDir: func(dirname string) ([]fs.DirEntry, error) {
|
||||
ctx := &Context{basePath: ".", fs: filesystem.FromFileSystem(filesystem.FileSystem{ReadDir: func(dirname string) ([]fs.DirEntry, error) {
|
||||
if dirname != expectedDirname {
|
||||
return nil, fmt.Errorf("unexpected filename: expected=%v, actual=%s", expectedDirname, dirname)
|
||||
}
|
||||
return result, nil
|
||||
}}
|
||||
}})}
|
||||
|
||||
actual, err := ctx.ReadDir(expectedDirname)
|
||||
require.NoError(t, err)
|
||||
@@ -146,12 +154,12 @@ func TestReadDirEntries(t *testing.T) {
|
||||
}
|
||||
|
||||
expectedDirname := "sampleDirectory"
|
||||
ctx := &Context{basePath: ".", readDir: func(dirname string) ([]fs.DirEntry, error) {
|
||||
ctx := &Context{basePath: ".", fs: filesystem.FromFileSystem(filesystem.FileSystem{ReadDir: func(dirname string) ([]fs.DirEntry, error) {
|
||||
if dirname != expectedDirname {
|
||||
return nil, fmt.Errorf("unexpected filename: expected=%v, actual=%s", expectedDirname, dirname)
|
||||
}
|
||||
return result, nil
|
||||
}}
|
||||
}})}
|
||||
|
||||
actual, err := ctx.ReadDirEntries(expectedDirname)
|
||||
require.NoError(t, err)
|
||||
@@ -163,12 +171,7 @@ func TestReadFile_PassAbsPath(t *testing.T) {
|
||||
bar: BAR
|
||||
`
|
||||
expectedFilename, _ := filepath.Abs("values.yaml")
|
||||
ctx := &Context{basePath: ".", readFile: func(filename string) ([]byte, error) {
|
||||
if filename != expectedFilename {
|
||||
return nil, fmt.Errorf("unexpected filename: expected=%v, actual=%s", expectedFilename, filename)
|
||||
}
|
||||
return []byte(expected), nil
|
||||
}}
|
||||
ctx := &Context{basePath: ".", fs: newFSExpecting(expectedFilename, expected)}
|
||||
actual, err := ctx.ReadFile(expectedFilename)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, actual, expected)
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
ffs "github.com/helmfile/helmfile/pkg/filesystem"
|
||||
)
|
||||
|
||||
func TestRenderTemplate_Values(t *testing.T) {
|
||||
@@ -14,12 +16,12 @@ func TestRenderTemplate_Values(t *testing.T) {
|
||||
bar: FOO_BAR
|
||||
`
|
||||
expectedFilename := "values.yaml"
|
||||
ctx := &Context{readFile: func(filename string) ([]byte, error) {
|
||||
ctx := &Context{fs: &ffs.FileSystem{ReadFile: func(filename string) ([]byte, error) {
|
||||
if filename != expectedFilename {
|
||||
return nil, fmt.Errorf("unexpected filename: expected=%v, actual=%s", expectedFilename, filename)
|
||||
}
|
||||
return []byte(valuesYamlContent), nil
|
||||
}}
|
||||
}}}
|
||||
buf, err := ctx.RenderTemplateToBuffer(`{{ readFile "values.yaml" | fromYaml | setValueAtPath "foo.bar" "FOO_BAR" | toYaml }}`)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
@@ -43,12 +45,12 @@ func TestRenderTemplate_WithData(t *testing.T) {
|
||||
"bar": "FOO_BAR",
|
||||
},
|
||||
}
|
||||
ctx := &Context{readFile: func(filename string) ([]byte, error) {
|
||||
ctx := &Context{fs: &ffs.FileSystem{ReadFile: func(filename string) ([]byte, error) {
|
||||
if filename != expectedFilename {
|
||||
return nil, fmt.Errorf("unexpected filename: expected=%v, actual=%s", expectedFilename, filename)
|
||||
}
|
||||
return []byte(valuesYamlContent), nil
|
||||
}}
|
||||
}}}
|
||||
buf, err := ctx.RenderTemplateToBuffer(valuesYamlContent, data)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
@@ -68,12 +70,12 @@ func TestRenderTemplate_AccessingMissingKeyWithGetOrNil(t *testing.T) {
|
||||
`
|
||||
expectedFilename := "values.yaml"
|
||||
data := map[string]interface{}{}
|
||||
ctx := &Context{readFile: func(filename string) ([]byte, error) {
|
||||
ctx := &Context{fs: &ffs.FileSystem{ReadFile: func(filename string) ([]byte, error) {
|
||||
if filename != expectedFilename {
|
||||
return nil, fmt.Errorf("unexpected filename: expected=%v, actual=%s", expectedFilename, filename)
|
||||
}
|
||||
return []byte(valuesYamlContent), nil
|
||||
}}
|
||||
}}}
|
||||
buf, err := ctx.RenderTemplateToBuffer(valuesYamlContent, data)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
@@ -93,12 +95,12 @@ func TestRenderTemplate_Defaulting(t *testing.T) {
|
||||
`
|
||||
expectedFilename := "values.yaml"
|
||||
data := map[string]interface{}{}
|
||||
ctx := &Context{readFile: func(filename string) ([]byte, error) {
|
||||
ctx := &Context{fs: &ffs.FileSystem{ReadFile: func(filename string) ([]byte, error) {
|
||||
if filename != expectedFilename {
|
||||
return nil, fmt.Errorf("unexpected filename: expected=%v, actual=%s", expectedFilename, filename)
|
||||
}
|
||||
return []byte(valuesYamlContent), nil
|
||||
}}
|
||||
}}}
|
||||
buf, err := ctx.RenderTemplateToBuffer(valuesYamlContent, data)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
@@ -110,9 +112,9 @@ func TestRenderTemplate_Defaulting(t *testing.T) {
|
||||
}
|
||||
|
||||
func renderTemplateToString(s string, data ...interface{}) (string, error) {
|
||||
ctx := &Context{readFile: func(filename string) ([]byte, error) {
|
||||
ctx := &Context{fs: &ffs.FileSystem{ReadFile: func(filename string) ([]byte, error) {
|
||||
return nil, fmt.Errorf("unexpected call to readFile: filename=%s", filename)
|
||||
}}
|
||||
}}}
|
||||
tplString, err := ctx.RenderTemplateToBuffer(s, data...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
+13
-13
@@ -3,43 +3,43 @@ package tmpl
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/helmfile/helmfile/pkg/filesystem"
|
||||
)
|
||||
|
||||
type FileRenderer struct {
|
||||
ReadFile func(string) ([]byte, error)
|
||||
Context *Context
|
||||
Data interface{}
|
||||
fs *filesystem.FileSystem
|
||||
Context *Context
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
func NewFileRenderer(readFile func(filename string) ([]byte, error), basePath string, data interface{}) *FileRenderer {
|
||||
func NewFileRenderer(fs *filesystem.FileSystem, basePath string, data interface{}) *FileRenderer {
|
||||
return &FileRenderer{
|
||||
ReadFile: readFile,
|
||||
fs: fs,
|
||||
Context: &Context{
|
||||
basePath: basePath,
|
||||
readFile: readFile,
|
||||
readDir: os.ReadDir,
|
||||
fs: fs,
|
||||
},
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
func NewFirstPassRenderer(basePath string, data interface{}) *FileRenderer {
|
||||
fs := filesystem.DefaultFileSystem()
|
||||
return &FileRenderer{
|
||||
ReadFile: os.ReadFile,
|
||||
fs: fs,
|
||||
Context: &Context{
|
||||
preRender: true,
|
||||
basePath: basePath,
|
||||
readFile: os.ReadFile,
|
||||
readDir: os.ReadDir,
|
||||
fs: fs,
|
||||
},
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *FileRenderer) RenderTemplateFileToBuffer(file string) (*bytes.Buffer, error) {
|
||||
content, err := r.ReadFile(file)
|
||||
content, err := r.fs.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -60,7 +60,7 @@ func (r *FileRenderer) RenderToBytes(path string) ([]byte, error) {
|
||||
yamlBytes = yamlBuf.Bytes()
|
||||
} else {
|
||||
var err error
|
||||
yamlBytes, err = r.ReadFile(path)
|
||||
yamlBytes, err = r.fs.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load [%s]: %v", path, err)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/helmfile/helmfile/pkg/environment"
|
||||
"github.com/helmfile/helmfile/pkg/filesystem"
|
||||
)
|
||||
|
||||
var emptyEnvTmplData = map[string]interface{}{
|
||||
@@ -23,7 +24,7 @@ func TestRenderToBytes_Gotmpl(t *testing.T) {
|
||||
`
|
||||
dataFile := "data.txt"
|
||||
valuesTmplFile := "values.yaml.gotmpl"
|
||||
r := NewFileRenderer(func(filename string) ([]byte, error) {
|
||||
r := NewFileRenderer(&filesystem.FileSystem{ReadFile: func(filename string) ([]byte, error) {
|
||||
switch filename {
|
||||
case valuesTmplFile:
|
||||
return []byte(valuesYamlTmplContent), nil
|
||||
@@ -31,7 +32,7 @@ func TestRenderToBytes_Gotmpl(t *testing.T) {
|
||||
return []byte(dataFileContent), nil
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected filename: expected=%v or %v, actual=%s", dataFile, valuesTmplFile, filename)
|
||||
}, "", emptyEnvTmplData)
|
||||
}}, "", emptyEnvTmplData)
|
||||
buf, err := r.RenderToBytes(valuesTmplFile)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
@@ -50,12 +51,12 @@ func TestRenderToBytes_Yaml(t *testing.T) {
|
||||
bar: '{{ readFile "data.txt" }}'
|
||||
`
|
||||
valuesFile := "values.yaml"
|
||||
r := NewFileRenderer(func(filename string) ([]byte, error) {
|
||||
r := NewFileRenderer(&filesystem.FileSystem{ReadFile: func(filename string) ([]byte, error) {
|
||||
if filename == valuesFile {
|
||||
return []byte(valuesYamlContent), nil
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected filename: expected=%v, actual=%s", valuesFile, filename)
|
||||
}, "", emptyEnvTmplData)
|
||||
}}, "", emptyEnvTmplData)
|
||||
buf, err := r.RenderToBytes(valuesFile)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package tmpl
|
||||
|
||||
import (
|
||||
"github.com/helmfile/helmfile/pkg/filesystem"
|
||||
)
|
||||
|
||||
type templateTextRenderer struct {
|
||||
ReadText func(string) ([]byte, error)
|
||||
Context *Context
|
||||
@@ -11,12 +15,12 @@ type TextRenderer interface {
|
||||
}
|
||||
|
||||
// nolint: golint
|
||||
func NewTextRenderer(readFile func(filename string) ([]byte, error), basePath string, data interface{}) *templateTextRenderer {
|
||||
func NewTextRenderer(fs *filesystem.FileSystem, basePath string, data interface{}) *templateTextRenderer {
|
||||
return &templateTextRenderer{
|
||||
ReadText: readFile,
|
||||
ReadText: fs.ReadFile,
|
||||
Context: &Context{
|
||||
basePath: basePath,
|
||||
readFile: readFile,
|
||||
fs: fs,
|
||||
},
|
||||
Data: data,
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package tmpl
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/helmfile/helmfile/pkg/filesystem"
|
||||
)
|
||||
|
||||
// TestTextRenderer tests the text renderer.
|
||||
@@ -12,7 +13,7 @@ func TestNewTextRenderer(t *testing.T) {
|
||||
tData := map[string]interface{}{
|
||||
"foo": "bar",
|
||||
}
|
||||
tr := NewTextRenderer(os.ReadFile, ".", tData)
|
||||
tr := NewTextRenderer(filesystem.DefaultFileSystem(), ".", tData)
|
||||
require.Equal(t, tData, tr.Data)
|
||||
require.Equal(t, ".", tr.Context.basePath)
|
||||
}
|
||||
@@ -22,7 +23,7 @@ func TestTextRender(t *testing.T) {
|
||||
tData := map[string]interface{}{
|
||||
"foot": "bart",
|
||||
}
|
||||
tr := NewTextRenderer(os.ReadFile, ".", tData)
|
||||
tr := NewTextRenderer(filesystem.DefaultFileSystem(), ".", tData)
|
||||
|
||||
tests := []struct {
|
||||
text string
|
||||
|
||||
Reference in New Issue
Block a user