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 }