github.com/wmuizelaar/kpt@v0.0.0-20221018115725-bd564717b2ed/internal/util/fetch/fetch_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 fetch_test
    16  
    17  import (
    18  	"os"
    19  	"path/filepath"
    20  	"testing"
    21  
    22  	"github.com/GoogleContainerTools/kpt/internal/pkg"
    23  	pkgtesting "github.com/GoogleContainerTools/kpt/internal/pkg/testing"
    24  	"github.com/GoogleContainerTools/kpt/internal/printer/fake"
    25  	"github.com/GoogleContainerTools/kpt/internal/testutil"
    26  	"github.com/GoogleContainerTools/kpt/internal/testutil/pkgbuilder"
    27  	. "github.com/GoogleContainerTools/kpt/internal/util/fetch"
    28  	kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1"
    29  	"github.com/GoogleContainerTools/kpt/pkg/kptfile/kptfileutil"
    30  	"github.com/stretchr/testify/assert"
    31  	"sigs.k8s.io/kustomize/kyaml/filesys"
    32  	"sigs.k8s.io/kustomize/kyaml/yaml"
    33  )
    34  
    35  func TestMain(m *testing.M) {
    36  	os.Exit(testutil.ConfigureTestKptCache(m))
    37  }
    38  
    39  func setupWorkspace(t *testing.T) (*testutil.TestGitRepo, *testutil.TestWorkspace, func()) {
    40  	g, w, clean := testutil.SetupRepoAndWorkspace(t, testutil.Content{
    41  		Data:   testutil.Dataset1,
    42  		Branch: "master",
    43  	})
    44  
    45  	w.PackageDir = g.RepoName
    46  	err := os.MkdirAll(w.FullPackagePath(), 0700)
    47  	if !assert.NoError(t, err) {
    48  		t.FailNow()
    49  	}
    50  	return g, w, clean
    51  }
    52  
    53  func createKptfile(workspace *testutil.TestWorkspace, git *kptfilev1.Git, strategy kptfilev1.UpdateStrategyType) error {
    54  	kf := kptfileutil.DefaultKptfile(workspace.PackageDir)
    55  	kf.Upstream = &kptfilev1.Upstream{
    56  		Type:           kptfilev1.GitOrigin,
    57  		Git:            git,
    58  		UpdateStrategy: strategy,
    59  	}
    60  	return kptfileutil.WriteFile(workspace.FullPackagePath(), kf)
    61  }
    62  
    63  func setKptfileName(workspace *testutil.TestWorkspace, name string) error {
    64  	kf, err := pkg.ReadKptfile(filesys.FileSystemOrOnDisk{}, workspace.FullPackagePath())
    65  	if err != nil {
    66  		return err
    67  	}
    68  
    69  	kf.Name = name
    70  	err = kptfileutil.WriteFile(workspace.FullPackagePath(), kf)
    71  	return err
    72  }
    73  
    74  // TestCommand_Run_failEmptyRepo verifies that Command fail if no Kptfile
    75  func TestCommand_Run_failNoKptfile(t *testing.T) {
    76  	g, w, clean := testutil.SetupRepoAndWorkspace(t, testutil.Content{
    77  		Data:   testutil.Dataset1,
    78  		Branch: "master",
    79  	})
    80  	defer clean()
    81  
    82  	pkgPath := filepath.Join(w.WorkspaceDirectory, g.RepoName)
    83  	err := os.MkdirAll(pkgPath, 0700)
    84  	if !assert.NoError(t, err) {
    85  		t.FailNow()
    86  	}
    87  
    88  	err = Command{
    89  		Pkg: pkgtesting.CreatePkgOrFail(t, pkgPath),
    90  	}.Run(fake.CtxWithDefaultPrinter())
    91  	if !assert.Error(t, err) {
    92  		t.FailNow()
    93  	}
    94  	assert.Contains(t, err.Error(), "no Kptfile found")
    95  }
    96  
    97  // TestCommand_Run_failEmptyRepo verifies that Command fail if not repo is provided.
    98  func TestCommand_Run_failNoGit(t *testing.T) {
    99  	_, w, clean := setupWorkspace(t)
   100  	defer clean()
   101  
   102  	err := createKptfile(w, nil, kptfilev1.ResourceMerge)
   103  	if !assert.NoError(t, err) {
   104  		t.FailNow()
   105  	}
   106  
   107  	err = Command{
   108  		Pkg: pkgtesting.CreatePkgOrFail(t, w.FullPackagePath()),
   109  	}.Run(fake.CtxWithDefaultPrinter())
   110  	if !assert.Error(t, err) {
   111  		t.FailNow()
   112  	}
   113  	assert.Contains(t, err.Error(), "kptfile upstream doesn't have git information")
   114  }
   115  
   116  // TestCommand_Run_failEmptyRepo verifies that Command fail if not repo is provided.
   117  func TestCommand_Run_failEmptyRepo(t *testing.T) {
   118  	_, w, clean := setupWorkspace(t)
   119  	defer clean()
   120  
   121  	err := createKptfile(w, &kptfilev1.Git{
   122  		Repo:      "",
   123  		Directory: "/",
   124  		Ref:       "main",
   125  	}, kptfilev1.ResourceMerge)
   126  	if !assert.NoError(t, err) {
   127  		t.FailNow()
   128  	}
   129  
   130  	err = Command{
   131  		Pkg: pkgtesting.CreatePkgOrFail(t, w.FullPackagePath()),
   132  	}.Run(fake.CtxWithDefaultPrinter())
   133  	if !assert.Error(t, err) {
   134  		t.FailNow()
   135  	}
   136  	assert.Contains(t, err.Error(), "must specify repo")
   137  }
   138  
   139  // TestCommand_Run_failEmptyRepo verifies that Command fail if not repo is provided.
   140  func TestCommand_Run_failNoRevision(t *testing.T) {
   141  	g, w, clean := setupWorkspace(t)
   142  	defer clean()
   143  
   144  	err := createKptfile(w, &kptfilev1.Git{
   145  		Repo:      "file://" + g.RepoDirectory,
   146  		Directory: "/",
   147  		Ref:       "",
   148  	}, kptfilev1.ResourceMerge)
   149  	if !assert.NoError(t, err) {
   150  		t.FailNow()
   151  	}
   152  
   153  	err = Command{
   154  		Pkg: pkgtesting.CreatePkgOrFail(t, w.FullPackagePath()),
   155  	}.Run(fake.CtxWithDefaultPrinter())
   156  	if !assert.Error(t, err) {
   157  		t.FailNow()
   158  	}
   159  	assert.Contains(t, err.Error(), "must specify ref")
   160  }
   161  
   162  // TestCommand_Run verifies that Command will clone the HEAD of the master branch.
   163  //
   164  // - destination directory should match the base name of the repo
   165  // - KptFile should be populated with values pointing to the origin
   166  func TestCommand_Run(t *testing.T) {
   167  	g, w, clean := setupWorkspace(t)
   168  	defer clean()
   169  
   170  	err := createKptfile(w, &kptfilev1.Git{
   171  		Repo:      "file://" + g.RepoDirectory,
   172  		Directory: "/",
   173  		Ref:       "master",
   174  	}, kptfilev1.ResourceMerge)
   175  	if !assert.NoError(t, err) {
   176  		t.FailNow()
   177  	}
   178  
   179  	absPath := filepath.Join(w.WorkspaceDirectory, g.RepoName)
   180  	err = Command{
   181  		Pkg: pkgtesting.CreatePkgOrFail(t, w.FullPackagePath()),
   182  	}.Run(fake.CtxWithDefaultPrinter())
   183  	assert.NoError(t, err)
   184  
   185  	// verify the cloned contents matches the repository
   186  	g.AssertEqual(t, filepath.Join(g.DatasetDirectory, testutil.Dataset1), absPath, false)
   187  
   188  	// verify the KptFile contains the expected values
   189  	commit, err := g.GetCommit()
   190  	assert.NoError(t, err)
   191  	g.AssertKptfile(t, absPath, kptfilev1.KptFile{
   192  		ResourceMeta: yaml.ResourceMeta{
   193  			ObjectMeta: yaml.ObjectMeta{
   194  				NameMeta: yaml.NameMeta{
   195  					Name: g.RepoName,
   196  				},
   197  			},
   198  			TypeMeta: yaml.TypeMeta{
   199  				APIVersion: kptfilev1.KptFileGVK().GroupVersion().String(),
   200  				Kind:       kptfilev1.KptFileGVK().Kind,
   201  			},
   202  		},
   203  		Upstream: &kptfilev1.Upstream{
   204  			Type: "git",
   205  			Git: &kptfilev1.Git{
   206  				Directory: "/",
   207  				Repo:      "file://" + g.RepoDirectory,
   208  				Ref:       "master",
   209  			},
   210  			UpdateStrategy: kptfilev1.ResourceMerge,
   211  		},
   212  		UpstreamLock: &kptfilev1.UpstreamLock{
   213  			Type: "git",
   214  			Git: &kptfilev1.GitLock{
   215  				Directory: "/",
   216  				Repo:      "file://" + g.RepoDirectory,
   217  				Ref:       "master",
   218  				Commit:    commit, // verify the commit matches the repo
   219  			},
   220  		},
   221  	})
   222  }
   223  
   224  // TestCommand_Run_subdir verifies that Command will clone a subdirectory of a repo.
   225  //
   226  // - destination dir should match the name of the subdirectory
   227  // - KptFile should have the subdir listed
   228  func TestCommand_Run_subdir(t *testing.T) {
   229  	g, w, clean := setupWorkspace(t)
   230  	defer clean()
   231  
   232  	subdir := "java"
   233  	err := createKptfile(w, &kptfilev1.Git{
   234  		Repo:      g.RepoDirectory,
   235  		Directory: subdir,
   236  		Ref:       "refs/heads/master",
   237  	}, kptfilev1.ResourceMerge)
   238  	if !assert.NoError(t, err) {
   239  		t.FailNow()
   240  	}
   241  
   242  	absPath := filepath.Join(w.WorkspaceDirectory, g.RepoName)
   243  	err = Command{
   244  		Pkg: pkgtesting.CreatePkgOrFail(t, w.FullPackagePath()),
   245  	}.Run(fake.CtxWithDefaultPrinter())
   246  	assert.NoError(t, err)
   247  
   248  	// verify the cloned contents matches the repository
   249  	g.AssertEqual(t, filepath.Join(g.DatasetDirectory, testutil.Dataset1, subdir), absPath, false)
   250  
   251  	// verify the KptFile contains the expected values
   252  	commit, err := g.GetCommit()
   253  	assert.NoError(t, err)
   254  	g.AssertKptfile(t, absPath, kptfilev1.KptFile{
   255  		ResourceMeta: yaml.ResourceMeta{
   256  			ObjectMeta: yaml.ObjectMeta{
   257  				NameMeta: yaml.NameMeta{
   258  					Name: g.RepoName,
   259  				},
   260  			},
   261  			TypeMeta: yaml.TypeMeta{
   262  				APIVersion: kptfilev1.KptFileGVK().GroupVersion().String(),
   263  				Kind:       kptfilev1.KptFileGVK().Kind},
   264  		},
   265  		Upstream: &kptfilev1.Upstream{
   266  			Type: kptfilev1.GitOrigin,
   267  			Git: &kptfilev1.Git{
   268  				Directory: subdir,
   269  				Ref:       "refs/heads/master",
   270  				Repo:      g.RepoDirectory,
   271  			},
   272  			UpdateStrategy: kptfilev1.ResourceMerge,
   273  		},
   274  		UpstreamLock: &kptfilev1.UpstreamLock{
   275  			Type: kptfilev1.GitOrigin,
   276  			Git: &kptfilev1.GitLock{
   277  				Commit:    commit,
   278  				Directory: subdir,
   279  				Ref:       "refs/heads/master",
   280  				Repo:      g.RepoDirectory,
   281  			},
   282  		},
   283  	})
   284  }
   285  
   286  // TestCommand_Run_branch verifies Command can clone a git branch
   287  //
   288  // 1. create a new branch
   289  // 2. add data to the branch
   290  // 3. checkout the master branch again
   291  // 4. clone the new branch
   292  // 5. verify contents match the new branch
   293  func TestCommand_Run_branch(t *testing.T) {
   294  	g, w, clean := setupWorkspace(t)
   295  	defer clean()
   296  
   297  	// add commits to the exp branch
   298  	err := g.CheckoutBranch("exp", true)
   299  	assert.NoError(t, err)
   300  	err = g.ReplaceData(testutil.Dataset2)
   301  	assert.NoError(t, err)
   302  	_, err = g.Commit("new dataset")
   303  	assert.NoError(t, err)
   304  	commit, err := g.GetCommit()
   305  	assert.NoError(t, err)
   306  	err = g.CheckoutBranch("master", false)
   307  	assert.NoError(t, err)
   308  	commit2, err := g.GetCommit()
   309  	assert.NoError(t, err)
   310  	assert.NotEqual(t, commit, commit2)
   311  
   312  	err = createKptfile(w, &kptfilev1.Git{
   313  		Repo:      g.RepoDirectory,
   314  		Directory: "/",
   315  		Ref:       "refs/heads/exp",
   316  	}, kptfilev1.ResourceMerge)
   317  	if !assert.NoError(t, err) {
   318  		t.FailNow()
   319  	}
   320  
   321  	err = Command{
   322  		Pkg: pkgtesting.CreatePkgOrFail(t, w.FullPackagePath()),
   323  	}.Run(fake.CtxWithDefaultPrinter())
   324  	assert.NoError(t, err)
   325  
   326  	// verify the cloned contents matches the repository
   327  	g.AssertEqual(t, filepath.Join(g.DatasetDirectory, testutil.Dataset2), w.FullPackagePath(), false)
   328  
   329  	// verify the KptFile contains the expected values
   330  	g.AssertKptfile(t, w.FullPackagePath(), kptfilev1.KptFile{
   331  		ResourceMeta: yaml.ResourceMeta{
   332  			ObjectMeta: yaml.ObjectMeta{
   333  				NameMeta: yaml.NameMeta{
   334  					Name: g.RepoName,
   335  				},
   336  			},
   337  			TypeMeta: yaml.TypeMeta{
   338  				APIVersion: kptfilev1.KptFileGVK().GroupVersion().String(),
   339  				Kind:       kptfilev1.KptFileGVK().Kind,
   340  			},
   341  		},
   342  		Upstream: &kptfilev1.Upstream{
   343  			Type: kptfilev1.GitOrigin,
   344  			Git: &kptfilev1.Git{
   345  				Directory: "/",
   346  				Repo:      g.RepoDirectory,
   347  				Ref:       "refs/heads/exp",
   348  			},
   349  			UpdateStrategy: kptfilev1.ResourceMerge,
   350  		},
   351  		UpstreamLock: &kptfilev1.UpstreamLock{
   352  			Type: kptfilev1.GitOrigin,
   353  			Git: &kptfilev1.GitLock{
   354  				Directory: "/",
   355  				Repo:      g.RepoDirectory,
   356  				Ref:       "refs/heads/exp",
   357  				Commit:    commit,
   358  			},
   359  		},
   360  	})
   361  }
   362  
   363  // TestCommand_Run_tag verifies Command can clone from a git tag
   364  //
   365  // 1. add data to the master branch
   366  // 2. commit and tag the master branch
   367  // 3. add more data to the master branch, commit it
   368  // 4. clone at the tag
   369  // 5. verify the clone has the data from the tagged version
   370  func TestCommand_Run_tag(t *testing.T) {
   371  	g, w, clean := setupWorkspace(t)
   372  	defer clean()
   373  
   374  	// create a commit with dataset2 and tag it v2, then add another commit on top with dataset3
   375  	commit0, err := g.GetCommit()
   376  	assert.NoError(t, err)
   377  	err = g.ReplaceData(testutil.Dataset2)
   378  	assert.NoError(t, err)
   379  	_, err = g.Commit("new-data for v2")
   380  	assert.NoError(t, err)
   381  	commit, err := g.GetCommit()
   382  	assert.NoError(t, err)
   383  	err = g.Tag("v2")
   384  	assert.NoError(t, err)
   385  	err = g.ReplaceData(testutil.Dataset3)
   386  	assert.NoError(t, err)
   387  	_, err = g.Commit("new-data post-v2")
   388  	assert.NoError(t, err)
   389  	commit2, err := g.GetCommit()
   390  	assert.NoError(t, err)
   391  	assert.NotEqual(t, commit, commit0)
   392  	assert.NotEqual(t, commit, commit2)
   393  
   394  	err = createKptfile(w, &kptfilev1.Git{
   395  		Repo:      g.RepoDirectory,
   396  		Directory: "/",
   397  		Ref:       "refs/tags/v2",
   398  	}, kptfilev1.ResourceMerge)
   399  	if !assert.NoError(t, err) {
   400  		t.FailNow()
   401  	}
   402  
   403  	err = Command{
   404  		Pkg: pkgtesting.CreatePkgOrFail(t, w.FullPackagePath()),
   405  	}.Run(fake.CtxWithDefaultPrinter())
   406  	assert.NoError(t, err)
   407  
   408  	// verify the cloned contents matches the repository
   409  	g.AssertEqual(t, filepath.Join(g.DatasetDirectory, testutil.Dataset2), w.FullPackagePath(), false)
   410  
   411  	// verify the KptFile contains the expected values
   412  	g.AssertKptfile(t, w.FullPackagePath(), kptfilev1.KptFile{
   413  		ResourceMeta: yaml.ResourceMeta{
   414  			ObjectMeta: yaml.ObjectMeta{
   415  				NameMeta: yaml.NameMeta{
   416  					Name: g.RepoName,
   417  				},
   418  			},
   419  			TypeMeta: yaml.TypeMeta{
   420  				APIVersion: kptfilev1.KptFileGVK().GroupVersion().String(),
   421  				Kind:       kptfilev1.KptFileGVK().Kind,
   422  			},
   423  		},
   424  		Upstream: &kptfilev1.Upstream{
   425  			Type: "git",
   426  			Git: &kptfilev1.Git{
   427  				Directory: "/",
   428  				Repo:      g.RepoDirectory,
   429  				Ref:       "refs/tags/v2",
   430  			},
   431  			UpdateStrategy: kptfilev1.ResourceMerge,
   432  		},
   433  		UpstreamLock: &kptfilev1.UpstreamLock{
   434  			Type: "git",
   435  			Git: &kptfilev1.GitLock{
   436  				Directory: "/",
   437  				Repo:      g.RepoDirectory,
   438  				Ref:       "refs/tags/v2",
   439  				Commit:    commit,
   440  			},
   441  		},
   442  	})
   443  }
   444  
   445  func TestCommand_Run_subdir_at_tag(t *testing.T) {
   446  	testCases := map[string]struct {
   447  		dir         string
   448  		tag         string
   449  		upstreamPkg *pkgbuilder.RootPkg
   450  	}{
   451  		"reads subdirectory": {
   452  			dir: "/java/expected",
   453  			tag: "java/v2",
   454  			upstreamPkg: pkgbuilder.NewRootPkg().
   455  				WithSubPackages(pkgbuilder.NewSubPkg("java").
   456  					WithResource("deployment").
   457  					WithSubPackages(pkgbuilder.NewSubPkg("expected").
   458  						WithFile("expected.txt", "My kptfile and I should be the only objects"))),
   459  		},
   460  		"reads subdirectory with no leading slash": {
   461  			dir: "java/expected",
   462  			tag: "java/v2",
   463  			upstreamPkg: pkgbuilder.NewRootPkg().
   464  				WithSubPackages(pkgbuilder.NewSubPkg("java").
   465  					WithResource("deployment").
   466  					WithSubPackages(pkgbuilder.NewSubPkg("expected").
   467  						WithFile("expected.txt", "My kptfile and I should be the only objects"))),
   468  		},
   469  		"reads specific subdirectory": {
   470  			dir: "/java/not_expected/java/expected",
   471  			tag: "java/expected/v2",
   472  			upstreamPkg: pkgbuilder.NewRootPkg().
   473  				WithSubPackages(pkgbuilder.NewSubPkg("java").
   474  					WithResource("deployment").
   475  					WithSubPackages(pkgbuilder.NewSubPkg("not_expected").
   476  						WithFile("not_actually_expected.txt", "I should not be present").
   477  						WithSubPackages(pkgbuilder.NewSubPkg("java").
   478  							WithSubPackages(pkgbuilder.NewSubPkg("expected").
   479  								WithFile("expected.txt", "My kptfile and I should be the only objects"))))),
   480  		},
   481  	}
   482  	for tn, tc := range testCases {
   483  		t.Run(tn, func(t *testing.T) {
   484  			expectedName := "expected"
   485  			repos, rw, clean := testutil.SetupReposAndWorkspace(t, map[string][]testutil.Content{
   486  				testutil.Upstream: {
   487  					{
   488  						Pkg:    tc.upstreamPkg,
   489  						Branch: "main",
   490  						Tag:    tc.tag,
   491  					},
   492  				},
   493  			})
   494  
   495  			defer clean()
   496  
   497  			g := repos[testutil.Upstream]
   498  			err := createKptfile(rw, &kptfilev1.Git{
   499  				Repo:      g.RepoDirectory,
   500  				Directory: tc.dir,
   501  				Ref:       tc.tag,
   502  			}, kptfilev1.ResourceMerge)
   503  			if !assert.NoError(t, err) {
   504  				t.FailNow()
   505  			}
   506  
   507  			err = setKptfileName(rw, expectedName)
   508  			if !assert.NoError(t, err) {
   509  				t.FailNow()
   510  			}
   511  
   512  			actualPkg := pkgtesting.CreatePkgOrFail(t, rw.FullPackagePath())
   513  			err = Command{
   514  				Pkg: actualPkg,
   515  			}.Run(fake.CtxWithDefaultPrinter())
   516  			if !assert.NoError(t, err) {
   517  				t.FailNow()
   518  			}
   519  
   520  			if !g.AssertEqual(t, rw.WorkspaceDirectory, actualPkg.UniquePath.String(), false) {
   521  				t.FailNow()
   522  			}
   523  			expectedPkg := pkgbuilder.NewRootPkg().
   524  				WithKptfile(
   525  					pkgbuilder.NewKptfile().
   526  						WithUpstreamRef(testutil.Upstream, tc.dir, tc.tag, "resource-merge").
   527  						WithUpstreamLockRef(testutil.Upstream, tc.dir, tc.tag, 0),
   528  				).WithFile("expected.txt", "My kptfile and I should be the only objects")
   529  			expectedPath := expectedPkg.ExpandPkgWithName(t, expectedName, testutil.ToReposInfo(repos))
   530  			testutil.KptfileAwarePkgEqual(t, actualPkg.UniquePath.String(), expectedPath, false)
   531  		})
   532  	}
   533  }
   534  
   535  func TestCommand_Run_no_subdir_at_valid_tag(t *testing.T) {
   536  	dir := "/java/expected"
   537  	tag := "java/v2"
   538  	expectedName := "expected_dir_is_not_here"
   539  	repos, rw, clean := testutil.SetupReposAndWorkspace(t, map[string][]testutil.Content{
   540  		testutil.Upstream: {
   541  			{
   542  				Pkg: pkgbuilder.NewRootPkg().
   543  					WithSubPackages(pkgbuilder.NewSubPkg("java").
   544  						WithResource("deployment").
   545  						WithSubPackages(pkgbuilder.NewSubPkg("not_expected").
   546  							WithFile("expected.txt", "My kptfile and I should be the only objects"))),
   547  				Branch: "main",
   548  				Tag:    tag,
   549  			},
   550  		},
   551  	})
   552  
   553  	defer clean()
   554  
   555  	g := repos[testutil.Upstream]
   556  	err := createKptfile(rw, &kptfilev1.Git{
   557  		Repo:      g.RepoDirectory,
   558  		Directory: dir,
   559  		Ref:       tag,
   560  	}, kptfilev1.ResourceMerge)
   561  	if !assert.NoError(t, err) {
   562  		t.FailNow()
   563  	}
   564  
   565  	err = setKptfileName(rw, expectedName)
   566  	if !assert.NoError(t, err) {
   567  		t.FailNow()
   568  	}
   569  
   570  	actualPkg := pkgtesting.CreatePkgOrFail(t, rw.FullPackagePath())
   571  	err = Command{
   572  		Pkg: actualPkg,
   573  	}.Run(fake.CtxWithDefaultPrinter())
   574  	if !assert.Error(t, err) {
   575  		t.FailNow()
   576  	}
   577  	assert.Contains(t, err.Error(), "does not exist in")
   578  	assert.Contains(t, err.Error(), g.RepoDirectory)
   579  	assert.Contains(t, err.Error(), dir)
   580  }
   581  
   582  func TestCommand_Run_no_subdir_at_invalid_tag(t *testing.T) {
   583  	dir := "/java/expected"
   584  	nonexistentTag := "notjava/v2"
   585  	expectedName := "expected_dir_is_here"
   586  	repos, rw, clean := testutil.SetupReposAndWorkspace(t, map[string][]testutil.Content{
   587  		testutil.Upstream: {
   588  			{
   589  				Pkg: pkgbuilder.NewRootPkg().
   590  					WithSubPackages(pkgbuilder.NewSubPkg("java").
   591  						WithResource("deployment").
   592  						WithSubPackages(pkgbuilder.NewSubPkg(expectedName).
   593  							WithFile("expected.txt", "My kptfile and I should be the only objects"))),
   594  				Branch: "main",
   595  				Tag:    "java/v2",
   596  			},
   597  		},
   598  	})
   599  
   600  	defer clean()
   601  
   602  	g := repos[testutil.Upstream]
   603  	err := createKptfile(rw, &kptfilev1.Git{
   604  		Repo:      g.RepoDirectory,
   605  		Directory: dir,
   606  		Ref:       nonexistentTag,
   607  	}, kptfilev1.ResourceMerge)
   608  	if !assert.NoError(t, err) {
   609  		t.FailNow()
   610  	}
   611  
   612  	err = setKptfileName(rw, expectedName)
   613  	if !assert.NoError(t, err) {
   614  		t.FailNow()
   615  	}
   616  
   617  	actualPkg := pkgtesting.CreatePkgOrFail(t, rw.FullPackagePath())
   618  	err = Command{
   619  		Pkg: actualPkg,
   620  	}.Run(fake.CtxWithDefaultPrinter())
   621  	if !assert.Error(t, err) {
   622  		t.FailNow()
   623  	}
   624  	assert.Contains(t, err.Error(), "unknown revision")
   625  }
   626  
   627  func TestCommand_Run_failInvalidRepo(t *testing.T) {
   628  	_, w, clean := setupWorkspace(t)
   629  	defer clean()
   630  
   631  	err := createKptfile(w, &kptfilev1.Git{
   632  		Repo:      "foo",
   633  		Directory: "/",
   634  		Ref:       "refs/heads/master",
   635  	}, kptfilev1.ResourceMerge)
   636  	if !assert.NoError(t, err) {
   637  		t.FailNow()
   638  	}
   639  
   640  	err = Command{
   641  		Pkg: pkgtesting.CreatePkgOrFail(t, w.FullPackagePath()),
   642  	}.Run(fake.CtxWithDefaultPrinter())
   643  	if !assert.Error(t, err) {
   644  		t.FailNow()
   645  	}
   646  	if !assert.Contains(t, err.Error(), "'foo' does not appear to be a git repository") {
   647  		t.FailNow()
   648  	}
   649  }
   650  
   651  func TestCommand_Run_failInvalidBranch(t *testing.T) {
   652  	g, w, clean := setupWorkspace(t)
   653  	defer clean()
   654  
   655  	err := createKptfile(w, &kptfilev1.Git{
   656  		Repo:      g.RepoDirectory,
   657  		Directory: "/",
   658  		Ref:       "refs/heads/foo",
   659  	}, kptfilev1.ResourceMerge)
   660  	if !assert.NoError(t, err) {
   661  		t.FailNow()
   662  	}
   663  
   664  	err = Command{
   665  		Pkg: pkgtesting.CreatePkgOrFail(t, w.FullPackagePath()),
   666  	}.Run(fake.CtxWithDefaultPrinter())
   667  	if !assert.Error(t, err) {
   668  		t.FailNow()
   669  	}
   670  	if !assert.Contains(t, err.Error(), "refs/heads/foo") {
   671  		t.FailNow()
   672  	}
   673  	if !assert.Contains(t, err.Error(), "exit status 128") {
   674  		t.FailNow()
   675  	}
   676  }
   677  
   678  func TestCommand_Run_failInvalidTag(t *testing.T) {
   679  	g, w, clean := setupWorkspace(t)
   680  	defer clean()
   681  
   682  	err := createKptfile(w, &kptfilev1.Git{
   683  		Repo:      g.RepoDirectory,
   684  		Directory: "/",
   685  		Ref:       "refs/tags/foo",
   686  	}, kptfilev1.FastForward)
   687  	if !assert.NoError(t, err) {
   688  		t.FailNow()
   689  	}
   690  
   691  	err = Command{
   692  		Pkg: pkgtesting.CreatePkgOrFail(t, w.FullPackagePath()),
   693  	}.Run(fake.CtxWithDefaultPrinter())
   694  	if !assert.Error(t, err) {
   695  		t.FailNow()
   696  	}
   697  	if !assert.Contains(t, err.Error(), "refs/tags/foo") {
   698  		t.FailNow()
   699  	}
   700  	if !assert.Contains(t, err.Error(), "exit status 128") {
   701  		t.FailNow()
   702  	}
   703  }