conf/config_test.go

394 lines
8.4 KiB
Go

package conf
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type testconf struct {
inUpdate func()
String string
Invariant string
Int int
}
func (t testconf) Update() {
if t.inUpdate != nil {
t.inUpdate()
}
}
func TestLoadFile(t *testing.T) {
t.Parallel()
t.Run("with a valid file", func(t *testing.T) {
t.Parallel()
c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
}
file := "test_data/valid.json"
err := LoadFile(file, &c)
require.NoError(t, err)
assert.Equal(t, "config string", c.String)
assert.Equal(t, 42, c.Int)
assert.Equal(t, "should not change", c.Invariant)
})
t.Run("with an invalid file", func(t *testing.T) {
t.Parallel()
c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
}
file := "test_data/invalid.json"
err := LoadFile(file, &c)
require.Error(t, err)
assert.Equal(t, "default string", c.String)
assert.Equal(t, 1, c.Int)
assert.Equal(t, "should not change", c.Invariant)
})
t.Run("with a non existent file", func(t *testing.T) {
t.Parallel()
c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
}
file := "does-not-exist.conf"
err := LoadFile(file, &c)
require.Error(t, err)
assert.Equal(t, "default string", c.String)
assert.Equal(t, 1, c.Int)
assert.Equal(t, "should not change", c.Invariant)
})
}
func TestLoadFiles(t *testing.T) {
t.Parallel()
t.Run("with two valid files with different options", func(t *testing.T) {
t.Parallel()
c := testconf{}
tmpDir := t.TempDir()
content1 := []byte(`{"String": "foo"}`)
content2 := []byte(`{"Int": 42}`)
paths := []string{
filepath.Join(tmpDir, "file1.json"),
filepath.Join(tmpDir, "file2.json"),
}
err := os.WriteFile(paths[0], content1, 0o600)
require.NoError(t, err)
err = os.WriteFile(paths[1], content2, 0o600)
require.NoError(t, err)
err = LoadFiles(&c, paths...)
require.NoError(t, err)
assert.Equal(t, "foo", c.String)
assert.Equal(t, 42, c.Int)
})
t.Run("with two valid files with the same option", func(t *testing.T) {
t.Parallel()
c := testconf{}
tmpDir := t.TempDir()
content1 := []byte(`{"String": "foo"}`)
content2 := []byte(`{"String": "bar"}`)
paths := []string{
filepath.Join(tmpDir, "file1.json"),
filepath.Join(tmpDir, "file2.json"),
}
err := os.WriteFile(paths[0], content1, 0o600)
require.NoError(t, err)
err = os.WriteFile(paths[1], content2, 0o600)
require.NoError(t, err)
err = LoadFiles(&c, paths...)
require.NoError(t, err)
assert.Equal(t, "bar", c.String)
})
t.Run("with one non-existing and one existing file", func(t *testing.T) {
t.Parallel()
c := testconf{}
tmpDir := t.TempDir()
content2 := []byte(`{"String": "bar"}`)
paths := []string{
"does-not-exist.json",
filepath.Join(tmpDir, "file2.json"),
}
err := os.WriteFile(paths[1], content2, 0o600)
require.NoError(t, err)
err = LoadFiles(&c, paths...)
require.NoError(t, err)
assert.Equal(t, "bar", c.String)
})
t.Run("with one valid and one invalid file", func(t *testing.T) {
t.Parallel()
c := testconf{}
tmpDir := t.TempDir()
content1 := []byte(`{"`)
content2 := []byte(`{"String": "bar"}`)
paths := []string{
filepath.Join(tmpDir, "file1.json"),
filepath.Join(tmpDir, "file2.json"),
}
err := os.WriteFile(paths[0], content1, 0o600)
require.NoError(t, err)
err = os.WriteFile(paths[1], content2, 0o600)
require.NoError(t, err)
err = LoadFiles(&c, paths...)
require.Error(t, err)
assert.Equal(t, "", c.String)
})
}
func TestSaveFile(t *testing.T) {
t.Parallel()
t.Run("with a valid path", func(t *testing.T) {
t.Parallel()
c := testconf{
String: "default string",
Invariant: "should not change",
Int: 1,
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test.conf")
err := SaveFile(file, &c)
require.NoError(t, err)
assert.FileExists(t, file)
expected := "{\n \"String\": \"default string\",\n \"Invariant\": \"should not change\",\n \"Int\": 1\n}"
got, err := os.ReadFile(file)
require.NoError(t, err)
assert.Equal(t, expected, string(got))
})
t.Run("with a valid path and invalid data", func(t *testing.T) {
t.Parallel()
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test.conf")
err := SaveFile(file, func() error { return nil })
require.Error(t, err)
assert.NoFileExists(t, file)
})
t.Run("with an invalid path", func(t *testing.T) {
t.Parallel()
c := testconf{
String: "default string",
Invariant: "should not change",
Int: 1,
}
file := "cannot/write/here.conf"
err := SaveFile(file, &c)
require.Error(t, err)
assert.NoFileExists(t, file)
})
}
func TestLoadAndUpdateFile(t *testing.T) {
t.Parallel()
t.Run("when the target file does not exist", func(t *testing.T) {
t.Parallel()
updated := false
c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test.conf")
err := LoadAndUpdateFile(file, &c)
require.NoError(t, err)
var c2 testconf
err = read(file, &c2)
require.NoError(t, err)
assert.Equal(t, c.String, c2.String)
assert.Equal(t, c.Int, c2.Int)
assert.Equal(t, c.Invariant, c2.Invariant)
assert.False(t, updated)
})
t.Run("when the path cannot be written", func(t *testing.T) {
t.Parallel()
updated := false
c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "does-not-exist", "test.conf")
err := LoadAndUpdateFile(file, &c)
require.Error(t, err)
assert.NoFileExists(t, file)
assert.False(t, updated)
})
t.Run("when the config file is invalid", func(t *testing.T) {
t.Parallel()
updated := false
c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test.conf")
content := []byte(`String: not json`)
err := os.WriteFile(file, content, 0o644)
require.NoError(t, err)
err = LoadAndUpdateFile(file, &c)
require.Error(t, err)
assert.False(t, updated)
})
t.Run("when the config file is valid", func(t *testing.T) {
t.Parallel()
updated := false
c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test.conf")
content := []byte(`{"String": "config string", "Int": 42}`)
err := os.WriteFile(file, content, 0o644)
require.NoError(t, err)
err = LoadAndUpdateFile(file, &c)
require.NoError(t, err)
var c2 testconf
err = read(file, &c2)
require.NoError(t, err)
assert.Equal(t, "config string", c2.String)
assert.Equal(t, 42, c2.Int)
assert.True(t, updated)
})
t.Run("when the config file is missing options", func(t *testing.T) {
t.Parallel()
updated := false
c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test.conf")
content := []byte(`{"String": "config string"}`)
err := os.WriteFile(file, content, 0o644)
require.NoError(t, err)
err = LoadAndUpdateFile(file, &c)
require.NoError(t, err)
newContent, err := os.ReadFile(file)
require.NoError(t, err)
assert.Contains(t, string(newContent), "Int")
assert.Contains(t, string(newContent), "Invariant")
assert.True(t, updated)
})
t.Run("when the config contains unknown options", func(t *testing.T) {
t.Parallel()
updated := false
c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test.conf")
content := []byte(`{"String": "config string", "Foo": "blah"}`)
err := os.WriteFile(file, content, 0o644)
require.NoError(t, err)
err = LoadAndUpdateFile(file, &c)
require.NoError(t, err)
newContent, err := os.ReadFile(file)
require.NoError(t, err)
assert.NotContains(t, string(newContent), "Foo")
assert.True(t, updated)
})
}