Files
ConfigKit/internal/engine/import_selection_test.go

258 lines
9.3 KiB
Go

package engine
import (
"io/fs"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
func TestSelectNamedImportsHandlesPartialAndEmptySelections(t *testing.T) {
t.Parallel()
root := t.TempDir()
if err := os.WriteFile(filepath.Join(root, "present.yaml"), []byte("value: present\n"), 0o600); err != nil {
t.Fatal(err)
}
access, err := openHostAccess(root)
if err != nil {
t.Fatal(err)
}
defer access.close()
specs, diagnostics := parseImportSpecsYAML(t, " - path: [missing.yaml, present.yaml]\n")
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
selection, diagnostics := selectNamedImportCandidates(access, root, specs[0], resolvedImportPolicy{})
if len(diagnostics) != 0 {
t.Fatalf("optional partial selection diagnostics = %#v", diagnostics)
}
if selection.outcome != importSelectionHasCandidates || len(selection.candidates) != 1 || filepath.Base(selection.candidates[0].path) != "present.yaml" {
t.Fatalf("partial selection = %#v", selection)
}
requiredSpecs, diagnostics := parseImportSpecsYAML(t, " - path: [missing.yaml, present.yaml]\n required: true\n")
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
_, diagnostics = selectNamedImportCandidates(access, root, requiredSpecs[0], resolvedImportPolicy{required: true})
if len(diagnostics) != 1 || diagnostics[0].Code != CodeImportMissing {
t.Fatalf("required partial selection diagnostics = %#v", diagnostics)
}
emptySpecs, diagnostics := parseImportSpecsYAML(t, " - path: []\n required: true\n")
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
empty, diagnostics := selectNamedImportCandidates(access, root, emptySpecs[0], resolvedImportPolicy{required: true})
if len(diagnostics) != 0 || empty.outcome != importSelectionNone || len(empty.candidates) != 0 {
t.Fatalf("required empty path selection, diagnostics = %#v, %#v", empty, diagnostics)
}
}
func TestSelectNamedImportsChecksRequiredTargetsBeforeExclusions(t *testing.T) {
t.Parallel()
root := t.TempDir()
access, err := openHostAccess(root)
if err != nil {
t.Fatal(err)
}
defer access.close()
specs, diagnostics := parseImportSpecsYAML(t, " - path: missing.yaml\n required: true\n exclude: '*.yaml'\n")
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
policy, diagnostics := resolveImportPolicy(specs[0], importDefaults{})
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
_, diagnostics = selectNamedImportCandidates(access, root, specs[0], policy)
if len(diagnostics) != 1 || diagnostics[0].Code != CodeImportMissing || diagnostics[0].Path.String() != "/configkit/imports/0/path" {
t.Fatalf("required excluded missing target diagnostics = %#v", diagnostics)
}
}
func TestSelectNamedImportsDeduplicatesLexicalPathsButRetainsAliases(t *testing.T) {
t.Parallel()
root := t.TempDir()
if err := os.WriteFile(filepath.Join(root, "real.yaml"), []byte("value: real\n"), 0o600); err != nil {
t.Fatal(err)
}
if err := os.Symlink("real.yaml", filepath.Join(root, "alias.yaml")); err != nil {
t.Skipf("symlinks are unavailable: %v", err)
}
access, err := openHostAccess(root)
if err != nil {
t.Fatal(err)
}
defer access.close()
specs, diagnostics := parseImportSpecsYAML(t, " - path: [real.yaml, nested/../real.yaml, alias.yaml]\n")
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
selection, diagnostics := selectNamedImportCandidates(access, root, specs[0], resolvedImportPolicy{})
if len(diagnostics) != 0 {
t.Fatalf("selection diagnostics = %#v", diagnostics)
}
if len(selection.candidates) != 2 {
t.Fatalf("candidates = %#v, want two alias spellings", selection.candidates)
}
if filepath.Base(selection.candidates[0].path) != "alias.yaml" || filepath.Base(selection.candidates[1].path) != "real.yaml" {
t.Fatalf("candidate order = %#v", selection.candidates)
}
}
func TestSelectNamedImportsDoesNotOpenExcludedContentOrApplySearchControls(t *testing.T) {
t.Parallel()
filesystem := &statOnlyImportFilesystem{files: map[string]bool{"secret.yaml": true, ".private.yaml": true}}
access := newNativeAccess(filesystem, ".", &namespaceToken{})
specs, diagnostics := parseImportSpecsYAML(t, " - path: secret.yaml\n required: true\n exclude: '*.yaml'\n")
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
policy, diagnostics := resolveImportPolicy(specs[0], importDefaults{})
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
selection, diagnostics := selectNamedImportCandidates(access, ".", specs[0], policy)
if len(diagnostics) != 0 || selection.outcome != importSelectionNone {
t.Fatalf("excluded selection, diagnostics = %#v, %#v", selection, diagnostics)
}
if filesystem.openCalls != 0 || filesystem.statCalls == 0 {
t.Fatalf("excluded target access = %d opens, %d stats", filesystem.openCalls, filesystem.statCalls)
}
private, diagnostics := parseImportSpecsYAML(t, " - path: .private.yaml\n")
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
hidden := false
privatePolicy, policyDiagnostics := resolveImportPolicy(private[0], importDefaults{hidden: &hidden})
if len(policyDiagnostics) != 0 || !privatePolicy.hidden {
t.Fatalf("path selector accepted search-only defaults: %#v, %#v", privatePolicy, policyDiagnostics)
}
selection, diagnostics = selectNamedImportCandidates(access, ".", private[0], privatePolicy)
if len(diagnostics) != 0 || len(selection.candidates) != 1 || selection.candidates[0].path != ".private.yaml" {
t.Fatalf("explicit hidden path was filtered: %#v, %#v", selection, diagnostics)
}
if filesystem.openCalls != 0 {
t.Fatalf("named selection opened content %d times", filesystem.openCalls)
}
}
func TestSelectNamedImportsChecksNormalizedPathsLexically(t *testing.T) {
t.Parallel()
filesystem := &statOnlyImportFilesystem{files: map[string]bool{"a.yaml": true, "z.yaml": true}}
access := newNativeAccess(filesystem, ".", &namespaceToken{})
specs, diagnostics := parseImportSpecsYAML(t, " - path: [z.yaml, a.yaml]\n")
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
selection, diagnostics := selectNamedImportCandidates(access, ".", specs[0], resolvedImportPolicy{})
if len(diagnostics) != 0 || len(selection.candidates) != 2 {
t.Fatalf("selection, diagnostics = %#v, %#v", selection, diagnostics)
}
if strings.Join(filesystem.statPaths, ",") != "a.yaml,a.yaml,z.yaml,z.yaml" {
t.Fatalf("target stat order = %#v", filesystem.statPaths)
}
}
func TestSelectNamedImportsDoesNotTreatInvalidTargetsAsAbsence(t *testing.T) {
t.Parallel()
root := t.TempDir()
if err := os.Mkdir(filepath.Join(root, "directory"), 0o700); err != nil {
t.Fatal(err)
}
outside := filepath.Join(t.TempDir(), "outside.yaml")
if err := os.WriteFile(outside, []byte("value: outside\n"), 0o600); err != nil {
t.Fatal(err)
}
if err := os.Symlink(outside, filepath.Join(root, "escape.yaml")); err != nil {
t.Skipf("symlinks are unavailable: %v", err)
}
access, err := openHostAccess(root)
if err != nil {
t.Fatal(err)
}
defer access.close()
for _, test := range []struct {
name, value string
code Code
}{
{name: "nonregular target", value: "directory", code: CodeSourceNotRegular},
{name: "outside symlink", value: "escape.yaml", code: CodeImportOutsideRoot},
} {
t.Run(test.name, func(t *testing.T) {
specs, diagnostics := parseImportSpecsYAML(t, " - path: "+test.value+"\n")
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
_, diagnostics = selectNamedImportCandidates(access, root, specs[0], resolvedImportPolicy{})
if len(diagnostics) != 1 || diagnostics[0].Code != test.code {
t.Fatalf("diagnostics = %#v, want %s", diagnostics, test.code)
}
})
}
}
func TestSelectNamedImportsDoesNotTreatPermissionErrorsAsAbsence(t *testing.T) {
t.Parallel()
filesystem := &statOnlyImportFilesystem{statErrors: map[string]error{"denied.yaml": fs.ErrPermission}}
access := newNativeAccess(filesystem, ".", &namespaceToken{})
specs, diagnostics := parseImportSpecsYAML(t, " - path: denied.yaml\n")
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
_, diagnostics = selectNamedImportCandidates(access, ".", specs[0], resolvedImportPolicy{})
if len(diagnostics) != 1 || diagnostics[0].Code != CodeImportInvalid {
t.Fatalf("optional permission failure diagnostics = %#v", diagnostics)
}
}
type statOnlyImportFilesystem struct {
files map[string]bool
statErrors map[string]error
openCalls int
statCalls int
statPaths []string
}
func (filesystem *statOnlyImportFilesystem) Open(name string) (fs.File, error) {
filesystem.openCalls++
return nil, fs.ErrPermission
}
func (filesystem *statOnlyImportFilesystem) Stat(name string) (fs.FileInfo, error) {
filesystem.statCalls++
filesystem.statPaths = append(filesystem.statPaths, name)
if err := filesystem.statErrors[name]; err != nil {
return nil, err
}
if !filesystem.files[name] {
return nil, fs.ErrNotExist
}
return importSelectionFileInfo{name: pathBaseForTest(name)}, nil
}
type importSelectionFileInfo struct{ name string }
func (info importSelectionFileInfo) Name() string { return info.name }
func (importSelectionFileInfo) Size() int64 { return 1 }
func (importSelectionFileInfo) Mode() fs.FileMode { return 0o600 }
func (importSelectionFileInfo) ModTime() time.Time { return time.Time{} }
func (importSelectionFileInfo) IsDir() bool { return false }
func (importSelectionFileInfo) Sys() any { return nil }
func pathBaseForTest(name string) string { return strings.TrimPrefix(name, "./") }