github.com/wmuizelaar/kpt@v0.0.0-20221018115725-bd564717b2ed/internal/testutil/setup_manager.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 testutil
    16  
    17  import (
    18  	"os"
    19  	"path"
    20  	"path/filepath"
    21  	"testing"
    22  
    23  	"github.com/GoogleContainerTools/kpt/internal/gitutil"
    24  	"github.com/GoogleContainerTools/kpt/internal/printer/fake"
    25  	"github.com/GoogleContainerTools/kpt/internal/testutil/pkgbuilder"
    26  	"github.com/GoogleContainerTools/kpt/internal/util/get"
    27  	kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1"
    28  	"github.com/stretchr/testify/assert"
    29  	"sigs.k8s.io/kustomize/kyaml/yaml"
    30  )
    31  
    32  const (
    33  	Upstream = "upstream"
    34  	Local    = "local"
    35  )
    36  
    37  type TestSetupManager struct {
    38  	T *testing.T
    39  
    40  	// GetRef is the git ref to fetch
    41  	GetRef string
    42  
    43  	// GetSubDirectory is the repo subdirectory containing the package
    44  	GetSubDirectory string
    45  
    46  	// ReposChanges are content for any repos.
    47  	ReposChanges map[string][]Content
    48  
    49  	LocalChanges []Content
    50  
    51  	Repos map[string]*TestGitRepo
    52  
    53  	LocalWorkspace *TestWorkspace
    54  
    55  	cleanTestRepos func()
    56  	cacheDir       string
    57  	targetDir      string
    58  }
    59  
    60  type Content struct {
    61  	CreateBranch bool
    62  	Branch       string
    63  	Data         string
    64  	Pkg          *pkgbuilder.RootPkg
    65  	Tag          string
    66  	Message      string
    67  
    68  	// UpdateFunc is invoked after the repo has been updated with the new
    69  	// content, but before it is committed. This allows for making changes
    70  	// that isn't supported by the pkgbuilder (like creating symlinks).
    71  	UpdateFunc func(path string) error
    72  }
    73  
    74  // Init initializes test data
    75  // - Setup a new upstream repo in a tmp directory
    76  // - Set the initial upstream content to Dataset1
    77  // - Setup a new cache location for git repos and update the environment variable
    78  // - Setup fetch the upstream package to a local package
    79  // - Verify the local package contains the upstream content
    80  func (g *TestSetupManager) Init() bool {
    81  	// Default optional values
    82  	if g.GetRef == "" {
    83  		g.GetRef = "master"
    84  	}
    85  	if g.GetSubDirectory == "" {
    86  		g.GetSubDirectory = "/"
    87  	}
    88  
    89  	// Configure the cache location for cloning repos
    90  	cacheDir, err := os.MkdirTemp("", "kpt-test-cache-repos-")
    91  	if !assert.NoError(g.T, err) {
    92  		return false
    93  	}
    94  	g.cacheDir = cacheDir
    95  	os.Setenv(gitutil.RepoCacheDirEnv, g.cacheDir)
    96  
    97  	g.Repos, g.LocalWorkspace, g.cleanTestRepos = SetupReposAndWorkspace(g.T, g.ReposChanges)
    98  	if g.GetSubDirectory == "/" {
    99  		g.targetDir = filepath.Base(g.Repos[Upstream].RepoName)
   100  	} else {
   101  		g.targetDir = filepath.Base(g.GetSubDirectory)
   102  	}
   103  	g.LocalWorkspace.PackageDir = g.targetDir
   104  
   105  	// Get the content from the upstream repo into the local workspace.
   106  	if !assert.NoError(g.T, get.Command{
   107  		Destination: filepath.Join(g.LocalWorkspace.WorkspaceDirectory, g.targetDir),
   108  		Git: &kptfilev1.Git{
   109  			Repo:      g.Repos[Upstream].RepoDirectory,
   110  			Ref:       g.GetRef,
   111  			Directory: g.GetSubDirectory,
   112  		}}.Run(fake.CtxWithDefaultPrinter())) {
   113  		return false
   114  	}
   115  	localGit, err := gitutil.NewLocalGitRunner(g.LocalWorkspace.WorkspaceDirectory)
   116  	if !assert.NoError(g.T, err) {
   117  		return false
   118  	}
   119  	_, err = localGit.Run(fake.CtxWithDefaultPrinter(), "add", ".")
   120  	if !assert.NoError(g.T, err) {
   121  		return false
   122  	}
   123  	_, err = localGit.Run(fake.CtxWithDefaultPrinter(), "commit", "-m", "add files")
   124  	if !assert.NoError(g.T, err) {
   125  		return false
   126  	}
   127  
   128  	// Modify other repos after initial fetch.
   129  	if err := UpdateRepos(g.T, g.Repos, g.ReposChanges); err != nil {
   130  		return false
   131  	}
   132  
   133  	// Modify local workspace after initial fetch.
   134  	if err := UpdateGitDir(g.T, Local, g.LocalWorkspace, g.LocalChanges, g.Repos); err != nil {
   135  		return false
   136  	}
   137  
   138  	return true
   139  }
   140  
   141  type GitDirectory interface {
   142  	CheckoutBranch(branch string, create bool) error
   143  	ReplaceData(data string) error
   144  	Commit(message string) (string, error)
   145  	Tag(tagName string) error
   146  	CustomUpdate(updateFunc func(string) error) error
   147  }
   148  
   149  func UpdateGitDir(t *testing.T, name string, gitDir GitDirectory, changes []Content, repos map[string]*TestGitRepo) error {
   150  	for _, content := range changes {
   151  		if content.Message == "" {
   152  			content.Message = "initializing data"
   153  		}
   154  		if len(content.Branch) > 0 {
   155  			err := gitDir.CheckoutBranch(content.Branch, content.CreateBranch)
   156  			if !assert.NoError(t, err) {
   157  				return err
   158  			}
   159  		}
   160  
   161  		var pkgData string
   162  		if content.Pkg != nil {
   163  			pkgData = content.Pkg.ExpandPkg(t, ToReposInfo(repos))
   164  		} else {
   165  			pkgData = content.Data
   166  		}
   167  
   168  		err := gitDir.ReplaceData(pkgData)
   169  		if !assert.NoError(t, err) {
   170  			return err
   171  		}
   172  
   173  		if content.UpdateFunc != nil {
   174  			err = gitDir.CustomUpdate(content.UpdateFunc)
   175  			if !assert.NoError(t, err) {
   176  				return err
   177  			}
   178  		}
   179  
   180  		sha, err := gitDir.Commit(content.Message)
   181  		if !assert.NoError(t, err) {
   182  			return err
   183  		}
   184  
   185  		// Update the list of commit shas for the repo.
   186  		if r, found := repos[name]; found {
   187  			r.Commits = append(r.Commits, sha)
   188  		}
   189  
   190  		if len(content.Tag) > 0 {
   191  			err = gitDir.Tag(content.Tag)
   192  			if !assert.NoError(t, err) {
   193  				return err
   194  			}
   195  		}
   196  	}
   197  	return nil
   198  }
   199  
   200  // GetSubPkg gets a subpkg specified by repo/upstreamDir to destination in the local workspace
   201  func (g *TestSetupManager) GetSubPkg(dest, repo, upstreamDir string) {
   202  	assert.NoError(g.T, get.Command{
   203  		Destination: path.Join(g.LocalWorkspace.FullPackagePath(), dest),
   204  		Git: &kptfilev1.Git{
   205  			Repo:      g.Repos[repo].RepoDirectory,
   206  			Ref:       g.GetRef,
   207  			Directory: path.Join(g.GetSubDirectory, upstreamDir),
   208  		}}.Run(fake.CtxWithDefaultPrinter()))
   209  
   210  	localGit, err := gitutil.NewLocalGitRunner(g.LocalWorkspace.WorkspaceDirectory)
   211  	assert.NoError(g.T, err)
   212  	_, err = localGit.Run(fake.CtxWithDefaultPrinter(), "add", ".")
   213  	assert.NoError(g.T, err)
   214  	_, err = localGit.Run(fake.CtxWithDefaultPrinter(), "commit", "-m", "add files")
   215  	assert.NoError(g.T, err)
   216  }
   217  
   218  func (g *TestSetupManager) AssertKptfile(name, commit, ref string, strategy kptfilev1.UpdateStrategyType) bool {
   219  	expectedKptfile := kptfilev1.KptFile{
   220  		ResourceMeta: yaml.ResourceMeta{
   221  			ObjectMeta: yaml.ObjectMeta{
   222  				NameMeta: yaml.NameMeta{
   223  					Name: name,
   224  				},
   225  			},
   226  			TypeMeta: yaml.TypeMeta{
   227  				APIVersion: kptfilev1.TypeMeta.APIVersion,
   228  				Kind:       kptfilev1.TypeMeta.Kind},
   229  		},
   230  		Upstream: &kptfilev1.Upstream{
   231  			Type: "git",
   232  			Git: &kptfilev1.Git{
   233  				Directory: g.GetSubDirectory,
   234  				Repo:      g.Repos[Upstream].RepoDirectory,
   235  				Ref:       ref,
   236  			},
   237  			UpdateStrategy: strategy,
   238  		},
   239  		UpstreamLock: &kptfilev1.UpstreamLock{
   240  			Type: "git",
   241  			Git: &kptfilev1.GitLock{
   242  				Directory: g.GetSubDirectory,
   243  				Repo:      g.Repos[Upstream].RepoDirectory,
   244  				Ref:       ref,
   245  				Commit:    commit,
   246  			},
   247  		},
   248  	}
   249  
   250  	return g.Repos[Upstream].AssertKptfile(
   251  		g.T, filepath.Join(g.LocalWorkspace.WorkspaceDirectory, g.targetDir), expectedKptfile)
   252  }
   253  
   254  func (g *TestSetupManager) AssertLocalDataEquals(path string, addMergeCommentToSource bool) bool {
   255  	var sourceDir string
   256  	if filepath.IsAbs(path) {
   257  		sourceDir = path
   258  	} else {
   259  		sourceDir = filepath.Join(g.Repos[Upstream].DatasetDirectory, path)
   260  	}
   261  	destDir := filepath.Join(g.LocalWorkspace.WorkspaceDirectory, g.targetDir)
   262  	return g.Repos[Upstream].AssertEqual(g.T, sourceDir, destDir, addMergeCommentToSource)
   263  }
   264  
   265  func (g *TestSetupManager) Clean() {
   266  	g.cleanTestRepos()
   267  	os.RemoveAll(g.cacheDir)
   268  }