github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/prow/pod-utils/clone/clone_test.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package clone 18 19 import ( 20 "io/ioutil" 21 "os" 22 "os/exec" 23 "reflect" 24 "testing" 25 26 "k8s.io/apimachinery/pkg/util/diff" 27 "k8s.io/test-infra/prow/kube" 28 ) 29 30 func TestPathForRefs(t *testing.T) { 31 var testCases = []struct { 32 name string 33 refs kube.Refs 34 expected string 35 }{ 36 { 37 name: "literal override", 38 refs: kube.Refs{ 39 PathAlias: "alias", 40 }, 41 expected: "base/src/alias", 42 }, 43 { 44 name: "default generated", 45 refs: kube.Refs{ 46 Org: "org", 47 Repo: "repo", 48 }, 49 expected: "base/src/github.com/org/repo", 50 }, 51 } 52 53 for _, testCase := range testCases { 54 if actual, expected := PathForRefs("base", testCase.refs), testCase.expected; actual != expected { 55 t.Errorf("%s: expected path %q, got %q", testCase.name, expected, actual) 56 } 57 } 58 } 59 60 func TestCommandsForRefs(t *testing.T) { 61 fakeTimestamp := 100200300 62 var testCases = []struct { 63 name string 64 refs kube.Refs 65 dir, gitUserName, gitUserEmail, cookiePath string 66 env []string 67 expectedBase []cloneCommand 68 expectedPull []cloneCommand 69 }{ 70 { 71 name: "simplest case, minimal refs", 72 refs: kube.Refs{ 73 Org: "org", 74 Repo: "repo", 75 BaseRef: "master", 76 }, 77 dir: "/go", 78 expectedBase: []cloneCommand{ 79 {dir: "/", command: "mkdir", args: []string{"-p", "/go/src/github.com/org/repo"}}, 80 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"init"}}, 81 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "--tags", "--prune"}}, 82 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "master"}}, 83 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "FETCH_HEAD"}}, 84 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"branch", "--force", "master", "FETCH_HEAD"}}, 85 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "master"}}, 86 }, 87 expectedPull: []cloneCommand{ 88 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"submodule", "update", "--init", "--recursive"}}, 89 }, 90 }, 91 { 92 name: "minimal refs with git user name", 93 refs: kube.Refs{ 94 Org: "org", 95 Repo: "repo", 96 BaseRef: "master", 97 }, 98 gitUserName: "user", 99 dir: "/go", 100 expectedBase: []cloneCommand{ 101 {dir: "/", command: "mkdir", args: []string{"-p", "/go/src/github.com/org/repo"}}, 102 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"init"}}, 103 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"config", "user.name", "user"}}, 104 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "--tags", "--prune"}}, 105 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "master"}}, 106 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "FETCH_HEAD"}}, 107 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"branch", "--force", "master", "FETCH_HEAD"}}, 108 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "master"}}, 109 }, 110 expectedPull: []cloneCommand{ 111 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"submodule", "update", "--init", "--recursive"}}, 112 }, 113 }, 114 { 115 name: "minimal refs with git user email", 116 refs: kube.Refs{ 117 Org: "org", 118 Repo: "repo", 119 BaseRef: "master", 120 }, 121 gitUserEmail: "user@go.com", 122 dir: "/go", 123 expectedBase: []cloneCommand{ 124 {dir: "/", command: "mkdir", args: []string{"-p", "/go/src/github.com/org/repo"}}, 125 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"init"}}, 126 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"config", "user.email", "user@go.com"}}, 127 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "--tags", "--prune"}}, 128 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "master"}}, 129 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "FETCH_HEAD"}}, 130 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"branch", "--force", "master", "FETCH_HEAD"}}, 131 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "master"}}, 132 }, 133 expectedPull: []cloneCommand{ 134 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"submodule", "update", "--init", "--recursive"}}, 135 }, 136 }, 137 { 138 name: "minimal refs with http cookie file", 139 refs: kube.Refs{ 140 Org: "org", 141 Repo: "repo", 142 BaseRef: "master", 143 }, 144 cookiePath: "/cookie.txt", 145 dir: "/go", 146 expectedBase: []cloneCommand{ 147 {dir: "/", command: "mkdir", args: []string{"-p", "/go/src/github.com/org/repo"}}, 148 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"init"}}, 149 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"config", "http.cookiefile", "/cookie.txt"}}, 150 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "--tags", "--prune"}}, 151 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "master"}}, 152 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "FETCH_HEAD"}}, 153 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"branch", "--force", "master", "FETCH_HEAD"}}, 154 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "master"}}, 155 }, 156 expectedPull: []cloneCommand{ 157 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"submodule", "update", "--init", "--recursive"}}, 158 }, 159 }, 160 { 161 name: "minimal refs with no submodules", 162 refs: kube.Refs{ 163 Org: "org", 164 Repo: "repo", 165 BaseRef: "master", 166 SkipSubmodules: true, 167 }, 168 dir: "/go", 169 expectedBase: []cloneCommand{ 170 {dir: "/", command: "mkdir", args: []string{"-p", "/go/src/github.com/org/repo"}}, 171 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"init"}}, 172 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "--tags", "--prune"}}, 173 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "master"}}, 174 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "FETCH_HEAD"}}, 175 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"branch", "--force", "master", "FETCH_HEAD"}}, 176 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "master"}}, 177 }, 178 expectedPull: nil, 179 }, 180 { 181 name: "refs with clone URI override", 182 refs: kube.Refs{ 183 Org: "org", 184 Repo: "repo", 185 BaseRef: "master", 186 CloneURI: "internet.com", 187 }, 188 dir: "/go", 189 expectedBase: []cloneCommand{ 190 {dir: "/", command: "mkdir", args: []string{"-p", "/go/src/github.com/org/repo"}}, 191 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"init"}}, 192 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "internet.com", "--tags", "--prune"}}, 193 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "internet.com", "master"}}, 194 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "FETCH_HEAD"}}, 195 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"branch", "--force", "master", "FETCH_HEAD"}}, 196 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "master"}}, 197 }, 198 expectedPull: []cloneCommand{ 199 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"submodule", "update", "--init", "--recursive"}}, 200 }, 201 }, 202 { 203 name: "refs with path alias", 204 refs: kube.Refs{ 205 Org: "org", 206 Repo: "repo", 207 BaseRef: "master", 208 PathAlias: "my/favorite/dir", 209 }, 210 dir: "/go", 211 expectedBase: []cloneCommand{ 212 {dir: "/", command: "mkdir", args: []string{"-p", "/go/src/my/favorite/dir"}}, 213 {dir: "/go/src/my/favorite/dir", command: "git", args: []string{"init"}}, 214 {dir: "/go/src/my/favorite/dir", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "--tags", "--prune"}}, 215 {dir: "/go/src/my/favorite/dir", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "master"}}, 216 {dir: "/go/src/my/favorite/dir", command: "git", args: []string{"checkout", "FETCH_HEAD"}}, 217 {dir: "/go/src/my/favorite/dir", command: "git", args: []string{"branch", "--force", "master", "FETCH_HEAD"}}, 218 {dir: "/go/src/my/favorite/dir", command: "git", args: []string{"checkout", "master"}}, 219 }, 220 expectedPull: []cloneCommand{ 221 {dir: "/go/src/my/favorite/dir", command: "git", args: []string{"submodule", "update", "--init", "--recursive"}}, 222 }, 223 }, 224 { 225 name: "refs with specific base sha", 226 refs: kube.Refs{ 227 Org: "org", 228 Repo: "repo", 229 BaseRef: "master", 230 BaseSHA: "abcdef", 231 }, 232 dir: "/go", 233 expectedBase: []cloneCommand{ 234 {dir: "/", command: "mkdir", args: []string{"-p", "/go/src/github.com/org/repo"}}, 235 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"init"}}, 236 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "--tags", "--prune"}}, 237 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "master"}}, 238 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "abcdef"}}, 239 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"branch", "--force", "master", "abcdef"}}, 240 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "master"}}, 241 }, 242 expectedPull: []cloneCommand{ 243 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"submodule", "update", "--init", "--recursive"}}, 244 }, 245 }, 246 { 247 name: "refs with simple pr ref", 248 refs: kube.Refs{ 249 Org: "org", 250 Repo: "repo", 251 BaseRef: "master", 252 Pulls: []kube.Pull{ 253 {Number: 1}, 254 }, 255 }, 256 dir: "/go", 257 expectedBase: []cloneCommand{ 258 {dir: "/", command: "mkdir", args: []string{"-p", "/go/src/github.com/org/repo"}}, 259 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"init"}}, 260 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "--tags", "--prune"}}, 261 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "master"}}, 262 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "FETCH_HEAD"}}, 263 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"branch", "--force", "master", "FETCH_HEAD"}}, 264 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "master"}}, 265 }, 266 expectedPull: []cloneCommand{ 267 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "pull/1/head"}}, 268 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"merge", "--no-ff", "FETCH_HEAD"}, env: gitTimestampEnvs(fakeTimestamp + 1)}, 269 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"submodule", "update", "--init", "--recursive"}}, 270 }, 271 }, 272 { 273 name: "refs with pr ref override", 274 refs: kube.Refs{ 275 Org: "org", 276 Repo: "repo", 277 BaseRef: "master", 278 Pulls: []kube.Pull{ 279 {Number: 1, Ref: "pull-me"}, 280 }, 281 }, 282 dir: "/go", 283 expectedBase: []cloneCommand{ 284 {dir: "/", command: "mkdir", args: []string{"-p", "/go/src/github.com/org/repo"}}, 285 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"init"}}, 286 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "--tags", "--prune"}}, 287 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "master"}}, 288 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "FETCH_HEAD"}}, 289 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"branch", "--force", "master", "FETCH_HEAD"}}, 290 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "master"}}, 291 }, 292 expectedPull: []cloneCommand{ 293 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "pull-me"}}, 294 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"merge", "--no-ff", "FETCH_HEAD"}, env: gitTimestampEnvs(fakeTimestamp + 1)}, 295 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"submodule", "update", "--init", "--recursive"}}, 296 }, 297 }, 298 { 299 name: "refs with pr ref with specific sha", 300 refs: kube.Refs{ 301 Org: "org", 302 Repo: "repo", 303 BaseRef: "master", 304 Pulls: []kube.Pull{ 305 {Number: 1, SHA: "abcdef"}, 306 }, 307 }, 308 dir: "/go", 309 expectedBase: []cloneCommand{ 310 {dir: "/", command: "mkdir", args: []string{"-p", "/go/src/github.com/org/repo"}}, 311 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"init"}}, 312 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "--tags", "--prune"}}, 313 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "master"}}, 314 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "FETCH_HEAD"}}, 315 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"branch", "--force", "master", "FETCH_HEAD"}}, 316 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "master"}}, 317 }, 318 expectedPull: []cloneCommand{ 319 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "pull/1/head"}}, 320 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"merge", "--no-ff", "abcdef"}, env: gitTimestampEnvs(fakeTimestamp + 1)}, 321 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"submodule", "update", "--init", "--recursive"}}, 322 }, 323 }, 324 { 325 name: "refs with multiple simple pr refs", 326 refs: kube.Refs{ 327 Org: "org", 328 Repo: "repo", 329 BaseRef: "master", 330 Pulls: []kube.Pull{ 331 {Number: 1}, 332 {Number: 2}, 333 }, 334 }, 335 dir: "/go", 336 expectedBase: []cloneCommand{ 337 {dir: "/", command: "mkdir", args: []string{"-p", "/go/src/github.com/org/repo"}}, 338 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"init"}}, 339 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "--tags", "--prune"}}, 340 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "master"}}, 341 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "FETCH_HEAD"}}, 342 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"branch", "--force", "master", "FETCH_HEAD"}}, 343 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"checkout", "master"}}, 344 }, 345 expectedPull: []cloneCommand{ 346 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "pull/1/head"}}, 347 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"merge", "--no-ff", "FETCH_HEAD"}, env: gitTimestampEnvs(fakeTimestamp + 1)}, 348 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"fetch", "https://github.com/org/repo.git", "pull/2/head"}}, 349 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"merge", "--no-ff", "FETCH_HEAD"}, env: gitTimestampEnvs(fakeTimestamp + 2)}, 350 {dir: "/go/src/github.com/org/repo", command: "git", args: []string{"submodule", "update", "--init", "--recursive"}}, 351 }, 352 }, 353 } 354 355 for _, testCase := range testCases { 356 g := gitCtxForRefs(testCase.refs, testCase.dir, testCase.env) 357 actualBase := g.commandsForBaseRef(testCase.refs, testCase.gitUserName, testCase.gitUserEmail, testCase.cookiePath) 358 if !reflect.DeepEqual(actualBase, testCase.expectedBase) { 359 t.Errorf("%s: generated incorrect commands: %v", testCase.name, diff.ObjectGoPrintDiff(testCase.expectedBase, actualBase)) 360 } 361 actualPull := g.commandsForPullRefs(testCase.refs, fakeTimestamp) 362 if !reflect.DeepEqual(actualPull, testCase.expectedPull) { 363 t.Errorf("%s: generated incorrect commands: %v", testCase.name, diff.ObjectGoPrintDiff(testCase.expectedPull, actualPull)) 364 } 365 } 366 } 367 368 func TestGitHeadTimestamp(t *testing.T) { 369 fakeTimestamp := 987654321 370 fakeGitDir, err := makeFakeGitRepo(fakeTimestamp) 371 if err != nil { 372 t.Errorf("error creating fake git dir: %v", err) 373 } 374 defer func() { 375 if err := os.RemoveAll(fakeGitDir); err != nil { 376 t.Errorf("error cleaning up fake git dir: %v", err) 377 } 378 }() 379 380 var testCases = []struct { 381 name string 382 dir string 383 noPath bool 384 expected int 385 expectError bool 386 }{ 387 { 388 name: "root - no git", 389 dir: "/", 390 expected: 0, 391 expectError: true, 392 }, 393 { 394 name: "fake git repo", 395 dir: fakeGitDir, 396 expected: fakeTimestamp, 397 expectError: false, 398 }, 399 { 400 name: "fake git repo but no git binary", 401 dir: fakeGitDir, 402 noPath: true, 403 expected: 0, 404 expectError: true, 405 }, 406 } 407 origCwd, err := os.Getwd() 408 if err != nil { 409 t.Errorf("failed getting cwd: %v", err) 410 } 411 origPath := os.Getenv("PATH") 412 for _, testCase := range testCases { 413 t.Run(testCase.name, func(t *testing.T) { 414 if err := os.Chdir(testCase.dir); err != nil { 415 t.Errorf("%s: failed to chdir to %s: %v", testCase.name, testCase.dir, err) 416 } 417 if testCase.noPath { 418 if err := os.Unsetenv("PATH"); err != nil { 419 t.Errorf("%s: failed to unset PATH: %v", testCase.name, err) 420 } 421 } 422 g := gitCtx{ 423 cloneDir: testCase.dir, 424 } 425 timestamp, err := g.gitHeadTimestamp() 426 if timestamp != testCase.expected { 427 t.Errorf("%s: timestamp %d does not match expected timestamp %d", testCase.name, timestamp, testCase.expected) 428 } 429 if (err == nil && testCase.expectError) || (err != nil && !testCase.expectError) { 430 t.Errorf("%s: expect error is %v but received error %v", testCase.name, testCase.expectError, err) 431 } 432 if err := os.Chdir(origCwd); err != nil { 433 t.Errorf("%s: failed to chdir to original cwd %s: %v", testCase.name, origCwd, err) 434 } 435 if testCase.noPath { 436 if err := os.Setenv("PATH", origPath); err != nil { 437 t.Errorf("%s: failed to set PATH to original: %v", testCase.name, err) 438 } 439 } 440 441 }) 442 } 443 } 444 445 // makeFakeGitRepo creates a fake git repo with a constant digest and timestamp. 446 func makeFakeGitRepo(fakeTimestamp int) (string, error) { 447 fakeGitDir, err := ioutil.TempDir("", "fakegit") 448 if err != nil { 449 return "", err 450 } 451 cmds := [][]string{ 452 {"git", "init"}, 453 {"git", "config", "user.email", "test@test.test"}, 454 {"git", "config", "user.name", "test test"}, 455 {"touch", "a_file"}, 456 {"git", "add", "a_file"}, 457 {"git", "commit", "-m", "adding a_file"}, 458 } 459 for _, cmd := range cmds { 460 c := exec.Command(cmd[0], cmd[1:]...) 461 c.Dir = fakeGitDir 462 c.Env = append(os.Environ(), gitTimestampEnvs(fakeTimestamp)...) 463 if err := c.Run(); err != nil { 464 return fakeGitDir, err 465 } 466 } 467 return fakeGitDir, nil 468 }