Remove more side effects from application config testing (#1684)

* remove a few side effects from config testing

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix xdg config app name prefix

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* account for restoring and protecting xdg state throughout testing

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

---------

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman 2023-03-20 16:53:45 -04:00 committed by GitHub
parent f11a7b5e9f
commit 100cf1003d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 37 deletions

View File

@ -270,13 +270,12 @@ func loadConfig(v *viper.Viper, configPath string) error {
} }
} }
// 4. look for .<appname>/config.yaml in xdg locations (starting with xdg home config dir, then moving upwards) // 4. look for <appname>/config.yaml in xdg locations (starting with xdg home config dir, then moving upwards)
v.SetConfigName("config") v.SetConfigName("config")
configPath = path.Join(xdg.ConfigHome, "."+internal.ApplicationName) configPath = path.Join(xdg.ConfigHome, internal.ApplicationName)
v.AddConfigPath(configPath) v.AddConfigPath(configPath)
for _, dir := range xdg.ConfigDirs { for _, dir := range xdg.ConfigDirs {
v.AddConfigPath(path.Join(dir, "."+internal.ApplicationName)) v.AddConfigPath(path.Join(dir, internal.ApplicationName))
} }
if err = v.ReadInConfig(); err == nil { if err = v.ReadInConfig(); err == nil {
v.Set("config", v.ConfigFileUsed()) v.Set("config", v.ConfigFileUsed())

View File

@ -1,17 +1,35 @@
package config package config
import ( import (
"fmt"
"os" "os"
"path" "path"
"testing" "testing"
"github.com/adrg/xdg" "github.com/adrg/xdg"
"github.com/mitchellh/go-homedir"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
// TODO: set negative case when config.yaml is no longer a valid option // TODO: set negative case when config.yaml is no longer a valid option
func TestApplicationConfig(t *testing.T) { func TestApplicationConfig(t *testing.T) {
// disable homedir package cache for testing
originalCacheOpt := homedir.DisableCache
homedir.DisableCache = true
t.Cleanup(func() {
homedir.DisableCache = originalCacheOpt
})
// ensure we have no side effects for xdg package for future tests
originalXDG := os.Getenv("XDG_CONFIG_HOME")
t.Cleanup(func() {
// note: we're not using t.Setenv since the effect we're trying to eliminate is within the xdg package
require.NoError(t, os.Setenv("XDG_CONFIG_HOME", originalXDG))
xdg.Reload()
})
// config is picked up at desired configuration paths // config is picked up at desired configuration paths
// VALID: .syft.yaml, .syft/config.yaml, ~/.syft.yaml, <XDG_CONFIG_HOME>/syft/config.yaml // VALID: .syft.yaml, .syft/config.yaml, ~/.syft.yaml, <XDG_CONFIG_HOME>/syft/config.yaml
// DEPRECATED: config.yaml is currently supported by // DEPRECATED: config.yaml is currently supported by
@ -19,7 +37,7 @@ func TestApplicationConfig(t *testing.T) {
name string name string
setup func(t *testing.T) string setup func(t *testing.T) string
assertions func(t *testing.T, app *Application) assertions func(t *testing.T, app *Application)
Cleanup func(t *testing.T) cleanup func()
}{ }{
{ {
name: "explicit config", name: "explicit config",
@ -29,92 +47,82 @@ func TestApplicationConfig(t *testing.T) {
assertions: func(t *testing.T, app *Application) { assertions: func(t *testing.T, app *Application) {
assert.Equal(t, "test-explicit-config", app.File) assert.Equal(t, "test-explicit-config", app.File)
}, },
Cleanup: func(t *testing.T) {},
}, },
{ {
name: "current working directory named config", name: "current working directory named config",
setup: func(t *testing.T) string { setup: func(t *testing.T) string {
err := os.Chdir("./test-fixtures/config-wd-file") // change application cwd to test-fixtures err := os.Chdir("./test-fixtures/config-wd-file") // change application cwd to test-fixtures
if err != nil { require.NoError(t, err)
t.Fatalf("%s failed to change cwd: %+v", t.Name(), err)
}
return "" return ""
}, },
assertions: func(t *testing.T, app *Application) { assertions: func(t *testing.T, app *Application) {
assert.Equal(t, "test-wd-named-config", app.File) assert.Equal(t, "test-wd-named-config", app.File)
}, },
Cleanup: func(t *testing.T) {},
}, },
{ {
name: "current working directory syft dir config", name: "current working directory syft dir config",
setup: func(t *testing.T) string { setup: func(t *testing.T) string {
err := os.Chdir("./test-fixtures/config-dir-test") // change application cwd to test-fixtures err := os.Chdir("./test-fixtures/config-dir-test") // change application cwd to test-fixtures
if err != nil { require.NoError(t, err)
t.Fatalf("%s failed to change cwd: %+v", t.Name(), err)
}
return "" return ""
}, },
assertions: func(t *testing.T, app *Application) { assertions: func(t *testing.T, app *Application) {
assert.Equal(t, "test-dir-config", app.File) assert.Equal(t, "test-dir-config", app.File)
}, },
Cleanup: func(t *testing.T) {},
}, },
{ {
name: "home directory file config", name: "home directory file config",
setup: func(t *testing.T) string { setup: func(t *testing.T) string {
// Because Setenv affects the whole process, it cannot be used in parallel tests or // Because Setenv affects the whole process, it cannot be used in parallel tests or
// tests with parallel ancestors: see separate XDG test for consequence of this // tests with parallel ancestors: see separate XDG test for consequence of this
t.Setenv("HOME", "./test-fixtures/config-home-test") t.Setenv("HOME", "./test-fixtures/config-home-test/config-file")
err := os.Link("./test-fixtures/config-home-test/config-file/.syft.yaml", "./test-fixtures/config-home-test/.syft.yaml")
if err != nil {
t.Fatalf("%s failed to link home config: %+v", t.Name(), err)
}
return "" return ""
}, },
assertions: func(t *testing.T, app *Application) { assertions: func(t *testing.T, app *Application) {
assert.Equal(t, "test-home-config", app.File) assert.Equal(t, "test-home-config", app.File)
}, },
Cleanup: func(t *testing.T) {
err := os.Remove("./test-fixtures/config-home-test/.syft.yaml") //
if err != nil {
t.Fatalf("%s failed to remove home config link: %+v", t.Name(), err)
}
},
}, },
{ {
name: "XDG file config", name: "XDG file config",
setup: func(t *testing.T) string { setup: func(t *testing.T) string {
wd, err := os.Getwd() wd, err := os.Getwd()
if err != nil { require.NoError(t, err)
t.Fatalf("%s: failed to get working directory: %+v", t.Name(), err)
}
configDir := path.Join(wd, "./test-fixtures/config-home-test") // set HOME to testdata configDir := path.Join(wd, "./test-fixtures/config-home-test") // set HOME to testdata
t.Setenv("XDG_CONFIG_DIRS", configDir) // note: this explicitly has multiple XDG paths, make certain we use the first VALID one (not the first one)
t.Setenv("XDG_CONFIG_DIRS", fmt.Sprintf("/another/foo/bar:%s", configDir))
xdg.Reload() xdg.Reload()
return "" return ""
}, },
assertions: func(t *testing.T, app *Application) { assertions: func(t *testing.T, app *Application) {
assert.Equal(t, "test-home-XDG-config", app.File) assert.Equal(t, "test-home-XDG-config", app.File)
}, },
Cleanup: func(t *testing.T) {}, cleanup: func() {
require.NoError(t, os.Unsetenv("XDG_CONFIG_DIRS"))
xdg.Reload()
},
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
defer test.Cleanup(t) if test.cleanup != nil {
wd, err := os.Getwd() t.Cleanup(test.cleanup)
if err != nil {
t.Fatalf("failed to get working directory: %+v", err)
} }
wd, err := os.Getwd()
require.NoError(t, err)
defer os.Chdir(wd) // reset working directory after test defer os.Chdir(wd) // reset working directory after test
application := &Application{} application := &Application{}
viperInstance := viper.New() viperInstance := viper.New()
// this will override home in case you are running this test locally and DO have a syft config
// in your home directory... now it will be ignored. Same for XDG_CONFIG_DIRS.
t.Setenv("HOME", "/foo/bar")
t.Setenv("XDG_CONFIG_DIRS", "/foo/bar")
xdg.Reload()
configPath := test.setup(t) configPath := test.setup(t)
err = application.LoadAllValues(viperInstance, configPath) err = application.LoadAllValues(viperInstance, configPath)
if err != nil { require.NoError(t, err)
t.Fatalf("failed to load application config: %+v", err)
}
test.assertions(t, application) test.assertions(t, application)
}) })
} }