diff options
author | Gavin Mak <gavinmak@google.com> | 2023-03-11 06:46:20 +0000 |
---|---|---|
committer | LUCI <gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-03-22 17:46:28 +0000 |
commit | ea2e330e43c182dc16b0111ebc69ee5a71ee4ce1 (patch) | |
tree | dc33ba0e56825b3e007d0589891756724725a465 /tests/test_project.py | |
parent | 1604cf255f8c1786a23388db6d5277ac7949a24a (diff) | |
download | git-repo-ea2e330e43c182dc16b0111ebc69ee5a71ee4ce1.tar.gz |
Format codebase with black and check formatting in CQ
Apply rules set by https://gerrit-review.googlesource.com/c/git-repo/+/362954/ across the codebase and fix any lingering errors caught
by flake8. Also check black formatting in run_tests (and CQ).
Bug: b/267675342
Change-Id: I972d77649dac351150dcfeb1cd1ad0ea2efc1956
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/363474
Reviewed-by: Mike Frysinger <vapier@google.com>
Tested-by: Gavin Mak <gavinmak@google.com>
Commit-Queue: Gavin Mak <gavinmak@google.com>
Diffstat (limited to 'tests/test_project.py')
-rw-r--r-- | tests/test_project.py | 855 |
1 files changed, 448 insertions, 407 deletions
diff --git a/tests/test_project.py b/tests/test_project.py index c50d9940..bc8330b2 100644 --- a/tests/test_project.py +++ b/tests/test_project.py | |||
@@ -31,452 +31,493 @@ import project | |||
31 | 31 | ||
32 | @contextlib.contextmanager | 32 | @contextlib.contextmanager |
33 | def TempGitTree(): | 33 | def TempGitTree(): |
34 | """Create a new empty git checkout for testing.""" | 34 | """Create a new empty git checkout for testing.""" |
35 | with tempfile.TemporaryDirectory(prefix='repo-tests') as tempdir: | 35 | with tempfile.TemporaryDirectory(prefix="repo-tests") as tempdir: |
36 | # Tests need to assume, that main is default branch at init, | 36 | # Tests need to assume, that main is default branch at init, |
37 | # which is not supported in config until 2.28. | 37 | # which is not supported in config until 2.28. |
38 | cmd = ['git', 'init'] | 38 | cmd = ["git", "init"] |
39 | if git_command.git_require((2, 28, 0)): | 39 | if git_command.git_require((2, 28, 0)): |
40 | cmd += ['--initial-branch=main'] | 40 | cmd += ["--initial-branch=main"] |
41 | else: | 41 | else: |
42 | # Use template dir for init. | 42 | # Use template dir for init. |
43 | templatedir = tempfile.mkdtemp(prefix='.test-template') | 43 | templatedir = tempfile.mkdtemp(prefix=".test-template") |
44 | with open(os.path.join(templatedir, 'HEAD'), 'w') as fp: | 44 | with open(os.path.join(templatedir, "HEAD"), "w") as fp: |
45 | fp.write('ref: refs/heads/main\n') | 45 | fp.write("ref: refs/heads/main\n") |
46 | cmd += ['--template', templatedir] | 46 | cmd += ["--template", templatedir] |
47 | subprocess.check_call(cmd, cwd=tempdir) | 47 | subprocess.check_call(cmd, cwd=tempdir) |
48 | yield tempdir | 48 | yield tempdir |
49 | 49 | ||
50 | 50 | ||
51 | class FakeProject(object): | 51 | class FakeProject(object): |
52 | """A fake for Project for basic functionality.""" | 52 | """A fake for Project for basic functionality.""" |
53 | 53 | ||
54 | def __init__(self, worktree): | 54 | def __init__(self, worktree): |
55 | self.worktree = worktree | 55 | self.worktree = worktree |
56 | self.gitdir = os.path.join(worktree, '.git') | 56 | self.gitdir = os.path.join(worktree, ".git") |
57 | self.name = 'fakeproject' | 57 | self.name = "fakeproject" |
58 | self.work_git = project.Project._GitGetByExec( | 58 | self.work_git = project.Project._GitGetByExec( |
59 | self, bare=False, gitdir=self.gitdir) | 59 | self, bare=False, gitdir=self.gitdir |
60 | self.bare_git = project.Project._GitGetByExec( | 60 | ) |
61 | self, bare=True, gitdir=self.gitdir) | 61 | self.bare_git = project.Project._GitGetByExec( |
62 | self.config = git_config.GitConfig.ForRepository(gitdir=self.gitdir) | 62 | self, bare=True, gitdir=self.gitdir |
63 | ) | ||
64 | self.config = git_config.GitConfig.ForRepository(gitdir=self.gitdir) | ||
63 | 65 | ||
64 | 66 | ||
65 | class ReviewableBranchTests(unittest.TestCase): | 67 | class ReviewableBranchTests(unittest.TestCase): |
66 | """Check ReviewableBranch behavior.""" | 68 | """Check ReviewableBranch behavior.""" |
67 | 69 | ||
68 | def test_smoke(self): | 70 | def test_smoke(self): |
69 | """A quick run through everything.""" | 71 | """A quick run through everything.""" |
70 | with TempGitTree() as tempdir: | 72 | with TempGitTree() as tempdir: |
71 | fakeproj = FakeProject(tempdir) | 73 | fakeproj = FakeProject(tempdir) |
72 | 74 | ||
73 | # Generate some commits. | 75 | # Generate some commits. |
74 | with open(os.path.join(tempdir, 'readme'), 'w') as fp: | 76 | with open(os.path.join(tempdir, "readme"), "w") as fp: |
75 | fp.write('txt') | 77 | fp.write("txt") |
76 | fakeproj.work_git.add('readme') | 78 | fakeproj.work_git.add("readme") |
77 | fakeproj.work_git.commit('-mAdd file') | 79 | fakeproj.work_git.commit("-mAdd file") |
78 | fakeproj.work_git.checkout('-b', 'work') | 80 | fakeproj.work_git.checkout("-b", "work") |
79 | fakeproj.work_git.rm('-f', 'readme') | 81 | fakeproj.work_git.rm("-f", "readme") |
80 | fakeproj.work_git.commit('-mDel file') | 82 | fakeproj.work_git.commit("-mDel file") |
81 | 83 | ||
82 | # Start off with the normal details. | 84 | # Start off with the normal details. |
83 | rb = project.ReviewableBranch( | 85 | rb = project.ReviewableBranch( |
84 | fakeproj, fakeproj.config.GetBranch('work'), 'main') | 86 | fakeproj, fakeproj.config.GetBranch("work"), "main" |
85 | self.assertEqual('work', rb.name) | 87 | ) |
86 | self.assertEqual(1, len(rb.commits)) | 88 | self.assertEqual("work", rb.name) |
87 | self.assertIn('Del file', rb.commits[0]) | 89 | self.assertEqual(1, len(rb.commits)) |
88 | d = rb.unabbrev_commits | 90 | self.assertIn("Del file", rb.commits[0]) |
89 | self.assertEqual(1, len(d)) | 91 | d = rb.unabbrev_commits |
90 | short, long = next(iter(d.items())) | 92 | self.assertEqual(1, len(d)) |
91 | self.assertTrue(long.startswith(short)) | 93 | short, long = next(iter(d.items())) |
92 | self.assertTrue(rb.base_exists) | 94 | self.assertTrue(long.startswith(short)) |
93 | # Hard to assert anything useful about this. | 95 | self.assertTrue(rb.base_exists) |
94 | self.assertTrue(rb.date) | 96 | # Hard to assert anything useful about this. |
95 | 97 | self.assertTrue(rb.date) | |
96 | # Now delete the tracking branch! | 98 | |
97 | fakeproj.work_git.branch('-D', 'main') | 99 | # Now delete the tracking branch! |
98 | rb = project.ReviewableBranch( | 100 | fakeproj.work_git.branch("-D", "main") |
99 | fakeproj, fakeproj.config.GetBranch('work'), 'main') | 101 | rb = project.ReviewableBranch( |
100 | self.assertEqual(0, len(rb.commits)) | 102 | fakeproj, fakeproj.config.GetBranch("work"), "main" |
101 | self.assertFalse(rb.base_exists) | 103 | ) |
102 | # Hard to assert anything useful about this. | 104 | self.assertEqual(0, len(rb.commits)) |
103 | self.assertTrue(rb.date) | 105 | self.assertFalse(rb.base_exists) |
106 | # Hard to assert anything useful about this. | ||
107 | self.assertTrue(rb.date) | ||
104 | 108 | ||
105 | 109 | ||
106 | class CopyLinkTestCase(unittest.TestCase): | 110 | class CopyLinkTestCase(unittest.TestCase): |
107 | """TestCase for stub repo client checkouts. | 111 | """TestCase for stub repo client checkouts. |
108 | 112 | ||
109 | It'll have a layout like this: | 113 | It'll have a layout like this: |
110 | tempdir/ # self.tempdir | 114 | tempdir/ # self.tempdir |
111 | checkout/ # self.topdir | 115 | checkout/ # self.topdir |
112 | git-project/ # self.worktree | 116 | git-project/ # self.worktree |
113 | 117 | ||
114 | Attributes: | 118 | Attributes: |
115 | tempdir: A dedicated temporary directory. | 119 | tempdir: A dedicated temporary directory. |
116 | worktree: The top of the repo client checkout. | 120 | worktree: The top of the repo client checkout. |
117 | topdir: The top of a project checkout. | 121 | topdir: The top of a project checkout. |
118 | """ | 122 | """ |
119 | 123 | ||
120 | def setUp(self): | 124 | def setUp(self): |
121 | self.tempdirobj = tempfile.TemporaryDirectory(prefix='repo_tests') | 125 | self.tempdirobj = tempfile.TemporaryDirectory(prefix="repo_tests") |
122 | self.tempdir = self.tempdirobj.name | 126 | self.tempdir = self.tempdirobj.name |
123 | self.topdir = os.path.join(self.tempdir, 'checkout') | 127 | self.topdir = os.path.join(self.tempdir, "checkout") |
124 | self.worktree = os.path.join(self.topdir, 'git-project') | 128 | self.worktree = os.path.join(self.topdir, "git-project") |
125 | os.makedirs(self.topdir) | 129 | os.makedirs(self.topdir) |
126 | os.makedirs(self.worktree) | 130 | os.makedirs(self.worktree) |
127 | 131 | ||
128 | def tearDown(self): | 132 | def tearDown(self): |
129 | self.tempdirobj.cleanup() | 133 | self.tempdirobj.cleanup() |
130 | 134 | ||
131 | @staticmethod | 135 | @staticmethod |
132 | def touch(path): | 136 | def touch(path): |
133 | with open(path, 'w'): | 137 | with open(path, "w"): |
134 | pass | 138 | pass |
135 | 139 | ||
136 | def assertExists(self, path, msg=None): | 140 | def assertExists(self, path, msg=None): |
137 | """Make sure |path| exists.""" | 141 | """Make sure |path| exists.""" |
138 | if os.path.exists(path): | 142 | if os.path.exists(path): |
139 | return | 143 | return |
140 | 144 | ||
141 | if msg is None: | 145 | if msg is None: |
142 | msg = ['path is missing: %s' % path] | 146 | msg = ["path is missing: %s" % path] |
143 | while path != '/': | 147 | while path != "/": |
144 | path = os.path.dirname(path) | 148 | path = os.path.dirname(path) |
145 | if not path: | 149 | if not path: |
146 | # If we're given something like "foo", abort once we get to "". | 150 | # If we're given something like "foo", abort once we get to |
147 | break | 151 | # "". |
148 | result = os.path.exists(path) | 152 | break |
149 | msg.append('\tos.path.exists(%s): %s' % (path, result)) | 153 | result = os.path.exists(path) |
150 | if result: | 154 | msg.append("\tos.path.exists(%s): %s" % (path, result)) |
151 | msg.append('\tcontents: %r' % os.listdir(path)) | 155 | if result: |
152 | break | 156 | msg.append("\tcontents: %r" % os.listdir(path)) |
153 | msg = '\n'.join(msg) | 157 | break |
154 | 158 | msg = "\n".join(msg) | |
155 | raise self.failureException(msg) | 159 | |
160 | raise self.failureException(msg) | ||
156 | 161 | ||
157 | 162 | ||
158 | class CopyFile(CopyLinkTestCase): | 163 | class CopyFile(CopyLinkTestCase): |
159 | """Check _CopyFile handling.""" | 164 | """Check _CopyFile handling.""" |
160 | 165 | ||
161 | def CopyFile(self, src, dest): | 166 | def CopyFile(self, src, dest): |
162 | return project._CopyFile(self.worktree, src, self.topdir, dest) | 167 | return project._CopyFile(self.worktree, src, self.topdir, dest) |
163 | 168 | ||
164 | def test_basic(self): | 169 | def test_basic(self): |
165 | """Basic test of copying a file from a project to the toplevel.""" | 170 | """Basic test of copying a file from a project to the toplevel.""" |
166 | src = os.path.join(self.worktree, 'foo.txt') | 171 | src = os.path.join(self.worktree, "foo.txt") |
167 | self.touch(src) | 172 | self.touch(src) |
168 | cf = self.CopyFile('foo.txt', 'foo') | 173 | cf = self.CopyFile("foo.txt", "foo") |
169 | cf._Copy() | 174 | cf._Copy() |
170 | self.assertExists(os.path.join(self.topdir, 'foo')) | 175 | self.assertExists(os.path.join(self.topdir, "foo")) |
171 | 176 | ||
172 | def test_src_subdir(self): | 177 | def test_src_subdir(self): |
173 | """Copy a file from a subdir of a project.""" | 178 | """Copy a file from a subdir of a project.""" |
174 | src = os.path.join(self.worktree, 'bar', 'foo.txt') | 179 | src = os.path.join(self.worktree, "bar", "foo.txt") |
175 | os.makedirs(os.path.dirname(src)) | 180 | os.makedirs(os.path.dirname(src)) |
176 | self.touch(src) | 181 | self.touch(src) |
177 | cf = self.CopyFile('bar/foo.txt', 'new.txt') | 182 | cf = self.CopyFile("bar/foo.txt", "new.txt") |
178 | cf._Copy() | 183 | cf._Copy() |
179 | self.assertExists(os.path.join(self.topdir, 'new.txt')) | 184 | self.assertExists(os.path.join(self.topdir, "new.txt")) |
180 | 185 | ||
181 | def test_dest_subdir(self): | 186 | def test_dest_subdir(self): |
182 | """Copy a file to a subdir of a checkout.""" | 187 | """Copy a file to a subdir of a checkout.""" |
183 | src = os.path.join(self.worktree, 'foo.txt') | 188 | src = os.path.join(self.worktree, "foo.txt") |
184 | self.touch(src) | 189 | self.touch(src) |
185 | cf = self.CopyFile('foo.txt', 'sub/dir/new.txt') | 190 | cf = self.CopyFile("foo.txt", "sub/dir/new.txt") |
186 | self.assertFalse(os.path.exists(os.path.join(self.topdir, 'sub'))) | 191 | self.assertFalse(os.path.exists(os.path.join(self.topdir, "sub"))) |
187 | cf._Copy() | 192 | cf._Copy() |
188 | self.assertExists(os.path.join(self.topdir, 'sub', 'dir', 'new.txt')) | 193 | self.assertExists(os.path.join(self.topdir, "sub", "dir", "new.txt")) |
189 | 194 | ||
190 | def test_update(self): | 195 | def test_update(self): |
191 | """Make sure changed files get copied again.""" | 196 | """Make sure changed files get copied again.""" |
192 | src = os.path.join(self.worktree, 'foo.txt') | 197 | src = os.path.join(self.worktree, "foo.txt") |
193 | dest = os.path.join(self.topdir, 'bar') | 198 | dest = os.path.join(self.topdir, "bar") |
194 | with open(src, 'w') as f: | 199 | with open(src, "w") as f: |
195 | f.write('1st') | 200 | f.write("1st") |
196 | cf = self.CopyFile('foo.txt', 'bar') | 201 | cf = self.CopyFile("foo.txt", "bar") |
197 | cf._Copy() | 202 | cf._Copy() |
198 | self.assertExists(dest) | 203 | self.assertExists(dest) |
199 | with open(dest) as f: | 204 | with open(dest) as f: |
200 | self.assertEqual(f.read(), '1st') | 205 | self.assertEqual(f.read(), "1st") |
201 | 206 | ||
202 | with open(src, 'w') as f: | 207 | with open(src, "w") as f: |
203 | f.write('2nd!') | 208 | f.write("2nd!") |
204 | cf._Copy() | 209 | cf._Copy() |
205 | with open(dest) as f: | 210 | with open(dest) as f: |
206 | self.assertEqual(f.read(), '2nd!') | 211 | self.assertEqual(f.read(), "2nd!") |
207 | 212 | ||
208 | def test_src_block_symlink(self): | 213 | def test_src_block_symlink(self): |
209 | """Do not allow reading from a symlinked path.""" | 214 | """Do not allow reading from a symlinked path.""" |
210 | src = os.path.join(self.worktree, 'foo.txt') | 215 | src = os.path.join(self.worktree, "foo.txt") |
211 | sym = os.path.join(self.worktree, 'sym') | 216 | sym = os.path.join(self.worktree, "sym") |
212 | self.touch(src) | 217 | self.touch(src) |
213 | platform_utils.symlink('foo.txt', sym) | 218 | platform_utils.symlink("foo.txt", sym) |
214 | self.assertExists(sym) | 219 | self.assertExists(sym) |
215 | cf = self.CopyFile('sym', 'foo') | 220 | cf = self.CopyFile("sym", "foo") |
216 | self.assertRaises(error.ManifestInvalidPathError, cf._Copy) | 221 | self.assertRaises(error.ManifestInvalidPathError, cf._Copy) |
217 | 222 | ||
218 | def test_src_block_symlink_traversal(self): | 223 | def test_src_block_symlink_traversal(self): |
219 | """Do not allow reading through a symlink dir.""" | 224 | """Do not allow reading through a symlink dir.""" |
220 | realfile = os.path.join(self.tempdir, 'file.txt') | 225 | realfile = os.path.join(self.tempdir, "file.txt") |
221 | self.touch(realfile) | 226 | self.touch(realfile) |
222 | src = os.path.join(self.worktree, 'bar', 'file.txt') | 227 | src = os.path.join(self.worktree, "bar", "file.txt") |
223 | platform_utils.symlink(self.tempdir, os.path.join(self.worktree, 'bar')) | 228 | platform_utils.symlink(self.tempdir, os.path.join(self.worktree, "bar")) |
224 | self.assertExists(src) | 229 | self.assertExists(src) |
225 | cf = self.CopyFile('bar/file.txt', 'foo') | 230 | cf = self.CopyFile("bar/file.txt", "foo") |
226 | self.assertRaises(error.ManifestInvalidPathError, cf._Copy) | 231 | self.assertRaises(error.ManifestInvalidPathError, cf._Copy) |
227 | 232 | ||
228 | def test_src_block_copy_from_dir(self): | 233 | def test_src_block_copy_from_dir(self): |
229 | """Do not allow copying from a directory.""" | 234 | """Do not allow copying from a directory.""" |
230 | src = os.path.join(self.worktree, 'dir') | 235 | src = os.path.join(self.worktree, "dir") |
231 | os.makedirs(src) | 236 | os.makedirs(src) |
232 | cf = self.CopyFile('dir', 'foo') | 237 | cf = self.CopyFile("dir", "foo") |
233 | self.assertRaises(error.ManifestInvalidPathError, cf._Copy) | 238 | self.assertRaises(error.ManifestInvalidPathError, cf._Copy) |
234 | 239 | ||
235 | def test_dest_block_symlink(self): | 240 | def test_dest_block_symlink(self): |
236 | """Do not allow writing to a symlink.""" | 241 | """Do not allow writing to a symlink.""" |
237 | src = os.path.join(self.worktree, 'foo.txt') | 242 | src = os.path.join(self.worktree, "foo.txt") |
238 | self.touch(src) | 243 | self.touch(src) |
239 | platform_utils.symlink('dest', os.path.join(self.topdir, 'sym')) | 244 | platform_utils.symlink("dest", os.path.join(self.topdir, "sym")) |
240 | cf = self.CopyFile('foo.txt', 'sym') | 245 | cf = self.CopyFile("foo.txt", "sym") |
241 | self.assertRaises(error.ManifestInvalidPathError, cf._Copy) | 246 | self.assertRaises(error.ManifestInvalidPathError, cf._Copy) |
242 | 247 | ||
243 | def test_dest_block_symlink_traversal(self): | 248 | def test_dest_block_symlink_traversal(self): |
244 | """Do not allow writing through a symlink dir.""" | 249 | """Do not allow writing through a symlink dir.""" |
245 | src = os.path.join(self.worktree, 'foo.txt') | 250 | src = os.path.join(self.worktree, "foo.txt") |
246 | self.touch(src) | 251 | self.touch(src) |
247 | platform_utils.symlink(tempfile.gettempdir(), | 252 | platform_utils.symlink( |
248 | os.path.join(self.topdir, 'sym')) | 253 | tempfile.gettempdir(), os.path.join(self.topdir, "sym") |
249 | cf = self.CopyFile('foo.txt', 'sym/foo.txt') | 254 | ) |
250 | self.assertRaises(error.ManifestInvalidPathError, cf._Copy) | 255 | cf = self.CopyFile("foo.txt", "sym/foo.txt") |
251 | 256 | self.assertRaises(error.ManifestInvalidPathError, cf._Copy) | |
252 | def test_src_block_copy_to_dir(self): | 257 | |
253 | """Do not allow copying to a directory.""" | 258 | def test_src_block_copy_to_dir(self): |
254 | src = os.path.join(self.worktree, 'foo.txt') | 259 | """Do not allow copying to a directory.""" |
255 | self.touch(src) | 260 | src = os.path.join(self.worktree, "foo.txt") |
256 | os.makedirs(os.path.join(self.topdir, 'dir')) | 261 | self.touch(src) |
257 | cf = self.CopyFile('foo.txt', 'dir') | 262 | os.makedirs(os.path.join(self.topdir, "dir")) |
258 | self.assertRaises(error.ManifestInvalidPathError, cf._Copy) | 263 | cf = self.CopyFile("foo.txt", "dir") |
264 | self.assertRaises(error.ManifestInvalidPathError, cf._Copy) | ||
259 | 265 | ||
260 | 266 | ||
261 | class LinkFile(CopyLinkTestCase): | 267 | class LinkFile(CopyLinkTestCase): |
262 | """Check _LinkFile handling.""" | 268 | """Check _LinkFile handling.""" |
263 | 269 | ||
264 | def LinkFile(self, src, dest): | 270 | def LinkFile(self, src, dest): |
265 | return project._LinkFile(self.worktree, src, self.topdir, dest) | 271 | return project._LinkFile(self.worktree, src, self.topdir, dest) |
266 | 272 | ||
267 | def test_basic(self): | 273 | def test_basic(self): |
268 | """Basic test of linking a file from a project into the toplevel.""" | 274 | """Basic test of linking a file from a project into the toplevel.""" |
269 | src = os.path.join(self.worktree, 'foo.txt') | 275 | src = os.path.join(self.worktree, "foo.txt") |
270 | self.touch(src) | 276 | self.touch(src) |
271 | lf = self.LinkFile('foo.txt', 'foo') | 277 | lf = self.LinkFile("foo.txt", "foo") |
272 | lf._Link() | 278 | lf._Link() |
273 | dest = os.path.join(self.topdir, 'foo') | 279 | dest = os.path.join(self.topdir, "foo") |
274 | self.assertExists(dest) | 280 | self.assertExists(dest) |
275 | self.assertTrue(os.path.islink(dest)) | 281 | self.assertTrue(os.path.islink(dest)) |
276 | self.assertEqual(os.path.join('git-project', 'foo.txt'), os.readlink(dest)) | 282 | self.assertEqual( |
277 | 283 | os.path.join("git-project", "foo.txt"), os.readlink(dest) | |
278 | def test_src_subdir(self): | 284 | ) |
279 | """Link to a file in a subdir of a project.""" | 285 | |
280 | src = os.path.join(self.worktree, 'bar', 'foo.txt') | 286 | def test_src_subdir(self): |
281 | os.makedirs(os.path.dirname(src)) | 287 | """Link to a file in a subdir of a project.""" |
282 | self.touch(src) | 288 | src = os.path.join(self.worktree, "bar", "foo.txt") |
283 | lf = self.LinkFile('bar/foo.txt', 'foo') | 289 | os.makedirs(os.path.dirname(src)) |
284 | lf._Link() | 290 | self.touch(src) |
285 | self.assertExists(os.path.join(self.topdir, 'foo')) | 291 | lf = self.LinkFile("bar/foo.txt", "foo") |
286 | 292 | lf._Link() | |
287 | def test_src_self(self): | 293 | self.assertExists(os.path.join(self.topdir, "foo")) |
288 | """Link to the project itself.""" | 294 | |
289 | dest = os.path.join(self.topdir, 'foo', 'bar') | 295 | def test_src_self(self): |
290 | lf = self.LinkFile('.', 'foo/bar') | 296 | """Link to the project itself.""" |
291 | lf._Link() | 297 | dest = os.path.join(self.topdir, "foo", "bar") |
292 | self.assertExists(dest) | 298 | lf = self.LinkFile(".", "foo/bar") |
293 | self.assertEqual(os.path.join('..', 'git-project'), os.readlink(dest)) | 299 | lf._Link() |
294 | 300 | self.assertExists(dest) | |
295 | def test_dest_subdir(self): | 301 | self.assertEqual(os.path.join("..", "git-project"), os.readlink(dest)) |
296 | """Link a file to a subdir of a checkout.""" | 302 | |
297 | src = os.path.join(self.worktree, 'foo.txt') | 303 | def test_dest_subdir(self): |
298 | self.touch(src) | 304 | """Link a file to a subdir of a checkout.""" |
299 | lf = self.LinkFile('foo.txt', 'sub/dir/foo/bar') | 305 | src = os.path.join(self.worktree, "foo.txt") |
300 | self.assertFalse(os.path.exists(os.path.join(self.topdir, 'sub'))) | 306 | self.touch(src) |
301 | lf._Link() | 307 | lf = self.LinkFile("foo.txt", "sub/dir/foo/bar") |
302 | self.assertExists(os.path.join(self.topdir, 'sub', 'dir', 'foo', 'bar')) | 308 | self.assertFalse(os.path.exists(os.path.join(self.topdir, "sub"))) |
303 | 309 | lf._Link() | |
304 | def test_src_block_relative(self): | 310 | self.assertExists(os.path.join(self.topdir, "sub", "dir", "foo", "bar")) |
305 | """Do not allow relative symlinks.""" | 311 | |
306 | BAD_SOURCES = ( | 312 | def test_src_block_relative(self): |
307 | './', | 313 | """Do not allow relative symlinks.""" |
308 | '..', | 314 | BAD_SOURCES = ( |
309 | '../', | 315 | "./", |
310 | 'foo/.', | 316 | "..", |
311 | 'foo/./bar', | 317 | "../", |
312 | 'foo/..', | 318 | "foo/.", |
313 | 'foo/../foo', | 319 | "foo/./bar", |
314 | ) | 320 | "foo/..", |
315 | for src in BAD_SOURCES: | 321 | "foo/../foo", |
316 | lf = self.LinkFile(src, 'foo') | 322 | ) |
317 | self.assertRaises(error.ManifestInvalidPathError, lf._Link) | 323 | for src in BAD_SOURCES: |
318 | 324 | lf = self.LinkFile(src, "foo") | |
319 | def test_update(self): | 325 | self.assertRaises(error.ManifestInvalidPathError, lf._Link) |
320 | """Make sure changed targets get updated.""" | 326 | |
321 | dest = os.path.join(self.topdir, 'sym') | 327 | def test_update(self): |
322 | 328 | """Make sure changed targets get updated.""" | |
323 | src = os.path.join(self.worktree, 'foo.txt') | 329 | dest = os.path.join(self.topdir, "sym") |
324 | self.touch(src) | 330 | |
325 | lf = self.LinkFile('foo.txt', 'sym') | 331 | src = os.path.join(self.worktree, "foo.txt") |
326 | lf._Link() | 332 | self.touch(src) |
327 | self.assertEqual(os.path.join('git-project', 'foo.txt'), os.readlink(dest)) | 333 | lf = self.LinkFile("foo.txt", "sym") |
328 | 334 | lf._Link() | |
329 | # Point the symlink somewhere else. | 335 | self.assertEqual( |
330 | os.unlink(dest) | 336 | os.path.join("git-project", "foo.txt"), os.readlink(dest) |
331 | platform_utils.symlink(self.tempdir, dest) | 337 | ) |
332 | lf._Link() | 338 | |
333 | self.assertEqual(os.path.join('git-project', 'foo.txt'), os.readlink(dest)) | 339 | # Point the symlink somewhere else. |
340 | os.unlink(dest) | ||
341 | platform_utils.symlink(self.tempdir, dest) | ||
342 | lf._Link() | ||
343 | self.assertEqual( | ||
344 | os.path.join("git-project", "foo.txt"), os.readlink(dest) | ||
345 | ) | ||
334 | 346 | ||
335 | 347 | ||
336 | class MigrateWorkTreeTests(unittest.TestCase): | 348 | class MigrateWorkTreeTests(unittest.TestCase): |
337 | """Check _MigrateOldWorkTreeGitDir handling.""" | 349 | """Check _MigrateOldWorkTreeGitDir handling.""" |
338 | 350 | ||
339 | _SYMLINKS = { | 351 | _SYMLINKS = { |
340 | 'config', 'description', 'hooks', 'info', 'logs', 'objects', | 352 | "config", |
341 | 'packed-refs', 'refs', 'rr-cache', 'shallow', 'svn', | 353 | "description", |
342 | } | 354 | "hooks", |
343 | _FILES = { | 355 | "info", |
344 | 'COMMIT_EDITMSG', 'FETCH_HEAD', 'HEAD', 'index', 'ORIG_HEAD', | 356 | "logs", |
345 | 'unknown-file-should-be-migrated', | 357 | "objects", |
346 | } | 358 | "packed-refs", |
347 | _CLEAN_FILES = { | 359 | "refs", |
348 | 'a-vim-temp-file~', '#an-emacs-temp-file#', | 360 | "rr-cache", |
349 | } | 361 | "shallow", |
350 | 362 | "svn", | |
351 | @classmethod | 363 | } |
352 | @contextlib.contextmanager | 364 | _FILES = { |
353 | def _simple_layout(cls): | 365 | "COMMIT_EDITMSG", |
354 | """Create a simple repo client checkout to test against.""" | 366 | "FETCH_HEAD", |
355 | with tempfile.TemporaryDirectory() as tempdir: | 367 | "HEAD", |
356 | tempdir = Path(tempdir) | 368 | "index", |
357 | 369 | "ORIG_HEAD", | |
358 | gitdir = tempdir / '.repo/projects/src/test.git' | 370 | "unknown-file-should-be-migrated", |
359 | gitdir.mkdir(parents=True) | 371 | } |
360 | cmd = ['git', 'init', '--bare', str(gitdir)] | 372 | _CLEAN_FILES = { |
361 | subprocess.check_call(cmd) | 373 | "a-vim-temp-file~", |
362 | 374 | "#an-emacs-temp-file#", | |
363 | dotgit = tempdir / 'src/test/.git' | 375 | } |
364 | dotgit.mkdir(parents=True) | 376 | |
365 | for name in cls._SYMLINKS: | 377 | @classmethod |
366 | (dotgit / name).symlink_to(f'../../../.repo/projects/src/test.git/{name}') | 378 | @contextlib.contextmanager |
367 | for name in cls._FILES | cls._CLEAN_FILES: | 379 | def _simple_layout(cls): |
368 | (dotgit / name).write_text(name) | 380 | """Create a simple repo client checkout to test against.""" |
369 | 381 | with tempfile.TemporaryDirectory() as tempdir: | |
370 | yield tempdir | 382 | tempdir = Path(tempdir) |
371 | 383 | ||
372 | def test_standard(self): | 384 | gitdir = tempdir / ".repo/projects/src/test.git" |
373 | """Migrate a standard checkout that we expect.""" | 385 | gitdir.mkdir(parents=True) |
374 | with self._simple_layout() as tempdir: | 386 | cmd = ["git", "init", "--bare", str(gitdir)] |
375 | dotgit = tempdir / 'src/test/.git' | 387 | subprocess.check_call(cmd) |
376 | project.Project._MigrateOldWorkTreeGitDir(str(dotgit)) | 388 | |
377 | 389 | dotgit = tempdir / "src/test/.git" | |
378 | # Make sure the dir was transformed into a symlink. | 390 | dotgit.mkdir(parents=True) |
379 | self.assertTrue(dotgit.is_symlink()) | 391 | for name in cls._SYMLINKS: |
380 | self.assertEqual(os.readlink(dotgit), os.path.normpath('../../.repo/projects/src/test.git')) | 392 | (dotgit / name).symlink_to( |
381 | 393 | f"../../../.repo/projects/src/test.git/{name}" | |
382 | # Make sure files were moved over. | 394 | ) |
383 | gitdir = tempdir / '.repo/projects/src/test.git' | 395 | for name in cls._FILES | cls._CLEAN_FILES: |
384 | for name in self._FILES: | 396 | (dotgit / name).write_text(name) |
385 | self.assertEqual(name, (gitdir / name).read_text()) | 397 | |
386 | # Make sure files were removed. | 398 | yield tempdir |
387 | for name in self._CLEAN_FILES: | 399 | |
388 | self.assertFalse((gitdir / name).exists()) | 400 | def test_standard(self): |
389 | 401 | """Migrate a standard checkout that we expect.""" | |
390 | def test_unknown(self): | 402 | with self._simple_layout() as tempdir: |
391 | """A checkout with unknown files should abort.""" | 403 | dotgit = tempdir / "src/test/.git" |
392 | with self._simple_layout() as tempdir: | 404 | project.Project._MigrateOldWorkTreeGitDir(str(dotgit)) |
393 | dotgit = tempdir / 'src/test/.git' | 405 | |
394 | (tempdir / '.repo/projects/src/test.git/random-file').write_text('one') | 406 | # Make sure the dir was transformed into a symlink. |
395 | (dotgit / 'random-file').write_text('two') | 407 | self.assertTrue(dotgit.is_symlink()) |
396 | with self.assertRaises(error.GitError): | 408 | self.assertEqual( |
397 | project.Project._MigrateOldWorkTreeGitDir(str(dotgit)) | 409 | os.readlink(dotgit), |
398 | 410 | os.path.normpath("../../.repo/projects/src/test.git"), | |
399 | # Make sure no content was actually changed. | 411 | ) |
400 | self.assertTrue(dotgit.is_dir()) | 412 | |
401 | for name in self._FILES: | 413 | # Make sure files were moved over. |
402 | self.assertTrue((dotgit / name).is_file()) | 414 | gitdir = tempdir / ".repo/projects/src/test.git" |
403 | for name in self._CLEAN_FILES: | 415 | for name in self._FILES: |
404 | self.assertTrue((dotgit / name).is_file()) | 416 | self.assertEqual(name, (gitdir / name).read_text()) |
405 | for name in self._SYMLINKS: | 417 | # Make sure files were removed. |
406 | self.assertTrue((dotgit / name).is_symlink()) | 418 | for name in self._CLEAN_FILES: |
419 | self.assertFalse((gitdir / name).exists()) | ||
420 | |||
421 | def test_unknown(self): | ||
422 | """A checkout with unknown files should abort.""" | ||
423 | with self._simple_layout() as tempdir: | ||
424 | dotgit = tempdir / "src/test/.git" | ||
425 | (tempdir / ".repo/projects/src/test.git/random-file").write_text( | ||
426 | "one" | ||
427 | ) | ||
428 | (dotgit / "random-file").write_text("two") | ||
429 | with self.assertRaises(error.GitError): | ||
430 | project.Project._MigrateOldWorkTreeGitDir(str(dotgit)) | ||
431 | |||
432 | # Make sure no content was actually changed. | ||
433 | self.assertTrue(dotgit.is_dir()) | ||
434 | for name in self._FILES: | ||
435 | self.assertTrue((dotgit / name).is_file()) | ||
436 | for name in self._CLEAN_FILES: | ||
437 | self.assertTrue((dotgit / name).is_file()) | ||
438 | for name in self._SYMLINKS: | ||
439 | self.assertTrue((dotgit / name).is_symlink()) | ||
407 | 440 | ||
408 | 441 | ||
409 | class ManifestPropertiesFetchedCorrectly(unittest.TestCase): | 442 | class ManifestPropertiesFetchedCorrectly(unittest.TestCase): |
410 | """Ensure properties are fetched properly.""" | 443 | """Ensure properties are fetched properly.""" |
411 | 444 | ||
412 | def setUpManifest(self, tempdir): | 445 | def setUpManifest(self, tempdir): |
413 | repodir = os.path.join(tempdir, '.repo') | 446 | repodir = os.path.join(tempdir, ".repo") |
414 | manifest_dir = os.path.join(repodir, 'manifests') | 447 | manifest_dir = os.path.join(repodir, "manifests") |
415 | manifest_file = os.path.join( | 448 | manifest_file = os.path.join(repodir, manifest_xml.MANIFEST_FILE_NAME) |
416 | repodir, manifest_xml.MANIFEST_FILE_NAME) | 449 | os.mkdir(repodir) |
417 | local_manifest_dir = os.path.join( | 450 | os.mkdir(manifest_dir) |
418 | repodir, manifest_xml.LOCAL_MANIFESTS_DIR_NAME) | 451 | manifest = manifest_xml.XmlManifest(repodir, manifest_file) |
419 | os.mkdir(repodir) | ||
420 | os.mkdir(manifest_dir) | ||
421 | manifest = manifest_xml.XmlManifest(repodir, manifest_file) | ||
422 | 452 | ||
423 | return project.ManifestProject( | 453 | return project.ManifestProject( |
424 | manifest, 'test/manifest', os.path.join(tempdir, '.git'), tempdir) | 454 | manifest, "test/manifest", os.path.join(tempdir, ".git"), tempdir |
455 | ) | ||
425 | 456 | ||
426 | def test_manifest_config_properties(self): | 457 | def test_manifest_config_properties(self): |
427 | """Test we are fetching the manifest config properties correctly.""" | 458 | """Test we are fetching the manifest config properties correctly.""" |
428 | 459 | ||
429 | with TempGitTree() as tempdir: | 460 | with TempGitTree() as tempdir: |
430 | fakeproj = self.setUpManifest(tempdir) | 461 | fakeproj = self.setUpManifest(tempdir) |
431 | 462 | ||
432 | # Set property using the expected Set method, then ensure | 463 | # Set property using the expected Set method, then ensure |
433 | # the porperty functions are using the correct Get methods. | 464 | # the porperty functions are using the correct Get methods. |
434 | fakeproj.config.SetString( | 465 | fakeproj.config.SetString( |
435 | 'manifest.standalone', 'https://chicken/manifest.git') | 466 | "manifest.standalone", "https://chicken/manifest.git" |
436 | self.assertEqual( | 467 | ) |
437 | fakeproj.standalone_manifest_url, 'https://chicken/manifest.git') | 468 | self.assertEqual( |
469 | fakeproj.standalone_manifest_url, "https://chicken/manifest.git" | ||
470 | ) | ||
438 | 471 | ||
439 | fakeproj.config.SetString('manifest.groups', 'test-group, admin-group') | 472 | fakeproj.config.SetString( |
440 | self.assertEqual(fakeproj.manifest_groups, 'test-group, admin-group') | 473 | "manifest.groups", "test-group, admin-group" |
474 | ) | ||
475 | self.assertEqual( | ||
476 | fakeproj.manifest_groups, "test-group, admin-group" | ||
477 | ) | ||
441 | 478 | ||
442 | fakeproj.config.SetString('repo.reference', 'mirror/ref') | 479 | fakeproj.config.SetString("repo.reference", "mirror/ref") |
443 | self.assertEqual(fakeproj.reference, 'mirror/ref') | 480 | self.assertEqual(fakeproj.reference, "mirror/ref") |
444 | 481 | ||
445 | fakeproj.config.SetBoolean('repo.dissociate', False) | 482 | fakeproj.config.SetBoolean("repo.dissociate", False) |
446 | self.assertFalse(fakeproj.dissociate) | 483 | self.assertFalse(fakeproj.dissociate) |
447 | 484 | ||
448 | fakeproj.config.SetBoolean('repo.archive', False) | 485 | fakeproj.config.SetBoolean("repo.archive", False) |
449 | self.assertFalse(fakeproj.archive) | 486 | self.assertFalse(fakeproj.archive) |
450 | 487 | ||
451 | fakeproj.config.SetBoolean('repo.mirror', False) | 488 | fakeproj.config.SetBoolean("repo.mirror", False) |
452 | self.assertFalse(fakeproj.mirror) | 489 | self.assertFalse(fakeproj.mirror) |
453 | 490 | ||
454 | fakeproj.config.SetBoolean('repo.worktree', False) | 491 | fakeproj.config.SetBoolean("repo.worktree", False) |
455 | self.assertFalse(fakeproj.use_worktree) | 492 | self.assertFalse(fakeproj.use_worktree) |
456 | 493 | ||
457 | fakeproj.config.SetBoolean('repo.clonebundle', False) | 494 | fakeproj.config.SetBoolean("repo.clonebundle", False) |
458 | self.assertFalse(fakeproj.clone_bundle) | 495 | self.assertFalse(fakeproj.clone_bundle) |
459 | 496 | ||
460 | fakeproj.config.SetBoolean('repo.submodules', False) | 497 | fakeproj.config.SetBoolean("repo.submodules", False) |
461 | self.assertFalse(fakeproj.submodules) | 498 | self.assertFalse(fakeproj.submodules) |
462 | 499 | ||
463 | fakeproj.config.SetBoolean('repo.git-lfs', False) | 500 | fakeproj.config.SetBoolean("repo.git-lfs", False) |
464 | self.assertFalse(fakeproj.git_lfs) | 501 | self.assertFalse(fakeproj.git_lfs) |
465 | 502 | ||
466 | fakeproj.config.SetBoolean('repo.superproject', False) | 503 | fakeproj.config.SetBoolean("repo.superproject", False) |
467 | self.assertFalse(fakeproj.use_superproject) | 504 | self.assertFalse(fakeproj.use_superproject) |
468 | 505 | ||
469 | fakeproj.config.SetBoolean('repo.partialclone', False) | 506 | fakeproj.config.SetBoolean("repo.partialclone", False) |
470 | self.assertFalse(fakeproj.partial_clone) | 507 | self.assertFalse(fakeproj.partial_clone) |
471 | 508 | ||
472 | fakeproj.config.SetString('repo.depth', '48') | 509 | fakeproj.config.SetString("repo.depth", "48") |
473 | self.assertEqual(fakeproj.depth, '48') | 510 | self.assertEqual(fakeproj.depth, "48") |
474 | 511 | ||
475 | fakeproj.config.SetString('repo.clonefilter', 'blob:limit=10M') | 512 | fakeproj.config.SetString("repo.clonefilter", "blob:limit=10M") |
476 | self.assertEqual(fakeproj.clone_filter, 'blob:limit=10M') | 513 | self.assertEqual(fakeproj.clone_filter, "blob:limit=10M") |
477 | 514 | ||
478 | fakeproj.config.SetString('repo.partialcloneexclude', 'third_party/big_repo') | 515 | fakeproj.config.SetString( |
479 | self.assertEqual(fakeproj.partial_clone_exclude, 'third_party/big_repo') | 516 | "repo.partialcloneexclude", "third_party/big_repo" |
517 | ) | ||
518 | self.assertEqual( | ||
519 | fakeproj.partial_clone_exclude, "third_party/big_repo" | ||
520 | ) | ||
480 | 521 | ||
481 | fakeproj.config.SetString('manifest.platform', 'auto') | 522 | fakeproj.config.SetString("manifest.platform", "auto") |
482 | self.assertEqual(fakeproj.manifest_platform, 'auto') | 523 | self.assertEqual(fakeproj.manifest_platform, "auto") |