github.com/SamarSidharth/kpt@v0.0.0-20231122062228-c7d747ae3ace/internal/pkg/pkg_test.go (about) 1 // Copyright 2020 The kpt Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package pkg 16 17 import ( 18 "fmt" 19 "os" 20 "path/filepath" 21 "runtime" 22 "sort" 23 "testing" 24 25 "github.com/GoogleContainerTools/kpt/internal/testutil/pkgbuilder" 26 "github.com/GoogleContainerTools/kpt/internal/util/pathutil" 27 kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" 28 "github.com/stretchr/testify/assert" 29 "sigs.k8s.io/kustomize/kyaml/filesys" 30 ) 31 32 func TestNewPkg(t *testing.T) { 33 // this test creates a folders with structure 34 // foo 35 // └── bar 36 // └── baz 37 var tests = []struct { 38 name string 39 workingDir string 40 inputPath string 41 displayPath string 42 }{ 43 { 44 name: "invoked from working directory foo on path .", 45 workingDir: "foo", 46 inputPath: ".", 47 displayPath: "foo", 48 }, 49 { 50 name: "invoked from working directory foo/bar on path ../", 51 workingDir: "foo/bar", 52 inputPath: "../", 53 displayPath: "foo", 54 }, 55 { 56 name: "invoked from working directory foo on nested package baz", 57 workingDir: "foo", 58 inputPath: "./bar/baz", 59 displayPath: "baz", 60 }, 61 { 62 name: "invoked from working directory foo/bar on nested package baz", 63 workingDir: "foo/bar", 64 inputPath: "../../foo/bar/baz", 65 displayPath: "baz", 66 }, 67 { 68 name: "invoked from working directory baz on ancestor package foo", 69 workingDir: "foo/bar/baz", 70 inputPath: "../../", 71 displayPath: "foo", 72 }, 73 } 74 for i := range tests { 75 test := tests[i] 76 t.Run(test.name, func(t *testing.T) { 77 dir := t.TempDir() 78 err := os.MkdirAll(filepath.Join(dir, "foo", "bar", "baz"), 0700) 79 assert.NoError(t, err) 80 revert := Chdir(t, filepath.Join(dir, test.workingDir)) 81 defer revert() 82 absInputPath, _, err := pathutil.ResolveAbsAndRelPaths(test.inputPath) 83 assert.NoError(t, err) 84 p, err := New(filesys.FileSystemOrOnDisk{}, absInputPath) 85 assert.NoError(t, err) 86 assert.Equal(t, test.displayPath, string(p.DisplayPath)) 87 }) 88 } 89 } 90 91 func TestAdjustDisplayPathForSubpkg(t *testing.T) { 92 // this test creates a folders with structure 93 // rootPkgParentDir 94 // └── rootPkg 95 // └── subPkg 96 // └── nestedPkg 97 var tests = []struct { 98 name string 99 workingDir string 100 pkgPath string 101 subPkgPath string 102 rootPkgParentDirPath string 103 displayPath string 104 }{ 105 { 106 name: "display path of subPkg should include rootPkg", 107 workingDir: "rootPkg", 108 pkgPath: ".", 109 subPkgPath: "./subPkg", 110 displayPath: "rootPkg/subPkg", 111 }, 112 { 113 name: "display path of nestedPkg should include rootPkg/subPkg", 114 workingDir: "rootPkg", 115 pkgPath: ".", 116 subPkgPath: "./subPkg/nestedPkg", 117 displayPath: "rootPkg/subPkg/nestedPkg", 118 }, 119 { 120 name: "display path of subPkg should include rootPkg independent of workingDir", 121 workingDir: "rootPkg/subPkg", 122 pkgPath: "../", 123 subPkgPath: "../subPkg", 124 displayPath: "rootPkg/subPkg", 125 }, 126 { 127 name: "display path of nestedPkg should include rootPkg independent of workingDir 1", 128 workingDir: "rootPkg/subPkg/nestedPkg", 129 pkgPath: "../../", 130 subPkgPath: "../../subPkg/nestedPkg", 131 displayPath: "rootPkg/subPkg/nestedPkg", 132 }, 133 { 134 name: "display path of nestedPkg should include rootPkg independent of workingDir 2", 135 workingDir: "rootPkg", 136 rootPkgParentDirPath: "../", 137 pkgPath: "./subPkg", 138 subPkgPath: "./subPkg/nestedPkg", 139 displayPath: "rootPkg/subPkg/nestedPkg", 140 }, 141 { 142 name: "display path of nestedPkg should include rootPkg independent of workingDir 3", 143 workingDir: "rootPkg/subPkg", 144 rootPkgParentDirPath: "../../", 145 pkgPath: "../subPkg", 146 subPkgPath: "../subPkg/nestedPkg", 147 displayPath: "rootPkg/subPkg/nestedPkg", 148 }, 149 { 150 name: "display path of nestedPkg should include rootPkg independent of workingDir 4", 151 workingDir: "rootPkg/subPkg/nestedPkg", 152 rootPkgParentDirPath: "../../../", 153 pkgPath: "../../subPkg", 154 subPkgPath: "../../subPkg/nestedPkg", 155 displayPath: "rootPkg/subPkg/nestedPkg", 156 }, 157 } 158 for i := range tests { 159 test := tests[i] 160 t.Run(test.name, func(t *testing.T) { 161 dir := t.TempDir() 162 err := os.MkdirAll(filepath.Join(dir, "rootPkgParentDir", "rootPkg", "subPkg", "nestedPkg"), 0700) 163 assert.NoError(t, err) 164 revert := Chdir(t, filepath.Join(dir, "rootPkgParentDir", test.workingDir)) 165 defer revert() 166 absPkgPath, _, err := pathutil.ResolveAbsAndRelPaths(test.pkgPath) 167 assert.NoError(t, err) 168 parent, err := New(filesys.FileSystemOrOnDisk{}, absPkgPath) 169 assert.NoError(t, err) 170 if test.rootPkgParentDirPath != "" { 171 absRootPkgPath, _, err := pathutil.ResolveAbsAndRelPaths(test.rootPkgParentDirPath) 172 assert.NoError(t, err) 173 rootPkg, err := New(filesys.FileSystemOrOnDisk{}, absRootPkgPath) 174 assert.NoError(t, err) 175 parent.rootPkgParentDirPath = string(rootPkg.UniquePath) 176 } 177 absSubPkgPath, _, err := pathutil.ResolveAbsAndRelPaths(test.subPkgPath) 178 assert.NoError(t, err) 179 subPkg, err := New(filesys.FileSystemOrOnDisk{}, absSubPkgPath) 180 assert.NoError(t, err) 181 err = parent.adjustDisplayPathForSubpkg(subPkg) 182 assert.NoError(t, err) 183 assert.Equal(t, test.displayPath, string(subPkg.DisplayPath)) 184 }) 185 } 186 } 187 188 func TestDirectSubpackages(t *testing.T) { 189 testCases := map[string]struct { 190 pkg *pkgbuilder.RootPkg 191 expected []string 192 }{ 193 "includes remote subpackages": { 194 pkg: pkgbuilder.NewRootPkg(). 195 WithResource(pkgbuilder.DeploymentResource). 196 WithSubPackages( 197 pkgbuilder.NewSubPkg("foo"). 198 WithKptfile( 199 pkgbuilder.NewKptfile(). 200 WithUpstream("github.com/GoogleContainerTools/kpt", 201 "/", "main", string(kptfilev1.ResourceMerge)), 202 ). 203 WithResource(pkgbuilder.ConfigMapResource), 204 ), 205 expected: []string{ 206 "foo", 207 }, 208 }, 209 "includes local subpackages": { 210 pkg: pkgbuilder.NewRootPkg(). 211 WithResource(pkgbuilder.DeploymentResource). 212 WithSubPackages( 213 pkgbuilder.NewSubPkg("foo"). 214 WithKptfile(). 215 WithResource(pkgbuilder.ConfigMapResource), 216 ), 217 expected: []string{ 218 "foo", 219 }, 220 }, 221 "does not include root package": { 222 pkg: pkgbuilder.NewRootPkg(). 223 WithKptfile(). 224 WithResource(pkgbuilder.DeploymentResource), 225 expected: []string{}, 226 }, 227 "does not include nested remote subpackages": { 228 pkg: pkgbuilder.NewRootPkg(). 229 WithResource(pkgbuilder.DeploymentResource). 230 WithSubPackages( 231 pkgbuilder.NewSubPkg("foo"). 232 WithKptfile( 233 pkgbuilder.NewKptfile(). 234 WithUpstream("github.com/GoogleContainerTools/kpt", 235 "/", "main", string(kptfilev1.ResourceMerge)), 236 ). 237 WithResource(pkgbuilder.ConfigMapResource). 238 WithSubPackages( 239 pkgbuilder.NewSubPkg("bar"). 240 WithSubPackages( 241 pkgbuilder.NewSubPkg("zork"). 242 WithKptfile( 243 pkgbuilder.NewKptfile(). 244 WithUpstream("github.com/GoogleContainerTools/kpt", 245 "/", "main", string(kptfilev1.ResourceMerge)), 246 ). 247 WithResource(pkgbuilder.ConfigMapResource), 248 ), 249 ), 250 ), 251 expected: []string{ 252 "foo", 253 }, 254 }, 255 "does not include nested local subpackages": { 256 pkg: pkgbuilder.NewRootPkg(). 257 WithResource(pkgbuilder.DeploymentResource). 258 WithSubPackages( 259 pkgbuilder.NewSubPkg("foo"). 260 WithKptfile(). 261 WithResource(pkgbuilder.ConfigMapResource). 262 WithSubPackages( 263 pkgbuilder.NewSubPkg("zork"). 264 WithKptfile(). 265 WithResource(pkgbuilder.ConfigMapResource), 266 ), 267 pkgbuilder.NewSubPkg("subpkg"). 268 WithKptfile(), 269 ), 270 expected: []string{ 271 "foo", 272 "subpkg", 273 }, 274 }, 275 } 276 277 for tn, tc := range testCases { 278 t.Run(tn, func(t *testing.T) { 279 pkgPath := tc.pkg.ExpandPkg(t, nil) 280 defer os.RemoveAll(pkgPath) 281 absPkgPath, _, err := pathutil.ResolveAbsAndRelPaths(pkgPath) 282 if !assert.NoError(t, err) { 283 t.FailNow() 284 } 285 p, err := New(filesys.FileSystemOrOnDisk{}, absPkgPath) 286 if !assert.NoError(t, err) { 287 t.FailNow() 288 } 289 subPkgs, err := p.DirectSubpackages() 290 if !assert.NoError(t, err) { 291 t.FailNow() 292 } 293 294 relPaths := []string{} 295 for _, subPkg := range subPkgs { 296 fullPath := subPkg.UniquePath.String() 297 relPath, err := filepath.Rel(pkgPath, fullPath) 298 if !assert.NoError(t, err) { 299 t.FailNow() 300 } 301 relPaths = append(relPaths, relPath) 302 } 303 sort.Strings(relPaths) 304 305 assert.Equal(t, tc.expected, relPaths) 306 }) 307 } 308 } 309 310 //nolint:scopelint 311 func TestSubpackages(t *testing.T) { 312 type variants struct { 313 matcher []SubpackageMatcher 314 recursive []bool 315 expected []string 316 } 317 318 testCases := map[string]struct { 319 pkg *pkgbuilder.RootPkg 320 cases []variants 321 }{ 322 "remote and local nested subpackages": { 323 // root 324 // ├── remote-sub1 (remote) 325 // │ ├── Kptfile 326 // │ └── directory 327 // │ └── remote-sub3 (remote) 328 // │ └── Kptfile 329 // └── local-sub1 (local) 330 // ├── Kptfile 331 // ├── directory 332 // │ └── remote-sub3 (remote) 333 // │ └── Kptfile 334 // └── local-sub2 (local) 335 // └── Kptfile 336 pkg: pkgbuilder.NewRootPkg(). 337 WithSubPackages( 338 pkgbuilder.NewSubPkg("remote-sub1"). 339 WithKptfile( 340 pkgbuilder.NewKptfile(). 341 WithUpstream("github.com/GoogleContainerTools/kpt", 342 "/", "main", string(kptfilev1.ResourceMerge)), 343 ). 344 WithSubPackages( 345 pkgbuilder.NewSubPkg("directory"). 346 WithSubPackages( 347 pkgbuilder.NewSubPkg("remote-sub3"). 348 WithKptfile( 349 pkgbuilder.NewKptfile(). 350 WithUpstream("github.com/GoogleContainerTools/kpt", 351 "/", "main", string(kptfilev1.ResourceMerge)), 352 ), 353 ), 354 ), 355 pkgbuilder.NewSubPkg("local-sub1"). 356 WithKptfile(). 357 WithSubPackages( 358 pkgbuilder.NewSubPkg("directory"). 359 WithSubPackages( 360 pkgbuilder.NewSubPkg("remote-sub3"). 361 WithKptfile( 362 pkgbuilder.NewKptfile(). 363 WithUpstream("github.com/GoogleContainerTools/kpt", 364 "/", "main", string(kptfilev1.ResourceMerge)), 365 ), 366 ), 367 pkgbuilder.NewSubPkg("local-sub2"). 368 WithKptfile(), 369 ), 370 ), 371 cases: []variants{ 372 { 373 matcher: []SubpackageMatcher{All}, 374 recursive: []bool{true}, 375 expected: []string{ 376 "local-sub1", 377 "local-sub1/directory/remote-sub3", 378 "local-sub1/local-sub2", 379 "remote-sub1", 380 "remote-sub1/directory/remote-sub3", 381 }, 382 }, 383 { 384 matcher: []SubpackageMatcher{All}, 385 recursive: []bool{false}, 386 expected: []string{ 387 "local-sub1", 388 "remote-sub1", 389 }, 390 }, 391 { 392 matcher: []SubpackageMatcher{Remote}, 393 recursive: []bool{true}, 394 expected: []string{ 395 "local-sub1/directory/remote-sub3", 396 "remote-sub1", 397 "remote-sub1/directory/remote-sub3", 398 }, 399 }, 400 { 401 matcher: []SubpackageMatcher{Remote}, 402 recursive: []bool{false}, 403 expected: []string{ 404 "remote-sub1", 405 }, 406 }, 407 { 408 matcher: []SubpackageMatcher{Local}, 409 recursive: []bool{true}, 410 expected: []string{ 411 "local-sub1", 412 "local-sub1/local-sub2", 413 }, 414 }, 415 { 416 matcher: []SubpackageMatcher{Local}, 417 recursive: []bool{false}, 418 expected: []string{ 419 "local-sub1", 420 }, 421 }, 422 { 423 matcher: []SubpackageMatcher{None}, 424 recursive: []bool{false}, 425 expected: []string{}, 426 }, 427 { 428 matcher: []SubpackageMatcher{None}, 429 recursive: []bool{true}, 430 expected: []string{}, 431 }, 432 }, 433 }, 434 "no subpackages": { 435 // root 436 // └── Kptfile 437 pkg: pkgbuilder.NewRootPkg(). 438 WithKptfile(), 439 cases: []variants{ 440 { 441 matcher: []SubpackageMatcher{All, Local, Remote, None}, 442 recursive: []bool{true, false}, 443 expected: []string{}, 444 }, 445 }, 446 }, 447 "no Kptfile in root": { 448 // root 449 pkg: pkgbuilder.NewRootPkg(), 450 cases: []variants{ 451 { 452 matcher: []SubpackageMatcher{All, Local, Remote, None}, 453 recursive: []bool{true, false}, 454 expected: []string{}, 455 }, 456 }, 457 }, 458 } 459 460 for tn, tc := range testCases { 461 t.Run(tn, func(t *testing.T) { 462 pkgPath := tc.pkg.ExpandPkg(t, nil) 463 defer func() { 464 _ = os.RemoveAll(pkgPath) 465 }() 466 467 for _, v := range tc.cases { 468 for _, matcher := range v.matcher { 469 for _, recursive := range v.recursive { 470 t.Run(fmt.Sprintf("matcher:%s-recursive:%t", matcher, recursive), func(t *testing.T) { 471 paths, err := Subpackages(filesys.FileSystemOrOnDisk{}, pkgPath, matcher, recursive) 472 if !assert.NoError(t, err) { 473 t.FailNow() 474 } 475 476 sort.Strings(paths) 477 sort.Strings(v.expected) 478 479 assert.Equal(t, v.expected, paths) 480 }) 481 } 482 } 483 } 484 }) 485 } 486 } 487 488 func TestSubpackages_symlinks(t *testing.T) { 489 if runtime.GOOS == "windows" { 490 t.SkipNow() 491 } 492 493 pkg := pkgbuilder.NewRootPkg(). 494 WithResource(pkgbuilder.DeploymentResource). 495 WithSubPackages( 496 pkgbuilder.NewSubPkg("subpkg"). 497 WithKptfile(). 498 WithResource(pkgbuilder.ConfigMapResource), 499 ) 500 501 pkgPath := pkg.ExpandPkg(t, nil) 502 defer func() { 503 _ = os.RemoveAll(pkgPath) 504 }() 505 506 symLinkOld := filepath.Join(pkgPath, "subpkg") 507 symLinkNew := filepath.Join(pkgPath, "symlink-subpkg") 508 509 err := os.Symlink(symLinkOld, symLinkNew) 510 if !assert.NoError(t, err) { 511 t.FailNow() 512 } 513 514 paths, err := Subpackages(filesys.FileSystemOrOnDisk{}, pkgPath, All, true) 515 if !assert.NoError(t, err) { 516 t.FailNow() 517 } 518 assert.Equal(t, []string{"subpkg"}, paths) 519 } 520 521 func Chdir(t *testing.T, path string) func() { 522 cwd, err := os.Getwd() 523 if !assert.NoError(t, err) { 524 t.FailNow() 525 } 526 revertFunc := func() { 527 if err := os.Chdir(cwd); err != nil { 528 panic(err) 529 } 530 } 531 err = os.Chdir(path) 532 if !assert.NoError(t, err) { 533 defer revertFunc() 534 t.FailNow() 535 } 536 return revertFunc 537 }