mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
Add accumulateResources error tests for local files (#5225)
* Add accumulateResources error tests for local files. Add tests demonstrating accumulateResources errors when the resource is a local file. Works to address #4807. * Improve readability
This commit is contained in:
@@ -17,6 +17,18 @@ import (
|
|||||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const validResource = `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: myService
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
backend: bungie
|
||||||
|
ports:
|
||||||
|
- port: 7002
|
||||||
|
`
|
||||||
|
|
||||||
func TestTargetMustHaveKustomizationFile(t *testing.T) {
|
func TestTargetMustHaveKustomizationFile(t *testing.T) {
|
||||||
th := kusttest_test.MakeHarness(t)
|
th := kusttest_test.MakeHarness(t)
|
||||||
th.WriteF("service.yaml", `
|
th.WriteF("service.yaml", `
|
||||||
@@ -63,17 +75,7 @@ func TestBaseMustHaveKustomizationFile(t *testing.T) {
|
|||||||
resources:
|
resources:
|
||||||
- base
|
- base
|
||||||
`)
|
`)
|
||||||
th.WriteF("base/service.yaml", `
|
th.WriteF("base/service.yaml", validResource)
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: myService
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
backend: bungie
|
|
||||||
ports:
|
|
||||||
- port: 7002
|
|
||||||
`)
|
|
||||||
err := th.RunWithErr(".", th.MakeDefaultOptions())
|
err := th.RunWithErr(".", th.MakeDefaultOptions())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected an error")
|
t.Fatalf("expected an error")
|
||||||
@@ -167,12 +169,35 @@ spec:
|
|||||||
|
|
||||||
func TestAccumulateResourcesErrors(t *testing.T) {
|
func TestAccumulateResourcesErrors(t *testing.T) {
|
||||||
type testcase struct {
|
type testcase struct {
|
||||||
name string
|
name string
|
||||||
resource string
|
resource string
|
||||||
// regex error message that is output when kustomize tries to
|
isAbsolute bool
|
||||||
// accumulate resource as file and dir, respectively
|
files map[string]string
|
||||||
|
// errFile, errDir are regex for the expected error message output
|
||||||
|
// when kustomize tries to accumulate resource as file and dir,
|
||||||
|
// respectively. The test substitutes occurrences of "%s" in the
|
||||||
|
// error strings with the absolute path where kustomize looks for it.
|
||||||
errFile, errDir string
|
errFile, errDir string
|
||||||
}
|
}
|
||||||
|
populateAbsolutePaths := func(tc testcase, dir string) testcase {
|
||||||
|
filePaths := make(map[string]string, len(tc.files)+1)
|
||||||
|
for file, content := range tc.files {
|
||||||
|
filePaths[filepath.Join(dir, file)] = content
|
||||||
|
}
|
||||||
|
resourcePath := filepath.Join(dir, tc.resource)
|
||||||
|
if tc.isAbsolute {
|
||||||
|
tc.resource = resourcePath
|
||||||
|
}
|
||||||
|
filePaths[filepath.Join(dir, "kustomization.yaml")] = fmt.Sprintf(`
|
||||||
|
resources:
|
||||||
|
- %s
|
||||||
|
`, tc.resource)
|
||||||
|
tc.files = filePaths
|
||||||
|
regPath := regexp.QuoteMeta(resourcePath)
|
||||||
|
tc.errFile = strings.ReplaceAll(tc.errFile, "%s", regPath)
|
||||||
|
tc.errDir = strings.ReplaceAll(tc.errDir, "%s", regPath)
|
||||||
|
return tc
|
||||||
|
}
|
||||||
buildError := func(tc testcase) string {
|
buildError := func(tc testcase) string {
|
||||||
const (
|
const (
|
||||||
prefix = "accumulating resources"
|
prefix = "accumulating resources"
|
||||||
@@ -196,39 +221,89 @@ func TestAccumulateResourcesErrors(t *testing.T) {
|
|||||||
for _, test := range []testcase{
|
for _, test := range []testcase{
|
||||||
{
|
{
|
||||||
name: "remote file not considered repo",
|
name: "remote file not considered repo",
|
||||||
// This url is too short to be considered a remote repo.
|
// The example.com second-level domain is reserved and
|
||||||
resource: "https://raw.githubusercontent.com/kustomize",
|
// safe to access, see RFC 2606.
|
||||||
// It is acceptable that the error for a remote file-like reference
|
resource: "https://example.com/segments-too-few-to-be-repo",
|
||||||
// (that is not long enough to be considered a repo) does not
|
// It's acceptable for the error output of a remote file-like
|
||||||
// indicate said reference is not a local directory.
|
// resource to not indicate the resource's status as a
|
||||||
// Though it is possible for the remote file-like reference to be
|
// local directory. Though it is possible for a remote file-like
|
||||||
// a local directory, it is very unlikely.
|
// resource to be a local directory, it is very unlikely.
|
||||||
errFile: `HTTP Error: status code 400 \(Bad Request\)\z`,
|
errFile: `HTTP Error: status code 404 \(Not Found\)\z`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "remote file qualifies as repo",
|
name: "remote file qualifies as repo",
|
||||||
resource: "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/kustomize/v5.0.0/examples/helloWorld/configMap",
|
resource: "https://example.com/long/enough/to/have/org/and/repo",
|
||||||
// TODO(4788): This error message is technically wrong. Just
|
// TODO(4788): This error message is technically wrong. Just
|
||||||
// because we fail to GET a reference does not mean the reference is
|
// because we fail to GET a resource does not mean the resource is
|
||||||
// not a remote file. We should return the GET status code instead.
|
// not a remote file. We should return the GET status code as well.
|
||||||
errFile: "URL is a git repository",
|
errFile: "URL is a git repository",
|
||||||
errDir: `failed to run \S+/git fetch --depth=1 .+`,
|
errDir: `failed to run \S+/git fetch --depth=1 .+`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "local file qualifies as repo",
|
||||||
|
// The .example top level domain is reserved for example purposes,
|
||||||
|
// see RFC 2606.
|
||||||
|
resource: "package@v1.28.0.example/configs/base",
|
||||||
|
errFile: `evalsymlink failure on '%s' .+`,
|
||||||
|
errDir: `failed to run \S+/git fetch --depth=1 .+`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "relative path does not exist",
|
||||||
|
resource: "file-or-directory",
|
||||||
|
errFile: `evalsymlink failure on '%s' .+`,
|
||||||
|
errDir: `must build at directory: not a valid directory: evalsymlink failure .+`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "absolute path does not exist",
|
||||||
|
resource: "file-or-directory",
|
||||||
|
isAbsolute: true,
|
||||||
|
errFile: `evalsymlink failure on '%s' .+`,
|
||||||
|
errDir: `new root '%s' cannot be absolute`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "relative file violates restrictions",
|
||||||
|
resource: "../base/resource.yaml",
|
||||||
|
files: map[string]string{
|
||||||
|
"../base/resource.yaml": validResource,
|
||||||
|
},
|
||||||
|
errFile: "security; file '%s' is not in or below .+",
|
||||||
|
// TODO(4348): Over-inclusion of directory error message when we
|
||||||
|
// know resource is file.
|
||||||
|
errDir: "must build at directory: '%s': file is not directory",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "absolute file violates restrictions",
|
||||||
|
resource: "../base/resource.yaml",
|
||||||
|
isAbsolute: true,
|
||||||
|
files: map[string]string{
|
||||||
|
"../base/resource.yaml": validResource,
|
||||||
|
},
|
||||||
|
errFile: "security; file '%s' is not in or below .+",
|
||||||
|
// TODO(4348): Over-inclusion of directory error message when we
|
||||||
|
// know resource is file.
|
||||||
|
errDir: `new root '%s' cannot be absolute`,
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
// should use real file system to indicate that we are creating
|
// Should use real file system to indicate that we are creating
|
||||||
// new temporary directories on disk when we attempt to fetch repos
|
// new temporary directories on disk when we attempt to fetch repos.
|
||||||
fSys, tmpDir := kusttest_test.CreateKustDir(t, fmt.Sprintf(`
|
fs, tmpDir := kusttest_test.Setup(t)
|
||||||
resources:
|
root := tmpDir.Join("root")
|
||||||
- %s
|
require.NoError(t, fs.Mkdir(root))
|
||||||
`, test.resource))
|
|
||||||
|
test = populateAbsolutePaths(test, root)
|
||||||
|
for file, content := range test.files {
|
||||||
|
dir := filepath.Dir(file)
|
||||||
|
require.NoError(t, fs.MkdirAll(dir))
|
||||||
|
require.NoError(t, fs.WriteFile(file, []byte(content)))
|
||||||
|
}
|
||||||
|
|
||||||
b := krusty.MakeKustomizer(krusty.MakeDefaultOptions())
|
b := krusty.MakeKustomizer(krusty.MakeDefaultOptions())
|
||||||
_, err := b.Run(fSys, tmpDir.String())
|
_, err := b.Run(fs, root)
|
||||||
require.Regexp(t, buildError(test), err.Error())
|
require.Regexp(t, buildError(test), err.Error())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// TODO(annasong): add tests that check accumulateResources errors for
|
// TODO(annasong): add tests that check accumulateResources errors for
|
||||||
// - local files
|
|
||||||
// - repos
|
// - repos
|
||||||
// - local directories
|
// - local directories
|
||||||
// - files that yield malformed yaml errors
|
// - files that yield malformed yaml errors
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ func TestIsRemoteFile(t *testing.T) {
|
|||||||
"https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/helloWorld/configMap.yaml",
|
"https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/helloWorld/configMap.yaml",
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
"malformed https": {
|
||||||
|
// TODO(annasong): Maybe we want to fix this. Needs more research.
|
||||||
|
"https:/raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/helloWorld/configMap.yaml",
|
||||||
|
true,
|
||||||
|
},
|
||||||
"https dir": {
|
"https dir": {
|
||||||
"https://github.com/kubernetes-sigs/kustomize//examples/helloWorld/",
|
"https://github.com/kubernetes-sigs/kustomize//examples/helloWorld/",
|
||||||
true,
|
true,
|
||||||
@@ -201,23 +206,44 @@ func TestNewEmptyLoader(t *testing.T) {
|
|||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewLoaderHTTP(t *testing.T) {
|
func TestNewRemoteLoaderDoesNotExist(t *testing.T) {
|
||||||
t.Run("doesn't exist", func(t *testing.T) {
|
_, err := makeLoader().New("https://example.com/org/repo")
|
||||||
_, err := makeLoader().New("https://google.com/project")
|
require.ErrorContains(t, err, "fetch")
|
||||||
require.Error(t, err)
|
}
|
||||||
})
|
|
||||||
// Though it is unlikely and we do not weigh this use case in our designs,
|
func TestLoaderLocalScheme(t *testing.T) {
|
||||||
// it is possible for a reference that is considered a remote file to
|
// It is unlikely but possible for a reference with a url scheme to
|
||||||
// actually be a directory
|
// actually refer to a local file or directory.
|
||||||
t.Run("exists", func(t *testing.T) {
|
t.Run("file", func(t *testing.T) {
|
||||||
const remoteFileLikeRoot = "https://domain"
|
|
||||||
require.True(t, IsRemoteFile(remoteFileLikeRoot))
|
|
||||||
fSys, dir := setupOnDisk(t)
|
fSys, dir := setupOnDisk(t)
|
||||||
require.NoError(t, fSys.MkdirAll(dir.Join("https:/domain")))
|
parts := []string{
|
||||||
|
"ssh:",
|
||||||
|
"resource.yaml",
|
||||||
|
}
|
||||||
|
require.NoError(t, fSys.Mkdir(dir.Join(parts[0])))
|
||||||
|
const content = "resource config"
|
||||||
|
require.NoError(t, fSys.WriteFile(
|
||||||
|
dir.Join(filepath.Join(parts...)),
|
||||||
|
[]byte(content),
|
||||||
|
))
|
||||||
|
actualContent, err := newLoaderOrDie(RestrictionRootOnly,
|
||||||
|
fSys,
|
||||||
|
dir.String(),
|
||||||
|
).Load(strings.Join(parts, "//"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, content, string(actualContent))
|
||||||
|
})
|
||||||
|
t.Run("directory", func(t *testing.T) {
|
||||||
|
fSys, dir := setupOnDisk(t)
|
||||||
|
parts := []string{
|
||||||
|
"https:",
|
||||||
|
"root",
|
||||||
|
}
|
||||||
|
require.NoError(t, fSys.MkdirAll(dir.Join(filepath.Join(parts...))))
|
||||||
ldr, err := newLoaderOrDie(RestrictionRootOnly,
|
ldr, err := newLoaderOrDie(RestrictionRootOnly,
|
||||||
fSys,
|
fSys,
|
||||||
dir.String(),
|
dir.String(),
|
||||||
).New(remoteFileLikeRoot)
|
).New(strings.Join(parts, "//"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Empty(t, ldr.Repo())
|
require.Empty(t, ldr.Repo())
|
||||||
})
|
})
|
||||||
@@ -635,6 +661,8 @@ func TestLoaderHTTP(t *testing.T) {
|
|||||||
|
|
||||||
// setupOnDisk sets up a file system on disk and directory that is cleaned after
|
// setupOnDisk sets up a file system on disk and directory that is cleaned after
|
||||||
// test completion.
|
// test completion.
|
||||||
|
// TODO(annasong): Move all loader tests that require real file system into
|
||||||
|
// api/krusty.
|
||||||
func setupOnDisk(t *testing.T) (filesys.FileSystem, filesys.ConfirmedDir) {
|
func setupOnDisk(t *testing.T) (filesys.FileSystem, filesys.ConfirmedDir) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
|||||||
@@ -11,19 +11,27 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Setup sets up a file system on disk and directory that is cleaned after
|
||||||
|
// test completion.
|
||||||
|
func Setup(t *testing.T) (filesys.FileSystem, filesys.ConfirmedDir) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
fSys := filesys.MakeFsOnDisk()
|
||||||
|
dir, err := filesys.NewTmpConfirmedDir()
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
_ = fSys.RemoveAll(dir.String())
|
||||||
|
})
|
||||||
|
return fSys, dir
|
||||||
|
}
|
||||||
|
|
||||||
// CreateKustDir creates a file system on disk and a new directory
|
// CreateKustDir creates a file system on disk and a new directory
|
||||||
// that holds a kustomization file with content. The directory is removed on
|
// that holds a kustomization file with content. The directory is removed on
|
||||||
// test completion.
|
// test completion.
|
||||||
func CreateKustDir(t *testing.T, content string) (filesys.FileSystem, filesys.ConfirmedDir) {
|
func CreateKustDir(t *testing.T, content string) (filesys.FileSystem, filesys.ConfirmedDir) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
fSys := filesys.MakeFsOnDisk()
|
fSys, tmpDir := Setup(t)
|
||||||
tmpDir, err := filesys.NewTmpConfirmedDir()
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(content)))
|
require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(content)))
|
||||||
|
|
||||||
t.Cleanup(func() {
|
|
||||||
require.NoError(t, fSys.RemoveAll(tmpDir.String()))
|
|
||||||
})
|
|
||||||
return fSys, tmpDir
|
return fSys, tmpDir
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user