...

Source file src/sigs.k8s.io/kustomize/api/internal/localizer/locloader_test.go

Documentation: sigs.k8s.io/kustomize/api/internal/localizer

     1  // Copyright 2022 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package localizer_test
     5  
     6  import (
     7  	"bytes"
     8  	"log"
     9  	"os"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/require"
    13  	"sigs.k8s.io/kustomize/api/ifc"
    14  	. "sigs.k8s.io/kustomize/api/internal/localizer"
    15  	"sigs.k8s.io/kustomize/kyaml/filesys"
    16  )
    17  
    18  func checkNewLoader(req *require.Assertions, ldr *Loader, args *Args, target string, scope string, newDir string, fSys filesys.FileSystem) {
    19  	checkLoader(req, ldr, target)
    20  	checkArgs(req, args, target, scope, newDir, fSys)
    21  }
    22  
    23  func checkLoader(req *require.Assertions, ldr ifc.Loader, root string) {
    24  	req.Equal(root, ldr.Root())
    25  	req.Empty(ldr.Repo())
    26  }
    27  
    28  func checkArgs(req *require.Assertions, args *Args, target string, scope string, newDir string, fSys filesys.FileSystem) {
    29  	req.Equal(target, args.Target.String())
    30  	req.Equal(scope, args.Scope.String())
    31  	req.Equal(newDir, args.NewDir.String())
    32  	req.True(fSys.Exists(newDir))
    33  }
    34  
    35  func TestLocalLoadNewAndCleanup(t *testing.T) {
    36  	req := require.New(t)
    37  	fSys := makeMemoryFs(t)
    38  
    39  	var buf bytes.Buffer
    40  	log.SetOutput(&buf)
    41  	defer func() {
    42  		log.SetOutput(os.Stderr)
    43  	}()
    44  	// typical setup
    45  	ldr, args, err := NewLoader("a", "/", "/newDir", fSys)
    46  	req.NoError(err)
    47  	checkNewLoader(req, ldr, &args, "/a", "/", "/newDir", fSys)
    48  
    49  	fSysCopy := makeMemoryFs(t)
    50  	req.NoError(fSysCopy.Mkdir("/newDir"))
    51  	req.Equal(fSysCopy, fSys)
    52  
    53  	// easy load directly in root
    54  	content, err := ldr.Load("pod.yaml")
    55  	req.NoError(err)
    56  	req.Equal([]byte(podConfiguration), content)
    57  
    58  	// typical sibling root reference
    59  	sibLdr, err := ldr.New("../alpha")
    60  	req.NoError(err)
    61  	checkLoader(req, sibLdr, "/alpha")
    62  
    63  	// only need to test once, since don't need to call Cleanup() on local target
    64  	req.NoError(sibLdr.Cleanup())
    65  	req.NoError(ldr.Cleanup())
    66  
    67  	// file system and buffer checks are also one-time
    68  	req.Equal(fSysCopy, fSys)
    69  	req.Empty(buf.String())
    70  }
    71  
    72  func TestNewLocLoaderDefaultForRootTarget(t *testing.T) {
    73  	cases := map[string]struct {
    74  		target string
    75  		scope  string
    76  	}{
    77  		"explicit": {
    78  			"/",
    79  			".",
    80  		},
    81  		"implicit": {
    82  			".",
    83  			"",
    84  		},
    85  	}
    86  	for name, params := range cases {
    87  		params := params
    88  		t.Run(name, func(t *testing.T) {
    89  			req := require.New(t)
    90  			fSys := makeMemoryFs(t)
    91  
    92  			ldr, args, err := NewLoader(params.target, params.scope, "", fSys)
    93  			req.NoError(err)
    94  			checkNewLoader(req, ldr, &args, "/", "/", "/"+DstPrefix, fSys)
    95  
    96  			// file in root, but nested
    97  			content, err := ldr.Load("a/pod.yaml")
    98  			req.NoError(err)
    99  			req.Equal([]byte(podConfiguration), content)
   100  
   101  			childLdr, err := ldr.New("a")
   102  			req.NoError(err)
   103  			checkLoader(req, childLdr, "/a")
   104  
   105  			// messy, uncleaned path
   106  			content, err = childLdr.Load("./../a/pod.yaml")
   107  			req.NoError(err)
   108  			req.Equal([]byte(podConfiguration), content)
   109  		})
   110  	}
   111  }
   112  
   113  func TestNewMultiple(t *testing.T) {
   114  	req := require.New(t)
   115  	fSys := makeMemoryFs(t)
   116  
   117  	// default destination for non-file system root target
   118  	// destination outside of scope
   119  	ldr, args, err := NewLoader("/alpha/beta", "/alpha", "", fSys)
   120  	req.NoError(err)
   121  	checkNewLoader(req, ldr, &args, "/alpha/beta", "/alpha", "/"+DstPrefix+"-beta", fSys)
   122  
   123  	// nested child root that isn't cleaned
   124  	descLdr, err := ldr.New("../beta/gamma/delta")
   125  	req.NoError(err)
   126  	checkLoader(req, descLdr, "/alpha/beta/gamma/delta")
   127  
   128  	// upwards traversal
   129  	higherLdr, err := descLdr.New("../../say")
   130  	req.NoError(err)
   131  	checkLoader(req, higherLdr, "/alpha/beta/say")
   132  }
   133  
   134  func makeWdFs(t *testing.T) map[string]filesys.FileSystem {
   135  	t.Helper()
   136  	req := require.New(t)
   137  
   138  	root := filesys.MakeEmptyDirInMemory()
   139  	req.NoError(root.MkdirAll("a/b/c/d/e"))
   140  
   141  	outer, err := root.Find("a")
   142  	req.NoError(err)
   143  	middle, err := root.Find("a/b/c")
   144  	req.NoError(err)
   145  
   146  	return map[string]filesys.FileSystem{
   147  		"a":     outer,
   148  		"a/b/c": middle,
   149  	}
   150  }
   151  
   152  func TestNewLocLoaderCwdNotRoot(t *testing.T) {
   153  	cases := map[string]struct {
   154  		wd     string
   155  		target string
   156  		scope  string
   157  		newDir string
   158  	}{
   159  		// target not immediate child of scope
   160  		"outer dir": {
   161  			"a",
   162  			"b/c/d/e",
   163  			"b/c",
   164  			"b/newDir",
   165  		},
   166  		"scope": {
   167  			"a/b/c",
   168  			"d/e",
   169  			".",
   170  			"d/e/newDir",
   171  		},
   172  	}
   173  
   174  	for name, test := range cases {
   175  		test := test
   176  		t.Run(name, func(t *testing.T) {
   177  			req := require.New(t)
   178  			fSys := makeWdFs(t)[test.wd]
   179  
   180  			ldr, args, err := NewLoader(test.target, test.scope, test.newDir, fSys)
   181  			req.NoError(err)
   182  			checkLoader(req, ldr, "a/b/c/d/e")
   183  
   184  			req.Equal("a/b/c/d/e", args.Target.String())
   185  			req.Equal("a/b/c", args.Scope.String())
   186  			req.Equal(test.wd+"/"+test.newDir, args.NewDir.String())
   187  			// memory file system can only find paths rooted at current node
   188  			req.True(fSys.Exists(test.newDir))
   189  		})
   190  	}
   191  }
   192  
   193  func TestNewLocLoaderFails(t *testing.T) {
   194  	cases := map[string]struct {
   195  		target string
   196  		scope  string
   197  		dest   string
   198  	}{
   199  		"non-existent target": {
   200  			"/b",
   201  			"/",
   202  			"/newDir",
   203  		},
   204  		"file target": {
   205  			"/a/pod.yaml",
   206  			"/",
   207  			"/newDir",
   208  		},
   209  		"inner scope": {
   210  			"/alpha",
   211  			"/alpha/beta",
   212  			"/newDir",
   213  		},
   214  		"side scope": {
   215  			"/alpha",
   216  			"/a",
   217  			"/newDir",
   218  		},
   219  		"existing dst": {
   220  			"/alpha",
   221  			"/",
   222  			"/a",
   223  		},
   224  	}
   225  	for name, params := range cases {
   226  		params := params
   227  		t.Run(name, func(t *testing.T) {
   228  			var buf bytes.Buffer
   229  			log.SetOutput(&buf)
   230  			defer func() {
   231  				log.SetOutput(os.Stderr)
   232  			}()
   233  
   234  			_, _, err := NewLoader(params.target, params.scope, params.dest, makeMemoryFs(t))
   235  			require.Error(t, err)
   236  			require.Empty(t, buf.String())
   237  		})
   238  	}
   239  }
   240  
   241  func TestNewFails(t *testing.T) {
   242  	req := require.New(t)
   243  	fSys := makeMemoryFs(t)
   244  
   245  	ldr, args, err := NewLoader("/alpha/beta/gamma", "alpha", "alpha/beta/gamma/newDir", fSys)
   246  	req.NoError(err)
   247  	checkNewLoader(req, ldr, &args, "/alpha/beta/gamma", "/alpha", "/alpha/beta/gamma/newDir", fSys)
   248  
   249  	cases := map[string]string{
   250  		"outside scope":     "../../../a",
   251  		"at dst":            "newDir",
   252  		"ancestor":          "../../beta",
   253  		"non-existent root": "delt",
   254  		"file":              "delta/deployment.yaml",
   255  	}
   256  	for name, root := range cases {
   257  		root := root
   258  		t.Run(name, func(t *testing.T) {
   259  			fSys := makeMemoryFs(t)
   260  
   261  			ldr, _, err := NewLoader("/alpha/beta/gamma", "alpha", "alpha/beta/gamma/newDir", fSys)
   262  			require.NoError(t, err)
   263  
   264  			_, err = ldr.New(root)
   265  			require.Error(t, err)
   266  		})
   267  	}
   268  }
   269  
   270  func TestLoadFails(t *testing.T) {
   271  	req := require.New(t)
   272  	fSys := makeMemoryFs(t)
   273  
   274  	ldr, args, err := NewLoader("./a/../a", "/a/../a", "/a/newDir", fSys)
   275  	req.NoError(err)
   276  	checkNewLoader(req, ldr, &args, "/a", "/a", "/a/newDir", fSys)
   277  
   278  	cases := map[string]string{
   279  		"absolute path":     "/a/pod.yaml",
   280  		"directory":         "b",
   281  		"non-existent file": "kubectl.yaml",
   282  		"file outside root": "../alpha/beta/gamma/delta/deployment.yaml",
   283  		"inside dst":        "newDir/pod.yaml",
   284  	}
   285  	for name, file := range cases {
   286  		file := file
   287  		t.Run(name, func(t *testing.T) {
   288  			req := require.New(t)
   289  			fSys := makeMemoryFs(t)
   290  
   291  			ldr, _, err := NewLoader("./a/../a", "/a/../a", "/a/newDir", fSys)
   292  			req.NoError(err)
   293  
   294  			req.NoError(fSys.WriteFile("/a/newDir/pod.yaml", []byte(podConfiguration)))
   295  
   296  			_, err = ldr.Load(file)
   297  			req.Error(err)
   298  		})
   299  	}
   300  }
   301  

View as plain text