github.com/sdboyer/gps@v0.16.3/vcs_source_test.go (about) 1 package gps 2 3 import ( 4 "context" 5 "io/ioutil" 6 "net/url" 7 "os/exec" 8 "reflect" 9 "sync" 10 "testing" 11 ) 12 13 // Parent test that executes all the slow vcs interaction tests in parallel. 14 func TestSlowVcs(t *testing.T) { 15 t.Run("write-deptree", testWriteDepTree) 16 t.Run("source-gateway", testSourceGateway) 17 t.Run("bzr-repo", testBzrRepo) 18 t.Run("bzr-source", testBzrSourceInteractions) 19 t.Run("svn-repo", testSvnRepo) 20 // TODO(sdboyer) svn-source 21 t.Run("hg-repo", testHgRepo) 22 t.Run("hg-source", testHgSourceInteractions) 23 t.Run("git-repo", testGitRepo) 24 t.Run("git-source", testGitSourceInteractions) 25 t.Run("gopkgin-source", testGopkginSourceInteractions) 26 } 27 28 func testGitSourceInteractions(t *testing.T) { 29 t.Parallel() 30 31 // This test is slowish, skip it on -short 32 if testing.Short() { 33 t.Skip("Skipping git source version fetching test in short mode") 34 } 35 requiresBins(t, "git") 36 37 cpath, err := ioutil.TempDir("", "smcache") 38 if err != nil { 39 t.Errorf("Failed to create temp dir: %s", err) 40 } 41 defer func() { 42 if err := removeAll(cpath); err != nil { 43 t.Errorf("removeAll failed: %s", err) 44 } 45 }() 46 47 n := "github.com/sdboyer/gpkt" 48 un := "https://" + n 49 u, err := url.Parse(un) 50 if err != nil { 51 t.Fatalf("Error parsing URL %s: %s", un, err) 52 } 53 mb := maybeGitSource{ 54 url: u, 55 } 56 57 ctx := context.Background() 58 superv := newSupervisor(ctx) 59 isrc, state, err := mb.try(ctx, cpath, newMemoryCache(), superv) 60 if err != nil { 61 t.Fatalf("Unexpected error while setting up gitSource for test repo: %s", err) 62 } 63 64 wantstate := sourceIsSetUp | sourceExistsUpstream | sourceHasLatestVersionList 65 if state != wantstate { 66 t.Errorf("Expected return state to be %v, got %v", wantstate, state) 67 } 68 69 err = isrc.initLocal(ctx) 70 if err != nil { 71 t.Fatalf("Error on cloning git repo: %s", err) 72 } 73 74 src, ok := isrc.(*gitSource) 75 if !ok { 76 t.Fatalf("Expected a gitSource, got a %T", isrc) 77 } 78 79 if un != src.upstreamURL() { 80 t.Errorf("Expected %s as source URL, got %s", un, src.upstreamURL()) 81 } 82 83 pvlist, err := src.listVersions(ctx) 84 if err != nil { 85 t.Fatalf("Unexpected error getting version pairs from git repo: %s", err) 86 } 87 88 vlist := hidePair(pvlist) 89 // check that an expected rev is present 90 is, err := src.revisionPresentIn(Revision("4a54adf81c75375d26d376459c00d5ff9b703e5e")) 91 if err != nil { 92 t.Errorf("Unexpected error while checking revision presence: %s", err) 93 } else if !is { 94 t.Errorf("Revision that should exist was not present") 95 } 96 97 if len(vlist) != 7 { 98 t.Errorf("git test repo should've produced seven versions, got %v: vlist was %s", len(vlist), vlist) 99 } else { 100 SortForUpgrade(vlist) 101 evl := []Version{ 102 NewVersion("v2.0.0").Is(Revision("4a54adf81c75375d26d376459c00d5ff9b703e5e")), 103 NewVersion("v1.1.0").Is(Revision("b2cb48dda625f6640b34d9ffb664533359ac8b91")), 104 NewVersion("v1.0.0").Is(Revision("bf85021c0405edbc4f3648b0603818d641674f72")), 105 newDefaultBranch("master").Is(Revision("bf85021c0405edbc4f3648b0603818d641674f72")), 106 NewBranch("v1").Is(Revision("e3777f683305eafca223aefe56b4e8ecf103f467")), 107 NewBranch("v1.1").Is(Revision("f1fbc520489a98306eb28c235204e39fa8a89c84")), 108 NewBranch("v3").Is(Revision("4a54adf81c75375d26d376459c00d5ff9b703e5e")), 109 } 110 if !reflect.DeepEqual(vlist, evl) { 111 t.Errorf("Version list was not what we expected:\n\t(GOT): %s\n\t(WNT): %s", vlist, evl) 112 } 113 } 114 115 // recheck that rev is present, this time interacting with cache differently 116 is, err = src.revisionPresentIn(Revision("30605f6ac35fcb075ad0bfa9296f90a7d891523e")) 117 if err != nil { 118 t.Errorf("Unexpected error while re-checking revision presence: %s", err) 119 } else if !is { 120 t.Errorf("Revision that should exist was not present on re-check") 121 } 122 } 123 124 func testGopkginSourceInteractions(t *testing.T) { 125 t.Parallel() 126 127 // This test is slowish, skip it on -short 128 if testing.Short() { 129 t.Skip("Skipping gopkg.in source version fetching test in short mode") 130 } 131 requiresBins(t, "git") 132 133 cpath, err := ioutil.TempDir("", "smcache") 134 if err != nil { 135 t.Errorf("Failed to create temp dir: %s", err) 136 } 137 defer func() { 138 if err := removeAll(cpath); err != nil { 139 t.Errorf("removeAll failed: %s", err) 140 } 141 }() 142 143 tfunc := func(opath, n string, major uint64, evl []Version) { 144 un := "https://" + n 145 u, err := url.Parse(un) 146 if err != nil { 147 t.Errorf("URL was bad, lolwut? errtext: %s", err) 148 return 149 } 150 mb := maybeGopkginSource{ 151 opath: opath, 152 url: u, 153 major: major, 154 } 155 156 ctx := context.Background() 157 superv := newSupervisor(ctx) 158 isrc, state, err := mb.try(ctx, cpath, newMemoryCache(), superv) 159 if err != nil { 160 t.Errorf("Unexpected error while setting up gopkginSource for test repo: %s", err) 161 return 162 } 163 164 wantstate := sourceIsSetUp | sourceExistsUpstream | sourceHasLatestVersionList 165 if state != wantstate { 166 t.Errorf("Expected return state to be %v, got %v", wantstate, state) 167 } 168 169 err = isrc.initLocal(ctx) 170 if err != nil { 171 t.Fatalf("Error on cloning git repo: %s", err) 172 } 173 174 src, ok := isrc.(*gopkginSource) 175 if !ok { 176 t.Errorf("Expected a gopkginSource, got a %T", isrc) 177 return 178 } 179 180 if un != src.upstreamURL() { 181 t.Errorf("Expected %s as source URL, got %s", un, src.upstreamURL()) 182 } 183 if src.major != major { 184 t.Errorf("Expected %v as major version filter on gopkginSource, got %v", major, src.major) 185 } 186 187 // check that an expected rev is present 188 rev := evl[0].(PairedVersion).Underlying() 189 is, err := src.revisionPresentIn(rev) 190 if err != nil { 191 t.Errorf("Unexpected error while checking revision presence: %s", err) 192 } else if !is { 193 t.Errorf("Revision %s that should exist was not present", rev) 194 } 195 196 pvlist, err := src.listVersions(ctx) 197 if err != nil { 198 t.Errorf("Unexpected error getting version pairs from hg repo: %s", err) 199 } 200 201 vlist := hidePair(pvlist) 202 if len(vlist) != len(evl) { 203 t.Errorf("gopkgin test repo should've produced %v versions, got %v", len(evl), len(vlist)) 204 } else { 205 SortForUpgrade(vlist) 206 if !reflect.DeepEqual(vlist, evl) { 207 t.Errorf("Version list was not what we expected:\n\t(GOT): %s\n\t(WNT): %s", vlist, evl) 208 } 209 } 210 211 // Run again, this time to ensure cache outputs correctly 212 pvlist, err = src.listVersions(ctx) 213 if err != nil { 214 t.Errorf("Unexpected error getting version pairs from hg repo: %s", err) 215 } 216 217 vlist = hidePair(pvlist) 218 if len(vlist) != len(evl) { 219 t.Errorf("gopkgin test repo should've produced %v versions, got %v", len(evl), len(vlist)) 220 } else { 221 SortForUpgrade(vlist) 222 if !reflect.DeepEqual(vlist, evl) { 223 t.Errorf("Version list was not what we expected:\n\t(GOT): %s\n\t(WNT): %s", vlist, evl) 224 } 225 } 226 227 // recheck that rev is present, this time interacting with cache differently 228 is, err = src.revisionPresentIn(rev) 229 if err != nil { 230 t.Errorf("Unexpected error while re-checking revision presence: %s", err) 231 } else if !is { 232 t.Errorf("Revision that should exist was not present on re-check") 233 } 234 } 235 236 // simultaneously run for v1, v2, and v3 filters of the target repo 237 wg := &sync.WaitGroup{} 238 wg.Add(3) 239 go func() { 240 tfunc("gopkg.in/sdboyer/gpkt.v1", "github.com/sdboyer/gpkt", 1, []Version{ 241 NewVersion("v1.1.0").Is(Revision("b2cb48dda625f6640b34d9ffb664533359ac8b91")), 242 NewVersion("v1.0.0").Is(Revision("bf85021c0405edbc4f3648b0603818d641674f72")), 243 newDefaultBranch("v1.1").Is(Revision("f1fbc520489a98306eb28c235204e39fa8a89c84")), 244 NewBranch("v1").Is(Revision("e3777f683305eafca223aefe56b4e8ecf103f467")), 245 }) 246 wg.Done() 247 }() 248 249 go func() { 250 tfunc("gopkg.in/sdboyer/gpkt.v2", "github.com/sdboyer/gpkt", 2, []Version{ 251 NewVersion("v2.0.0").Is(Revision("4a54adf81c75375d26d376459c00d5ff9b703e5e")), 252 }) 253 wg.Done() 254 }() 255 256 go func() { 257 tfunc("gopkg.in/sdboyer/gpkt.v3", "github.com/sdboyer/gpkt", 3, []Version{ 258 newDefaultBranch("v3").Is(Revision("4a54adf81c75375d26d376459c00d5ff9b703e5e")), 259 }) 260 wg.Done() 261 }() 262 263 wg.Wait() 264 } 265 266 func testBzrSourceInteractions(t *testing.T) { 267 t.Parallel() 268 269 // This test is quite slow (ugh bzr), so skip it on -short 270 if testing.Short() { 271 t.Skip("Skipping bzr source version fetching test in short mode") 272 } 273 requiresBins(t, "bzr") 274 275 cpath, err := ioutil.TempDir("", "smcache") 276 if err != nil { 277 t.Errorf("Failed to create temp dir: %s", err) 278 } 279 defer func() { 280 if err := removeAll(cpath); err != nil { 281 t.Errorf("removeAll failed: %s", err) 282 } 283 }() 284 285 n := "launchpad.net/govcstestbzrrepo" 286 un := "https://" + n 287 u, err := url.Parse(un) 288 if err != nil { 289 t.Fatalf("Error parsing URL %s: %s", un, err) 290 } 291 mb := maybeBzrSource{ 292 url: u, 293 } 294 295 ctx := context.Background() 296 superv := newSupervisor(ctx) 297 isrc, state, err := mb.try(ctx, cpath, newMemoryCache(), superv) 298 if err != nil { 299 t.Fatalf("Unexpected error while setting up bzrSource for test repo: %s", err) 300 } 301 302 wantstate := sourceIsSetUp | sourceExistsUpstream 303 if state != wantstate { 304 t.Errorf("Expected return state to be %v, got %v", wantstate, state) 305 } 306 307 err = isrc.initLocal(ctx) 308 if err != nil { 309 t.Fatalf("Error on cloning git repo: %s", err) 310 } 311 312 src, ok := isrc.(*bzrSource) 313 if !ok { 314 t.Fatalf("Expected a bzrSource, got a %T", isrc) 315 } 316 317 if state != wantstate { 318 t.Errorf("Expected return state to be %v, got %v", wantstate, state) 319 } 320 if un != src.upstreamURL() { 321 t.Errorf("Expected %s as source URL, got %s", un, src.upstreamURL()) 322 } 323 evl := []Version{ 324 NewVersion("1.0.0").Is(Revision("matt@mattfarina.com-20150731135137-pbphasfppmygpl68")), 325 newDefaultBranch("(default)").Is(Revision("matt@mattfarina.com-20150731135137-pbphasfppmygpl68")), 326 } 327 328 // check that an expected rev is present 329 is, err := src.revisionPresentIn(Revision("matt@mattfarina.com-20150731135137-pbphasfppmygpl68")) 330 if err != nil { 331 t.Errorf("Unexpected error while checking revision presence: %s", err) 332 } else if !is { 333 t.Errorf("Revision that should exist was not present") 334 } 335 336 pvlist, err := src.listVersions(ctx) 337 if err != nil { 338 t.Errorf("Unexpected error getting version pairs from bzr repo: %s", err) 339 } 340 341 vlist := hidePair(pvlist) 342 if len(vlist) != 2 { 343 t.Errorf("bzr test repo should've produced two versions, got %v", len(vlist)) 344 } else { 345 SortForUpgrade(vlist) 346 if !reflect.DeepEqual(vlist, evl) { 347 t.Errorf("bzr version list was not what we expected:\n\t(GOT): %s\n\t(WNT): %s", vlist, evl) 348 } 349 } 350 351 // Run again, this time to ensure cache outputs correctly 352 pvlist, err = src.listVersions(ctx) 353 if err != nil { 354 t.Errorf("Unexpected error getting version pairs from bzr repo: %s", err) 355 } 356 357 vlist = hidePair(pvlist) 358 if len(vlist) != 2 { 359 t.Errorf("bzr test repo should've produced two versions, got %v", len(vlist)) 360 } else { 361 SortForUpgrade(vlist) 362 if !reflect.DeepEqual(vlist, evl) { 363 t.Errorf("bzr version list was not what we expected:\n\t(GOT): %s\n\t(WNT): %s", vlist, evl) 364 } 365 } 366 367 // recheck that rev is present, this time interacting with cache differently 368 is, err = src.revisionPresentIn(Revision("matt@mattfarina.com-20150731135137-pbphasfppmygpl68")) 369 if err != nil { 370 t.Errorf("Unexpected error while re-checking revision presence: %s", err) 371 } else if !is { 372 t.Errorf("Revision that should exist was not present on re-check") 373 } 374 } 375 376 func testHgSourceInteractions(t *testing.T) { 377 t.Parallel() 378 379 // This test is slow, so skip it on -short 380 if testing.Short() { 381 t.Skip("Skipping hg source version fetching test in short mode") 382 } 383 requiresBins(t, "hg") 384 385 cpath, err := ioutil.TempDir("", "smcache") 386 if err != nil { 387 t.Errorf("Failed to create temp dir: %s", err) 388 } 389 defer func() { 390 if err := removeAll(cpath); err != nil { 391 t.Errorf("removeAll failed: %s", err) 392 } 393 }() 394 395 tfunc := func(n string, evl []Version) { 396 un := "https://" + n 397 u, err := url.Parse(un) 398 if err != nil { 399 t.Errorf("URL was bad, lolwut? errtext: %s", err) 400 return 401 } 402 mb := maybeHgSource{ 403 url: u, 404 } 405 406 ctx := context.Background() 407 superv := newSupervisor(ctx) 408 isrc, state, err := mb.try(ctx, cpath, newMemoryCache(), superv) 409 if err != nil { 410 t.Errorf("Unexpected error while setting up hgSource for test repo: %s", err) 411 return 412 } 413 414 wantstate := sourceIsSetUp | sourceExistsUpstream 415 if state != wantstate { 416 t.Errorf("Expected return state to be %v, got %v", wantstate, state) 417 } 418 419 err = isrc.initLocal(ctx) 420 if err != nil { 421 t.Fatalf("Error on cloning git repo: %s", err) 422 } 423 424 src, ok := isrc.(*hgSource) 425 if !ok { 426 t.Errorf("Expected a hgSource, got a %T", isrc) 427 return 428 } 429 430 if state != wantstate { 431 t.Errorf("Expected return state to be %v, got %v", wantstate, state) 432 } 433 if un != src.upstreamURL() { 434 t.Errorf("Expected %s as source URL, got %s", un, src.upstreamURL()) 435 } 436 437 // check that an expected rev is present 438 is, err := src.revisionPresentIn(Revision("103d1bddef2199c80aad7c42041223083d613ef9")) 439 if err != nil { 440 t.Errorf("Unexpected error while checking revision presence: %s", err) 441 } else if !is { 442 t.Errorf("Revision that should exist was not present") 443 } 444 445 pvlist, err := src.listVersions(ctx) 446 if err != nil { 447 t.Errorf("Unexpected error getting version pairs from hg repo: %s", err) 448 } 449 450 vlist := hidePair(pvlist) 451 if len(vlist) != len(evl) { 452 t.Errorf("hg test repo should've produced %v versions, got %v", len(evl), len(vlist)) 453 } else { 454 SortForUpgrade(vlist) 455 if !reflect.DeepEqual(vlist, evl) { 456 t.Errorf("Version list was not what we expected:\n\t(GOT): %s\n\t(WNT): %s", vlist, evl) 457 } 458 } 459 460 // Run again, this time to ensure cache outputs correctly 461 pvlist, err = src.listVersions(ctx) 462 if err != nil { 463 t.Errorf("Unexpected error getting version pairs from hg repo: %s", err) 464 } 465 466 vlist = hidePair(pvlist) 467 if len(vlist) != len(evl) { 468 t.Errorf("hg test repo should've produced %v versions, got %v", len(evl), len(vlist)) 469 } else { 470 SortForUpgrade(vlist) 471 if !reflect.DeepEqual(vlist, evl) { 472 t.Errorf("Version list was not what we expected:\n\t(GOT): %s\n\t(WNT): %s", vlist, evl) 473 } 474 } 475 476 // recheck that rev is present, this time interacting with cache differently 477 is, err = src.revisionPresentIn(Revision("103d1bddef2199c80aad7c42041223083d613ef9")) 478 if err != nil { 479 t.Errorf("Unexpected error while re-checking revision presence: %s", err) 480 } else if !is { 481 t.Errorf("Revision that should exist was not present on re-check") 482 } 483 } 484 485 // simultaneously run for both the repo with and without the magic bookmark 486 donech := make(chan struct{}) 487 go func() { 488 tfunc("bitbucket.org/sdboyer/withbm", []Version{ 489 NewVersion("v1.0.0").Is(Revision("aa110802a0c64195d0a6c375c9f66668827c90b4")), 490 newDefaultBranch("@").Is(Revision("b10d05d581e5401f383e48ccfeb84b48fde99d06")), 491 NewBranch("another").Is(Revision("b10d05d581e5401f383e48ccfeb84b48fde99d06")), 492 NewBranch("default").Is(Revision("3d466f437f6616da594bbab6446cc1cb4328d1bb")), 493 NewBranch("newbranch").Is(Revision("5e2a01be9aee942098e44590ae545c7143da9675")), 494 }) 495 close(donech) 496 }() 497 498 tfunc("bitbucket.org/sdboyer/nobm", []Version{ 499 NewVersion("v1.0.0").Is(Revision("aa110802a0c64195d0a6c375c9f66668827c90b4")), 500 newDefaultBranch("default").Is(Revision("3d466f437f6616da594bbab6446cc1cb4328d1bb")), 501 NewBranch("another").Is(Revision("b10d05d581e5401f383e48ccfeb84b48fde99d06")), 502 NewBranch("newbranch").Is(Revision("5e2a01be9aee942098e44590ae545c7143da9675")), 503 }) 504 505 <-donech 506 } 507 508 // Fail a test if the specified binaries aren't installed. 509 func requiresBins(t *testing.T, bins ...string) { 510 for _, b := range bins { 511 _, err := exec.LookPath(b) 512 if err != nil { 513 t.Fatalf("%s is not installed", b) 514 } 515 } 516 }