github.com/wmuizelaar/kpt@v0.0.0-20221018115725-bd564717b2ed/internal/util/update/update_test.go (about)

     1  // Copyright 2019 Google LLC
     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 update_test
    16  
    17  import (
    18  	"fmt"
    19  	"os"
    20  	"path"
    21  	"path/filepath"
    22  	"reflect"
    23  	"testing"
    24  
    25  	"github.com/GoogleContainerTools/kpt/internal/pkg"
    26  	pkgtest "github.com/GoogleContainerTools/kpt/internal/pkg/testing"
    27  	"github.com/GoogleContainerTools/kpt/internal/printer/fake"
    28  	"github.com/GoogleContainerTools/kpt/internal/testutil"
    29  	"github.com/GoogleContainerTools/kpt/internal/testutil/pkgbuilder"
    30  	. "github.com/GoogleContainerTools/kpt/internal/util/update"
    31  	kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1"
    32  	"github.com/GoogleContainerTools/kpt/pkg/kptfile/kptfileutil"
    33  	"github.com/stretchr/testify/assert"
    34  	"sigs.k8s.io/kustomize/kyaml/copyutil"
    35  	"sigs.k8s.io/kustomize/kyaml/filesys"
    36  	"sigs.k8s.io/kustomize/kyaml/kio"
    37  	"sigs.k8s.io/kustomize/kyaml/kio/filters"
    38  )
    39  
    40  const (
    41  	kptRepo         = "github.com/GoogleContainerTools/kpt"
    42  	masterBranch    = "master"
    43  	testPackageName = "test-package"
    44  )
    45  
    46  func TestMain(m *testing.M) {
    47  	os.Exit(testutil.ConfigureTestKptCache(m))
    48  }
    49  
    50  // TestCommand_Run_noRefChanges updates a package without specifying a new ref.
    51  // - Get a package using  a branch ref
    52  // - Modify upstream with new content
    53  // - Update the local package to fetch the upstream content
    54  func TestCommand_Run_noRefChanges(t *testing.T) {
    55  	for i := range kptfilev1.UpdateStrategies {
    56  		strategy := kptfilev1.UpdateStrategies[i]
    57  		t.Run(string(strategy), func(t *testing.T) {
    58  			// Setup the test upstream and local packages
    59  			g := &testutil.TestSetupManager{
    60  				T: t,
    61  				ReposChanges: map[string][]testutil.Content{
    62  					testutil.Upstream: {
    63  						{
    64  							Data:   testutil.Dataset1,
    65  							Branch: masterBranch,
    66  						},
    67  						{
    68  							Data: testutil.Dataset2,
    69  						},
    70  					},
    71  				},
    72  			}
    73  			defer g.Clean()
    74  			if !g.Init() {
    75  				return
    76  			}
    77  			upstreamRepo := g.Repos[testutil.Upstream]
    78  			cmd := &Command{
    79  				Pkg:      pkgtest.CreatePkgOrFail(t, g.LocalWorkspace.FullPackagePath()),
    80  				Strategy: strategy,
    81  			}
    82  			// Update the local package
    83  			if !assert.NoError(t, cmd.Run(fake.CtxWithDefaultPrinter())) {
    84  				return
    85  			}
    86  
    87  			// Expect upstream repo to be cached
    88  			cachedGURs := cmd.GetCachedUpstreamRepos()
    89  			assert.Equal(t, 1, len(cachedGURs))
    90  			for _, gur := range cachedGURs {
    91  				assert.Equal(t, upstreamRepo.RepoDirectory, gur.URI)
    92  				// Expect two fetched refs
    93  				// 1 for upstream ref (master) and 1 for previous upstream lock
    94  				assert.ElementsMatch(t, []string{masterBranch, upstreamRepo.Commits[0]}, gur.GetFetchedRefs())
    95  			}
    96  
    97  			// Expect the local package to have Dataset2
    98  			if !g.AssertLocalDataEquals(testutil.Dataset2, true) {
    99  				return
   100  			}
   101  			commit, err := upstreamRepo.GetCommit()
   102  			if !assert.NoError(t, err) {
   103  				return
   104  			}
   105  			if !g.AssertKptfile(upstreamRepo.RepoName, commit, masterBranch,
   106  				strategy) {
   107  				return
   108  			}
   109  		})
   110  	}
   111  }
   112  
   113  func TestCommand_Run_subDir(t *testing.T) {
   114  	for i := range kptfilev1.UpdateStrategies {
   115  		strategy := kptfilev1.UpdateStrategies[i]
   116  		t.Run(string(strategy), func(t *testing.T) {
   117  			// Setup the test upstream and local packages
   118  			g := &testutil.TestSetupManager{
   119  				T: t,
   120  				ReposChanges: map[string][]testutil.Content{
   121  					testutil.Upstream: {
   122  						{
   123  							Data:   testutil.Dataset1,
   124  							Branch: masterBranch,
   125  						},
   126  						{
   127  							Tag:  "v1.2",
   128  							Data: testutil.Dataset2,
   129  						},
   130  					},
   131  				},
   132  				GetSubDirectory: "java",
   133  			}
   134  			defer g.Clean()
   135  			if !g.Init() {
   136  				return
   137  			}
   138  			upstreamRepo := g.Repos[testutil.Upstream]
   139  
   140  			// Update the local package
   141  			if !assert.NoError(t, (&Command{
   142  				Pkg:      pkgtest.CreatePkgOrFail(t, g.LocalWorkspace.FullPackagePath()),
   143  				Ref:      "v1.2",
   144  				Strategy: strategy,
   145  			}).Run(fake.CtxWithDefaultPrinter())) {
   146  				return
   147  			}
   148  
   149  			// Expect the local package to have Dataset2
   150  			if !g.AssertLocalDataEquals(filepath.Join(testutil.Dataset2, "java"), true) {
   151  				return
   152  			}
   153  			commit, err := upstreamRepo.GetCommit()
   154  			if !assert.NoError(t, err) {
   155  				return
   156  			}
   157  			if !g.AssertKptfile(g.GetSubDirectory, commit, "v1.2",
   158  				strategy) {
   159  				return
   160  			}
   161  		})
   162  	}
   163  }
   164  
   165  func TestCommand_Run_noChanges(t *testing.T) {
   166  	updates := []struct {
   167  		updater kptfilev1.UpdateStrategyType
   168  		err     string
   169  	}{
   170  		{kptfilev1.FastForward, ""},
   171  		{kptfilev1.ForceDeleteReplace, ""},
   172  		// {AlphaGitPatch, "no updates"},
   173  		{kptfilev1.ResourceMerge, ""},
   174  	}
   175  	for i := range updates {
   176  		u := updates[i]
   177  		t.Run(string(u.updater), func(t *testing.T) {
   178  			// Setup the test upstream and local packages
   179  			g := &testutil.TestSetupManager{
   180  				T: t,
   181  				ReposChanges: map[string][]testutil.Content{
   182  					testutil.Upstream: {
   183  						{
   184  							Data:   testutil.Dataset1,
   185  							Branch: masterBranch,
   186  						},
   187  					},
   188  				},
   189  			}
   190  			defer g.Clean()
   191  			if !g.Init() {
   192  				return
   193  			}
   194  			upstreamRepo := g.Repos[testutil.Upstream]
   195  
   196  			// Update the local package
   197  			err := (&Command{
   198  				Pkg:      pkgtest.CreatePkgOrFail(t, g.LocalWorkspace.FullPackagePath()),
   199  				Strategy: u.updater,
   200  			}).Run(fake.CtxWithDefaultPrinter())
   201  			if u.err == "" {
   202  				if !assert.NoError(t, err) {
   203  					return
   204  				}
   205  			} else {
   206  				if assert.Error(t, err) {
   207  					assert.Contains(t, err.Error(), "no updates")
   208  				}
   209  			}
   210  
   211  			if !g.AssertLocalDataEquals(testutil.Dataset1, true) {
   212  				return
   213  			}
   214  			commit, err := upstreamRepo.GetCommit()
   215  			if !assert.NoError(t, err) {
   216  				return
   217  			}
   218  			if !g.AssertKptfile(upstreamRepo.RepoName, commit, masterBranch, u.updater) {
   219  				return
   220  			}
   221  		})
   222  	}
   223  }
   224  
   225  func TestCommand_Run_localPackageChanges(t *testing.T) {
   226  	testCases := map[string]struct {
   227  		strategy        kptfilev1.UpdateStrategyType
   228  		initialUpstream testutil.Content
   229  		updatedUpstream testutil.Content
   230  		updatedLocal    testutil.Content
   231  		expectedLocal   testutil.Content
   232  		expectedErr     string
   233  		expectedCommit  func(writer *testutil.TestSetupManager) (string, error)
   234  	}{
   235  		"update using resource-merge strategy with local changes": {
   236  			strategy: kptfilev1.ResourceMerge,
   237  			initialUpstream: testutil.Content{
   238  				Data:   testutil.Dataset1,
   239  				Branch: masterBranch,
   240  			},
   241  			updatedUpstream: testutil.Content{
   242  				Data: testutil.Dataset2,
   243  			},
   244  			updatedLocal: testutil.Content{
   245  				Data: testutil.Dataset3,
   246  			},
   247  			expectedLocal: testutil.Content{
   248  				Data: testutil.DatasetMerged,
   249  			},
   250  			expectedCommit: func(writer *testutil.TestSetupManager) (string, error) {
   251  				return writer.Repos[testutil.Upstream].GetCommit()
   252  			},
   253  		},
   254  		"update using fast-forward strategy with local changes": {
   255  			strategy: kptfilev1.FastForward,
   256  			initialUpstream: testutil.Content{
   257  				Data:   testutil.Dataset1,
   258  				Branch: masterBranch,
   259  			},
   260  			updatedUpstream: testutil.Content{
   261  				Data: testutil.Dataset2,
   262  			},
   263  			updatedLocal: testutil.Content{
   264  				Data: testutil.Dataset3,
   265  			},
   266  			expectedLocal: testutil.Content{
   267  				Data: testutil.Dataset3,
   268  			},
   269  			expectedErr: "local package files have been modified",
   270  			expectedCommit: func(writer *testutil.TestSetupManager) (string, error) {
   271  				upstreamRepo := writer.Repos[testutil.Upstream]
   272  				f, err := pkg.ReadKptfile(filesys.FileSystemOrOnDisk{}, filepath.Join(writer.LocalWorkspace.WorkspaceDirectory, upstreamRepo.RepoName))
   273  				if err != nil {
   274  					return "", err
   275  				}
   276  				return f.UpstreamLock.Git.Commit, nil
   277  			},
   278  		},
   279  		"update using force-delete-replace strategy with local changes": {
   280  			strategy: kptfilev1.ForceDeleteReplace,
   281  			initialUpstream: testutil.Content{
   282  				Data:   testutil.Dataset1,
   283  				Branch: masterBranch,
   284  			},
   285  			updatedUpstream: testutil.Content{
   286  				Data: testutil.Dataset2,
   287  			},
   288  			updatedLocal: testutil.Content{
   289  				Data: testutil.Dataset3,
   290  			},
   291  			expectedLocal: testutil.Content{
   292  				Data: testutil.Dataset2,
   293  			},
   294  			expectedCommit: func(writer *testutil.TestSetupManager) (string, error) {
   295  				return writer.Repos[testutil.Upstream].GetCommit()
   296  			},
   297  		},
   298  		"conflicting field with resource-merge strategy": {
   299  			strategy: kptfilev1.ResourceMerge,
   300  			initialUpstream: testutil.Content{
   301  				Pkg: pkgbuilder.NewRootPkg().
   302  					WithResource(pkgbuilder.DeploymentResource),
   303  				Branch: masterBranch,
   304  			},
   305  			updatedUpstream: testutil.Content{
   306  				Pkg: pkgbuilder.NewRootPkg().
   307  					WithResource(pkgbuilder.DeploymentResource,
   308  						pkgbuilder.SetFieldPath("42", "spec", "replicas")),
   309  			},
   310  			updatedLocal: testutil.Content{
   311  				Pkg: pkgbuilder.NewRootPkg().
   312  					WithResource(pkgbuilder.DeploymentResource,
   313  						pkgbuilder.SetFieldPath("21", "spec", "replicas")),
   314  			},
   315  			expectedLocal: testutil.Content{
   316  				Pkg: pkgbuilder.NewRootPkg().
   317  					WithResource(pkgbuilder.DeploymentResource,
   318  						pkgbuilder.SetFieldPath("42", "spec", "replicas")),
   319  			},
   320  			expectedCommit: func(writer *testutil.TestSetupManager) (string, error) {
   321  				return writer.Repos[testutil.Upstream].GetCommit()
   322  			},
   323  		},
   324  		"conflicting field with force-delete-replace strategy": {
   325  			strategy: kptfilev1.ForceDeleteReplace,
   326  			initialUpstream: testutil.Content{
   327  				Pkg: pkgbuilder.NewRootPkg().
   328  					WithResource(pkgbuilder.DeploymentResource),
   329  				Branch: masterBranch,
   330  			},
   331  			updatedUpstream: testutil.Content{
   332  				Pkg: pkgbuilder.NewRootPkg().
   333  					WithResource(pkgbuilder.DeploymentResource,
   334  						pkgbuilder.SetFieldPath("42", "spec", "replicas")),
   335  			},
   336  			updatedLocal: testutil.Content{
   337  				Pkg: pkgbuilder.NewRootPkg().
   338  					WithResource(pkgbuilder.DeploymentResource,
   339  						pkgbuilder.SetFieldPath("21", "spec", "replicas")),
   340  			},
   341  			expectedLocal: testutil.Content{
   342  				Pkg: pkgbuilder.NewRootPkg().
   343  					WithResource(pkgbuilder.DeploymentResource,
   344  						pkgbuilder.SetFieldPath("42", "spec", "replicas")),
   345  			},
   346  			expectedCommit: func(writer *testutil.TestSetupManager) (string, error) {
   347  				return writer.Repos[testutil.Upstream].GetCommit()
   348  			},
   349  		},
   350  	}
   351  	for tn, tc := range testCases {
   352  		t.Run(tn, func(t *testing.T) {
   353  			g := &testutil.TestSetupManager{
   354  				T: t,
   355  				ReposChanges: map[string][]testutil.Content{
   356  					testutil.Upstream: {
   357  						tc.initialUpstream,
   358  						tc.updatedUpstream,
   359  					},
   360  				},
   361  			}
   362  			defer g.Clean()
   363  
   364  			if !reflect.DeepEqual(tc.updatedLocal, testutil.Content{}) {
   365  				g.LocalChanges = []testutil.Content{tc.updatedLocal}
   366  			}
   367  
   368  			if !g.Init() {
   369  				t.FailNow()
   370  			}
   371  
   372  			// record the expected commit after update
   373  			expectedCommit, err := tc.expectedCommit(g)
   374  			if !assert.NoError(t, err) {
   375  				t.FailNow()
   376  			}
   377  
   378  			// run the command
   379  			err = (&Command{
   380  				Pkg:      pkgtest.CreatePkgOrFail(t, g.LocalWorkspace.FullPackagePath()),
   381  				Ref:      masterBranch,
   382  				Strategy: tc.strategy,
   383  			}).Run(fake.CtxWithDefaultPrinter())
   384  
   385  			// check the error response
   386  			if tc.expectedErr == "" {
   387  				if !assert.NoError(t, err) {
   388  					t.FailNow()
   389  				}
   390  			} else {
   391  				if !assert.Error(t, err) {
   392  					t.FailNow()
   393  				}
   394  				if !assert.Contains(t, err.Error(), tc.expectedErr) {
   395  					t.FailNow()
   396  				}
   397  			}
   398  
   399  			expectedPath := tc.expectedLocal.Data
   400  			if tc.expectedLocal.Pkg != nil {
   401  				expectedPath = tc.expectedLocal.Pkg.ExpandPkgWithName(t,
   402  					g.LocalWorkspace.PackageDir, testutil.ToReposInfo(g.Repos))
   403  			}
   404  
   405  			if !g.AssertLocalDataEquals(expectedPath, true) {
   406  				t.FailNow()
   407  			}
   408  			if !g.AssertKptfile(g.Repos[testutil.Upstream].RepoName, expectedCommit, masterBranch,
   409  				tc.strategy) {
   410  				t.FailNow()
   411  			}
   412  		})
   413  	}
   414  }
   415  
   416  // TestCommand_Run_toBranchRef verifies the package contents are set to the contents of the branch
   417  // it was updated to.
   418  func TestCommand_Run_toBranchRef(t *testing.T) {
   419  	for i := range kptfilev1.UpdateStrategies {
   420  		strategy := kptfilev1.UpdateStrategies[i]
   421  		t.Run(string(strategy), func(t *testing.T) {
   422  			// Setup the test upstream and local packages
   423  			g := &testutil.TestSetupManager{
   424  				T: t,
   425  				ReposChanges: map[string][]testutil.Content{
   426  					testutil.Upstream: {
   427  						{
   428  							Data:   testutil.Dataset1,
   429  							Branch: masterBranch,
   430  						},
   431  						{
   432  							Data:   testutil.Dataset2,
   433  							Branch: "exp", CreateBranch: true,
   434  						},
   435  						{
   436  							Data:   testutil.Dataset3,
   437  							Branch: masterBranch,
   438  						},
   439  					},
   440  				},
   441  			}
   442  			defer g.Clean()
   443  			if !g.Init() {
   444  				return
   445  			}
   446  			upstreamRepo := g.Repos[testutil.Upstream]
   447  
   448  			// Update the local package
   449  			if !assert.NoError(t, (&Command{
   450  				Pkg:      pkgtest.CreatePkgOrFail(t, g.LocalWorkspace.FullPackagePath()),
   451  				Strategy: strategy,
   452  				Ref:      "exp",
   453  			}).Run(fake.CtxWithDefaultPrinter())) {
   454  				return
   455  			}
   456  
   457  			// Expect the local package to have Dataset2
   458  			if !g.AssertLocalDataEquals(testutil.Dataset2, true) {
   459  				return
   460  			}
   461  
   462  			if !assert.NoError(t, upstreamRepo.CheckoutBranch("exp", false)) {
   463  				return
   464  			}
   465  			commit, err := upstreamRepo.GetCommit()
   466  			if !assert.NoError(t, err) {
   467  				return
   468  			}
   469  			if !g.AssertKptfile(upstreamRepo.RepoName, commit, "exp",
   470  				strategy) {
   471  				return
   472  			}
   473  		})
   474  	}
   475  }
   476  
   477  func TestCommand_Run_toBranchRefWithSubpkgs(t *testing.T) {
   478  	testCases := map[string]struct {
   479  		strategy      kptfilev1.UpdateStrategyType
   480  		updateRef     string
   481  		reposChanges  map[string][]testutil.Content
   482  		updateFunc    func(g *testutil.TestSetupManager)
   483  		updateSubPkg  string
   484  		expectedLocal *pkgbuilder.RootPkg
   485  	}{
   486  		"update with single subpkg from same repo": {
   487  			strategy:  kptfilev1.ResourceMerge,
   488  			updateRef: "subpkg-update",
   489  			reposChanges: map[string][]testutil.Content{
   490  				testutil.Upstream: {
   491  					{
   492  						Pkg: pkgbuilder.NewRootPkg().
   493  							WithKptfile(pkgbuilder.NewKptfile()).
   494  							WithResource(pkgbuilder.ConfigMapResource).
   495  							WithSubPackages(pkgbuilder.NewSubPkg("subpkg").
   496  								WithKptfile(pkgbuilder.NewKptfile()).
   497  								WithResource(pkgbuilder.DeploymentResource),
   498  							),
   499  						Branch: masterBranch,
   500  					},
   501  					{
   502  						Pkg: pkgbuilder.NewRootPkg().
   503  							WithKptfile(pkgbuilder.NewKptfile()).
   504  							WithResource(pkgbuilder.ConfigMapResource).
   505  							WithSubPackages(pkgbuilder.NewSubPkg("subpkg").
   506  								WithKptfile(pkgbuilder.NewKptfile()).
   507  								WithResource(pkgbuilder.DeploymentResource,
   508  									pkgbuilder.SetFieldPath("42", "spec", "replicas"),
   509  								),
   510  							),
   511  						Branch: "subpkg-update", CreateBranch: true,
   512  					},
   513  				},
   514  			},
   515  			updateFunc: func(g *testutil.TestSetupManager) {
   516  				g.GetSubPkg("test", testutil.Upstream, "subpkg")
   517  			},
   518  			expectedLocal: pkgbuilder.NewRootPkg().
   519  				WithKptfile(pkgbuilder.NewKptfile().
   520  					WithUpstreamRef(testutil.Upstream, "/", "subpkg-update", "resource-merge").
   521  					WithUpstreamLockRef(testutil.Upstream, "/", "subpkg-update", 1),
   522  				).
   523  				WithResource(pkgbuilder.ConfigMapResource).
   524  				WithSubPackages(
   525  					pkgbuilder.NewSubPkg("subpkg").
   526  						WithKptfile(pkgbuilder.NewKptfile()).
   527  						WithResource(pkgbuilder.DeploymentResource,
   528  							pkgbuilder.SetFieldPath("42", "spec", "replicas")),
   529  					pkgbuilder.NewSubPkg("test").
   530  						WithKptfile(
   531  							pkgbuilder.NewKptfile().
   532  								WithUpstreamRef(testutil.Upstream, "/subpkg", "subpkg-update", "resource-merge").
   533  								WithUpstreamLockRef(testutil.Upstream, "/subpkg", "subpkg-update", 1),
   534  						).
   535  						WithResource(pkgbuilder.DeploymentResource,
   536  							pkgbuilder.SetFieldPath("42", "spec", "replicas")),
   537  				),
   538  		},
   539  		"update strategy with single subpkg from same repo": {
   540  			strategy:  kptfilev1.FastForward,
   541  			updateRef: "subpkg-update",
   542  			reposChanges: map[string][]testutil.Content{
   543  				testutil.Upstream: {
   544  					{
   545  						Pkg: pkgbuilder.NewRootPkg().
   546  							WithKptfile(pkgbuilder.NewKptfile()).
   547  							WithResource(pkgbuilder.ConfigMapResource).
   548  							WithSubPackages(pkgbuilder.NewSubPkg("subpkg").
   549  								WithKptfile(pkgbuilder.NewKptfile()).
   550  								WithResource(pkgbuilder.DeploymentResource),
   551  							),
   552  						Branch: masterBranch,
   553  					},
   554  					{
   555  						Pkg: pkgbuilder.NewRootPkg().
   556  							WithKptfile(pkgbuilder.NewKptfile()).
   557  							WithResource(pkgbuilder.ConfigMapResource).
   558  							WithSubPackages(pkgbuilder.NewSubPkg("subpkg").
   559  								WithKptfile(pkgbuilder.NewKptfile()).
   560  								WithResource(pkgbuilder.DeploymentResource,
   561  									pkgbuilder.SetFieldPath("42", "spec", "replicas"),
   562  								),
   563  							),
   564  						Branch: "subpkg-update", CreateBranch: true,
   565  					},
   566  				},
   567  			},
   568  			updateFunc: func(g *testutil.TestSetupManager) {
   569  				g.GetSubPkg("test", testutil.Upstream, "subpkg")
   570  			},
   571  			expectedLocal: pkgbuilder.NewRootPkg().
   572  				WithKptfile(pkgbuilder.NewKptfile().
   573  					WithUpstreamRef(testutil.Upstream, "/", "subpkg-update", "fast-forward").
   574  					WithUpstreamLockRef(testutil.Upstream, "/", "subpkg-update", 1),
   575  				).
   576  				WithResource(pkgbuilder.ConfigMapResource).
   577  				WithSubPackages(
   578  					pkgbuilder.NewSubPkg("subpkg").
   579  						WithKptfile(pkgbuilder.NewKptfile()).
   580  						WithResource(pkgbuilder.DeploymentResource,
   581  							pkgbuilder.SetFieldPath("42", "spec", "replicas")),
   582  					pkgbuilder.NewSubPkg("test").
   583  						WithKptfile(
   584  							pkgbuilder.NewKptfile().
   585  								WithUpstreamRef(testutil.Upstream, "/subpkg", "subpkg-update", "fast-forward").
   586  								WithUpstreamLockRef(testutil.Upstream, "/subpkg", "subpkg-update", 1),
   587  						).
   588  						WithResource(pkgbuilder.DeploymentResource,
   589  							pkgbuilder.SetFieldPath("42", "spec", "replicas")),
   590  				),
   591  		},
   592  		"update with single subpkg from different repo": {
   593  			strategy:  kptfilev1.ResourceMerge,
   594  			updateRef: "subpkg-update",
   595  			reposChanges: map[string][]testutil.Content{
   596  				testutil.Upstream: {
   597  					{
   598  						Pkg: pkgbuilder.NewRootPkg().
   599  							WithKptfile(pkgbuilder.NewKptfile()).
   600  							WithResource(pkgbuilder.ConfigMapResource).
   601  							WithSubPackages(pkgbuilder.NewSubPkg("subpkg").
   602  								WithKptfile(pkgbuilder.NewKptfile()).
   603  								WithResource(pkgbuilder.SecretResource),
   604  							),
   605  						Branch: masterBranch,
   606  					},
   607  					{
   608  						Pkg: pkgbuilder.NewRootPkg().
   609  							WithKptfile(pkgbuilder.NewKptfile()).
   610  							WithResource(pkgbuilder.ConfigMapResource).
   611  							WithSubPackages(pkgbuilder.NewSubPkg("subpkg").
   612  								WithKptfile(pkgbuilder.NewKptfile()).
   613  								WithResource(pkgbuilder.ConfigMapResource),
   614  							),
   615  						Branch: "subpkg-update", CreateBranch: true,
   616  					},
   617  				},
   618  				"foo": {
   619  					{
   620  						Pkg: pkgbuilder.NewRootPkg().
   621  							WithKptfile(pkgbuilder.NewKptfile()).
   622  							WithResource(pkgbuilder.ConfigMapResource).
   623  							WithSubPackages(pkgbuilder.NewSubPkg("subpkg").
   624  								WithKptfile(pkgbuilder.NewKptfile()).
   625  								WithResource(pkgbuilder.DeploymentResource),
   626  							),
   627  						Branch: masterBranch,
   628  					},
   629  					{
   630  						Pkg: pkgbuilder.NewRootPkg().
   631  							WithKptfile(pkgbuilder.NewKptfile()).
   632  							WithResource(pkgbuilder.ConfigMapResource).
   633  							WithSubPackages(pkgbuilder.NewSubPkg("subpkg").
   634  								WithKptfile(pkgbuilder.NewKptfile()).
   635  								WithResource(pkgbuilder.DeploymentResource,
   636  									pkgbuilder.SetFieldPath("42", "spec", "replicas"),
   637  								),
   638  							),
   639  						Branch: "subpkg-update", CreateBranch: true,
   640  					}},
   641  			},
   642  			updateFunc: func(g *testutil.TestSetupManager) {
   643  				g.GetSubPkg("fooSubPkg", "foo", "subpkg")
   644  			},
   645  			expectedLocal: pkgbuilder.NewRootPkg().
   646  				WithKptfile(pkgbuilder.NewKptfile().
   647  					WithUpstreamRef(testutil.Upstream, "/", "subpkg-update", "resource-merge").
   648  					WithUpstreamLockRef(testutil.Upstream, "/", "subpkg-update", 1),
   649  				).
   650  				WithResource(pkgbuilder.ConfigMapResource).
   651  				WithSubPackages(
   652  					pkgbuilder.NewSubPkg("subpkg").
   653  						WithKptfile(pkgbuilder.NewKptfile()).
   654  						WithResource(pkgbuilder.ConfigMapResource),
   655  					pkgbuilder.NewSubPkg("fooSubPkg").
   656  						WithKptfile(
   657  							pkgbuilder.NewKptfile().
   658  								WithUpstreamRef("foo", "/subpkg", "master", "resource-merge").
   659  								WithUpstreamLockRef("foo", "/subpkg", "master", 0),
   660  						).
   661  						WithResource(pkgbuilder.DeploymentResource),
   662  				),
   663  		},
   664  		"update with multiple subpkgs from same repo": {
   665  			strategy:  kptfilev1.ResourceMerge,
   666  			updateRef: "subpkg-update",
   667  			reposChanges: map[string][]testutil.Content{
   668  				testutil.Upstream: {
   669  					{
   670  						Pkg: pkgbuilder.NewRootPkg().
   671  							WithKptfile(pkgbuilder.NewKptfile()).
   672  							WithResource(pkgbuilder.ConfigMapResource).
   673  							WithSubPackages(pkgbuilder.NewSubPkg("subpkg1").
   674  								WithKptfile(pkgbuilder.NewKptfile()).
   675  								WithResource(pkgbuilder.SecretResource).
   676  								WithSubPackages(
   677  									pkgbuilder.NewSubPkg("nestedOne").
   678  										WithKptfile(pkgbuilder.NewKptfile()).
   679  										WithResource(pkgbuilder.DeploymentResource),
   680  									pkgbuilder.NewSubPkg("nestedTwo").
   681  										WithKptfile(pkgbuilder.NewKptfile()).
   682  										WithResource(pkgbuilder.DeploymentResource),
   683  								),
   684  								pkgbuilder.NewSubPkg("subpkg2").WithKptfile(pkgbuilder.NewKptfile()).
   685  									WithResource(pkgbuilder.SecretResource).
   686  									WithSubPackages(
   687  										pkgbuilder.NewSubPkg("nestedThree").
   688  											WithKptfile(pkgbuilder.NewKptfile()).
   689  											WithResource(pkgbuilder.DeploymentResource),
   690  										pkgbuilder.NewSubPkg("nestedFour").
   691  											WithKptfile(pkgbuilder.NewKptfile()).
   692  											WithResource(pkgbuilder.DeploymentResource),
   693  									),
   694  							),
   695  						Branch: masterBranch,
   696  					},
   697  					{
   698  						Pkg: pkgbuilder.NewRootPkg().
   699  							WithKptfile(pkgbuilder.NewKptfile()).
   700  							WithResource(pkgbuilder.ConfigMapResource).
   701  							WithSubPackages(pkgbuilder.NewSubPkg("subpkg1").
   702  								WithKptfile(pkgbuilder.NewKptfile()).
   703  								WithResource(pkgbuilder.SecretResource).
   704  								WithSubPackages(
   705  									pkgbuilder.NewSubPkg("nestedOne").
   706  										WithKptfile(pkgbuilder.NewKptfile()).
   707  										WithResource(pkgbuilder.DeploymentResource, pkgbuilder.SetFieldPath("42", "spec", "replicas")),
   708  									pkgbuilder.NewSubPkg("nestedTwo").
   709  										WithKptfile(pkgbuilder.NewKptfile()).
   710  										WithResource(pkgbuilder.DeploymentResource, pkgbuilder.SetFieldPath("43", "spec", "replicas")),
   711  								),
   712  								pkgbuilder.NewSubPkg("subpkg2").WithKptfile(pkgbuilder.NewKptfile()).
   713  									WithResource(pkgbuilder.SecretResource).
   714  									WithSubPackages(
   715  										pkgbuilder.NewSubPkg("nestedThree").
   716  											WithKptfile(pkgbuilder.NewKptfile()).
   717  											WithResource(pkgbuilder.DeploymentResource, pkgbuilder.SetFieldPath("44", "spec", "replicas")),
   718  										pkgbuilder.NewSubPkg("nestedFour").
   719  											WithKptfile(pkgbuilder.NewKptfile()).
   720  											WithResource(pkgbuilder.DeploymentResource, pkgbuilder.SetFieldPath("45", "spec", "replicas")),
   721  									),
   722  							),
   723  						Branch: "subpkg-update", CreateBranch: true,
   724  					},
   725  				},
   726  			},
   727  			updateFunc: func(g *testutil.TestSetupManager) {
   728  				g.GetSubPkg("subpkgvariant", testutil.Upstream, "subpkg1")
   729  				g.GetSubPkg("subpkgvariant/nestedTwoVariant", testutil.Upstream, "subpkg1/nestedTwo")
   730  				g.GetSubPkg("subpkgvariant/nestedThreeVariant", testutil.Upstream, "subpkg2/nestedThree")
   731  			},
   732  			updateSubPkg: "subpkgvariant",
   733  			expectedLocal: pkgbuilder.NewRootPkg().
   734  				WithKptfile(
   735  					pkgbuilder.NewKptfile().
   736  						WithUpstreamRef(testutil.Upstream, "/", "master", "resource-merge").
   737  						WithUpstreamLockRef(testutil.Upstream, "/", "master", 0),
   738  				).
   739  				WithResource(pkgbuilder.ConfigMapResource).
   740  				WithSubPackages(
   741  					pkgbuilder.NewSubPkg("subpkg1").
   742  						WithKptfile(pkgbuilder.NewKptfile()).
   743  						WithResource(pkgbuilder.SecretResource).
   744  						WithSubPackages(
   745  							pkgbuilder.NewSubPkg("nestedOne").
   746  								WithKptfile(pkgbuilder.NewKptfile()).
   747  								WithResource(pkgbuilder.DeploymentResource),
   748  							pkgbuilder.NewSubPkg("nestedTwo").
   749  								WithKptfile(pkgbuilder.NewKptfile()).
   750  								WithResource(pkgbuilder.DeploymentResource),
   751  						),
   752  					pkgbuilder.NewSubPkg("subpkg2").WithKptfile(pkgbuilder.NewKptfile()).
   753  						WithResource(pkgbuilder.SecretResource).
   754  						WithSubPackages(
   755  							pkgbuilder.NewSubPkg("nestedThree").
   756  								WithKptfile(pkgbuilder.NewKptfile()).
   757  								WithResource(pkgbuilder.DeploymentResource),
   758  							pkgbuilder.NewSubPkg("nestedFour").
   759  								WithKptfile(pkgbuilder.NewKptfile()).
   760  								WithResource(pkgbuilder.DeploymentResource),
   761  						),
   762  					pkgbuilder.NewSubPkg("subpkgvariant").
   763  						WithKptfile(
   764  							pkgbuilder.NewKptfile().
   765  								WithUpstreamRef(testutil.Upstream, "/subpkg1", "subpkg-update", "resource-merge").
   766  								WithUpstreamLockRef(testutil.Upstream, "/subpkg1", "subpkg-update", 1),
   767  						).
   768  						WithResource(pkgbuilder.SecretResource).
   769  						WithSubPackages(
   770  							pkgbuilder.NewSubPkg("nestedOne").
   771  								WithKptfile(pkgbuilder.NewKptfile()).
   772  								WithResource(pkgbuilder.DeploymentResource, pkgbuilder.SetFieldPath("42", "spec", "replicas")),
   773  							pkgbuilder.NewSubPkg("nestedTwo").
   774  								WithKptfile(pkgbuilder.NewKptfile()).
   775  								WithResource(pkgbuilder.DeploymentResource, pkgbuilder.SetFieldPath("43", "spec", "replicas")),
   776  							pkgbuilder.NewSubPkg("nestedTwoVariant").
   777  								WithKptfile(
   778  									pkgbuilder.NewKptfile().
   779  										WithUpstreamRef(testutil.Upstream, "/subpkg1/nestedTwo", "subpkg-update", "resource-merge").
   780  										WithUpstreamLockRef(testutil.Upstream, "/subpkg1/nestedTwo", "subpkg-update", 1),
   781  								).
   782  								WithResource(pkgbuilder.DeploymentResource, pkgbuilder.SetFieldPath("43", "spec", "replicas")),
   783  							pkgbuilder.NewSubPkg("nestedThreeVariant").
   784  								WithKptfile(
   785  									pkgbuilder.NewKptfile().
   786  										WithUpstreamRef(testutil.Upstream, "/subpkg2/nestedThree", "master", "resource-merge").
   787  										WithUpstreamLockRef(testutil.Upstream, "/subpkg2/nestedThree", "master", 0),
   788  								).
   789  								WithResource(pkgbuilder.DeploymentResource),
   790  						),
   791  				),
   792  		},
   793  	}
   794  	for tn, tc := range testCases {
   795  		t.Run(tn, func(t *testing.T) {
   796  			// Setup the test upstream and local packages
   797  			g := &testutil.TestSetupManager{
   798  				T:            t,
   799  				ReposChanges: tc.reposChanges,
   800  			}
   801  			defer g.Clean()
   802  
   803  			if !g.Init() {
   804  				return
   805  			}
   806  
   807  			// perform any additional updates to local pkg
   808  			if tc.updateFunc != nil {
   809  				tc.updateFunc(g)
   810  			}
   811  
   812  			// Update the local package
   813  			if !assert.NoError(t, (&Command{
   814  				Pkg:      pkgtest.CreatePkgOrFail(t, path.Join(g.LocalWorkspace.FullPackagePath(), tc.updateSubPkg)),
   815  				Strategy: tc.strategy,
   816  				Ref:      tc.updateRef,
   817  			}).Run(fake.CtxWithDefaultPrinter())) {
   818  				return
   819  			}
   820  			expectedPath := tc.expectedLocal.ExpandPkgWithName(t,
   821  				g.LocalWorkspace.PackageDir, testutil.ToReposInfo(g.Repos))
   822  			testutil.KptfileAwarePkgEqual(t, expectedPath, g.LocalWorkspace.FullPackagePath(), true)
   823  		})
   824  	}
   825  }
   826  
   827  // TestCommand_Run_toTagRef verifies the package contents are set to the contents of the tag
   828  // it was updated to.
   829  func TestCommand_Run_toTagRef(t *testing.T) {
   830  	for i := range kptfilev1.UpdateStrategies {
   831  		strategy := kptfilev1.UpdateStrategies[i]
   832  		t.Run(string(strategy), func(t *testing.T) {
   833  			// Setup the test upstream and local packages
   834  			g := &testutil.TestSetupManager{
   835  				T: t,
   836  				ReposChanges: map[string][]testutil.Content{
   837  					testutil.Upstream: {
   838  						{
   839  							Data:   testutil.Dataset1,
   840  							Branch: masterBranch,
   841  						},
   842  						{
   843  							Data: testutil.Dataset2,
   844  							Tag:  "v1.0",
   845  						},
   846  						{
   847  							Data: testutil.Dataset3,
   848  						},
   849  					},
   850  				},
   851  			}
   852  			defer g.Clean()
   853  			if !g.Init() {
   854  				return
   855  			}
   856  			upstreamRepo := g.Repos[testutil.Upstream]
   857  
   858  			// Update the local package
   859  			if !assert.NoError(t, (&Command{
   860  				Pkg:      pkgtest.CreatePkgOrFail(t, g.LocalWorkspace.FullPackagePath()),
   861  				Strategy: strategy,
   862  				Ref:      "v1.0",
   863  			}).Run(fake.CtxWithDefaultPrinter())) {
   864  				return
   865  			}
   866  
   867  			// Expect the local package to have Dataset2
   868  			if !g.AssertLocalDataEquals(testutil.Dataset2, true) {
   869  				return
   870  			}
   871  
   872  			if !assert.NoError(t, upstreamRepo.CheckoutBranch("v1.0", false)) {
   873  				return
   874  			}
   875  			commit, err := upstreamRepo.GetCommit()
   876  			if !assert.NoError(t, err) {
   877  				return
   878  			}
   879  			if !g.AssertKptfile(upstreamRepo.RepoName, commit, "v1.0",
   880  				strategy) {
   881  				return
   882  			}
   883  		})
   884  	}
   885  }
   886  
   887  // TestCommand_ResourceMerge_NonKRMUpdates tests if the local non KRM files are updated
   888  func TestCommand_ResourceMerge_NonKRMUpdates(t *testing.T) {
   889  	strategies := []kptfilev1.UpdateStrategyType{kptfilev1.ResourceMerge}
   890  	for i := range strategies {
   891  		strategy := strategies[i]
   892  		t.Run(string(strategy), func(t *testing.T) {
   893  			// Setup the test upstream and local packages
   894  			g := &testutil.TestSetupManager{
   895  				T: t,
   896  				ReposChanges: map[string][]testutil.Content{
   897  					testutil.Upstream: {
   898  						{
   899  							Data:   testutil.Dataset1,
   900  							Branch: masterBranch,
   901  						},
   902  						{
   903  							Data: testutil.Dataset5,
   904  							Tag:  "v1.0",
   905  						},
   906  					},
   907  				},
   908  			}
   909  			defer g.Clean()
   910  			if !g.Init() {
   911  				t.FailNow()
   912  			}
   913  			upstreamRepo := g.Repos[testutil.Upstream]
   914  
   915  			// Update the local package
   916  			if !assert.NoError(t, (&Command{
   917  				Pkg:      pkgtest.CreatePkgOrFail(t, g.LocalWorkspace.FullPackagePath()),
   918  				Strategy: strategy,
   919  				Ref:      "v1.0",
   920  			}).Run(fake.CtxWithDefaultPrinter())) {
   921  				t.FailNow()
   922  			}
   923  
   924  			// Expect the local package to have Dataset5
   925  			if !g.AssertLocalDataEquals(testutil.Dataset5, true) {
   926  				t.FailNow()
   927  			}
   928  
   929  			if !assert.NoError(t, upstreamRepo.CheckoutBranch("v1.0", false)) {
   930  				t.FailNow()
   931  			}
   932  			commit, err := upstreamRepo.GetCommit()
   933  			if !assert.NoError(t, err) {
   934  				t.FailNow()
   935  			}
   936  			if !g.AssertKptfile(upstreamRepo.RepoName, commit, "v1.0",
   937  				strategy) {
   938  				t.FailNow()
   939  			}
   940  		})
   941  	}
   942  }
   943  
   944  func TestCommand_Run_noUpstreamReference(t *testing.T) {
   945  	_, w, clean := testutil.SetupReposAndWorkspace(t, map[string][]testutil.Content{
   946  		testutil.Upstream: {
   947  			{
   948  				Branch: masterBranch,
   949  			},
   950  		},
   951  	})
   952  	defer clean()
   953  
   954  	w.PackageDir = testPackageName
   955  	kf := kptfileutil.DefaultKptfile(testPackageName)
   956  	testutil.AddKptfileToWorkspace(t, w, kf)
   957  
   958  	// Update the local package
   959  	err := (&Command{
   960  		Pkg: pkgtest.CreatePkgOrFail(t, w.FullPackagePath()),
   961  	}).Run(fake.CtxWithDefaultPrinter())
   962  
   963  	assert.Contains(t, err.Error(), "must have an upstream reference")
   964  }
   965  
   966  // TestCommand_Run_failInvalidPath verifies Run fails if the path is invalid
   967  func TestCommand_Run_failInvalidPath(t *testing.T) {
   968  	for i := range kptfilev1.UpdateStrategies {
   969  		strategy := kptfilev1.UpdateStrategies[i]
   970  		t.Run(string(strategy), func(t *testing.T) {
   971  			path := filepath.Join("fake", "path")
   972  			err := (&Command{
   973  				Pkg:      pkgtest.CreatePkgOrFail(t, path),
   974  				Strategy: strategy,
   975  			}).Run(fake.CtxWithDefaultPrinter())
   976  			if assert.Error(t, err) {
   977  				assert.Contains(t, err.Error(), "no such file or directory")
   978  			}
   979  		})
   980  	}
   981  }
   982  
   983  func TestCommand_Run_badUpstreamLock(t *testing.T) {
   984  	testCases := map[string]struct {
   985  		commit           string
   986  		repo             string
   987  		expectedErrorMsg string
   988  	}{
   989  		"bad commit": {
   990  			commit:           "fake",
   991  			repo:             testutil.Upstream,
   992  			expectedErrorMsg: "unknown revision or path"},
   993  		"bad repo": {
   994  			repo:             "fake",
   995  			expectedErrorMsg: "does not appear to be a git repository"},
   996  	}
   997  	for tn, tc := range testCases {
   998  		t.Run(tn, func(t *testing.T) {
   999  			upstreamContent := testutil.Content{
  1000  				Pkg: pkgbuilder.NewRootPkg().
  1001  					WithResource(pkgbuilder.DeploymentResource),
  1002  				Branch: masterBranch,
  1003  			}
  1004  
  1005  			g := &testutil.TestSetupManager{
  1006  				T: t,
  1007  				ReposChanges: map[string][]testutil.Content{
  1008  					testutil.Upstream: {
  1009  						upstreamContent,
  1010  					},
  1011  				},
  1012  			}
  1013  
  1014  			defer g.Clean()
  1015  
  1016  			if !g.Init() {
  1017  				return
  1018  			}
  1019  
  1020  			// If tc.repo exists in the testbed, use its repo directory for the UpstreamLock.
  1021  			repoDir := tc.repo
  1022  			if repo, repoExists := g.Repos[tc.repo]; repoExists {
  1023  				repoDir = repo.RepoDirectory
  1024  			}
  1025  			localChanges := []testutil.Content{{
  1026  				Pkg: pkgbuilder.NewRootPkg().WithKptfile(pkgbuilder.NewKptfile().
  1027  					WithUpstreamRef(testutil.Upstream, "/", masterBranch, "resource-merge").
  1028  					WithUpstreamLock(repoDir, "/", masterBranch, tc.commit),
  1029  				),
  1030  			}}
  1031  			err := testutil.UpdateGitDir(g.T, testutil.Local, g.LocalWorkspace, localChanges, g.Repos)
  1032  			if !assert.NoError(t, err) {
  1033  				t.FailNow()
  1034  			}
  1035  
  1036  			// Update the local package.
  1037  			err = (&Command{
  1038  				Pkg: pkgtest.CreatePkgOrFail(t, g.LocalWorkspace.FullPackagePath()),
  1039  			}).Run(fake.CtxWithDefaultPrinter())
  1040  
  1041  			if assert.Error(t, err) {
  1042  				assert.Contains(t, err.Error(), tc.expectedErrorMsg)
  1043  			}
  1044  		})
  1045  	}
  1046  }
  1047  
  1048  // TestCommand_Run_failInvalidRef verifies Run fails if the ref is invalid
  1049  func TestCommand_Run_failInvalidRef(t *testing.T) {
  1050  	for i := range kptfilev1.UpdateStrategies {
  1051  		strategy := kptfilev1.UpdateStrategies[i]
  1052  		t.Run(string(strategy), func(t *testing.T) {
  1053  			g := &testutil.TestSetupManager{
  1054  				T: t,
  1055  				ReposChanges: map[string][]testutil.Content{
  1056  					testutil.Upstream: {
  1057  						{
  1058  							Data:   testutil.Dataset1,
  1059  							Branch: masterBranch,
  1060  						},
  1061  						{
  1062  							Data: testutil.Dataset2,
  1063  						},
  1064  					},
  1065  				},
  1066  			}
  1067  			defer g.Clean()
  1068  			if !g.Init() {
  1069  				return
  1070  			}
  1071  
  1072  			err := (&Command{
  1073  				Pkg:      pkgtest.CreatePkgOrFail(t, g.LocalWorkspace.FullPackagePath()),
  1074  				Ref:      "exp",
  1075  				Strategy: strategy,
  1076  			}).Run(fake.CtxWithDefaultPrinter())
  1077  			if !assert.Error(t, err) {
  1078  				return
  1079  			}
  1080  			assert.Contains(t, err.Error(), "unknown revision or path not in the working tree")
  1081  
  1082  			if !g.AssertLocalDataEquals(testutil.Dataset1, true) {
  1083  				return
  1084  			}
  1085  		})
  1086  	}
  1087  }
  1088  
  1089  func TestCommand_Run_manualChange(t *testing.T) {
  1090  	g := &testutil.TestSetupManager{
  1091  		T: t,
  1092  		ReposChanges: map[string][]testutil.Content{
  1093  			testutil.Upstream: {
  1094  				{
  1095  					Pkg: pkgbuilder.NewRootPkg().
  1096  						WithResource(pkgbuilder.DeploymentResource),
  1097  					Branch: masterBranch,
  1098  					Tag:    "v1",
  1099  				},
  1100  				{
  1101  					Pkg: pkgbuilder.NewRootPkg().
  1102  						WithResource(pkgbuilder.ConfigMapResource),
  1103  					Tag: "v2",
  1104  				},
  1105  				{
  1106  					Pkg: pkgbuilder.NewRootPkg().
  1107  						WithResource(pkgbuilder.SecretResource),
  1108  					Tag: "v3",
  1109  				},
  1110  			},
  1111  		},
  1112  		GetRef: "v1",
  1113  		LocalChanges: []testutil.Content{
  1114  			{
  1115  				Pkg: pkgbuilder.NewRootPkg().
  1116  					WithKptfile(
  1117  						pkgbuilder.NewKptfile().
  1118  							WithUpstreamRef(testutil.Upstream, "/", "v3", "resource-merge").
  1119  							WithUpstreamLockRef(testutil.Upstream, "/", "v1", 0),
  1120  					).
  1121  					WithResource(pkgbuilder.DeploymentResource),
  1122  			},
  1123  		},
  1124  	}
  1125  	defer g.Clean()
  1126  	if !g.Init() {
  1127  		return
  1128  	}
  1129  
  1130  	err := (&Command{
  1131  		Pkg: pkgtest.CreatePkgOrFail(t, g.LocalWorkspace.FullPackagePath()),
  1132  	}).Run(fake.CtxWithDefaultPrinter())
  1133  	if !assert.NoError(t, err) {
  1134  		t.FailNow()
  1135  	}
  1136  
  1137  	expLocal := pkgbuilder.NewRootPkg().
  1138  		WithKptfile(
  1139  			pkgbuilder.NewKptfile().
  1140  				WithUpstreamRef(testutil.Upstream, "/", "v3", "resource-merge").
  1141  				WithUpstreamLockRef(testutil.Upstream, "/", "v3", 2),
  1142  		).
  1143  		WithResource(pkgbuilder.SecretResource)
  1144  	expectedPath := expLocal.ExpandPkgWithName(t,
  1145  		g.LocalWorkspace.PackageDir, testutil.ToReposInfo(g.Repos))
  1146  
  1147  	testutil.KptfileAwarePkgEqual(t, expectedPath, g.LocalWorkspace.FullPackagePath(), true)
  1148  }
  1149  
  1150  func TestCommand_Run_symlinks(t *testing.T) {
  1151  	g := &testutil.TestSetupManager{
  1152  		T: t,
  1153  		ReposChanges: map[string][]testutil.Content{
  1154  			testutil.Upstream: {
  1155  				{
  1156  					Branch: masterBranch,
  1157  					Pkg: pkgbuilder.NewRootPkg().
  1158  						WithResource(pkgbuilder.DeploymentResource),
  1159  				},
  1160  				{
  1161  					Pkg: pkgbuilder.NewRootPkg().
  1162  						WithResource(pkgbuilder.SecretResource).
  1163  						WithSubPackages(
  1164  							pkgbuilder.NewSubPkg("subpkg").
  1165  								WithKptfile().
  1166  								WithResource(pkgbuilder.ConfigMapResource),
  1167  						),
  1168  					UpdateFunc: func(path string) error {
  1169  						// Create symlink in the upstream repo.
  1170  						return os.Symlink(filepath.Join(path, "subpkg"),
  1171  							filepath.Join(path, "subpkg-sym"))
  1172  					},
  1173  				},
  1174  			},
  1175  		},
  1176  		GetRef: masterBranch,
  1177  	}
  1178  	defer g.Clean()
  1179  	if !g.Init() {
  1180  		return
  1181  	}
  1182  	upstreamRepo := g.Repos[testutil.Upstream]
  1183  
  1184  	err := (&Command{
  1185  		Pkg: pkgtest.CreatePkgOrFail(t, g.LocalWorkspace.FullPackagePath()),
  1186  	}).Run(fake.CtxWithDefaultPrinter())
  1187  	if !assert.NoError(t, err) {
  1188  		t.FailNow()
  1189  	}
  1190  
  1191  	expectedPkg := pkgbuilder.NewRootPkg().
  1192  		WithKptfile(
  1193  			pkgbuilder.NewKptfile().
  1194  				WithUpstreamRef(testutil.Upstream, "/", "master", "resource-merge").
  1195  				WithUpstreamLockRef(testutil.Upstream, "/", "master", 1),
  1196  		).
  1197  		WithResource(pkgbuilder.SecretResource).
  1198  		WithSubPackages(
  1199  			pkgbuilder.NewSubPkg("subpkg").
  1200  				WithKptfile().
  1201  				WithResource(pkgbuilder.ConfigMapResource),
  1202  		)
  1203  	expectedPath := expectedPkg.ExpandPkgWithName(t, upstreamRepo.RepoName, testutil.ToReposInfo(g.Repos))
  1204  
  1205  	testutil.KptfileAwarePkgEqual(t, expectedPath, g.LocalWorkspace.FullPackagePath(), true)
  1206  }
  1207  
  1208  func TestCommand_Run_badStrategy(t *testing.T) {
  1209  	strategy := kptfilev1.UpdateStrategyType("foo")
  1210  
  1211  	// Setup the test upstream and local packages
  1212  	g := &testutil.TestSetupManager{
  1213  		T: t,
  1214  		ReposChanges: map[string][]testutil.Content{
  1215  			testutil.Upstream: {
  1216  				{
  1217  					Data:   testutil.Dataset1,
  1218  					Branch: masterBranch,
  1219  				},
  1220  				{
  1221  					Data: testutil.Dataset2,
  1222  				},
  1223  			},
  1224  		},
  1225  	}
  1226  	defer g.Clean()
  1227  	if !g.Init() {
  1228  		return
  1229  	}
  1230  
  1231  	// Update the local package
  1232  	err := (&Command{
  1233  		Pkg:      pkgtest.CreatePkgOrFail(t, g.LocalWorkspace.FullPackagePath()),
  1234  		Strategy: strategy,
  1235  	}).Run(fake.CtxWithDefaultPrinter())
  1236  	if !assert.Error(t, err, strategy) {
  1237  		return
  1238  	}
  1239  	assert.Contains(t, err.Error(), "unrecognized update strategy")
  1240  }
  1241  
  1242  func TestCommand_Run_local_subpackages(t *testing.T) {
  1243  	testCases := []struct {
  1244  		name            string
  1245  		reposChanges    map[string][]testutil.Content
  1246  		updatedLocal    testutil.Content
  1247  		expectedResults []resultForStrategy
  1248  	}{
  1249  		{
  1250  			name: "update fetches any new subpackages",
  1251  			reposChanges: map[string][]testutil.Content{
  1252  				testutil.Upstream: {
  1253  					{
  1254  						Pkg: pkgbuilder.NewRootPkg().
  1255  							WithKptfile().
  1256  							WithSubPackages(
  1257  								pkgbuilder.NewSubPkg("bar").
  1258  									WithKptfile(),
  1259  							),
  1260  						Branch: masterBranch,
  1261  					},
  1262  					{
  1263  						Pkg: pkgbuilder.NewRootPkg().
  1264  							WithKptfile().
  1265  							WithSubPackages(
  1266  								pkgbuilder.NewSubPkg("bar").
  1267  									WithKptfile().
  1268  									WithSubPackages(
  1269  										pkgbuilder.NewSubPkg("nestedbar").
  1270  											WithKptfile(),
  1271  									),
  1272  								pkgbuilder.NewSubPkg("zork").
  1273  									WithKptfile(),
  1274  							),
  1275  					},
  1276  				},
  1277  			},
  1278  			expectedResults: []resultForStrategy{
  1279  				{
  1280  					strategies: []kptfilev1.UpdateStrategyType{
  1281  						kptfilev1.ResourceMerge,
  1282  						kptfilev1.FastForward,
  1283  						kptfilev1.ForceDeleteReplace,
  1284  					},
  1285  					expectedLocal: pkgbuilder.NewRootPkg().
  1286  						WithKptfile(
  1287  							pkgbuilder.NewKptfile().
  1288  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1289  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1290  						).
  1291  						WithSubPackages(
  1292  							pkgbuilder.NewSubPkg("bar").
  1293  								WithKptfile().
  1294  								WithSubPackages(
  1295  									pkgbuilder.NewSubPkg("nestedbar").
  1296  										WithKptfile(),
  1297  								),
  1298  							pkgbuilder.NewSubPkg("zork").
  1299  								WithKptfile(),
  1300  						),
  1301  				},
  1302  			},
  1303  		},
  1304  		{
  1305  			name: "local changes and a noop update",
  1306  			reposChanges: map[string][]testutil.Content{
  1307  				testutil.Upstream: {
  1308  					{
  1309  						Pkg: pkgbuilder.NewRootPkg().
  1310  							WithKptfile().
  1311  							WithSubPackages(
  1312  								pkgbuilder.NewSubPkg("bar").
  1313  									WithKptfile(),
  1314  							),
  1315  						Branch: masterBranch,
  1316  					},
  1317  				},
  1318  			},
  1319  			updatedLocal: testutil.Content{
  1320  				Pkg: pkgbuilder.NewRootPkg().
  1321  					WithKptfile().
  1322  					WithSubPackages(
  1323  						pkgbuilder.NewSubPkg("bar").
  1324  							WithKptfile(),
  1325  						pkgbuilder.NewSubPkg("zork").
  1326  							WithKptfile(),
  1327  					),
  1328  			},
  1329  			expectedResults: []resultForStrategy{
  1330  				{
  1331  					strategies: []kptfilev1.UpdateStrategyType{
  1332  						kptfilev1.ResourceMerge,
  1333  					},
  1334  					expectedLocal: pkgbuilder.NewRootPkg().
  1335  						WithKptfile(
  1336  							pkgbuilder.NewKptfile().
  1337  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1338  								WithUpstreamLockRef("upstream", "/", masterBranch, 0),
  1339  						).
  1340  						WithSubPackages(
  1341  							pkgbuilder.NewSubPkg("bar").
  1342  								WithKptfile(),
  1343  							pkgbuilder.NewSubPkg("zork").
  1344  								WithKptfile(),
  1345  						),
  1346  				},
  1347  				{
  1348  					strategies: []kptfilev1.UpdateStrategyType{
  1349  						kptfilev1.FastForward,
  1350  					},
  1351  					expectedErrMsg: "use a different update --strategy",
  1352  				},
  1353  				{
  1354  					strategies: []kptfilev1.UpdateStrategyType{
  1355  						kptfilev1.ForceDeleteReplace,
  1356  					},
  1357  					expectedLocal: pkgbuilder.NewRootPkg().
  1358  						WithKptfile(
  1359  							pkgbuilder.NewKptfile().
  1360  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1361  								WithUpstreamLockRef("upstream", "/", masterBranch, 0),
  1362  						).
  1363  						WithSubPackages(
  1364  							pkgbuilder.NewSubPkg("bar").
  1365  								WithKptfile(),
  1366  						),
  1367  				},
  1368  			},
  1369  		},
  1370  		{
  1371  			name: "non-overlapping additions in both upstream and local",
  1372  			reposChanges: map[string][]testutil.Content{
  1373  				testutil.Upstream: {
  1374  					{
  1375  						Pkg: pkgbuilder.NewRootPkg().
  1376  							WithKptfile().
  1377  							WithSubPackages(
  1378  								pkgbuilder.NewSubPkg("bar").
  1379  									WithKptfile(),
  1380  							),
  1381  						Branch: masterBranch,
  1382  					},
  1383  					{
  1384  						Pkg: pkgbuilder.NewRootPkg().
  1385  							WithKptfile().
  1386  							WithSubPackages(
  1387  								pkgbuilder.NewSubPkg("bar").
  1388  									WithKptfile(),
  1389  								pkgbuilder.NewSubPkg("zork").
  1390  									WithKptfile(),
  1391  							),
  1392  					},
  1393  				},
  1394  			},
  1395  			updatedLocal: testutil.Content{
  1396  				Pkg: pkgbuilder.NewRootPkg().
  1397  					WithKptfile().
  1398  					WithSubPackages(
  1399  						pkgbuilder.NewSubPkg("bar").
  1400  							WithKptfile(),
  1401  						pkgbuilder.NewSubPkg("abc").
  1402  							WithKptfile(),
  1403  					),
  1404  			},
  1405  			expectedResults: []resultForStrategy{
  1406  				{
  1407  					strategies: []kptfilev1.UpdateStrategyType{
  1408  						kptfilev1.ResourceMerge,
  1409  					},
  1410  					expectedLocal: pkgbuilder.NewRootPkg().
  1411  						WithKptfile(
  1412  							pkgbuilder.NewKptfile().
  1413  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1414  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1415  						).
  1416  						WithSubPackages(
  1417  							pkgbuilder.NewSubPkg("bar").
  1418  								WithKptfile(),
  1419  							pkgbuilder.NewSubPkg("zork").
  1420  								WithKptfile(),
  1421  							pkgbuilder.NewSubPkg("abc").
  1422  								WithKptfile(),
  1423  						),
  1424  				},
  1425  				{
  1426  					strategies: []kptfilev1.UpdateStrategyType{
  1427  						kptfilev1.FastForward,
  1428  					},
  1429  					expectedErrMsg: "use a different update --strategy",
  1430  				},
  1431  				{
  1432  					strategies: []kptfilev1.UpdateStrategyType{
  1433  						kptfilev1.ForceDeleteReplace,
  1434  					},
  1435  					expectedLocal: pkgbuilder.NewRootPkg().
  1436  						WithKptfile(
  1437  							pkgbuilder.NewKptfile().
  1438  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1439  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1440  						).
  1441  						WithSubPackages(
  1442  							pkgbuilder.NewSubPkg("bar").
  1443  								WithKptfile(),
  1444  							pkgbuilder.NewSubPkg("zork").
  1445  								WithKptfile(),
  1446  						),
  1447  				},
  1448  			},
  1449  		},
  1450  		{
  1451  			name: "overlapping additions in both upstream and local",
  1452  			reposChanges: map[string][]testutil.Content{
  1453  				testutil.Upstream: {
  1454  					{
  1455  						Pkg: pkgbuilder.NewRootPkg().
  1456  							WithKptfile().
  1457  							WithSubPackages(
  1458  								pkgbuilder.NewSubPkg("bar").
  1459  									WithKptfile(),
  1460  							),
  1461  						Branch: masterBranch,
  1462  					},
  1463  					{
  1464  						Pkg: pkgbuilder.NewRootPkg().
  1465  							WithKptfile().
  1466  							WithSubPackages(
  1467  								pkgbuilder.NewSubPkg("bar").
  1468  									WithKptfile(),
  1469  								pkgbuilder.NewSubPkg("abc").
  1470  									WithKptfile(),
  1471  							),
  1472  					},
  1473  				},
  1474  			},
  1475  			updatedLocal: testutil.Content{
  1476  				Pkg: pkgbuilder.NewRootPkg().
  1477  					WithKptfile().
  1478  					WithSubPackages(
  1479  						pkgbuilder.NewSubPkg("bar").
  1480  							WithKptfile(),
  1481  						pkgbuilder.NewSubPkg("abc").
  1482  							WithKptfile(),
  1483  					),
  1484  			},
  1485  			expectedResults: []resultForStrategy{
  1486  				{
  1487  					strategies: []kptfilev1.UpdateStrategyType{
  1488  						kptfilev1.ResourceMerge,
  1489  					},
  1490  					expectedErrMsg: "subpackage \"abc\" added in both upstream and local",
  1491  				},
  1492  				{
  1493  					strategies: []kptfilev1.UpdateStrategyType{
  1494  						kptfilev1.FastForward,
  1495  					},
  1496  					expectedErrMsg: "use a different update --strategy",
  1497  				},
  1498  				{
  1499  					strategies: []kptfilev1.UpdateStrategyType{
  1500  						kptfilev1.ForceDeleteReplace,
  1501  					},
  1502  					expectedLocal: pkgbuilder.NewRootPkg().
  1503  						WithKptfile(
  1504  							pkgbuilder.NewKptfile().
  1505  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1506  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1507  						).
  1508  						WithSubPackages(
  1509  							pkgbuilder.NewSubPkg("bar").
  1510  								WithKptfile(),
  1511  							pkgbuilder.NewSubPkg("abc").
  1512  								WithKptfile(),
  1513  						),
  1514  				},
  1515  			},
  1516  		},
  1517  		{
  1518  			name: "subpackages deleted in upstream",
  1519  			reposChanges: map[string][]testutil.Content{
  1520  				testutil.Upstream: {
  1521  					{
  1522  						Pkg: pkgbuilder.NewRootPkg().
  1523  							WithKptfile().
  1524  							WithSubPackages(
  1525  								pkgbuilder.NewSubPkg("bar").
  1526  									WithKptfile(),
  1527  							),
  1528  						Branch: masterBranch,
  1529  					},
  1530  					{
  1531  						Pkg: pkgbuilder.NewRootPkg().
  1532  							WithKptfile(),
  1533  					},
  1534  				},
  1535  			},
  1536  			expectedResults: []resultForStrategy{
  1537  				{
  1538  					strategies: []kptfilev1.UpdateStrategyType{
  1539  						kptfilev1.ResourceMerge,
  1540  						kptfilev1.FastForward,
  1541  						kptfilev1.ForceDeleteReplace,
  1542  					},
  1543  					expectedLocal: pkgbuilder.NewRootPkg().
  1544  						WithKptfile(
  1545  							pkgbuilder.NewKptfile().
  1546  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1547  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1548  						),
  1549  				},
  1550  			},
  1551  		},
  1552  		{
  1553  			name: "multiple layers of subpackages added in upstream",
  1554  			reposChanges: map[string][]testutil.Content{
  1555  				testutil.Upstream: {
  1556  					{
  1557  						Pkg: pkgbuilder.NewRootPkg().
  1558  							WithKptfile(),
  1559  						Branch: masterBranch,
  1560  					},
  1561  					{
  1562  						Pkg: pkgbuilder.NewRootPkg().
  1563  							WithKptfile().
  1564  							WithSubPackages(
  1565  								pkgbuilder.NewSubPkg("bar").
  1566  									WithKptfile().
  1567  									WithSubPackages(
  1568  										pkgbuilder.NewSubPkg("nestedbar").
  1569  											WithKptfile(),
  1570  									),
  1571  							),
  1572  					},
  1573  				},
  1574  			},
  1575  			expectedResults: []resultForStrategy{
  1576  				{
  1577  					strategies: []kptfilev1.UpdateStrategyType{
  1578  						kptfilev1.ResourceMerge,
  1579  						kptfilev1.FastForward,
  1580  						kptfilev1.ForceDeleteReplace,
  1581  					},
  1582  					expectedLocal: pkgbuilder.NewRootPkg().
  1583  						WithKptfile(
  1584  							pkgbuilder.NewKptfile().
  1585  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1586  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1587  						).
  1588  						WithSubPackages(
  1589  							pkgbuilder.NewSubPkg("bar").
  1590  								WithKptfile().
  1591  								WithSubPackages(
  1592  									pkgbuilder.NewSubPkg("nestedbar").
  1593  										WithKptfile(),
  1594  								),
  1595  						),
  1596  				},
  1597  			},
  1598  		},
  1599  		{
  1600  			name: "removed Kptfile from upstream",
  1601  			reposChanges: map[string][]testutil.Content{
  1602  				testutil.Upstream: {
  1603  					{
  1604  						Pkg: pkgbuilder.NewRootPkg().
  1605  							WithKptfile().
  1606  							WithSubPackages(
  1607  								pkgbuilder.NewSubPkg("bar").
  1608  									WithKptfile(pkgbuilder.NewKptfile()).
  1609  									WithResource(pkgbuilder.DeploymentResource),
  1610  							),
  1611  						Branch: masterBranch,
  1612  					},
  1613  					{
  1614  						Pkg: pkgbuilder.NewRootPkg().
  1615  							WithKptfile().
  1616  							WithSubPackages(
  1617  								pkgbuilder.NewSubPkg("bar").
  1618  									WithResource(pkgbuilder.DeploymentResource),
  1619  							),
  1620  					},
  1621  				},
  1622  			},
  1623  			expectedResults: []resultForStrategy{
  1624  				// TODO(mortent): Revisit this. Not clear that the Kptfile
  1625  				// shouldn't be deleted here since it doesn't really have any
  1626  				// local changes.
  1627  				{
  1628  					strategies: []kptfilev1.UpdateStrategyType{
  1629  						kptfilev1.ResourceMerge,
  1630  					},
  1631  					expectedLocal: pkgbuilder.NewRootPkg().
  1632  						WithKptfile(
  1633  							pkgbuilder.NewKptfile().
  1634  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1635  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1636  						).
  1637  						WithSubPackages(
  1638  							pkgbuilder.NewSubPkg("bar").
  1639  								WithKptfile(pkgbuilder.NewKptfile()).
  1640  								WithResource(pkgbuilder.DeploymentResource),
  1641  						),
  1642  				},
  1643  				{
  1644  					strategies: []kptfilev1.UpdateStrategyType{
  1645  						kptfilev1.FastForward,
  1646  						kptfilev1.ForceDeleteReplace,
  1647  					},
  1648  					expectedLocal: pkgbuilder.NewRootPkg().
  1649  						WithKptfile(
  1650  							pkgbuilder.NewKptfile().
  1651  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1652  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1653  						).
  1654  						WithSubPackages(
  1655  							pkgbuilder.NewSubPkg("bar").
  1656  								WithResource(pkgbuilder.DeploymentResource),
  1657  						),
  1658  				},
  1659  			},
  1660  		},
  1661  		{
  1662  			name: "kptfile added only on local",
  1663  			reposChanges: map[string][]testutil.Content{
  1664  				testutil.Upstream: {
  1665  					{
  1666  						Pkg: pkgbuilder.NewRootPkg().
  1667  							WithKptfile().
  1668  							WithSubPackages(
  1669  								pkgbuilder.NewSubPkg("bar").
  1670  									WithResource(pkgbuilder.DeploymentResource),
  1671  							),
  1672  						Branch: masterBranch,
  1673  					},
  1674  					{
  1675  						Pkg: pkgbuilder.NewRootPkg().
  1676  							WithKptfile().
  1677  							WithSubPackages(
  1678  								pkgbuilder.NewSubPkg("bar").
  1679  									WithResource(pkgbuilder.DeploymentResource).
  1680  									WithResource(pkgbuilder.ConfigMapResource),
  1681  							),
  1682  					},
  1683  				},
  1684  			},
  1685  			updatedLocal: testutil.Content{
  1686  				Pkg: pkgbuilder.NewRootPkg().
  1687  					WithKptfile().
  1688  					WithSubPackages(
  1689  						pkgbuilder.NewSubPkg("bar").
  1690  							WithKptfile(pkgbuilder.NewKptfile()).
  1691  							WithResource(pkgbuilder.DeploymentResource),
  1692  					),
  1693  			},
  1694  			expectedResults: []resultForStrategy{
  1695  				{
  1696  					strategies: []kptfilev1.UpdateStrategyType{
  1697  						kptfilev1.ResourceMerge,
  1698  					},
  1699  					expectedLocal: pkgbuilder.NewRootPkg().
  1700  						WithKptfile(
  1701  							pkgbuilder.NewKptfile().
  1702  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1703  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1704  						).
  1705  						WithSubPackages(
  1706  							pkgbuilder.NewSubPkg("bar").
  1707  								WithKptfile(pkgbuilder.NewKptfile()).
  1708  								WithResource(pkgbuilder.DeploymentResource).
  1709  								WithResource(pkgbuilder.ConfigMapResource),
  1710  						),
  1711  				},
  1712  				{
  1713  					strategies: []kptfilev1.UpdateStrategyType{
  1714  						kptfilev1.FastForward,
  1715  					},
  1716  					expectedErrMsg: "use a different update --strategy",
  1717  				},
  1718  				{
  1719  					strategies: []kptfilev1.UpdateStrategyType{
  1720  						kptfilev1.ForceDeleteReplace,
  1721  					},
  1722  					expectedLocal: pkgbuilder.NewRootPkg().
  1723  						WithKptfile(
  1724  							pkgbuilder.NewKptfile().
  1725  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1726  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1727  						).
  1728  						WithSubPackages(
  1729  							pkgbuilder.NewSubPkg("bar").
  1730  								WithResource(pkgbuilder.DeploymentResource).
  1731  								WithResource(pkgbuilder.ConfigMapResource),
  1732  						),
  1733  				},
  1734  			},
  1735  		},
  1736  		{
  1737  			name: "subpackage deleted from upstream but is unchanged in local",
  1738  			reposChanges: map[string][]testutil.Content{
  1739  				testutil.Upstream: {
  1740  					{
  1741  						Pkg: pkgbuilder.NewRootPkg().
  1742  							WithKptfile().
  1743  							WithSubPackages(
  1744  								pkgbuilder.NewSubPkg("bar").
  1745  									WithKptfile(pkgbuilder.NewKptfile()).
  1746  									WithResource(pkgbuilder.DeploymentResource),
  1747  							),
  1748  						Branch: masterBranch,
  1749  					},
  1750  					{
  1751  						Pkg: pkgbuilder.NewRootPkg().
  1752  							WithKptfile(),
  1753  					},
  1754  				},
  1755  			},
  1756  			expectedResults: []resultForStrategy{
  1757  				{
  1758  					strategies: []kptfilev1.UpdateStrategyType{
  1759  						kptfilev1.ResourceMerge,
  1760  						kptfilev1.FastForward,
  1761  						kptfilev1.ForceDeleteReplace,
  1762  					},
  1763  					expectedLocal: pkgbuilder.NewRootPkg().
  1764  						WithKptfile(
  1765  							pkgbuilder.NewKptfile().
  1766  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1767  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1768  						),
  1769  				},
  1770  			},
  1771  		},
  1772  		{
  1773  			name: "subpackage deleted from upstream but has local changes",
  1774  			reposChanges: map[string][]testutil.Content{
  1775  				testutil.Upstream: {
  1776  					{
  1777  						Pkg: pkgbuilder.NewRootPkg().
  1778  							WithKptfile().
  1779  							WithSubPackages(
  1780  								pkgbuilder.NewSubPkg("bar").
  1781  									WithKptfile(pkgbuilder.NewKptfile()).
  1782  									WithResource(pkgbuilder.DeploymentResource),
  1783  							),
  1784  						Branch: masterBranch,
  1785  					},
  1786  					{
  1787  						Pkg: pkgbuilder.NewRootPkg().
  1788  							WithKptfile(),
  1789  					},
  1790  				},
  1791  			},
  1792  			updatedLocal: testutil.Content{
  1793  				Pkg: pkgbuilder.NewRootPkg().
  1794  					WithKptfile().
  1795  					WithSubPackages(
  1796  						pkgbuilder.NewSubPkg("bar").
  1797  							WithKptfile(pkgbuilder.NewKptfile()).
  1798  							WithResource(pkgbuilder.DeploymentResource,
  1799  								pkgbuilder.SetFieldPath("34", "spec", "replicas")),
  1800  					),
  1801  			},
  1802  			expectedResults: []resultForStrategy{
  1803  				{
  1804  					strategies: []kptfilev1.UpdateStrategyType{
  1805  						kptfilev1.ResourceMerge,
  1806  					},
  1807  					expectedLocal: pkgbuilder.NewRootPkg().
  1808  						WithKptfile(
  1809  							pkgbuilder.NewKptfile().
  1810  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1811  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1812  						).
  1813  						WithSubPackages(
  1814  							pkgbuilder.NewSubPkg("bar").
  1815  								WithKptfile(pkgbuilder.NewKptfile()).
  1816  								WithResource(pkgbuilder.DeploymentResource,
  1817  									pkgbuilder.SetFieldPath("34", "spec", "replicas")),
  1818  						),
  1819  				},
  1820  				{
  1821  					strategies: []kptfilev1.UpdateStrategyType{
  1822  						kptfilev1.FastForward,
  1823  					},
  1824  					expectedErrMsg: "use a different update --strategy",
  1825  				},
  1826  				{
  1827  					strategies: []kptfilev1.UpdateStrategyType{
  1828  						kptfilev1.ForceDeleteReplace,
  1829  					},
  1830  					expectedLocal: pkgbuilder.NewRootPkg().
  1831  						WithKptfile(
  1832  							pkgbuilder.NewKptfile().
  1833  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1834  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1835  						),
  1836  				},
  1837  			},
  1838  		},
  1839  		{
  1840  			name: "upstream package doesn't need to have a Kptfile in the root",
  1841  			reposChanges: map[string][]testutil.Content{
  1842  				testutil.Upstream: {
  1843  					{
  1844  						Pkg: pkgbuilder.NewRootPkg().
  1845  							WithResource(pkgbuilder.DeploymentResource).
  1846  							WithSubPackages(
  1847  								pkgbuilder.NewSubPkg("subpkg").
  1848  									WithKptfile(pkgbuilder.NewKptfile()),
  1849  							),
  1850  						Branch: masterBranch,
  1851  					},
  1852  					{
  1853  						Pkg: pkgbuilder.NewRootPkg().
  1854  							WithResource(pkgbuilder.DeploymentResource).
  1855  							WithResource(pkgbuilder.ConfigMapResource).
  1856  							WithSubPackages(
  1857  								pkgbuilder.NewSubPkg("subpkg").
  1858  									WithKptfile(pkgbuilder.NewKptfile()),
  1859  							),
  1860  					},
  1861  				},
  1862  			},
  1863  			expectedResults: []resultForStrategy{
  1864  				{
  1865  					strategies: []kptfilev1.UpdateStrategyType{
  1866  						kptfilev1.ResourceMerge,
  1867  						kptfilev1.FastForward,
  1868  						kptfilev1.ForceDeleteReplace,
  1869  					},
  1870  					expectedLocal: pkgbuilder.NewRootPkg().
  1871  						WithKptfile(
  1872  							pkgbuilder.NewKptfile().
  1873  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1874  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1875  						).
  1876  						WithResource(pkgbuilder.DeploymentResource).
  1877  						WithResource(pkgbuilder.ConfigMapResource).
  1878  						WithSubPackages(
  1879  							pkgbuilder.NewSubPkg("subpkg").
  1880  								WithKptfile(pkgbuilder.NewKptfile()),
  1881  						),
  1882  				},
  1883  			},
  1884  		},
  1885  		{
  1886  			name: "non-krm files updated in upstream",
  1887  			reposChanges: map[string][]testutil.Content{
  1888  				testutil.Upstream: {
  1889  					{
  1890  						Pkg: pkgbuilder.NewRootPkg().
  1891  							WithKptfile(pkgbuilder.NewKptfile()).
  1892  							WithFile("data.txt", "initial content").
  1893  							WithSubPackages(
  1894  								pkgbuilder.NewSubPkg("subpkg").
  1895  									WithKptfile(pkgbuilder.NewKptfile()).
  1896  									WithFile("information", "first version"),
  1897  							),
  1898  						Branch: masterBranch,
  1899  					},
  1900  					{
  1901  						Pkg: pkgbuilder.NewRootPkg().
  1902  							WithKptfile(pkgbuilder.NewKptfile()).
  1903  							WithFile("data.txt", "updated content").
  1904  							WithSubPackages(
  1905  								pkgbuilder.NewSubPkg("subpkg").
  1906  									WithKptfile(pkgbuilder.NewKptfile()).
  1907  									WithFile("information", "second version"),
  1908  							),
  1909  					},
  1910  				},
  1911  			},
  1912  			expectedResults: []resultForStrategy{
  1913  				{
  1914  					strategies: []kptfilev1.UpdateStrategyType{
  1915  						kptfilev1.ResourceMerge,
  1916  						kptfilev1.FastForward,
  1917  						kptfilev1.ForceDeleteReplace,
  1918  					},
  1919  					expectedLocal: pkgbuilder.NewRootPkg().
  1920  						WithKptfile(
  1921  							pkgbuilder.NewKptfile().
  1922  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1923  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1924  						).
  1925  						WithFile("data.txt", "updated content").
  1926  						WithSubPackages(
  1927  							pkgbuilder.NewSubPkg("subpkg").
  1928  								WithKptfile(pkgbuilder.NewKptfile()).
  1929  								WithFile("information", "second version"),
  1930  						),
  1931  				},
  1932  			},
  1933  		},
  1934  		{
  1935  			name: "non-krm files updated in both upstream and local",
  1936  			reposChanges: map[string][]testutil.Content{
  1937  				testutil.Upstream: {
  1938  					{
  1939  						Pkg: pkgbuilder.NewRootPkg().
  1940  							WithKptfile(pkgbuilder.NewKptfile()).
  1941  							WithFile("data.txt", "initial content"),
  1942  						Branch: masterBranch,
  1943  					},
  1944  					{
  1945  						Pkg: pkgbuilder.NewRootPkg().
  1946  							WithKptfile(pkgbuilder.NewKptfile()).
  1947  							WithFile("data.txt", "updated content"),
  1948  					},
  1949  				},
  1950  			},
  1951  			updatedLocal: testutil.Content{
  1952  				Pkg: pkgbuilder.NewRootPkg().
  1953  					WithKptfile(pkgbuilder.NewKptfile()).
  1954  					WithFile("data.txt", "local content"),
  1955  			},
  1956  			expectedResults: []resultForStrategy{
  1957  				{
  1958  					strategies: []kptfilev1.UpdateStrategyType{
  1959  						kptfilev1.ResourceMerge,
  1960  					},
  1961  					expectedLocal: pkgbuilder.NewRootPkg().
  1962  						WithKptfile(
  1963  							pkgbuilder.NewKptfile().
  1964  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1965  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1966  						).
  1967  						WithFile("data.txt", "local content"),
  1968  				},
  1969  				{
  1970  					strategies: []kptfilev1.UpdateStrategyType{
  1971  						kptfilev1.FastForward,
  1972  					},
  1973  					expectedErrMsg: "use a different update --strategy",
  1974  				},
  1975  				{
  1976  					strategies: []kptfilev1.UpdateStrategyType{
  1977  						kptfilev1.ForceDeleteReplace,
  1978  					},
  1979  					expectedLocal: pkgbuilder.NewRootPkg().
  1980  						WithKptfile(
  1981  							pkgbuilder.NewKptfile().
  1982  								WithUpstreamRef("upstream", "/", masterBranch, "PLACEHOLDER").
  1983  								WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  1984  						).
  1985  						WithFile("data.txt", "updated content"),
  1986  				},
  1987  			},
  1988  		},
  1989  	}
  1990  
  1991  	for i := range testCases {
  1992  		test := testCases[i]
  1993  		strategies := findStrategiesForTestCase(test.expectedResults)
  1994  		for i := range strategies {
  1995  			strategy := strategies[i]
  1996  			t.Run(fmt.Sprintf("%s#%s", test.name, string(strategy)), func(t *testing.T) {
  1997  				g := &testutil.TestSetupManager{
  1998  					T:            t,
  1999  					ReposChanges: test.reposChanges,
  2000  				}
  2001  				defer g.Clean()
  2002  				if test.updatedLocal.Pkg != nil {
  2003  					g.LocalChanges = []testutil.Content{
  2004  						test.updatedLocal,
  2005  					}
  2006  				}
  2007  				if !g.Init() {
  2008  					return
  2009  				}
  2010  
  2011  				err := (&Command{
  2012  					Pkg:      pkgtest.CreatePkgOrFail(t, g.LocalWorkspace.FullPackagePath()),
  2013  					Strategy: strategy,
  2014  				}).Run(fake.CtxWithDefaultPrinter())
  2015  
  2016  				result := findExpectedResultForStrategy(test.expectedResults, strategy)
  2017  
  2018  				if result.expectedErrMsg != "" {
  2019  					if !assert.Error(t, err) {
  2020  						t.FailNow()
  2021  					}
  2022  					assert.Contains(t, err.Error(), result.expectedErrMsg)
  2023  					return
  2024  				}
  2025  				if !assert.NoError(t, err) {
  2026  					t.FailNow()
  2027  				}
  2028  
  2029  				// Format the Kptfiles so we can diff the output without
  2030  				// formatting issues.
  2031  				rw := &kio.LocalPackageReadWriter{
  2032  					NoDeleteFiles:     true,
  2033  					PackagePath:       g.LocalWorkspace.FullPackagePath(),
  2034  					MatchFilesGlob:    []string{kptfilev1.KptFileName},
  2035  					PreserveSeqIndent: true,
  2036  					WrapBareSeqNode:   true,
  2037  				}
  2038  				err = kio.Pipeline{
  2039  					Inputs:  []kio.Reader{rw},
  2040  					Filters: []kio.Filter{filters.FormatFilter{}},
  2041  					Outputs: []kio.Writer{rw},
  2042  				}.Execute()
  2043  				if !assert.NoError(t, err) {
  2044  					t.FailNow()
  2045  				}
  2046  
  2047  				expectedPath := result.expectedLocal.ExpandPkgWithName(t,
  2048  					g.LocalWorkspace.PackageDir, testutil.ToReposInfo(g.Repos))
  2049  				kf, err := pkg.ReadKptfile(filesys.FileSystemOrOnDisk{}, expectedPath)
  2050  				if !assert.NoError(t, err) {
  2051  					t.FailNow()
  2052  				}
  2053  				kf.Upstream.UpdateStrategy = strategy
  2054  				err = kptfileutil.WriteFile(expectedPath, kf)
  2055  				if !assert.NoError(t, err) {
  2056  					t.FailNow()
  2057  				}
  2058  
  2059  				testutil.KptfileAwarePkgEqual(t, expectedPath, g.LocalWorkspace.FullPackagePath(), true)
  2060  			})
  2061  		}
  2062  	}
  2063  }
  2064  
  2065  type resultForStrategy struct {
  2066  	strategies     []kptfilev1.UpdateStrategyType
  2067  	expectedLocal  *pkgbuilder.RootPkg
  2068  	expectedErrMsg string
  2069  }
  2070  
  2071  func findStrategiesForTestCase(expectedResults []resultForStrategy) []kptfilev1.UpdateStrategyType {
  2072  	var strategies []kptfilev1.UpdateStrategyType
  2073  	for _, er := range expectedResults {
  2074  		strategies = append(strategies, er.strategies...)
  2075  	}
  2076  	return strategies
  2077  }
  2078  
  2079  func findExpectedResultForStrategy(strategyResults []resultForStrategy,
  2080  	strategy kptfilev1.UpdateStrategyType) resultForStrategy {
  2081  	for _, sr := range strategyResults {
  2082  		for _, s := range sr.strategies {
  2083  			if s == strategy {
  2084  				return sr
  2085  			}
  2086  		}
  2087  	}
  2088  	panic(fmt.Errorf("unknown strategy %s", string(strategy)))
  2089  }
  2090  
  2091  func TestRun_remote_subpackages(t *testing.T) {
  2092  	testCases := map[string]struct {
  2093  		reposChanges   map[string][]testutil.Content
  2094  		updatedLocal   testutil.Content
  2095  		expectedLocal  *pkgbuilder.RootPkg
  2096  		expectedErrMsg string
  2097  	}{
  2098  		"subpackages are updated based on the version specified in their Kptfile": {
  2099  			reposChanges: map[string][]testutil.Content{
  2100  				testutil.Upstream: {
  2101  					{
  2102  						Pkg: pkgbuilder.NewRootPkg().
  2103  							WithKptfile().
  2104  							WithSubPackages(
  2105  								pkgbuilder.NewSubPkg("foo").
  2106  									WithKptfile(
  2107  										pkgbuilder.NewKptfile().
  2108  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge"),
  2109  									),
  2110  							),
  2111  						Branch: masterBranch,
  2112  					},
  2113  					{
  2114  						Pkg: pkgbuilder.NewRootPkg().
  2115  							WithKptfile().
  2116  							WithResource(pkgbuilder.DeploymentResource).
  2117  							WithSubPackages(
  2118  								pkgbuilder.NewSubPkg("foo").
  2119  									WithKptfile(
  2120  										pkgbuilder.NewKptfile().
  2121  											WithUpstreamRef("foo", "/", "v1.0", "resource-merge"),
  2122  									),
  2123  							),
  2124  					},
  2125  				},
  2126  				"foo": {
  2127  					{
  2128  						Pkg: pkgbuilder.NewRootPkg().
  2129  							WithKptfile().
  2130  							WithResource(pkgbuilder.DeploymentResource),
  2131  						Branch: masterBranch,
  2132  					},
  2133  					{
  2134  						Pkg: pkgbuilder.NewRootPkg().
  2135  							WithKptfile().
  2136  							WithResource(pkgbuilder.ConfigMapResource),
  2137  						Tag: "v1.0",
  2138  					},
  2139  				},
  2140  			},
  2141  			expectedLocal: pkgbuilder.NewRootPkg().
  2142  				WithKptfile(
  2143  					pkgbuilder.NewKptfile().
  2144  						WithUpstreamRef("upstream", "/", masterBranch, "resource-merge").
  2145  						WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  2146  				).
  2147  				WithResource(pkgbuilder.DeploymentResource).
  2148  				WithSubPackages(
  2149  					pkgbuilder.NewSubPkg("foo").
  2150  						WithKptfile(
  2151  							pkgbuilder.NewKptfile().
  2152  								WithUpstreamRef("foo", "/", "v1.0", "resource-merge").
  2153  								WithUpstreamLockRef("foo", "/", "v1.0", 1),
  2154  						).
  2155  						WithResource(pkgbuilder.ConfigMapResource),
  2156  				),
  2157  		},
  2158  		"subpackage with changes can not be updated with fast-forward strategy": {
  2159  			reposChanges: map[string][]testutil.Content{
  2160  				testutil.Upstream: {
  2161  					{
  2162  						Pkg: pkgbuilder.NewRootPkg().
  2163  							WithKptfile().
  2164  							WithResource(pkgbuilder.ConfigMapResource).
  2165  							WithSubPackages(
  2166  								pkgbuilder.NewSubPkg("foo").
  2167  									WithKptfile(
  2168  										pkgbuilder.NewKptfile().
  2169  											WithUpstreamRef("foo", "/", masterBranch, "fast-forward"),
  2170  									),
  2171  							),
  2172  						Branch: masterBranch,
  2173  					},
  2174  					{
  2175  						Pkg: pkgbuilder.NewRootPkg().
  2176  							WithKptfile().
  2177  							WithResource(pkgbuilder.DeploymentResource).
  2178  							WithSubPackages(
  2179  								pkgbuilder.NewSubPkg("foo").
  2180  									WithKptfile(
  2181  										pkgbuilder.NewKptfile().
  2182  											WithUpstreamRef("foo", "/", "v1.0", "fast-forward"),
  2183  									),
  2184  							),
  2185  					},
  2186  				},
  2187  				"foo": {
  2188  					{
  2189  						Pkg: pkgbuilder.NewRootPkg().
  2190  							WithKptfile().
  2191  							WithResource(pkgbuilder.DeploymentResource),
  2192  						Branch: masterBranch,
  2193  					},
  2194  					{
  2195  						Pkg: pkgbuilder.NewRootPkg().
  2196  							WithKptfile().
  2197  							WithResource(pkgbuilder.ConfigMapResource),
  2198  						Tag: "v1.0",
  2199  					},
  2200  				},
  2201  			},
  2202  			updatedLocal: testutil.Content{
  2203  				Pkg: pkgbuilder.NewRootPkg().
  2204  					WithKptfile().
  2205  					WithResource(pkgbuilder.ConfigMapResource).
  2206  					WithSubPackages(
  2207  						pkgbuilder.NewSubPkg("foo").
  2208  							WithKptfile(
  2209  								pkgbuilder.NewKptfile().
  2210  									WithUpstreamRef("foo", "/", masterBranch, "fast-forward").
  2211  									WithUpstreamLockRef("foo", "/", masterBranch, 0),
  2212  							).
  2213  							WithResource(pkgbuilder.DeploymentResource,
  2214  								pkgbuilder.SetFieldPath("34", "spec", "replicas")),
  2215  					),
  2216  			},
  2217  			expectedErrMsg: "use a different update --strategy",
  2218  		},
  2219  		"subpackage with changes can be updated with resource-merge": {
  2220  			reposChanges: map[string][]testutil.Content{
  2221  				testutil.Upstream: {
  2222  					{
  2223  						Pkg: pkgbuilder.NewRootPkg().
  2224  							WithKptfile().
  2225  							WithResource(pkgbuilder.ConfigMapResource).
  2226  							WithSubPackages(
  2227  								pkgbuilder.NewSubPkg("foo").
  2228  									WithKptfile(
  2229  										pkgbuilder.NewKptfile().
  2230  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge"),
  2231  									),
  2232  							),
  2233  						Branch: masterBranch,
  2234  					},
  2235  					{
  2236  						Pkg: pkgbuilder.NewRootPkg().
  2237  							WithKptfile().
  2238  							WithResource(pkgbuilder.DeploymentResource).
  2239  							WithSubPackages(
  2240  								pkgbuilder.NewSubPkg("foo").
  2241  									WithKptfile(
  2242  										pkgbuilder.NewKptfile().
  2243  											WithUpstreamRef("foo", "/", "v1.0", "resource-merge"),
  2244  									),
  2245  							),
  2246  					},
  2247  				},
  2248  				"foo": {
  2249  					{
  2250  						Pkg: pkgbuilder.NewRootPkg().
  2251  							WithKptfile().
  2252  							WithResource(pkgbuilder.DeploymentResource),
  2253  						Branch: masterBranch,
  2254  					},
  2255  					{
  2256  						Pkg: pkgbuilder.NewRootPkg().
  2257  							WithKptfile().
  2258  							WithResource(pkgbuilder.DeploymentResource,
  2259  								pkgbuilder.SetFieldPath("zork", "spec", "foo")),
  2260  						Tag: "v1.0",
  2261  					},
  2262  				},
  2263  			},
  2264  			updatedLocal: testutil.Content{
  2265  				Pkg: pkgbuilder.NewRootPkg().
  2266  					WithKptfile().
  2267  					WithResource(pkgbuilder.ConfigMapResource).
  2268  					WithSubPackages(
  2269  						pkgbuilder.NewSubPkg("foo").
  2270  							WithKptfile(
  2271  								pkgbuilder.NewKptfile().
  2272  									WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  2273  									WithUpstreamLockRef("foo", "/", masterBranch, 0),
  2274  							).
  2275  							WithResource(pkgbuilder.DeploymentResource,
  2276  								pkgbuilder.SetFieldPath("34", "spec", "replicas")),
  2277  					),
  2278  			},
  2279  			expectedLocal: pkgbuilder.NewRootPkg().
  2280  				WithKptfile(
  2281  					pkgbuilder.NewKptfile().
  2282  						WithUpstreamRef("upstream", "/", masterBranch, "resource-merge").
  2283  						WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  2284  				).
  2285  				WithResource(pkgbuilder.DeploymentResource).
  2286  				WithSubPackages(
  2287  					pkgbuilder.NewSubPkg("foo").
  2288  						WithKptfile(
  2289  							pkgbuilder.NewKptfile().
  2290  								WithUpstreamRef("foo", "/", "v1.0", "resource-merge").
  2291  								WithUpstreamLockRef("foo", "/", "v1.0", 1),
  2292  						).
  2293  						WithResource(pkgbuilder.DeploymentResource,
  2294  							pkgbuilder.SetFieldPath("34", "spec", "replicas"),
  2295  							pkgbuilder.SetFieldPath("zork", "spec", "foo"),
  2296  						),
  2297  				),
  2298  		},
  2299  		"multiple layers of remote packages": {
  2300  			reposChanges: map[string][]testutil.Content{
  2301  				testutil.Upstream: {
  2302  					{
  2303  						Pkg: pkgbuilder.NewRootPkg().
  2304  							WithKptfile().
  2305  							WithResource(pkgbuilder.DeploymentResource).
  2306  							WithSubPackages(
  2307  								pkgbuilder.NewSubPkg("foo").
  2308  									WithKptfile(
  2309  										pkgbuilder.NewKptfile().
  2310  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge"),
  2311  									),
  2312  							),
  2313  						Branch: masterBranch,
  2314  					},
  2315  					{
  2316  						Pkg: pkgbuilder.NewRootPkg().
  2317  							WithKptfile().
  2318  							WithResource(pkgbuilder.ConfigMapResource).
  2319  							WithSubPackages(
  2320  								pkgbuilder.NewSubPkg("foo").
  2321  									WithKptfile(
  2322  										pkgbuilder.NewKptfile().
  2323  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge"),
  2324  									),
  2325  							),
  2326  					},
  2327  				},
  2328  				"foo": {
  2329  					{
  2330  						Pkg: pkgbuilder.NewRootPkg().
  2331  							WithKptfile().
  2332  							WithResource(pkgbuilder.DeploymentResource).
  2333  							WithSubPackages(
  2334  								pkgbuilder.NewSubPkg("bar").
  2335  									WithKptfile(
  2336  										pkgbuilder.NewKptfile().
  2337  											WithUpstreamRef("bar", "/", masterBranch, "fast-forward"),
  2338  									),
  2339  							),
  2340  						Branch: masterBranch,
  2341  					},
  2342  					{
  2343  						Pkg: pkgbuilder.NewRootPkg().
  2344  							WithKptfile().
  2345  							WithResource(pkgbuilder.ConfigMapResource).
  2346  							WithSubPackages(
  2347  								pkgbuilder.NewSubPkg("bar").
  2348  									WithKptfile(
  2349  										pkgbuilder.NewKptfile().
  2350  											WithUpstreamRef("bar", "/", masterBranch, "resource-merge"),
  2351  									),
  2352  							),
  2353  					},
  2354  				},
  2355  				"bar": {
  2356  					{
  2357  						Pkg: pkgbuilder.NewRootPkg().
  2358  							WithKptfile().
  2359  							WithResource(pkgbuilder.DeploymentResource),
  2360  						Branch: masterBranch,
  2361  					}, {
  2362  						Pkg: pkgbuilder.NewRootPkg().
  2363  							WithKptfile().
  2364  							WithResource(pkgbuilder.ConfigMapResource),
  2365  					},
  2366  				},
  2367  			},
  2368  			expectedLocal: pkgbuilder.NewRootPkg().
  2369  				WithKptfile(
  2370  					pkgbuilder.NewKptfile().
  2371  						WithUpstreamRef("upstream", "/", masterBranch, "resource-merge").
  2372  						WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  2373  				).
  2374  				WithResource(pkgbuilder.ConfigMapResource).
  2375  				WithSubPackages(
  2376  					pkgbuilder.NewSubPkg("foo").
  2377  						WithKptfile(
  2378  							pkgbuilder.NewKptfile().
  2379  								WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  2380  								WithUpstreamLockRef("foo", "/", masterBranch, 1),
  2381  						).
  2382  						WithResource(pkgbuilder.ConfigMapResource).
  2383  						WithSubPackages(
  2384  							pkgbuilder.NewSubPkg("bar").
  2385  								WithKptfile(
  2386  									pkgbuilder.NewKptfile().
  2387  										WithUpstreamRef("bar", "/", masterBranch, "resource-merge").
  2388  										WithUpstreamLockRef("bar", "/", masterBranch, 1),
  2389  								).
  2390  								WithResource(pkgbuilder.ConfigMapResource),
  2391  						),
  2392  				),
  2393  		},
  2394  		"remote subpackages distributed with the parent package": {
  2395  			reposChanges: map[string][]testutil.Content{
  2396  				testutil.Upstream: {
  2397  					{
  2398  						Pkg: pkgbuilder.NewRootPkg().
  2399  							WithKptfile().
  2400  							WithResource(pkgbuilder.DeploymentResource).
  2401  							WithSubPackages(
  2402  								pkgbuilder.NewSubPkg("foo").
  2403  									WithKptfile(
  2404  										pkgbuilder.NewKptfile().
  2405  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  2406  											WithUpstreamLockRef("foo", "/", masterBranch, 0),
  2407  									).
  2408  									WithResource(pkgbuilder.DeploymentResource).
  2409  									WithSubPackages(
  2410  										pkgbuilder.NewSubPkg("bar").
  2411  											WithKptfile(
  2412  												pkgbuilder.NewKptfile().
  2413  													WithUpstreamRef("bar", "/", masterBranch, "fast-forward").
  2414  													WithUpstreamLockRef("bar", "/", masterBranch, 0),
  2415  											).
  2416  											WithResource(pkgbuilder.DeploymentResource),
  2417  									),
  2418  							),
  2419  						Branch: masterBranch,
  2420  					},
  2421  					{
  2422  						Pkg: pkgbuilder.NewRootPkg().
  2423  							WithKptfile().
  2424  							WithResource(pkgbuilder.ConfigMapResource).
  2425  							WithSubPackages(
  2426  								pkgbuilder.NewSubPkg("foo").
  2427  									WithKptfile(
  2428  										pkgbuilder.NewKptfile().
  2429  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  2430  											WithUpstreamLockRef("foo", "/", masterBranch, 1),
  2431  									).
  2432  									WithResource(pkgbuilder.ConfigMapResource).
  2433  									WithSubPackages(
  2434  										pkgbuilder.NewSubPkg("bar").
  2435  											WithKptfile(
  2436  												pkgbuilder.NewKptfile().
  2437  													WithUpstreamRef("bar", "/", masterBranch, "resource-merge").
  2438  													WithUpstreamLockRef("bar", "/", masterBranch, 1),
  2439  											).
  2440  											WithResource(pkgbuilder.ConfigMapResource),
  2441  									),
  2442  							),
  2443  					},
  2444  				},
  2445  				"foo": {
  2446  					{
  2447  						Pkg: pkgbuilder.NewRootPkg().
  2448  							WithKptfile().
  2449  							WithResource(pkgbuilder.DeploymentResource).
  2450  							WithSubPackages(
  2451  								pkgbuilder.NewSubPkg("bar").
  2452  									WithKptfile(
  2453  										pkgbuilder.NewKptfile().
  2454  											WithUpstreamRef("bar", "/", masterBranch, "fast-forward").
  2455  											WithUpstreamLockRef("bar", "/", masterBranch, 0),
  2456  									).
  2457  									WithResource(pkgbuilder.DeploymentResource),
  2458  							),
  2459  						Branch: masterBranch,
  2460  					},
  2461  					{
  2462  						Pkg: pkgbuilder.NewRootPkg().
  2463  							WithKptfile().
  2464  							WithResource(pkgbuilder.ConfigMapResource).
  2465  							WithSubPackages(
  2466  								pkgbuilder.NewSubPkg("bar").
  2467  									WithKptfile(
  2468  										pkgbuilder.NewKptfile().
  2469  											WithUpstreamRef("bar", "/", masterBranch, "resource-merge").
  2470  											WithUpstreamLockRef("bar", "/", masterBranch, 1),
  2471  									).
  2472  									WithResource(pkgbuilder.ConfigMapResource),
  2473  							),
  2474  					},
  2475  				},
  2476  				"bar": {
  2477  					{
  2478  						Pkg: pkgbuilder.NewRootPkg().
  2479  							WithKptfile().
  2480  							WithResource(pkgbuilder.DeploymentResource),
  2481  						Branch: masterBranch,
  2482  					}, {
  2483  						Pkg: pkgbuilder.NewRootPkg().
  2484  							WithKptfile().
  2485  							WithResource(pkgbuilder.ConfigMapResource),
  2486  					},
  2487  				},
  2488  			},
  2489  			expectedLocal: pkgbuilder.NewRootPkg().
  2490  				WithKptfile(
  2491  					pkgbuilder.NewKptfile().
  2492  						WithUpstreamRef("upstream", "/", masterBranch, "resource-merge").
  2493  						WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  2494  				).
  2495  				WithResource(pkgbuilder.ConfigMapResource).
  2496  				WithSubPackages(
  2497  					pkgbuilder.NewSubPkg("foo").
  2498  						WithKptfile(
  2499  							pkgbuilder.NewKptfile().
  2500  								WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  2501  								WithUpstreamLockRef("foo", "/", masterBranch, 1),
  2502  						).
  2503  						WithResource(pkgbuilder.ConfigMapResource).
  2504  						WithSubPackages(
  2505  							pkgbuilder.NewSubPkg("bar").
  2506  								WithKptfile(
  2507  									pkgbuilder.NewKptfile().
  2508  										WithUpstreamRef("bar", "/", masterBranch, "resource-merge").
  2509  										WithUpstreamLockRef("bar", "/", masterBranch, 1),
  2510  								).
  2511  								WithResource(pkgbuilder.ConfigMapResource),
  2512  						),
  2513  				),
  2514  		},
  2515  		"subpackage with resource-merge strategy updated in both local and upstream": {
  2516  			reposChanges: map[string][]testutil.Content{
  2517  				testutil.Upstream: {
  2518  					{
  2519  						Pkg: pkgbuilder.NewRootPkg().
  2520  							WithKptfile().
  2521  							WithResource(pkgbuilder.DeploymentResource).
  2522  							WithSubPackages(
  2523  								pkgbuilder.NewSubPkg("foo").
  2524  									WithKptfile(
  2525  										pkgbuilder.NewKptfile().
  2526  											WithUpstreamRef("foo", "/", "v1.0", "resource-merge").
  2527  											WithUpstreamLockRef("foo", "/", "v1.0", 0),
  2528  									).
  2529  									WithResource(pkgbuilder.DeploymentResource),
  2530  							),
  2531  						Branch: masterBranch,
  2532  					},
  2533  					{
  2534  						Pkg: pkgbuilder.NewRootPkg().
  2535  							WithKptfile().
  2536  							WithResource(pkgbuilder.ConfigMapResource).
  2537  							WithSubPackages(
  2538  								pkgbuilder.NewSubPkg("foo").
  2539  									WithKptfile(
  2540  										pkgbuilder.NewKptfile().
  2541  											WithUpstreamRef("foo", "/", "v2.0", "resource-merge").
  2542  											WithUpstreamLockRef("foo", "/", "v2.0", 1),
  2543  									).
  2544  									WithResource(pkgbuilder.ConfigMapResource),
  2545  							),
  2546  					},
  2547  				},
  2548  				"foo": {
  2549  					{
  2550  						Pkg: pkgbuilder.NewRootPkg().
  2551  							WithKptfile().
  2552  							WithResource(pkgbuilder.DeploymentResource),
  2553  						Branch: "main",
  2554  						Tag:    "v1.0",
  2555  					},
  2556  					{
  2557  						Pkg: pkgbuilder.NewRootPkg().
  2558  							WithKptfile().
  2559  							WithResource(pkgbuilder.ConfigMapResource),
  2560  						Tag: "v2.0",
  2561  					},
  2562  					{
  2563  						Pkg: pkgbuilder.NewRootPkg().
  2564  							WithKptfile().
  2565  							WithResource(pkgbuilder.SecretResource),
  2566  						Tag: "v3.0",
  2567  					},
  2568  				},
  2569  			},
  2570  			updatedLocal: testutil.Content{
  2571  				Pkg: pkgbuilder.NewRootPkg().
  2572  					WithKptfile().
  2573  					WithResource(pkgbuilder.ConfigMapResource).
  2574  					WithSubPackages(
  2575  						pkgbuilder.NewSubPkg("foo").
  2576  							WithKptfile(
  2577  								pkgbuilder.NewKptfile().
  2578  									WithUpstreamRef("foo", "/", "v3.0", "resource-merge").
  2579  									WithUpstreamLockRef("foo", "/", "v3.0", 2),
  2580  							).
  2581  							WithResource(pkgbuilder.SecretResource),
  2582  					),
  2583  			},
  2584  			expectedLocal: pkgbuilder.NewRootPkg().
  2585  				WithKptfile(
  2586  					pkgbuilder.NewKptfile().
  2587  						WithUpstreamRef("upstream", "/", masterBranch, "resource-merge").
  2588  						WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  2589  				).
  2590  				WithResource(pkgbuilder.ConfigMapResource).
  2591  				WithSubPackages(
  2592  					pkgbuilder.NewSubPkg("foo").
  2593  						WithKptfile(
  2594  							pkgbuilder.NewKptfile().
  2595  								WithUpstreamRef("foo", "/", "v3.0", "resource-merge").
  2596  								WithUpstreamLockRef("foo", "/", "v3.0", 2),
  2597  						).
  2598  						WithResource(pkgbuilder.SecretResource),
  2599  				),
  2600  		},
  2601  		"subpackage with force-delete-replace strategy updated in both local and upstream": {
  2602  			reposChanges: map[string][]testutil.Content{
  2603  				testutil.Upstream: {
  2604  					{
  2605  						Pkg: pkgbuilder.NewRootPkg().
  2606  							WithKptfile().
  2607  							WithResource(pkgbuilder.DeploymentResource).
  2608  							WithSubPackages(
  2609  								pkgbuilder.NewSubPkg("foo").
  2610  									WithKptfile(
  2611  										pkgbuilder.NewKptfile().
  2612  											WithUpstreamRef("foo", "/", "v1.0", "force-delete-replace").
  2613  											WithUpstreamLockRef("foo", "/", "v1.0", 0),
  2614  									).
  2615  									WithResource(pkgbuilder.DeploymentResource),
  2616  							),
  2617  						Branch: masterBranch,
  2618  					},
  2619  					{
  2620  						Pkg: pkgbuilder.NewRootPkg().
  2621  							WithKptfile().
  2622  							WithResource(pkgbuilder.ConfigMapResource).
  2623  							WithSubPackages(
  2624  								pkgbuilder.NewSubPkg("foo").
  2625  									WithKptfile(
  2626  										pkgbuilder.NewKptfile().
  2627  											WithUpstreamRef("foo", "/", "v2.0", "force-delete-replace").
  2628  											WithUpstreamLockRef("foo", "/", "v2.0", 1),
  2629  									).
  2630  									WithResource(pkgbuilder.ConfigMapResource),
  2631  							),
  2632  					},
  2633  				},
  2634  				"foo": {
  2635  					{
  2636  						Pkg: pkgbuilder.NewRootPkg().
  2637  							WithKptfile().
  2638  							WithResource(pkgbuilder.DeploymentResource),
  2639  						Branch: "main",
  2640  						Tag:    "v1.0",
  2641  					},
  2642  					{
  2643  						Pkg: pkgbuilder.NewRootPkg().
  2644  							WithKptfile().
  2645  							WithResource(pkgbuilder.ConfigMapResource),
  2646  						Tag: "v2.0",
  2647  					},
  2648  					{
  2649  						Pkg: pkgbuilder.NewRootPkg().
  2650  							WithKptfile().
  2651  							WithResource(pkgbuilder.SecretResource),
  2652  						Tag: "v3.0",
  2653  					},
  2654  				},
  2655  			},
  2656  			updatedLocal: testutil.Content{
  2657  				Pkg: pkgbuilder.NewRootPkg().
  2658  					WithKptfile().
  2659  					WithResource(pkgbuilder.ConfigMapResource).
  2660  					WithSubPackages(
  2661  						pkgbuilder.NewSubPkg("foo").
  2662  							WithKptfile(
  2663  								pkgbuilder.NewKptfile().
  2664  									WithUpstreamRef("foo", "/", "v3.0", "force-delete-replace").
  2665  									WithUpstreamLockRef("foo", "/", "v3.0", 2),
  2666  							).
  2667  							WithResource(pkgbuilder.SecretResource),
  2668  					),
  2669  			},
  2670  			expectedLocal: pkgbuilder.NewRootPkg().
  2671  				WithKptfile(
  2672  					pkgbuilder.NewKptfile().
  2673  						WithUpstreamRef("upstream", "/", masterBranch, "resource-merge").
  2674  						WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  2675  				).
  2676  				WithResource(pkgbuilder.ConfigMapResource).
  2677  				WithSubPackages(
  2678  					pkgbuilder.NewSubPkg("foo").
  2679  						WithKptfile(
  2680  							pkgbuilder.NewKptfile().
  2681  								WithUpstreamRef("foo", "/", "v2.0", "force-delete-replace").
  2682  								WithUpstreamLockRef("foo", "/", "v2.0", 1),
  2683  						).
  2684  						WithResource(pkgbuilder.ConfigMapResource),
  2685  				),
  2686  		},
  2687  		"remote subpackage deleted from upstream": {
  2688  			reposChanges: map[string][]testutil.Content{
  2689  				testutil.Upstream: {
  2690  					{
  2691  						Pkg: pkgbuilder.NewRootPkg().
  2692  							WithKptfile().
  2693  							WithResource(pkgbuilder.DeploymentResource).
  2694  							WithSubPackages(
  2695  								pkgbuilder.NewSubPkg("foo").
  2696  									WithKptfile(
  2697  										pkgbuilder.NewKptfile().
  2698  											WithUpstreamRef("foo", "/", "v1.0", "force-delete-replace").
  2699  											WithUpstreamLockRef("foo", "/", "v1.0", 0),
  2700  									).
  2701  									WithResource(pkgbuilder.DeploymentResource),
  2702  							),
  2703  						Branch: masterBranch,
  2704  					},
  2705  					{
  2706  						Pkg: pkgbuilder.NewRootPkg().
  2707  							WithKptfile().
  2708  							WithResource(pkgbuilder.ConfigMapResource),
  2709  					},
  2710  				},
  2711  				"foo": {
  2712  					{
  2713  						Pkg: pkgbuilder.NewRootPkg().
  2714  							WithKptfile().
  2715  							WithResource(pkgbuilder.DeploymentResource),
  2716  						Branch: "main",
  2717  						Tag:    "v1.0",
  2718  					},
  2719  				},
  2720  			},
  2721  			expectedLocal: pkgbuilder.NewRootPkg().
  2722  				WithKptfile(
  2723  					pkgbuilder.NewKptfile().
  2724  						WithUpstreamRef("upstream", "/", masterBranch, "resource-merge").
  2725  						WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  2726  				).
  2727  				WithResource(pkgbuilder.ConfigMapResource),
  2728  		},
  2729  		"remote subpackage deleted from upstream, but local has updated package": {
  2730  			reposChanges: map[string][]testutil.Content{
  2731  				testutil.Upstream: {
  2732  					{
  2733  						Pkg: pkgbuilder.NewRootPkg().
  2734  							WithKptfile().
  2735  							WithResource(pkgbuilder.DeploymentResource).
  2736  							WithSubPackages(
  2737  								pkgbuilder.NewSubPkg("foo").
  2738  									WithKptfile(
  2739  										pkgbuilder.NewKptfile().
  2740  											WithUpstreamRef("foo", "/", "v1.0", "resource-merge").
  2741  											WithUpstreamLockRef("foo", "/", "v1.0", 0),
  2742  									).
  2743  									WithResource(pkgbuilder.DeploymentResource),
  2744  							),
  2745  						Branch: masterBranch,
  2746  					},
  2747  					{
  2748  						Pkg: pkgbuilder.NewRootPkg().
  2749  							WithKptfile().
  2750  							WithResource(pkgbuilder.ConfigMapResource),
  2751  					},
  2752  				},
  2753  				"foo": {
  2754  					{
  2755  						Pkg: pkgbuilder.NewRootPkg().
  2756  							WithKptfile().
  2757  							WithResource(pkgbuilder.DeploymentResource),
  2758  						Branch: "main",
  2759  						Tag:    "v1.0",
  2760  					},
  2761  					{
  2762  						Pkg: pkgbuilder.NewRootPkg().
  2763  							WithKptfile().
  2764  							WithResource(pkgbuilder.ConfigMapResource),
  2765  						Tag: "v2.0",
  2766  					},
  2767  				},
  2768  			},
  2769  			updatedLocal: testutil.Content{
  2770  				Pkg: pkgbuilder.NewRootPkg().
  2771  					WithKptfile(
  2772  						pkgbuilder.NewKptfile().
  2773  							WithUpstreamRef("upstream", "/", masterBranch, "resource-merge").
  2774  							WithUpstreamLockRef("upstream", "/", masterBranch, 0),
  2775  					).
  2776  					WithResource(pkgbuilder.ConfigMapResource).
  2777  					WithSubPackages(
  2778  						pkgbuilder.NewSubPkg("foo").
  2779  							WithKptfile(
  2780  								pkgbuilder.NewKptfile().
  2781  									WithUpstreamRef("foo", "/", "v2.0", "resource-merge").
  2782  									WithUpstreamLockRef("foo", "/", "v2.0", 1),
  2783  							).
  2784  							WithResource(pkgbuilder.ConfigMapResource),
  2785  					),
  2786  			},
  2787  			expectedLocal: pkgbuilder.NewRootPkg().
  2788  				WithKptfile(
  2789  					pkgbuilder.NewKptfile().
  2790  						WithUpstreamRef("upstream", "/", masterBranch, "resource-merge").
  2791  						WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  2792  				).
  2793  				WithResource(pkgbuilder.ConfigMapResource).
  2794  				WithSubPackages(
  2795  					pkgbuilder.NewSubPkg("foo").
  2796  						WithKptfile(
  2797  							pkgbuilder.NewKptfile().
  2798  								WithUpstreamRef("foo", "/", "v2.0", "resource-merge").
  2799  								WithUpstreamLockRef("foo", "/", "v2.0", 1),
  2800  						).
  2801  						WithResource(pkgbuilder.ConfigMapResource),
  2802  				),
  2803  		},
  2804  		"subpackage with nested remote subpackages deleted from upstream": {
  2805  			reposChanges: map[string][]testutil.Content{
  2806  				testutil.Upstream: {
  2807  					{
  2808  						Pkg: pkgbuilder.NewRootPkg().
  2809  							WithKptfile().
  2810  							WithResource(pkgbuilder.DeploymentResource).
  2811  							WithSubPackages(
  2812  								pkgbuilder.NewSubPkg("foo").
  2813  									WithKptfile(
  2814  										pkgbuilder.NewKptfile().
  2815  											WithUpstreamRef("foo", "/", "main", "resource-merge").
  2816  											WithUpstreamLockRef("foo", "/", "main", 0),
  2817  									).
  2818  									WithResource(pkgbuilder.DeploymentResource).
  2819  									WithSubPackages(
  2820  										pkgbuilder.NewSubPkg("bar").
  2821  											WithKptfile(
  2822  												pkgbuilder.NewKptfile().
  2823  													WithUpstreamRef("bar", "/", masterBranch, "resource-merge").
  2824  													WithUpstreamLockRef("bar", "/", masterBranch, 0),
  2825  											).
  2826  											WithResource(pkgbuilder.DeploymentResource),
  2827  									),
  2828  							),
  2829  						Branch: masterBranch,
  2830  					},
  2831  					{
  2832  						Pkg: pkgbuilder.NewRootPkg().
  2833  							WithKptfile().
  2834  							WithResource(pkgbuilder.ConfigMapResource),
  2835  					},
  2836  				},
  2837  				"foo": {
  2838  					{
  2839  						Pkg: pkgbuilder.NewRootPkg().
  2840  							WithKptfile().
  2841  							WithResource(pkgbuilder.DeploymentResource).
  2842  							WithSubPackages(
  2843  								pkgbuilder.NewSubPkg("bar").
  2844  									WithKptfile(
  2845  										pkgbuilder.NewKptfile().
  2846  											WithUpstreamRef("bar", "/", masterBranch, "resource-merge").
  2847  											WithUpstreamLockRef("bar", "/", masterBranch, 0),
  2848  									).
  2849  									WithResource(pkgbuilder.DeploymentResource),
  2850  							),
  2851  						Branch: "main",
  2852  					},
  2853  				},
  2854  				"bar": {
  2855  					{
  2856  						Pkg: pkgbuilder.NewRootPkg().
  2857  							WithKptfile().
  2858  							WithResource(pkgbuilder.DeploymentResource),
  2859  						Branch: masterBranch,
  2860  					},
  2861  				},
  2862  			},
  2863  			expectedLocal: pkgbuilder.NewRootPkg().
  2864  				WithKptfile(
  2865  					pkgbuilder.NewKptfile().
  2866  						WithUpstreamRef("upstream", "/", masterBranch, "resource-merge").
  2867  						WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  2868  				).
  2869  				WithResource(pkgbuilder.ConfigMapResource),
  2870  		},
  2871  		"remote and local subpackages added in local": {
  2872  			reposChanges: map[string][]testutil.Content{
  2873  				testutil.Upstream: {
  2874  					{
  2875  						Pkg: pkgbuilder.NewRootPkg().
  2876  							WithKptfile().
  2877  							WithResource(pkgbuilder.DeploymentResource),
  2878  						Branch: masterBranch,
  2879  					},
  2880  					{
  2881  						Pkg: pkgbuilder.NewRootPkg().
  2882  							WithKptfile().
  2883  							WithResource(pkgbuilder.ConfigMapResource),
  2884  					},
  2885  				},
  2886  				"foo": {
  2887  					{
  2888  						Pkg: pkgbuilder.NewRootPkg().
  2889  							WithKptfile().
  2890  							WithResource(pkgbuilder.DeploymentResource),
  2891  						Branch: "main",
  2892  						Tag:    "v1.0",
  2893  					},
  2894  				},
  2895  			},
  2896  			updatedLocal: testutil.Content{
  2897  				Pkg: pkgbuilder.NewRootPkg().
  2898  					WithKptfile(
  2899  						pkgbuilder.NewKptfile().
  2900  							WithUpstreamRef("upstream", "/", masterBranch, "resource-merge").
  2901  							WithUpstreamLockRef("upstream", "/", masterBranch, 0),
  2902  					).
  2903  					WithResource(pkgbuilder.DeploymentResource).
  2904  					WithSubPackages(
  2905  						pkgbuilder.NewSubPkg("subpkg").
  2906  							WithKptfile(
  2907  								pkgbuilder.NewKptfile().
  2908  									WithUpstreamRef("foo", "/", "v1.0", "fast-forward").
  2909  									WithUpstreamLockRef("foo", "/", "v1.0", 0),
  2910  							).
  2911  							WithResource(pkgbuilder.DeploymentResource),
  2912  						pkgbuilder.NewSubPkg("localsubpkg").
  2913  							WithKptfile().
  2914  							WithResource(pkgbuilder.SecretResource),
  2915  					),
  2916  			},
  2917  			expectedLocal: pkgbuilder.NewRootPkg().
  2918  				WithKptfile(
  2919  					pkgbuilder.NewKptfile().
  2920  						WithUpstreamRef("upstream", "/", masterBranch, "resource-merge").
  2921  						WithUpstreamLockRef("upstream", "/", masterBranch, 1),
  2922  				).
  2923  				WithResource(pkgbuilder.ConfigMapResource).
  2924  				WithSubPackages(
  2925  					pkgbuilder.NewSubPkg("subpkg").
  2926  						WithKptfile(
  2927  							pkgbuilder.NewKptfile().
  2928  								WithUpstreamRef("foo", "/", "v1.0", "fast-forward").
  2929  								WithUpstreamLockRef("foo", "/", "v1.0", 0),
  2930  						).
  2931  						WithResource(pkgbuilder.DeploymentResource),
  2932  					pkgbuilder.NewSubPkg("localsubpkg").
  2933  						WithKptfile().
  2934  						WithResource(pkgbuilder.SecretResource),
  2935  				),
  2936  		},
  2937  		"two different remote packages in same path added in upstream and local": {
  2938  			reposChanges: map[string][]testutil.Content{
  2939  				testutil.Upstream: {
  2940  					{
  2941  						Pkg: pkgbuilder.NewRootPkg().
  2942  							WithKptfile().
  2943  							WithResource(pkgbuilder.ConfigMapResource),
  2944  						Branch: masterBranch,
  2945  					},
  2946  					{
  2947  						Pkg: pkgbuilder.NewRootPkg().
  2948  							WithKptfile().
  2949  							WithResource(pkgbuilder.ConfigMapResource).
  2950  							WithSubPackages(
  2951  								pkgbuilder.NewSubPkg("subpkg").
  2952  									WithKptfile(
  2953  										pkgbuilder.NewKptfile().
  2954  											WithUpstreamRef("foo", "/", "v1.0", "resource-merge").
  2955  											WithUpstreamLockRef("foo", "/", "v1.0", 0),
  2956  									).
  2957  									WithResource(pkgbuilder.DeploymentResource),
  2958  							),
  2959  					},
  2960  				},
  2961  				"foo": {
  2962  					{
  2963  						Pkg: pkgbuilder.NewRootPkg().
  2964  							WithKptfile().
  2965  							WithResource(pkgbuilder.DeploymentResource),
  2966  						Branch: "main",
  2967  						Tag:    "v1.0",
  2968  					},
  2969  				},
  2970  				"bar": {
  2971  					{
  2972  						Pkg: pkgbuilder.NewRootPkg().
  2973  							WithKptfile().
  2974  							WithResource(pkgbuilder.ConfigMapResource),
  2975  						Branch: "main",
  2976  						Tag:    "v1.0",
  2977  					},
  2978  				},
  2979  			},
  2980  			updatedLocal: testutil.Content{
  2981  				Pkg: pkgbuilder.NewRootPkg().
  2982  					WithKptfile().
  2983  					WithResource(pkgbuilder.ConfigMapResource).
  2984  					WithSubPackages(
  2985  						pkgbuilder.NewSubPkg("subpkg").
  2986  							WithKptfile(
  2987  								pkgbuilder.NewKptfile().
  2988  									WithUpstreamRef("bar", "/", "v1.0", "resource-merge").
  2989  									WithUpstreamLockRef("bar", "/", "v1.0", 0),
  2990  							).
  2991  							WithResource(pkgbuilder.ConfigMapResource),
  2992  					),
  2993  			},
  2994  			expectedErrMsg: "package \"subpkg\" added in both upstream and local",
  2995  		},
  2996  		"remote subpackage added in upstream": {
  2997  			reposChanges: map[string][]testutil.Content{
  2998  				testutil.Upstream: {
  2999  					{
  3000  						Pkg: pkgbuilder.NewRootPkg().
  3001  							WithKptfile().
  3002  							WithResource(pkgbuilder.ConfigMapResource),
  3003  						Branch: masterBranch,
  3004  					},
  3005  					{
  3006  						Pkg: pkgbuilder.NewRootPkg().
  3007  							WithKptfile().
  3008  							WithResource(pkgbuilder.DeploymentResource).
  3009  							WithSubPackages(
  3010  								pkgbuilder.NewSubPkg("subpkg").
  3011  									WithKptfile(
  3012  										pkgbuilder.NewKptfile().
  3013  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3014  											WithUpstreamLockRef("foo", "/", masterBranch, 0),
  3015  									).
  3016  									WithResource(pkgbuilder.ConfigMapResource),
  3017  							),
  3018  					},
  3019  				},
  3020  				"foo": {
  3021  					{
  3022  						Pkg: pkgbuilder.NewRootPkg().
  3023  							WithKptfile().
  3024  							WithResource(pkgbuilder.ConfigMapResource),
  3025  						Branch: masterBranch,
  3026  					},
  3027  				},
  3028  			},
  3029  			expectedLocal: pkgbuilder.NewRootPkg().
  3030  				WithKptfile(
  3031  					pkgbuilder.NewKptfile().
  3032  						WithUpstreamRef(testutil.Upstream, "/", masterBranch, "resource-merge").
  3033  						WithUpstreamLockRef(testutil.Upstream, "/", masterBranch, 1),
  3034  				).
  3035  				WithResource(pkgbuilder.DeploymentResource).
  3036  				WithSubPackages(
  3037  					pkgbuilder.NewSubPkg("subpkg").
  3038  						WithKptfile(
  3039  							pkgbuilder.NewKptfile().
  3040  								WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3041  								WithUpstreamLockRef("foo", "/", masterBranch, 0),
  3042  						).
  3043  						WithResource(pkgbuilder.ConfigMapResource),
  3044  				),
  3045  		},
  3046  		"remote subpackage deleted from local": {
  3047  			reposChanges: map[string][]testutil.Content{
  3048  				testutil.Upstream: {
  3049  					{
  3050  						Pkg: pkgbuilder.NewRootPkg().
  3051  							WithKptfile().
  3052  							WithResource(pkgbuilder.DeploymentResource).
  3053  							WithSubPackages(
  3054  								pkgbuilder.NewSubPkg("subpkg").
  3055  									WithKptfile(
  3056  										pkgbuilder.NewKptfile().
  3057  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3058  											WithUpstreamLockRef("foo", "/", masterBranch, 0),
  3059  									).
  3060  									WithResource(pkgbuilder.ConfigMapResource),
  3061  							),
  3062  						Branch: masterBranch,
  3063  					},
  3064  					{
  3065  						Pkg: pkgbuilder.NewRootPkg().
  3066  							WithKptfile().
  3067  							WithResource(pkgbuilder.DeploymentResource).
  3068  							WithSubPackages(
  3069  								pkgbuilder.NewSubPkg("subpkg").
  3070  									WithKptfile(
  3071  										pkgbuilder.NewKptfile().
  3072  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3073  											WithUpstreamLockRef("foo", "/", masterBranch, 0),
  3074  									).
  3075  									WithResource(pkgbuilder.ConfigMapResource).
  3076  									WithResource(pkgbuilder.DeploymentResource,
  3077  										pkgbuilder.SetFieldPath("45", "spec", "replicas")),
  3078  							),
  3079  					},
  3080  				},
  3081  				"foo": {
  3082  					{
  3083  						Pkg: pkgbuilder.NewRootPkg().
  3084  							WithKptfile().
  3085  							WithResource(pkgbuilder.ConfigMapResource),
  3086  						Branch: masterBranch,
  3087  					},
  3088  				},
  3089  			},
  3090  			updatedLocal: testutil.Content{
  3091  				Pkg: pkgbuilder.NewRootPkg().
  3092  					WithKptfile(
  3093  						pkgbuilder.NewKptfile().
  3094  							WithUpstreamRef(testutil.Upstream, "/", masterBranch, "resource-merge").
  3095  							WithUpstreamLockRef(testutil.Upstream, "/", masterBranch, 0),
  3096  					).
  3097  					WithResource(pkgbuilder.DeploymentResource),
  3098  			},
  3099  			expectedLocal: pkgbuilder.NewRootPkg().
  3100  				WithKptfile(
  3101  					pkgbuilder.NewKptfile().
  3102  						WithUpstreamRef(testutil.Upstream, "/", masterBranch, "resource-merge").
  3103  						WithUpstreamLockRef(testutil.Upstream, "/", masterBranch, 1),
  3104  				).
  3105  				WithResource(pkgbuilder.DeploymentResource),
  3106  		},
  3107  		"remote subpackage has gone from unfetched to fetched state in upstream": {
  3108  			reposChanges: map[string][]testutil.Content{
  3109  				testutil.Upstream: {
  3110  					{
  3111  						Pkg: pkgbuilder.NewRootPkg().
  3112  							WithKptfile().
  3113  							WithResource(pkgbuilder.DeploymentResource).
  3114  							WithSubPackages(
  3115  								pkgbuilder.NewSubPkg("subpkg").
  3116  									WithKptfile(
  3117  										pkgbuilder.NewKptfile().
  3118  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge"),
  3119  									),
  3120  							),
  3121  						Branch: masterBranch,
  3122  					},
  3123  					{
  3124  						Pkg: pkgbuilder.NewRootPkg().
  3125  							WithKptfile().
  3126  							WithResource(pkgbuilder.DeploymentResource).
  3127  							WithSubPackages(
  3128  								pkgbuilder.NewSubPkg("subpkg").
  3129  									WithKptfile(
  3130  										pkgbuilder.NewKptfile().
  3131  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3132  											WithUpstreamLockRef("foo", "/", masterBranch, 1),
  3133  									).
  3134  									WithResource(pkgbuilder.DeploymentResource),
  3135  							),
  3136  					},
  3137  				},
  3138  				"foo": {
  3139  					{
  3140  						Pkg: pkgbuilder.NewRootPkg().
  3141  							WithKptfile().
  3142  							WithResource(pkgbuilder.ConfigMapResource),
  3143  						Branch: masterBranch,
  3144  					},
  3145  					{
  3146  						Pkg: pkgbuilder.NewRootPkg().
  3147  							WithKptfile().
  3148  							WithResource(pkgbuilder.DeploymentResource),
  3149  					},
  3150  				},
  3151  			},
  3152  			expectedErrMsg: "no origin available for package",
  3153  		},
  3154  		"remote subpackage has gone from fetched to unfetched state in upstream": {
  3155  			reposChanges: map[string][]testutil.Content{
  3156  				testutil.Upstream: {
  3157  					{
  3158  						Pkg: pkgbuilder.NewRootPkg().
  3159  							WithKptfile().
  3160  							WithResource(pkgbuilder.DeploymentResource).
  3161  							WithSubPackages(
  3162  								pkgbuilder.NewSubPkg("subpkg").
  3163  									WithKptfile(
  3164  										pkgbuilder.NewKptfile().
  3165  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3166  											WithUpstreamLockRef("foo", "/", masterBranch, 0),
  3167  									).
  3168  									WithResource(pkgbuilder.ConfigMapResource),
  3169  							),
  3170  						Branch: masterBranch,
  3171  					},
  3172  					{
  3173  						Pkg: pkgbuilder.NewRootPkg().
  3174  							WithKptfile().
  3175  							WithResource(pkgbuilder.DeploymentResource).
  3176  							WithSubPackages(
  3177  								pkgbuilder.NewSubPkg("subpkg").
  3178  									WithKptfile(
  3179  										pkgbuilder.NewKptfile().
  3180  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge"),
  3181  									),
  3182  							),
  3183  					},
  3184  				},
  3185  				"foo": {
  3186  					{
  3187  						Pkg: pkgbuilder.NewRootPkg().
  3188  							WithKptfile().
  3189  							WithResource(pkgbuilder.ConfigMapResource),
  3190  						Branch: masterBranch,
  3191  					},
  3192  				},
  3193  			},
  3194  			expectedLocal: pkgbuilder.NewRootPkg().
  3195  				WithKptfile(
  3196  					pkgbuilder.NewKptfile().
  3197  						WithUpstreamRef(testutil.Upstream, "/", masterBranch, "resource-merge").
  3198  						WithUpstreamLockRef(testutil.Upstream, "/", masterBranch, 1),
  3199  				).
  3200  				WithResource(pkgbuilder.DeploymentResource).
  3201  				WithSubPackages(
  3202  					pkgbuilder.NewSubPkg("subpkg").
  3203  						WithKptfile(
  3204  							pkgbuilder.NewKptfile().
  3205  								WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3206  								WithUpstreamLockRef("foo", "/", masterBranch, 0),
  3207  						).
  3208  						WithResource(pkgbuilder.ConfigMapResource),
  3209  				),
  3210  		},
  3211  		"fast-forward updates can be used even if subpackages has changes": {
  3212  			reposChanges: map[string][]testutil.Content{
  3213  				testutil.Upstream: {
  3214  					{
  3215  						Pkg: pkgbuilder.NewRootPkg().
  3216  							WithResource(pkgbuilder.DeploymentResource).
  3217  							WithSubPackages(
  3218  								pkgbuilder.NewSubPkg("subpkg").
  3219  									WithKptfile(
  3220  										pkgbuilder.NewKptfile().
  3221  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3222  											WithUpstreamLockRef("foo", "/", masterBranch, 0),
  3223  									).
  3224  									WithResource(pkgbuilder.ConfigMapResource),
  3225  							),
  3226  						Branch: masterBranch,
  3227  					},
  3228  					{
  3229  						Pkg: pkgbuilder.NewRootPkg().
  3230  							WithResource(pkgbuilder.SecretResource).
  3231  							WithSubPackages(
  3232  								pkgbuilder.NewSubPkg("subpkg").
  3233  									WithKptfile(
  3234  										pkgbuilder.NewKptfile().
  3235  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3236  											WithUpstreamLockRef("foo", "/", masterBranch, 0),
  3237  									).
  3238  									WithResource(pkgbuilder.ConfigMapResource),
  3239  							),
  3240  					},
  3241  				},
  3242  				"foo": {
  3243  					{
  3244  						Pkg: pkgbuilder.NewRootPkg().
  3245  							WithResource(pkgbuilder.ConfigMapResource),
  3246  						Branch: masterBranch,
  3247  					},
  3248  				},
  3249  			},
  3250  			updatedLocal: testutil.Content{
  3251  				Pkg: pkgbuilder.NewRootPkg().
  3252  					WithKptfile(
  3253  						pkgbuilder.NewKptfile().
  3254  							WithUpstreamRef(testutil.Upstream, "/", masterBranch, "fast-forward").
  3255  							WithUpstreamLockRef(testutil.Upstream, "/", masterBranch, 0),
  3256  					).
  3257  					WithResource(pkgbuilder.DeploymentResource).
  3258  					WithSubPackages(
  3259  						pkgbuilder.NewSubPkg("subpkg").
  3260  							WithKptfile(
  3261  								pkgbuilder.NewKptfile().
  3262  									WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3263  									WithUpstreamLockRef("foo", "/", masterBranch, 0),
  3264  							).
  3265  							WithResource(pkgbuilder.ConfigMapResource,
  3266  								pkgbuilder.SetAnnotation("foo", "bar")),
  3267  					),
  3268  			},
  3269  			expectedLocal: pkgbuilder.NewRootPkg().
  3270  				WithKptfile(
  3271  					pkgbuilder.NewKptfile().
  3272  						WithUpstreamRef(testutil.Upstream, "/", masterBranch, "fast-forward").
  3273  						WithUpstreamLockRef(testutil.Upstream, "/", masterBranch, 1),
  3274  				).
  3275  				WithResource(pkgbuilder.SecretResource).
  3276  				WithSubPackages(
  3277  					pkgbuilder.NewSubPkg("subpkg").
  3278  						WithKptfile(
  3279  							pkgbuilder.NewKptfile().
  3280  								WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3281  								WithUpstreamLockRef("foo", "/", masterBranch, 0),
  3282  						).
  3283  						WithResource(pkgbuilder.ConfigMapResource,
  3284  							pkgbuilder.SetAnnotation("foo", "bar")),
  3285  				),
  3286  		},
  3287  		"Kptfiles in unfetched subpackages are merged": {
  3288  			reposChanges: map[string][]testutil.Content{
  3289  				testutil.Upstream: {
  3290  					{
  3291  						Pkg: pkgbuilder.NewRootPkg().
  3292  							WithKptfile().
  3293  							WithResource(pkgbuilder.ConfigMapResource).
  3294  							WithSubPackages(
  3295  								pkgbuilder.NewSubPkg("subpkg").
  3296  									WithKptfile(
  3297  										pkgbuilder.NewKptfile().
  3298  											WithUpstreamRef("foo", "/", "v1.0", "resource-merge"),
  3299  									),
  3300  							),
  3301  						Branch: masterBranch,
  3302  					},
  3303  					{
  3304  						Pkg: pkgbuilder.NewRootPkg().
  3305  							WithKptfile().
  3306  							WithResource(pkgbuilder.ConfigMapResource).
  3307  							WithSubPackages(
  3308  								pkgbuilder.NewSubPkg("subpkg").
  3309  									WithKptfile(
  3310  										pkgbuilder.NewKptfile().
  3311  											WithUpstreamRef("foo", "/", "v1.0", "resource-merge").
  3312  											WithPipeline(
  3313  												pkgbuilder.NewFunction("gcr.io/kpt-dev/foo:latest"),
  3314  											),
  3315  									),
  3316  							),
  3317  					},
  3318  				},
  3319  				"foo": {
  3320  					{
  3321  						Pkg: pkgbuilder.NewRootPkg().
  3322  							WithKptfile().
  3323  							WithResource(pkgbuilder.DeploymentResource),
  3324  						Branch: "main",
  3325  						Tag:    "v1.0",
  3326  					},
  3327  				},
  3328  			},
  3329  			updatedLocal: testutil.Content{
  3330  				Pkg: pkgbuilder.NewRootPkg().
  3331  					WithKptfile(
  3332  						pkgbuilder.NewKptfile().
  3333  							WithUpstreamRef(testutil.Upstream, "/", masterBranch, "resource-merge").
  3334  							WithUpstreamLockRef(testutil.Upstream, "/", masterBranch, 0),
  3335  					).
  3336  					WithResource(pkgbuilder.ConfigMapResource).
  3337  					WithSubPackages(
  3338  						pkgbuilder.NewSubPkg("subpkg").
  3339  							WithKptfile(
  3340  								pkgbuilder.NewKptfile().
  3341  									WithUpstreamRef("foo", "/", "v1.0", "resource-merge").
  3342  									WithUpstreamLockRef("foo", "/", "v1.0", 0).
  3343  									WithPipeline(
  3344  										pkgbuilder.NewFunction("gcr.io/kpt-dev/bar:latest"),
  3345  									),
  3346  							).
  3347  							WithResource(pkgbuilder.DeploymentResource),
  3348  					),
  3349  			},
  3350  			expectedLocal: pkgbuilder.NewRootPkg().
  3351  				WithKptfile(
  3352  					pkgbuilder.NewKptfile().
  3353  						WithUpstreamRef(testutil.Upstream, "/", masterBranch, "resource-merge").
  3354  						WithUpstreamLockRef(testutil.Upstream, "/", masterBranch, 1),
  3355  				).
  3356  				WithResource(pkgbuilder.ConfigMapResource).
  3357  				WithSubPackages(
  3358  					pkgbuilder.NewSubPkg("subpkg").
  3359  						WithKptfile(
  3360  							pkgbuilder.NewKptfile().
  3361  								WithUpstreamRef("foo", "/", "v1.0", "resource-merge").
  3362  								WithUpstreamLockRef("foo", "/", "v1.0", 0).
  3363  								WithPipeline(
  3364  									pkgbuilder.NewFunction("gcr.io/kpt-dev/bar:latest"),
  3365  									pkgbuilder.NewFunction("gcr.io/kpt-dev/foo:latest"),
  3366  								),
  3367  						).
  3368  						WithResource(pkgbuilder.DeploymentResource),
  3369  				),
  3370  		},
  3371  		"Kptfile in the root package is merged": {
  3372  			reposChanges: map[string][]testutil.Content{
  3373  				testutil.Upstream: {
  3374  					{
  3375  						Pkg: pkgbuilder.NewRootPkg().
  3376  							WithKptfile(
  3377  								pkgbuilder.NewKptfile().
  3378  									WithPipeline(
  3379  										pkgbuilder.NewFunction("gcr.io/kpt-dev/foo:v1"),
  3380  									),
  3381  							).
  3382  							WithResource(pkgbuilder.ConfigMapResource),
  3383  						Branch: masterBranch,
  3384  					},
  3385  					{
  3386  						Pkg: pkgbuilder.NewRootPkg().
  3387  							WithKptfile(
  3388  								pkgbuilder.NewKptfile().
  3389  									WithPipeline(
  3390  										pkgbuilder.NewFunction("gcr.io/kpt-dev/foo:v1"),
  3391  										pkgbuilder.NewFunction("gcr.io/kpt-dev/bar:v1"),
  3392  									),
  3393  							).
  3394  							WithResource(pkgbuilder.ConfigMapResource),
  3395  					},
  3396  				},
  3397  			},
  3398  			updatedLocal: testutil.Content{
  3399  				Pkg: pkgbuilder.NewRootPkg().
  3400  					WithKptfile(
  3401  						pkgbuilder.NewKptfile().
  3402  							WithUpstreamRef(testutil.Upstream, "/", masterBranch, "resource-merge").
  3403  							WithUpstreamLockRef(testutil.Upstream, "/", masterBranch, 0).
  3404  							WithPipeline(
  3405  								pkgbuilder.NewFunction("gcr.io/kpt-dev/foo:v1"),
  3406  								pkgbuilder.NewFunction("gcr.io/kpt-dev/zork:v1"),
  3407  							),
  3408  					).
  3409  					WithResource(pkgbuilder.ConfigMapResource),
  3410  			},
  3411  			expectedLocal: pkgbuilder.NewRootPkg().
  3412  				WithKptfile(
  3413  					pkgbuilder.NewKptfile().
  3414  						WithUpstreamRef(testutil.Upstream, "/", masterBranch, "resource-merge").
  3415  						WithUpstreamLockRef(testutil.Upstream, "/", masterBranch, 1).
  3416  						WithPipeline(
  3417  							pkgbuilder.NewFunction("gcr.io/kpt-dev/foo:v1"),
  3418  							pkgbuilder.NewFunction("gcr.io/kpt-dev/zork:v1"),
  3419  							pkgbuilder.NewFunction("gcr.io/kpt-dev/bar:v1"),
  3420  						),
  3421  				).
  3422  				WithResource(pkgbuilder.ConfigMapResource),
  3423  		},
  3424  		"Kptfile in the nested package is merged": {
  3425  			reposChanges: map[string][]testutil.Content{
  3426  				testutil.Upstream: {
  3427  					{
  3428  						Pkg: pkgbuilder.NewRootPkg().
  3429  							WithKptfile().
  3430  							WithResource(pkgbuilder.ConfigMapResource).
  3431  							WithSubPackages(
  3432  								pkgbuilder.NewSubPkg("subpkg").
  3433  									WithKptfile(
  3434  										pkgbuilder.NewKptfile().
  3435  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3436  											WithUpstreamLockRef("foo", "/", masterBranch, 0).
  3437  											WithPipeline(
  3438  												pkgbuilder.NewFunction("gcr.io/kpt-dev/foo:v1"),
  3439  											),
  3440  									).
  3441  									WithResource(pkgbuilder.ConfigMapResource),
  3442  							),
  3443  						Branch: masterBranch,
  3444  					},
  3445  					{
  3446  						Pkg: pkgbuilder.NewRootPkg().
  3447  							WithKptfile().
  3448  							WithResource(pkgbuilder.ConfigMapResource).
  3449  							WithSubPackages(
  3450  								pkgbuilder.NewSubPkg("subpkg").
  3451  									WithKptfile(
  3452  										pkgbuilder.NewKptfile().
  3453  											WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3454  											WithUpstreamLockRef("foo", "/", masterBranch, 1).
  3455  											WithPipeline(
  3456  												pkgbuilder.NewFunction("gcr.io/kpt-dev/foo:latest"),
  3457  												pkgbuilder.NewFunction("gcr.io/kpt-dev/bar:latest"),
  3458  											),
  3459  									).
  3460  									WithResource(pkgbuilder.ConfigMapResource),
  3461  							),
  3462  					},
  3463  				},
  3464  				"foo": {
  3465  					{
  3466  						Pkg: pkgbuilder.NewRootPkg().
  3467  							WithKptfile(
  3468  								pkgbuilder.NewKptfile().
  3469  									WithPipeline(
  3470  										pkgbuilder.NewFunction("gcr.io/kpt-dev/foo:v1"),
  3471  										pkgbuilder.NewFunction("gcr.io/kpt-dev/bar:latest"),
  3472  									),
  3473  							).
  3474  							WithResource(pkgbuilder.ConfigMapResource),
  3475  						Branch: masterBranch,
  3476  					},
  3477  					{
  3478  						Pkg: pkgbuilder.NewRootPkg().
  3479  							WithKptfile(
  3480  								pkgbuilder.NewKptfile().
  3481  									WithPipeline(
  3482  										pkgbuilder.NewFunction("gcr.io/kpt-dev/foo:v1"),
  3483  										pkgbuilder.NewFunction("gcr.io/kpt-dev/bar:v1"),
  3484  									),
  3485  							).
  3486  							WithResource(pkgbuilder.ConfigMapResource),
  3487  					},
  3488  				},
  3489  			},
  3490  			updatedLocal: testutil.Content{
  3491  				Pkg: pkgbuilder.NewRootPkg().
  3492  					WithKptfile(
  3493  						pkgbuilder.NewKptfile().
  3494  							WithUpstreamRef(testutil.Upstream, "/", masterBranch, "resource-merge").
  3495  							WithUpstreamLockRef(testutil.Upstream, "/", masterBranch, 0),
  3496  					).
  3497  					WithResource(pkgbuilder.ConfigMapResource).
  3498  					WithSubPackages(
  3499  						pkgbuilder.NewSubPkg("subpkg").
  3500  							WithKptfile(
  3501  								pkgbuilder.NewKptfile().
  3502  									WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3503  									WithUpstreamLockRef("foo", "/", masterBranch, 0).
  3504  									WithPipeline(
  3505  										pkgbuilder.NewFunction("gcr.io/kpt-dev/zork:v1"),
  3506  									),
  3507  							).
  3508  							WithResource(pkgbuilder.ConfigMapResource),
  3509  					),
  3510  			},
  3511  			expectedLocal: pkgbuilder.NewRootPkg().
  3512  				WithKptfile(
  3513  					pkgbuilder.NewKptfile().
  3514  						WithUpstreamRef(testutil.Upstream, "/", masterBranch, "resource-merge").
  3515  						WithUpstreamLockRef(testutil.Upstream, "/", masterBranch, 1),
  3516  				).
  3517  				WithResource(pkgbuilder.ConfigMapResource).
  3518  				WithSubPackages(
  3519  					pkgbuilder.NewSubPkg("subpkg").
  3520  						WithKptfile(
  3521  							pkgbuilder.NewKptfile().
  3522  								WithUpstreamRef("foo", "/", masterBranch, "resource-merge").
  3523  								WithUpstreamLockRef("foo", "/", masterBranch, 1).
  3524  								WithPipeline(
  3525  									pkgbuilder.NewFunction("gcr.io/kpt-dev/zork:v1"),
  3526  									pkgbuilder.NewFunction("gcr.io/kpt-dev/foo:latest"),
  3527  									pkgbuilder.NewFunction("gcr.io/kpt-dev/bar:latest"),
  3528  								),
  3529  						).
  3530  						WithResource(pkgbuilder.ConfigMapResource),
  3531  				),
  3532  		},
  3533  	}
  3534  
  3535  	for tn, tc := range testCases {
  3536  		t.Run(tn, func(t *testing.T) {
  3537  			g := &testutil.TestSetupManager{
  3538  				T:            t,
  3539  				ReposChanges: tc.reposChanges,
  3540  			}
  3541  			defer g.Clean()
  3542  			if tc.updatedLocal.Pkg != nil {
  3543  				g.LocalChanges = []testutil.Content{
  3544  					tc.updatedLocal,
  3545  				}
  3546  			}
  3547  			if !g.Init() {
  3548  				return
  3549  			}
  3550  
  3551  			err := (&Command{
  3552  				Pkg: pkgtest.CreatePkgOrFail(t, g.LocalWorkspace.FullPackagePath()),
  3553  			}).Run(fake.CtxWithDefaultPrinter())
  3554  
  3555  			if tc.expectedErrMsg != "" {
  3556  				if !assert.Error(t, err) {
  3557  					t.FailNow()
  3558  				}
  3559  				assert.Contains(t, err.Error(), tc.expectedErrMsg)
  3560  				return
  3561  			}
  3562  			if !assert.NoError(t, err) {
  3563  				t.FailNow()
  3564  			}
  3565  
  3566  			// Format the Kptfiles so we can diff the output without
  3567  			// formatting issues.
  3568  			rw := &kio.LocalPackageReadWriter{
  3569  				NoDeleteFiles:     true,
  3570  				PackagePath:       g.LocalWorkspace.FullPackagePath(),
  3571  				MatchFilesGlob:    []string{kptfilev1.KptFileName},
  3572  				PreserveSeqIndent: true,
  3573  				WrapBareSeqNode:   true,
  3574  			}
  3575  			err = kio.Pipeline{
  3576  				Inputs:  []kio.Reader{rw},
  3577  				Filters: []kio.Filter{filters.FormatFilter{}},
  3578  				Outputs: []kio.Writer{rw},
  3579  			}.Execute()
  3580  			if !assert.NoError(t, err) {
  3581  				t.FailNow()
  3582  			}
  3583  
  3584  			expectedPath := tc.expectedLocal.ExpandPkgWithName(t,
  3585  				g.LocalWorkspace.PackageDir, testutil.ToReposInfo(g.Repos))
  3586  			testutil.KptfileAwarePkgEqual(t, expectedPath, g.LocalWorkspace.FullPackagePath(), true)
  3587  		})
  3588  	}
  3589  }
  3590  
  3591  func TestRootPackageIsUnfetched(t *testing.T) {
  3592  	testCases := map[string]struct {
  3593  		reposChanges   map[string][]testutil.Content
  3594  		directory      string
  3595  		ref            string
  3596  		expectedLocal  *pkgbuilder.RootPkg
  3597  		expectedErrMsg string
  3598  	}{
  3599  		"unfetched with no subpackages": {
  3600  			reposChanges: map[string][]testutil.Content{
  3601  				testutil.Upstream: {
  3602  					{
  3603  						Pkg: pkgbuilder.NewRootPkg().
  3604  							WithResource(pkgbuilder.DeploymentResource),
  3605  						Branch: "main",
  3606  					},
  3607  				},
  3608  			},
  3609  			directory: "/",
  3610  			ref:       "main",
  3611  			expectedLocal: pkgbuilder.NewRootPkg().
  3612  				WithKptfile(
  3613  					pkgbuilder.NewKptfile().
  3614  						WithUpstreamRef(testutil.Upstream, "/", "main", "resource-merge").
  3615  						WithUpstreamLockRef(testutil.Upstream, "/", "main", 0),
  3616  				).
  3617  				WithResource(pkgbuilder.DeploymentResource),
  3618  		},
  3619  		"unfetched with subpackages": {
  3620  			reposChanges: map[string][]testutil.Content{
  3621  				testutil.Upstream: {
  3622  					{
  3623  						Pkg: pkgbuilder.NewRootPkg().
  3624  							WithResource(pkgbuilder.DeploymentResource).
  3625  							WithSubPackages(
  3626  								pkgbuilder.NewSubPkg("subpkg-1").
  3627  									WithKptfile(
  3628  										pkgbuilder.NewKptfile().
  3629  											WithUpstreamRef("foo", "/", masterBranch, "fast-forward"),
  3630  									),
  3631  								pkgbuilder.NewSubPkg("subpkg-2").
  3632  									WithKptfile(
  3633  										pkgbuilder.NewKptfile().
  3634  											WithUpstreamRef("foo", "/", masterBranch, "fast-forward").
  3635  											WithUpstreamLockRef("foo", "/", masterBranch, 0),
  3636  									).
  3637  									WithResource(pkgbuilder.SecretResource),
  3638  							),
  3639  						Branch: "main",
  3640  					},
  3641  				},
  3642  				"foo": {
  3643  					{
  3644  						Pkg: pkgbuilder.NewRootPkg().
  3645  							WithResource(pkgbuilder.SecretResource),
  3646  						Branch: masterBranch,
  3647  					},
  3648  				},
  3649  			},
  3650  			directory: "/",
  3651  			ref:       "main",
  3652  			expectedLocal: pkgbuilder.NewRootPkg().
  3653  				WithKptfile(
  3654  					pkgbuilder.NewKptfile().
  3655  						WithUpstreamRef(testutil.Upstream, "/", "main", "resource-merge").
  3656  						WithUpstreamLockRef(testutil.Upstream, "/", "main", 0),
  3657  				).
  3658  				WithResource(pkgbuilder.DeploymentResource).
  3659  				WithSubPackages(
  3660  					pkgbuilder.NewSubPkg("subpkg-1").
  3661  						WithKptfile(
  3662  							pkgbuilder.NewKptfile().
  3663  								WithUpstreamRef("foo", "/", masterBranch, "fast-forward").
  3664  								WithUpstreamLockRef("foo", "/", masterBranch, 0),
  3665  						).
  3666  						WithResource(pkgbuilder.SecretResource),
  3667  					pkgbuilder.NewSubPkg("subpkg-2").
  3668  						WithKptfile(
  3669  							pkgbuilder.NewKptfile().
  3670  								WithUpstreamRef("foo", "/", masterBranch, "fast-forward").
  3671  								WithUpstreamLockRef("foo", "/", masterBranch, 0),
  3672  						).
  3673  						WithResource(pkgbuilder.SecretResource),
  3674  				),
  3675  		},
  3676  	}
  3677  
  3678  	for tn, tc := range testCases {
  3679  		t.Run(tn, func(t *testing.T) {
  3680  			repos, w, clean := testutil.SetupReposAndWorkspace(t, tc.reposChanges)
  3681  			defer clean()
  3682  
  3683  			w.PackageDir = testPackageName
  3684  			kf := kptfileutil.DefaultKptfile(testPackageName)
  3685  			kf.Upstream = &kptfilev1.Upstream{
  3686  				Type: kptfilev1.GitOrigin,
  3687  				Git: &kptfilev1.Git{
  3688  					Repo:      repos[testutil.Upstream].RepoDirectory,
  3689  					Directory: tc.directory,
  3690  					Ref:       tc.ref,
  3691  				},
  3692  				UpdateStrategy: kptfilev1.ResourceMerge,
  3693  			}
  3694  			testutil.AddKptfileToWorkspace(t, w, kf)
  3695  
  3696  			err := (&Command{
  3697  				Pkg: pkgtest.CreatePkgOrFail(t, w.FullPackagePath()),
  3698  			}).Run(fake.CtxWithDefaultPrinter())
  3699  			if !assert.NoError(t, err) {
  3700  				t.FailNow()
  3701  			}
  3702  
  3703  			expectedPath := tc.expectedLocal.ExpandPkgWithName(t, testPackageName, testutil.ToReposInfo(repos))
  3704  			testutil.KptfileAwarePkgEqual(t, expectedPath, w.FullPackagePath(), true)
  3705  		})
  3706  	}
  3707  }
  3708  
  3709  // TestMultiUpdateCache verifies that multiple sub packages
  3710  // with same upstream leverage the cache.
  3711  func TestMultiUpdateCache(t *testing.T) {
  3712  	numSubPkgs := 10
  3713  	blueprintsUpstream := "blueprints"
  3714  	// Generate multiple subpackages referencing blueprintsUpstream
  3715  	subPkgs := make([]*pkgbuilder.SubPkg, 0, numSubPkgs)
  3716  	for i := 1; i <= numSubPkgs; i++ {
  3717  		sub := pkgbuilder.NewSubPkg(fmt.Sprintf("subpkg-%d", i)).
  3718  			WithKptfile(
  3719  				pkgbuilder.NewKptfile().
  3720  					WithUpstreamRef(blueprintsUpstream, "/", masterBranch, "fast-forward").
  3721  					WithUpstreamLockRef(blueprintsUpstream, "/", masterBranch, 0),
  3722  			).
  3723  			WithResource(pkgbuilder.DeploymentResource)
  3724  		subPkgs = append(subPkgs, sub)
  3725  	}
  3726  
  3727  	reposChanges := map[string][]testutil.Content{
  3728  		testutil.Upstream: {
  3729  			{
  3730  				Pkg: pkgbuilder.NewRootPkg().
  3731  					WithSubPackages(subPkgs...),
  3732  				Branch: masterBranch,
  3733  			},
  3734  		},
  3735  		blueprintsUpstream: {
  3736  			{
  3737  				Pkg: pkgbuilder.NewRootPkg().
  3738  					WithResource(pkgbuilder.DeploymentResource),
  3739  				Branch: masterBranch,
  3740  			},
  3741  		},
  3742  	}
  3743  
  3744  	expectedLocal := pkgbuilder.NewRootPkg().
  3745  		WithKptfile(
  3746  			pkgbuilder.NewKptfile().
  3747  				WithUpstreamRef(testutil.Upstream, "/", masterBranch, "resource-merge").
  3748  				WithUpstreamLockRef(testutil.Upstream, "/", masterBranch, 0),
  3749  		).
  3750  		WithSubPackages(subPkgs...)
  3751  
  3752  	repos, w, clean := testutil.SetupReposAndWorkspace(t, reposChanges)
  3753  	defer clean()
  3754  
  3755  	w.PackageDir = testPackageName
  3756  	kf := kptfileutil.DefaultKptfile(testPackageName)
  3757  	kf.Upstream = &kptfilev1.Upstream{
  3758  		Type: kptfilev1.GitOrigin,
  3759  		Git: &kptfilev1.Git{
  3760  			Repo:      repos[testutil.Upstream].RepoDirectory,
  3761  			Directory: "/",
  3762  			Ref:       masterBranch,
  3763  		},
  3764  		UpdateStrategy: kptfilev1.ResourceMerge,
  3765  	}
  3766  	testutil.AddKptfileToWorkspace(t, w, kf)
  3767  	cmd := Command{
  3768  		Pkg: pkgtest.CreatePkgOrFail(t, w.FullPackagePath()),
  3769  	}
  3770  	err := cmd.Run(fake.CtxWithDefaultPrinter())
  3771  	if !assert.NoError(t, err) {
  3772  		t.FailNow()
  3773  	}
  3774  
  3775  	// Expect 2 cached repo refs - testutil.Upstream and blueprintsUpstream
  3776  	cachedGURs := cmd.GetCachedUpstreamRepos()
  3777  	assert.Equal(t, 2, len(cachedGURs))
  3778  
  3779  	// Assert cached refs for each upstream repo
  3780  	upstreamRepo := repos[testutil.Upstream].RepoDirectory
  3781  	blueprintsRepo := repos[blueprintsUpstream].RepoDirectory
  3782  	blueprintsRepoCommit := repos[blueprintsUpstream].Commits
  3783  	for cr, gur := range cachedGURs {
  3784  		switch cr {
  3785  		case upstreamRepo:
  3786  			// Expect only upstream ref master to be cached as there was no lock
  3787  			assert.ElementsMatch(t, []string{masterBranch}, gur.GetFetchedRefs())
  3788  		case blueprintsRepo:
  3789  			// Expect both upstream ref master and upstream lock commit to be cached
  3790  			assert.ElementsMatch(t, []string{masterBranch, blueprintsRepoCommit[0]}, gur.GetFetchedRefs())
  3791  		default:
  3792  			t.Fatalf("Unexpected upstream repo %s", cr)
  3793  		}
  3794  	}
  3795  
  3796  	expectedPath := expectedLocal.ExpandPkgWithName(t, testPackageName, testutil.ToReposInfo(repos))
  3797  	testutil.KptfileAwarePkgEqual(t, expectedPath, w.FullPackagePath(), true)
  3798  }
  3799  
  3800  type nonKRMTestCase struct {
  3801  	name            string
  3802  	updated         string
  3803  	original        string
  3804  	local           string
  3805  	modifyLocalFile bool
  3806  	expectedLocal   string
  3807  }
  3808  
  3809  var nonKRMTests = []nonKRMTestCase{
  3810  	// Dataset5 is replica of Dataset2 with additional non KRM files
  3811  	{
  3812  		name:          "updated-filesDeleted",
  3813  		updated:       testutil.Dataset2,
  3814  		original:      testutil.Dataset5,
  3815  		local:         testutil.Dataset5,
  3816  		expectedLocal: testutil.Dataset2,
  3817  	},
  3818  	{
  3819  		name:          "updated-filesAdded",
  3820  		updated:       testutil.Dataset5,
  3821  		original:      testutil.Dataset2,
  3822  		local:         testutil.Dataset2,
  3823  		expectedLocal: testutil.Dataset5,
  3824  	},
  3825  	{
  3826  		name:          "local-filesAdded",
  3827  		updated:       testutil.Dataset2,
  3828  		original:      testutil.Dataset2,
  3829  		local:         testutil.Dataset5,
  3830  		expectedLocal: testutil.Dataset5,
  3831  	},
  3832  	{
  3833  		name:            "local-filesModified",
  3834  		updated:         testutil.Dataset5,
  3835  		original:        testutil.Dataset5,
  3836  		local:           testutil.Dataset5,
  3837  		modifyLocalFile: true,
  3838  		expectedLocal:   testutil.Dataset5,
  3839  	},
  3840  }
  3841  
  3842  // TestReplaceNonKRMFiles tests if the non KRM files are updated in 3-way merge fashion
  3843  func TestReplaceNonKRMFiles(t *testing.T) {
  3844  	for i := range nonKRMTests {
  3845  		test := nonKRMTests[i]
  3846  		t.Run(test.name, func(t *testing.T) {
  3847  			ds, err := testutil.GetTestDataPath()
  3848  			assert.NoError(t, err)
  3849  			updated := t.TempDir()
  3850  			original := t.TempDir()
  3851  			local := t.TempDir()
  3852  			expectedLocal := t.TempDir()
  3853  
  3854  			err = copyutil.CopyDir(filepath.Join(ds, test.updated), updated)
  3855  			assert.NoError(t, err)
  3856  			err = copyutil.CopyDir(filepath.Join(ds, test.original), original)
  3857  			assert.NoError(t, err)
  3858  			err = copyutil.CopyDir(filepath.Join(ds, test.local), local)
  3859  			assert.NoError(t, err)
  3860  			err = copyutil.CopyDir(filepath.Join(ds, test.expectedLocal), expectedLocal)
  3861  			assert.NoError(t, err)
  3862  			if test.modifyLocalFile {
  3863  				err = os.WriteFile(filepath.Join(local, "somefunction.py"), []byte("Print some other thing"), 0600)
  3864  				assert.NoError(t, err)
  3865  				err = os.WriteFile(filepath.Join(expectedLocal, "somefunction.py"), []byte("Print some other thing"), 0600)
  3866  				assert.NoError(t, err)
  3867  			}
  3868  			// Add a yaml file in updated that should never be moved to
  3869  			// expectedLocal.
  3870  			err = os.WriteFile(filepath.Join(updated, "new.yaml"), []byte("a: b"), 0600)
  3871  			assert.NoError(t, err)
  3872  			err = ReplaceNonKRMFiles(updated, original, local)
  3873  			assert.NoError(t, err)
  3874  			tg := testutil.TestGitRepo{}
  3875  			tg.AssertEqual(t, local, expectedLocal, false)
  3876  		})
  3877  	}
  3878  }