go.fuchsia.dev/jiri@v0.0.0-20240502161911-b66513b29486/jiritest/fake.go (about)

     1  // Copyright 2015 The Vanadium Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package jiritest
     6  
     7  import (
     8  	"os"
     9  	"path/filepath"
    10  	"testing"
    11  
    12  	"go.fuchsia.dev/jiri"
    13  	"go.fuchsia.dev/jiri/gitutil"
    14  	"go.fuchsia.dev/jiri/jiritest/xtest"
    15  	"go.fuchsia.dev/jiri/project"
    16  )
    17  
    18  // FakeJiriRoot sets up a fake root under a tmp directory.
    19  type FakeJiriRoot struct {
    20  	X             *jiri.X
    21  	Projects      map[string]string
    22  	ProjectHashes map[string][]string
    23  	remote        string
    24  }
    25  
    26  const (
    27  	ManifestFileName    = "public"
    28  	ManifestProjectPath = "manifest"
    29  )
    30  const (
    31  	defaultDataDir      = "data"
    32  	ManifestProjectName = "manifest"
    33  )
    34  
    35  // NewFakeJiriRoot returns a new FakeJiriRoot and a cleanup closure.  The
    36  // closure must be run to cleanup temporary directories and restore the original
    37  // environment; typically it is run as a defer function.
    38  func NewFakeJiriRoot(t *testing.T) (*FakeJiriRoot, func()) {
    39  	// lockfiles are disabled in tests by defaults
    40  	jirix, cleanup := xtest.NewX(t)
    41  	fake := &FakeJiriRoot{
    42  		X:             jirix,
    43  		Projects:      map[string]string{},
    44  		ProjectHashes: make(map[string][]string),
    45  	}
    46  
    47  	// Create fake remote manifest projects.
    48  	remoteDir, err := os.MkdirTemp("", "")
    49  	if err != nil {
    50  		t.Fatalf("TempDir() failed: %v", err)
    51  	}
    52  	fake.remote = remoteDir
    53  	if err := fake.CreateRemoteProject(ManifestProjectPath); err != nil {
    54  		t.Fatal(err)
    55  	}
    56  	// Create a fake manifest.
    57  	manifestDir := filepath.Join(remoteDir, ManifestProjectPath)
    58  	if err := os.MkdirAll(manifestDir, os.FileMode(0700)); err != nil {
    59  		t.Fatal(err)
    60  	}
    61  	if err := fake.WriteRemoteManifest(&project.Manifest{}); err != nil {
    62  		t.Fatal(err)
    63  	}
    64  	// Add the "manifest" project to the manifest.
    65  	if err := fake.AddProject(project.Project{
    66  		Name:   ManifestProjectName,
    67  		Path:   ManifestProjectPath,
    68  		Remote: fake.Projects[ManifestProjectName],
    69  	}); err != nil {
    70  		t.Fatal(err)
    71  	}
    72  	// Create a .jiri_manifest file which imports the manifest created above.
    73  	if err := fake.WriteJiriManifest(&project.Manifest{
    74  		Imports: []project.Import{
    75  			{
    76  				Manifest: ManifestFileName,
    77  				Name:     ManifestProjectName,
    78  				Remote:   filepath.Join(fake.remote, ManifestProjectPath),
    79  			},
    80  		},
    81  	}); err != nil {
    82  		t.Fatal(err)
    83  	}
    84  
    85  	// Update the contents of the fake instance based on  the information
    86  	// recorded in the remote manifest.
    87  	if err := fake.UpdateUniverse(false); err != nil {
    88  		t.Fatal(err)
    89  	}
    90  
    91  	return fake, func() {
    92  		cleanup()
    93  		if err := os.RemoveAll(fake.remote); err != nil {
    94  			t.Fatalf("RemoveAll(%q) failed: %v", fake.remote, err)
    95  		}
    96  	}
    97  }
    98  
    99  // AddProject adds the given project to a remote manifest.
   100  func (fake FakeJiriRoot) AddProject(project project.Project) error {
   101  	manifest, err := fake.ReadRemoteManifest()
   102  	if err != nil {
   103  		return err
   104  	}
   105  	manifest.Projects = append(manifest.Projects, project)
   106  	if err := fake.WriteRemoteManifest(manifest); err != nil {
   107  		return err
   108  	}
   109  	return nil
   110  }
   111  
   112  // AddHook adds the given hook to a remote manifest.
   113  func (fake FakeJiriRoot) AddHook(hook project.Hook) error {
   114  	manifest, err := fake.ReadRemoteManifest()
   115  	if err != nil {
   116  		return err
   117  	}
   118  	manifest.Hooks = append(manifest.Hooks, hook)
   119  	if err := fake.WriteRemoteManifest(manifest); err != nil {
   120  		return err
   121  	}
   122  	return nil
   123  }
   124  
   125  // AddPackage adds the given package to a remote manifest.
   126  func (fake FakeJiriRoot) AddPackage(pkg project.Package) error {
   127  	manifest, err := fake.ReadRemoteManifest()
   128  	if err != nil {
   129  		return err
   130  	}
   131  	manifest.Packages = append(manifest.Packages, pkg)
   132  	if err := fake.WriteRemoteManifest(manifest); err != nil {
   133  		return err
   134  	}
   135  	return nil
   136  }
   137  
   138  // DisableRemoteManifestPush disables pushes to the remote manifest
   139  // repository.
   140  func (fake FakeJiriRoot) DisableRemoteManifestPush() error {
   141  	dir := gitutil.RootDirOpt(filepath.Join(fake.remote, ManifestProjectPath))
   142  	if err := gitutil.New(fake.X, dir).CheckoutBranch("main", false, false); err != nil {
   143  		return err
   144  	}
   145  	return nil
   146  }
   147  
   148  // EnableRemoteManifestPush enables pushes to the remote manifest
   149  // repository.
   150  func (fake FakeJiriRoot) EnableRemoteManifestPush() error {
   151  	dir := filepath.Join(fake.remote, ManifestProjectPath)
   152  	scm := gitutil.New(fake.X, gitutil.RootDirOpt(dir))
   153  	if ok, err := scm.BranchExists("non-main"); ok && err == nil {
   154  		if err := scm.CreateBranch("non-main"); err != nil {
   155  			return err
   156  		}
   157  	} else if err != nil {
   158  		return err
   159  	}
   160  	if err := scm.CheckoutBranch("non-main", false, false); err != nil {
   161  		return err
   162  	}
   163  	return nil
   164  }
   165  
   166  // CreateRemoteProject creates a new remote project.
   167  func (fake FakeJiriRoot) CreateRemoteProject(name string) error {
   168  	projectDir := filepath.Join(fake.remote, name)
   169  	if err := os.MkdirAll(projectDir, os.FileMode(0700)); err != nil {
   170  		return err
   171  	}
   172  	if err := gitutil.New(fake.X).Init(projectDir); err != nil {
   173  		return err
   174  	}
   175  	git := gitutil.New(fake.X, gitutil.RootDirOpt(projectDir))
   176  	if err := git.Config("user.email", "john.doe@example.com"); err != nil {
   177  		return err
   178  	}
   179  	if err := git.Config("user.name", "John Doe"); err != nil {
   180  		return err
   181  	}
   182  
   183  	if err := git.CommitWithMessage("initial commit"); err != nil {
   184  		return err
   185  	}
   186  
   187  	hash, err := git.CurrentRevisionOfBranch("HEAD")
   188  	if err != nil {
   189  		return err
   190  	}
   191  	fake.ProjectHashes[name] = append(fake.ProjectHashes[name], hash)
   192  	fake.Projects[name] = projectDir
   193  	return nil
   194  }
   195  
   196  // ReadRemoteManifest read a manifest from the remote manifest project.
   197  func (fake FakeJiriRoot) ReadRemoteManifest() (*project.Manifest, error) {
   198  	path := filepath.Join(fake.remote, ManifestProjectPath, ManifestFileName)
   199  	return project.ManifestFromFile(fake.X, path)
   200  }
   201  
   202  // UpdateUniverse synchronizes the content of the Vanadium fake based
   203  // on the content of the remote manifest.
   204  func (fake FakeJiriRoot) UpdateUniverse(gc bool) error {
   205  	if err := project.UpdateUniverse(fake.X, gc, false, false, false, false, true /*run-hooks*/, true /*run-packages*/, false /*rebase-subdmodules*/, project.DefaultHookTimeout, project.DefaultPackageTimeout, nil); err != nil {
   206  		return err
   207  	}
   208  	return nil
   209  }
   210  
   211  // ReadJiriManifest reads the .jiri_manifest manifest.
   212  func (fake FakeJiriRoot) ReadJiriManifest() (*project.Manifest, error) {
   213  	return project.ManifestFromFile(fake.X, fake.X.JiriManifestFile())
   214  }
   215  
   216  // WriteJiriManifest writes the given manifest to the .jiri_manifest file.
   217  func (fake FakeJiriRoot) WriteJiriManifest(manifest *project.Manifest) error {
   218  	return manifest.ToFile(fake.X, fake.X.JiriManifestFile())
   219  }
   220  
   221  // WriteRemoteManifest writes the given manifest to the remote
   222  // manifest project.
   223  func (fake FakeJiriRoot) WriteRemoteManifest(manifest *project.Manifest) error {
   224  	dir := filepath.Join(fake.remote, ManifestProjectPath)
   225  	path := filepath.Join(dir, ManifestFileName)
   226  	return fake.writeManifest(manifest, dir, path)
   227  }
   228  
   229  func (fake FakeJiriRoot) writeManifest(manifest *project.Manifest, dir, path string) error {
   230  	git := gitutil.New(fake.X, gitutil.UserNameOpt("John Doe"), gitutil.UserEmailOpt("john.doe@example.com"), gitutil.RootDirOpt(dir))
   231  	if err := manifest.ToFile(fake.X, path); err != nil {
   232  		return err
   233  	}
   234  	if err := git.Add(path); err != nil {
   235  		return err
   236  	}
   237  	if err := git.Commit(); err != nil {
   238  		return err
   239  	}
   240  	hash, err := git.CurrentRevisionOfBranch("HEAD")
   241  	if err != nil {
   242  		return err
   243  	}
   244  	fake.ProjectHashes[ManifestProjectName] = append(fake.ProjectHashes[ManifestProjectName], hash)
   245  	return nil
   246  }
   247  
   248  // AddProjectOverride adds a project override into .jiri_manifest of current FakeJiriRoot.
   249  func (fake FakeJiriRoot) AddProjectOverride(name, remote, revision string) error {
   250  	m, err := fake.ReadJiriManifest()
   251  	if err != nil {
   252  		return err
   253  	}
   254  	m.ProjectOverrides = append(m.ProjectOverrides, project.Project{
   255  		Name:     name,
   256  		Remote:   remote,
   257  		Revision: revision,
   258  	})
   259  	fake.WriteJiriManifest(m)
   260  	return nil
   261  }
   262  
   263  // AddImportOverride adds a import override into .jiri_manifest of current FakeJiriRoot.
   264  func (fake FakeJiriRoot) AddImportOverride(name, remote, revision, manifest string) error {
   265  	m, err := fake.ReadJiriManifest()
   266  	if err != nil {
   267  		return err
   268  	}
   269  	m.ImportOverrides = append(m.ImportOverrides, project.Import{
   270  		Name:     name,
   271  		Remote:   remote,
   272  		Revision: revision,
   273  		Manifest: manifest,
   274  	})
   275  	fake.WriteJiriManifest(m)
   276  	return nil
   277  }