github.com/golang/dep@v0.5.4/gps/vcs_source_test.go (about)

     1  // Copyright 2017 The Go 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 gps
     6  
     7  import (
     8  	"context"
     9  	"io/ioutil"
    10  	"log"
    11  	"net/url"
    12  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"reflect"
    16  	"runtime"
    17  	"strings"
    18  	"sync"
    19  	"testing"
    20  
    21  	"github.com/golang/dep/internal/test"
    22  )
    23  
    24  // Parent test that executes all the slow vcs interaction tests in parallel.
    25  func TestSlowVcs(t *testing.T) {
    26  	t.Run("write-deptree", testWriteDepTree)
    27  	t.Run("source-gateway", testSourceGateway)
    28  	t.Run("bzr-repo", testBzrRepo)
    29  	t.Run("bzr-source", testBzrSourceInteractions)
    30  	t.Run("svn-repo", testSvnRepo)
    31  	// TODO(sdboyer) svn-source
    32  	t.Run("hg-repo", testHgRepo)
    33  	t.Run("hg-source", testHgSourceInteractions)
    34  	t.Run("git-repo", testGitRepo)
    35  	t.Run("git-source", testGitSourceInteractions)
    36  	t.Run("gopkgin-source", testGopkginSourceInteractions)
    37  }
    38  
    39  func testGitSourceInteractions(t *testing.T) {
    40  	t.Parallel()
    41  
    42  	// This test is slowish, skip it on -short
    43  	if testing.Short() {
    44  		t.Skip("Skipping git source version fetching test in short mode")
    45  	}
    46  	requiresBins(t, "git")
    47  
    48  	cpath, err := ioutil.TempDir("", "smcache")
    49  	if err != nil {
    50  		t.Errorf("Failed to create temp dir: %s", err)
    51  	}
    52  	defer func() {
    53  		if err := os.RemoveAll(cpath); err != nil {
    54  			t.Errorf("removeAll failed: %s", err)
    55  		}
    56  	}()
    57  	os.Mkdir(filepath.Join(cpath, "sources"), 0777)
    58  
    59  	n := "github.com/sdboyer/gpkt"
    60  	un := "https://" + n
    61  	u, err := url.Parse(un)
    62  	if err != nil {
    63  		t.Fatalf("Error parsing URL %s: %s", un, err)
    64  	}
    65  	mb := maybeGitSource{
    66  		url: u,
    67  	}
    68  
    69  	ctx := context.Background()
    70  	isrc, err := mb.try(ctx, cpath)
    71  	if err != nil {
    72  		t.Fatalf("Unexpected error while setting up gitSource for test repo: %s", err)
    73  	}
    74  
    75  	err = isrc.initLocal(ctx)
    76  	if err != nil {
    77  		t.Fatalf("Error on cloning git repo: %s", err)
    78  	}
    79  
    80  	src, ok := isrc.(*gitSource)
    81  	if !ok {
    82  		t.Fatalf("Expected a gitSource, got a %T", isrc)
    83  	}
    84  
    85  	if un != src.upstreamURL() {
    86  		t.Errorf("Expected %s as source URL, got %s", un, src.upstreamURL())
    87  	}
    88  
    89  	pvlist, err := src.listVersions(ctx)
    90  	if err != nil {
    91  		t.Fatalf("Unexpected error getting version pairs from git repo: %s", err)
    92  	}
    93  
    94  	vlist := hidePair(pvlist)
    95  	// check that an expected rev is present
    96  	is, err := src.revisionPresentIn(Revision("4a54adf81c75375d26d376459c00d5ff9b703e5e"))
    97  	if err != nil {
    98  		t.Errorf("Unexpected error while checking revision presence: %s", err)
    99  	} else if !is {
   100  		t.Errorf("Revision that should exist was not present")
   101  	}
   102  
   103  	if len(vlist) != 7 {
   104  		t.Errorf("git test repo should've produced seven versions, got %v: vlist was %s", len(vlist), vlist)
   105  	} else {
   106  		SortForUpgrade(vlist)
   107  		evl := []Version{
   108  			NewVersion("v2.0.0").Pair(Revision("4a54adf81c75375d26d376459c00d5ff9b703e5e")),
   109  			NewVersion("v1.1.0").Pair(Revision("b2cb48dda625f6640b34d9ffb664533359ac8b91")),
   110  			NewVersion("v1.0.0").Pair(Revision("bf85021c0405edbc4f3648b0603818d641674f72")),
   111  			newDefaultBranch("master").Pair(Revision("bf85021c0405edbc4f3648b0603818d641674f72")),
   112  			NewBranch("v1").Pair(Revision("e3777f683305eafca223aefe56b4e8ecf103f467")),
   113  			NewBranch("v1.1").Pair(Revision("f1fbc520489a98306eb28c235204e39fa8a89c84")),
   114  			NewBranch("v3").Pair(Revision("4a54adf81c75375d26d376459c00d5ff9b703e5e")),
   115  		}
   116  		for k, e := range evl {
   117  			if !vlist[k].identical(e) {
   118  				t.Errorf("version list was not what we expected:\n\t(GOT): %#v\n\t(WNT): %#v", vlist, evl)
   119  				break
   120  			}
   121  		}
   122  	}
   123  
   124  	// recheck that rev is present, this time interacting with cache differently
   125  	is, err = src.revisionPresentIn(Revision("30605f6ac35fcb075ad0bfa9296f90a7d891523e"))
   126  	if err != nil {
   127  		t.Errorf("Unexpected error while re-checking revision presence: %s", err)
   128  	} else if !is {
   129  		t.Errorf("Revision that should exist was not present on re-check")
   130  	}
   131  }
   132  
   133  func testGopkginSourceInteractions(t *testing.T) {
   134  	t.Parallel()
   135  
   136  	// This test is slowish, skip it on -short
   137  	if testing.Short() {
   138  		t.Skip("Skipping gopkg.in source version fetching test in short mode")
   139  	}
   140  	requiresBins(t, "git")
   141  
   142  	cpath, err := ioutil.TempDir("", "smcache")
   143  	if err != nil {
   144  		t.Errorf("Failed to create temp dir: %s", err)
   145  	}
   146  	defer func() {
   147  		if err := os.RemoveAll(cpath); err != nil {
   148  			t.Errorf("removeAll failed: %s", err)
   149  		}
   150  	}()
   151  	os.Mkdir(filepath.Join(cpath, "sources"), 0777)
   152  
   153  	tfunc := func(opath, n string, major uint64, evl []Version) {
   154  		un := "https://" + opath
   155  		u, err := url.Parse("https://" + n)
   156  		if err != nil {
   157  			t.Errorf("URL was bad, lolwut? errtext: %s", err)
   158  			return
   159  		}
   160  		unstable := strings.HasSuffix(opath, gopkgUnstableSuffix)
   161  		mb := maybeGopkginSource{
   162  			opath:    opath,
   163  			url:      u,
   164  			major:    major,
   165  			unstable: unstable,
   166  		}
   167  
   168  		ctx := context.Background()
   169  		isrc, err := mb.try(ctx, cpath)
   170  		if err != nil {
   171  			t.Errorf("Unexpected error while setting up gopkginSource for test repo: %s", err)
   172  			return
   173  		}
   174  
   175  		err = isrc.initLocal(ctx)
   176  		if err != nil {
   177  			t.Fatalf("Error on cloning git repo: %s", err)
   178  		}
   179  
   180  		src, ok := isrc.(*gopkginSource)
   181  		if !ok {
   182  			t.Errorf("Expected a gopkginSource, got a %T", isrc)
   183  			return
   184  		}
   185  
   186  		if un != src.upstreamURL() {
   187  			t.Errorf("Expected %s as source URL, got %s", un, src.upstreamURL())
   188  		}
   189  		if src.major != major {
   190  			t.Errorf("Expected %v as major version filter on gopkginSource, got %v", major, src.major)
   191  		}
   192  
   193  		// check that an expected rev is present
   194  		rev := evl[0].(PairedVersion).Revision()
   195  		is, err := src.revisionPresentIn(rev)
   196  		if err != nil {
   197  			t.Errorf("Unexpected error while checking revision presence: %s", err)
   198  		} else if !is {
   199  			t.Errorf("Revision %s that should exist was not present", rev)
   200  		}
   201  
   202  		pvlist, err := src.listVersions(ctx)
   203  		if err != nil {
   204  			t.Errorf("Unexpected error getting version pairs from hg repo: %s", err)
   205  		}
   206  
   207  		vlist := hidePair(pvlist)
   208  		if len(vlist) != len(evl) {
   209  			t.Errorf("gopkgin test repo (%s) should've produced %v versions, got %v.\n%v", un, len(evl), len(vlist), vlist)
   210  		} else {
   211  			SortForUpgrade(vlist)
   212  			if !reflect.DeepEqual(vlist, evl) {
   213  				t.Errorf("Version list for %s was not what we expected:\n\t(GOT): %#v\n\t(WNT): %#v", un, vlist, evl)
   214  			}
   215  		}
   216  
   217  		// Run again, this time to ensure cache outputs correctly
   218  		pvlist, err = src.listVersions(ctx)
   219  		if err != nil {
   220  			t.Errorf("Unexpected error getting version pairs from hg repo: %s", err)
   221  		}
   222  
   223  		vlist = hidePair(pvlist)
   224  		if len(vlist) != len(evl) {
   225  			t.Errorf("gopkgin test repo should've produced %v versions, got %v", len(evl), len(vlist))
   226  		} else {
   227  			SortForUpgrade(vlist)
   228  			if !reflect.DeepEqual(vlist, evl) {
   229  				t.Errorf("Version list for %s was not what we expected:\n\t(GOT): %#v\n\t(WNT): %#v", un, vlist, evl)
   230  			}
   231  		}
   232  
   233  		// recheck that rev is present, this time interacting with cache differently
   234  		is, err = src.revisionPresentIn(rev)
   235  		if err != nil {
   236  			t.Errorf("Unexpected error while re-checking revision presence: %s", err)
   237  		} else if !is {
   238  			t.Errorf("Revision that should exist was not present on re-check")
   239  		}
   240  	}
   241  
   242  	// simultaneously run for v1, v2, and v3 filters of the target repo
   243  	wg := &sync.WaitGroup{}
   244  	wg.Add(6)
   245  
   246  	go func() {
   247  		// Treat master as v0 when no other branches/tags exist that match gopkg.in's rules
   248  		tfunc("gopkg.in/carolynvs/deptest-gopkgin-implicit-v0.v0", "github.com/carolynvs/deptest-gopkgin-implicit-v0", 0, []Version{
   249  			newDefaultBranch("notmaster").Pair(Revision("94ee631b9833cd805d15f50a52e0533124ec0292")),
   250  		})
   251  		wg.Done()
   252  	}()
   253  
   254  	go func() {
   255  		// Use the existing v0 branch for v0, not master
   256  		tfunc("gopkg.in/carolynvs/deptest-gopkgin-explicit-v0.v0", "github.com/carolynvs/deptest-gopkgin-explicit-v0", 0, []Version{
   257  			newDefaultBranch("v0").Pair(Revision("ec73e84554fb28f08dba630e48dbec868e77f734")),
   258  		})
   259  		wg.Done()
   260  	}()
   261  
   262  	go func() {
   263  		tfunc("gopkg.in/sdboyer/gpkt.v1", "github.com/sdboyer/gpkt", 1, []Version{
   264  			NewVersion("v1.1.0").Pair(Revision("b2cb48dda625f6640b34d9ffb664533359ac8b91")),
   265  			NewVersion("v1.0.0").Pair(Revision("bf85021c0405edbc4f3648b0603818d641674f72")),
   266  			newDefaultBranch("v1.1").Pair(Revision("f1fbc520489a98306eb28c235204e39fa8a89c84")),
   267  			NewBranch("v1").Pair(Revision("e3777f683305eafca223aefe56b4e8ecf103f467")),
   268  		})
   269  		wg.Done()
   270  	}()
   271  
   272  	go func() {
   273  		tfunc("gopkg.in/sdboyer/gpkt.v2", "github.com/sdboyer/gpkt", 2, []Version{
   274  			NewVersion("v2.0.0").Pair(Revision("4a54adf81c75375d26d376459c00d5ff9b703e5e")),
   275  		})
   276  		wg.Done()
   277  	}()
   278  
   279  	go func() {
   280  		tfunc("gopkg.in/sdboyer/gpkt.v3", "github.com/sdboyer/gpkt", 3, []Version{
   281  			newDefaultBranch("v3").Pair(Revision("4a54adf81c75375d26d376459c00d5ff9b703e5e")),
   282  		})
   283  		wg.Done()
   284  	}()
   285  
   286  	go func() {
   287  		tfunc("github.com/sdboyer/gpkt2.v1-unstable", "github.com/sdboyer/gpkt2", 1, []Version{
   288  			newDefaultBranch("v1-unstable").Pair(Revision("24de0be8f4a0b8a44321562117749b257bfcef69")),
   289  		})
   290  		wg.Done()
   291  	}()
   292  
   293  	wg.Wait()
   294  }
   295  
   296  func testBzrSourceInteractions(t *testing.T) {
   297  	t.Parallel()
   298  
   299  	// This test is quite slow (ugh bzr), so skip it on -short
   300  	if testing.Short() {
   301  		t.Skip("Skipping bzr source version fetching test in short mode")
   302  	}
   303  	if runtime.GOOS == "windows" {
   304  		// TODO bzr on Windows is sometimes weirdly reporting different
   305  		// "revision-id" (with mention of git), and it's breaking tests. Maybe
   306  		// this also breaks our model of bzr on Windows; maybe it breaks our
   307  		// model of bzr in general. But use of bzr is rare and dwindling, so for
   308  		// now it's least harmful to turn off the test on Windows, as the
   309  		// alternative is a DEEP dive and possible refactor.
   310  		t.Skip("TODO: Windows bzr reporting of underlying object ids is confusing")
   311  	}
   312  	requiresBins(t, "bzr")
   313  
   314  	cpath, err := ioutil.TempDir("", "smcache")
   315  	if err != nil {
   316  		t.Errorf("Failed to create temp dir: %s", err)
   317  	}
   318  	defer func() {
   319  		if err := os.RemoveAll(cpath); err != nil {
   320  			t.Errorf("removeAll failed: %s", err)
   321  		}
   322  	}()
   323  
   324  	n := "launchpad.net/govcstestbzrrepo"
   325  	un := "https://" + n
   326  	u, err := url.Parse(un)
   327  	if err != nil {
   328  		t.Fatalf("Error parsing URL %s: %s", un, err)
   329  	}
   330  	mb := maybeBzrSource{
   331  		url: u,
   332  	}
   333  
   334  	ctx := context.Background()
   335  	isrc, err := mb.try(ctx, cpath)
   336  	if err != nil {
   337  		t.Fatalf("Unexpected error while setting up bzrSource for test repo: %s", err)
   338  	}
   339  
   340  	err = isrc.initLocal(ctx)
   341  	if err != nil {
   342  		t.Fatalf("Error on cloning bzr repo: %s", err)
   343  	}
   344  
   345  	src, ok := isrc.(*bzrSource)
   346  	if !ok {
   347  		t.Fatalf("Expected a bzrSource, got a %T", isrc)
   348  	}
   349  
   350  	if un != src.upstreamURL() {
   351  		t.Errorf("Expected %s as source URL, got %s", un, src.upstreamURL())
   352  	}
   353  	evl := []Version{
   354  		NewVersion("1.0.0").Pair(Revision("matt@mattfarina.com-20150731135137-pbphasfppmygpl68")),
   355  		newDefaultBranch("(default)").Pair(Revision("matt@mattfarina.com-20150731135137-pbphasfppmygpl68")),
   356  	}
   357  
   358  	// check that an expected rev is present
   359  	is, err := src.revisionPresentIn(Revision("matt@mattfarina.com-20150731135137-pbphasfppmygpl68"))
   360  	if err != nil {
   361  		t.Errorf("Unexpected error while checking revision presence: %s", err)
   362  	} else if !is {
   363  		t.Errorf("Revision that should exist was not present")
   364  	}
   365  
   366  	pvlist, err := src.listVersions(ctx)
   367  	if err != nil {
   368  		t.Errorf("Unexpected error getting version pairs from bzr repo: %s", err)
   369  	}
   370  
   371  	vlist := hidePair(pvlist)
   372  	if len(vlist) != 2 {
   373  		t.Errorf("bzr test repo should've produced two versions, got %v", len(vlist))
   374  	} else {
   375  		SortForUpgrade(vlist)
   376  		if !reflect.DeepEqual(vlist, evl) {
   377  			t.Errorf("bzr version list was not what we expected:\n\t(GOT): %s\n\t(WNT): %s", vlist, evl)
   378  		}
   379  	}
   380  
   381  	// Run again, this time to ensure cache outputs correctly
   382  	pvlist, err = src.listVersions(ctx)
   383  	if err != nil {
   384  		t.Errorf("Unexpected error getting version pairs from bzr repo: %s", err)
   385  	}
   386  
   387  	vlist = hidePair(pvlist)
   388  	if len(vlist) != 2 {
   389  		t.Errorf("bzr test repo should've produced two versions, got %v", len(vlist))
   390  	} else {
   391  		SortForUpgrade(vlist)
   392  		if !reflect.DeepEqual(vlist, evl) {
   393  			t.Errorf("bzr version list was not what we expected:\n\t(GOT): %s\n\t(WNT): %s", vlist, evl)
   394  		}
   395  	}
   396  
   397  	// recheck that rev is present, this time interacting with cache differently
   398  	is, err = src.revisionPresentIn(Revision("matt@mattfarina.com-20150731135137-pbphasfppmygpl68"))
   399  	if err != nil {
   400  		t.Errorf("Unexpected error while re-checking revision presence: %s", err)
   401  	} else if !is {
   402  		t.Errorf("Revision that should exist was not present on re-check")
   403  	}
   404  }
   405  
   406  func testHgSourceInteractions(t *testing.T) {
   407  	t.Parallel()
   408  
   409  	// This test is slow, so skip it on -short
   410  	if testing.Short() {
   411  		t.Skip("Skipping hg source version fetching test in short mode")
   412  	}
   413  	requiresBins(t, "hg")
   414  
   415  	cpath, err := ioutil.TempDir("", "smcache")
   416  	if err != nil {
   417  		t.Errorf("Failed to create temp dir: %s", err)
   418  	}
   419  	defer func() {
   420  		if err := os.RemoveAll(cpath); err != nil {
   421  			t.Errorf("removeAll failed: %s", err)
   422  		}
   423  	}()
   424  
   425  	tfunc := func(n string, evl []Version) {
   426  		un := "https://" + n
   427  		u, err := url.Parse(un)
   428  		if err != nil {
   429  			t.Errorf("URL was bad, lolwut? errtext: %s", err)
   430  			return
   431  		}
   432  		mb := maybeHgSource{
   433  			url: u,
   434  		}
   435  
   436  		ctx := context.Background()
   437  		isrc, err := mb.try(ctx, cpath)
   438  		if err != nil {
   439  			t.Errorf("Unexpected error while setting up hgSource for test repo: %s", err)
   440  			return
   441  		}
   442  
   443  		err = isrc.initLocal(ctx)
   444  		if err != nil {
   445  			t.Errorf("Error on cloning hg repo: %s", err)
   446  			return
   447  		}
   448  
   449  		src, ok := isrc.(*hgSource)
   450  		if !ok {
   451  			t.Errorf("Expected a hgSource, got a %T", isrc)
   452  			return
   453  		}
   454  
   455  		if un != src.upstreamURL() {
   456  			t.Errorf("Expected %s as source URL, got %s", un, src.upstreamURL())
   457  		}
   458  
   459  		// check that an expected rev is present
   460  		is, err := src.revisionPresentIn(Revision("103d1bddef2199c80aad7c42041223083d613ef9"))
   461  		if err != nil {
   462  			t.Errorf("Unexpected error while checking revision presence: %s", err)
   463  		} else if !is {
   464  			t.Errorf("Revision that should exist was not present")
   465  		}
   466  
   467  		pvlist, err := src.listVersions(ctx)
   468  		if err != nil {
   469  			t.Errorf("Unexpected error getting version pairs from hg repo: %s", err)
   470  		}
   471  
   472  		vlist := hidePair(pvlist)
   473  		if len(vlist) != len(evl) {
   474  			t.Errorf("hg test repo should've produced %v versions, got %v", len(evl), len(vlist))
   475  		} else {
   476  			SortForUpgrade(vlist)
   477  
   478  			for k, e := range evl {
   479  				if !vlist[k].identical(e) {
   480  					t.Errorf("version list was not what we expected:\n\t(GOT): %#v\n\t(WNT): %#v", vlist, evl)
   481  					break
   482  				}
   483  			}
   484  		}
   485  
   486  		// Run again, this time to ensure cache outputs correctly
   487  		pvlist, err = src.listVersions(ctx)
   488  		if err != nil {
   489  			t.Errorf("Unexpected error getting version pairs from hg repo: %s", err)
   490  		}
   491  
   492  		vlist = hidePair(pvlist)
   493  		if len(vlist) != len(evl) {
   494  			t.Errorf("hg test repo should've produced %v versions, got %v", len(evl), len(vlist))
   495  		} else {
   496  			SortForUpgrade(vlist)
   497  			for k, e := range evl {
   498  				if !vlist[k].identical(e) {
   499  					t.Errorf("version list was not what we expected:\n\t(GOT): %#v\n\t(WNT): %#v", vlist, evl)
   500  					break
   501  				}
   502  			}
   503  		}
   504  
   505  		// recheck that rev is present, this time interacting with cache differently
   506  		is, err = src.revisionPresentIn(Revision("103d1bddef2199c80aad7c42041223083d613ef9"))
   507  		if err != nil {
   508  			t.Errorf("Unexpected error while re-checking revision presence: %s", err)
   509  		} else if !is {
   510  			t.Errorf("Revision that should exist was not present on re-check")
   511  		}
   512  	}
   513  
   514  	// simultaneously run for both the repo with and without the magic bookmark
   515  	donech := make(chan struct{})
   516  	go func() {
   517  		tfunc("bitbucket.org/sdboyer/withbm", []Version{
   518  			NewVersion("v1.0.0").Pair(Revision("aa110802a0c64195d0a6c375c9f66668827c90b4")),
   519  			newDefaultBranch("@").Pair(Revision("b10d05d581e5401f383e48ccfeb84b48fde99d06")),
   520  			NewBranch("another").Pair(Revision("b10d05d581e5401f383e48ccfeb84b48fde99d06")),
   521  			NewBranch("default").Pair(Revision("3d466f437f6616da594bbab6446cc1cb4328d1bb")),
   522  			NewBranch("newbranch").Pair(Revision("5e2a01be9aee942098e44590ae545c7143da9675")),
   523  		})
   524  		close(donech)
   525  	}()
   526  
   527  	tfunc("bitbucket.org/sdboyer/nobm", []Version{
   528  		NewVersion("v1.0.0").Pair(Revision("aa110802a0c64195d0a6c375c9f66668827c90b4")),
   529  		newDefaultBranch("default").Pair(Revision("3d466f437f6616da594bbab6446cc1cb4328d1bb")),
   530  		NewBranch("another").Pair(Revision("b10d05d581e5401f383e48ccfeb84b48fde99d06")),
   531  		NewBranch("newbranch").Pair(Revision("5e2a01be9aee942098e44590ae545c7143da9675")),
   532  	})
   533  
   534  	<-donech
   535  }
   536  
   537  func TestGitSourceListVersionsNoHEAD(t *testing.T) {
   538  	// t.Parallel()
   539  
   540  	requiresBins(t, "git")
   541  
   542  	h := test.NewHelper(t)
   543  	defer h.Cleanup()
   544  	h.TempDir("smcache")
   545  	cpath := h.Path("smcache")
   546  	os.Mkdir(filepath.Join(cpath, "sources"), 0777)
   547  
   548  	h.TempDir("repo")
   549  	repoPath := h.Path("repo")
   550  
   551  	// Create test repo with a single commit on the master branch
   552  	h.RunGit(repoPath, "init")
   553  	h.RunGit(repoPath, "config", "--local", "user.email", "test@example.com")
   554  	h.RunGit(repoPath, "config", "--local", "user.name", "Test author")
   555  	h.RunGit(repoPath, "commit", "--allow-empty", `--message="Initial commit"`)
   556  
   557  	// Make HEAD point at a nonexistent branch (deleting it is not allowed)
   558  	// The `git ls-remote` that listVersions() calls will not return a HEAD ref
   559  	// because it points at a nonexistent branch
   560  	h.RunGit(repoPath, "symbolic-ref", "HEAD", "refs/heads/nonexistent")
   561  
   562  	un := "file://" + filepath.ToSlash(repoPath)
   563  	u, err := url.Parse(un)
   564  	if err != nil {
   565  		t.Fatalf("Error parsing URL %s: %s", un, err)
   566  	}
   567  	mb := maybeGitSource{u}
   568  
   569  	ctx := context.Background()
   570  	isrc, err := mb.try(ctx, cpath)
   571  	if err != nil {
   572  		t.Fatalf("Unexpected error while setting up gitSource for test repo: %s", err)
   573  	}
   574  
   575  	err = isrc.initLocal(ctx)
   576  	if err != nil {
   577  		t.Fatalf("Error on cloning git repo: %s", err)
   578  	}
   579  
   580  	src, ok := isrc.(*gitSource)
   581  	if !ok {
   582  		t.Fatalf("Expected a gitSource, got a %T", isrc)
   583  	}
   584  
   585  	pvlist, err := src.listVersions(ctx)
   586  	if err != nil {
   587  		t.Fatalf("Unexpected error getting version pairs from git repo: %s", err)
   588  	}
   589  
   590  	if len(pvlist) != 1 {
   591  		t.Errorf("Unexpected version pair length:\n\t(GOT): %d\n\t(WNT): %d", len(pvlist), 1)
   592  	}
   593  }
   594  
   595  func TestGitSourceListVersionsNoDupes(t *testing.T) {
   596  	// t.Parallel()
   597  
   598  	// This test is slowish, skip it on -short
   599  	if testing.Short() {
   600  		t.Skip("Skipping git source version fetching test in short mode")
   601  	}
   602  	requiresBins(t, "git")
   603  
   604  	cpath, err := ioutil.TempDir("", "smcache")
   605  	if err != nil {
   606  		t.Errorf("Failed to create temp dir: %s", err)
   607  	}
   608  	defer func() {
   609  		if err := os.RemoveAll(cpath); err != nil {
   610  			t.Errorf("removeAll failed: %s", err)
   611  		}
   612  	}()
   613  	os.Mkdir(filepath.Join(cpath, "sources"), 0777)
   614  
   615  	n := "github.com/carolynvs/deptest-importers"
   616  	un := "https://" + n
   617  	u, err := url.Parse(un)
   618  	if err != nil {
   619  		t.Fatalf("Error parsing URL %s: %s", un, err)
   620  	}
   621  	mb := maybeGitSource{
   622  		url: u,
   623  	}
   624  
   625  	ctx := context.Background()
   626  	src, err := mb.try(ctx, cpath)
   627  	if err != nil {
   628  		t.Fatalf("Unexpected error while setting up gitSource for test repo: %s", err)
   629  	}
   630  
   631  	err = src.initLocal(ctx)
   632  	if err != nil {
   633  		t.Fatalf("Error on cloning git repo: %s", err)
   634  	}
   635  
   636  	pvlist, err := src.listVersions(ctx)
   637  	if err != nil {
   638  		t.Fatalf("Unexpected error getting version pairs from git repo: %s", err)
   639  	}
   640  
   641  	for i := range pvlist {
   642  		pv1 := pvlist[i]
   643  		uv1 := pv1.Unpair()
   644  		for j := range pvlist {
   645  			if i == j {
   646  				continue
   647  			}
   648  			pv2 := pvlist[j]
   649  			uv2 := pv2.Unpair()
   650  			if uv1 == uv2 {
   651  				t.Errorf("duplicate version pair mapping from %#v to both %q and %q", uv1, pv1.Revision(), pv2.Revision())
   652  			}
   653  		}
   654  	}
   655  }
   656  
   657  func TestGitSourceAdaptiveCleanup(t *testing.T) {
   658  	// t.Parallel()
   659  
   660  	// This test is slowish, skip it on -short
   661  	if testing.Short() {
   662  		t.Skip("Skipping git adaptive failure recovery test in short mode")
   663  	}
   664  	requiresBins(t, "git")
   665  
   666  	cpath, err := ioutil.TempDir("", "smcache")
   667  	if err != nil {
   668  		t.Fatalf("Failed to create temp dir: %s", err)
   669  	}
   670  
   671  	var sm *SourceMgr
   672  	mkSM := func() {
   673  		// If sm is already set, make sure it's released, then create a new one.
   674  		if sm != nil {
   675  			sm.Release()
   676  		}
   677  
   678  		var err error
   679  		sm, err = NewSourceManager(SourceManagerConfig{
   680  			Cachedir: cpath,
   681  			Logger:   log.New(test.Writer{TB: t}, "", 0),
   682  		})
   683  		if err != nil {
   684  			t.Fatalf("Unexpected error on SourceManager creation: %s", err)
   685  		}
   686  	}
   687  
   688  	mkSM()
   689  	id := mkPI("github.com/sdboyer/gpkt")
   690  	err = sm.SyncSourceFor(id)
   691  	if err != nil {
   692  		t.Fatal(err)
   693  	}
   694  
   695  	repodir := filepath.Join(sm.cachedir, "sources", "https---github.com-sdboyer-gpkt")
   696  	if _, err := os.Stat(repodir); err != nil {
   697  		if os.IsNotExist(err) {
   698  			t.Fatalf("expected location for repodir did not exist: %q", repodir)
   699  		} else {
   700  			t.Fatal(err)
   701  		}
   702  	}
   703  
   704  	// Create a file that git will see as untracked.
   705  	untrackedPath := filepath.Join(repodir, "untrackedfile")
   706  	err = ioutil.WriteFile(untrackedPath, []byte("foo"), 0644)
   707  	if err != nil {
   708  		t.Fatal(err)
   709  	}
   710  
   711  	mkSM()
   712  	err = sm.SyncSourceFor(id)
   713  	if err != nil {
   714  		t.Fatalf("choked after adding dummy file: %q", err)
   715  	}
   716  
   717  	if _, err := os.Stat(untrackedPath); err == nil {
   718  		t.Fatal("untracked file still existed after cleanup should've been triggered")
   719  	}
   720  
   721  	// Remove a file that we know exists, which `git status` checks should catch.
   722  	readmePath := filepath.Join(repodir, "README.md")
   723  	os.Remove(readmePath)
   724  
   725  	mkSM()
   726  	err = sm.SyncSourceFor(id)
   727  	if err != nil {
   728  		t.Fatalf("choked after removing known file: %q", err)
   729  	}
   730  
   731  	if _, err := os.Stat(readmePath); err != nil {
   732  		t.Fatal("README was still absent after cleanup should've been triggered")
   733  	}
   734  
   735  	// Remove .git/objects directory, which should make git bite it.
   736  	err = os.RemoveAll(filepath.Join(repodir, ".git", "objects"))
   737  	if err != nil {
   738  		t.Fatal(err)
   739  	}
   740  
   741  	mkSM()
   742  	err = sm.SyncSourceFor(id)
   743  	if err != nil {
   744  		t.Fatalf("choked after removing .git/objects directory: %q", err)
   745  	}
   746  
   747  	sm.Release()
   748  	os.RemoveAll(cpath)
   749  }
   750  
   751  func Test_bzrSource_exportRevisionTo_removeVcsFiles(t *testing.T) {
   752  	t.Parallel()
   753  
   754  	// This test is slow, so skip it on -short
   755  	if testing.Short() {
   756  		t.Skip("Skipping hg source version fetching test in short mode")
   757  	}
   758  	if runtime.GOOS == "windows" {
   759  		// TODO see todo in TestBzrSourceInteractions
   760  		t.Skip("TODO: Windows bzr reporting of underlying object ids is confusing")
   761  	}
   762  	requiresBins(t, "bzr")
   763  
   764  	h := test.NewHelper(t)
   765  	defer h.Cleanup()
   766  	h.TempDir("smcache")
   767  	cpath := h.Path("smcache")
   768  	repoPath := filepath.Join(h.Path("."), "repo")
   769  
   770  	rev := Revision("matt@mattfarina.com-20150731135137-pbphasfppmygpl68")
   771  	n := "launchpad.net/govcstestbzrrepo"
   772  	un := "https://" + n
   773  	u, err := url.Parse(un)
   774  	if err != nil {
   775  		t.Errorf("URL was bad, lolwut? errtext: %s", err)
   776  		return
   777  	}
   778  	mb := maybeBzrSource{u}
   779  
   780  	ctx := context.Background()
   781  	isrc, err := mb.try(ctx, cpath)
   782  	if err != nil {
   783  		t.Fatalf("unexpected error while setting up hgSource for test repo: %s", err)
   784  	}
   785  
   786  	err = isrc.initLocal(ctx)
   787  	if err != nil {
   788  		t.Fatalf("Error on cloning bzr repo: %s", err)
   789  	}
   790  
   791  	src, ok := isrc.(*bzrSource)
   792  	if !ok {
   793  		t.Fatalf("expected a bzrSource, got a %T", isrc)
   794  	}
   795  
   796  	if err := src.exportRevisionTo(ctx, rev, repoPath); err != nil {
   797  		t.Fatalf("unexpected error: %v", err)
   798  	}
   799  
   800  	_, err = os.Stat(filepath.Join(repoPath, ".bzr"))
   801  	if err == nil {
   802  		t.Fatal("expected .bzr/ to not exists")
   803  	} else if !os.IsNotExist(err) {
   804  		t.Fatalf("unexpected error: %v", err)
   805  	}
   806  }
   807  
   808  func Test_hgSource_exportRevisionTo_removeVcsFiles(t *testing.T) {
   809  	t.Parallel()
   810  
   811  	// This test is slow, so skip it on -short
   812  	if testing.Short() {
   813  		t.Skip("Skipping hg source version fetching test in short mode")
   814  	}
   815  	requiresBins(t, "hg")
   816  
   817  	h := test.NewHelper(t)
   818  	defer h.Cleanup()
   819  	h.TempDir("smcache")
   820  	cpath := h.Path("smcache")
   821  	repoPath := filepath.Join(h.Path("."), "repo")
   822  
   823  	rev := Revision("6f55e1f03d91f8a7cce35d1968eb60a2352e4d59")
   824  	n := "bitbucket.org/golang-dep/dep-test"
   825  	un := "https://" + n
   826  	u, err := url.Parse(un)
   827  	if err != nil {
   828  		t.Errorf("URL was bad, lolwut? errtext: %s", err)
   829  		return
   830  	}
   831  	mb := maybeHgSource{u}
   832  
   833  	ctx := context.Background()
   834  	isrc, err := mb.try(ctx, cpath)
   835  	if err != nil {
   836  		t.Fatalf("unexpected error while setting up hgSource for test repo: %s", err)
   837  	}
   838  
   839  	err = isrc.initLocal(ctx)
   840  	if err != nil {
   841  		t.Fatalf("Error on cloning hg repo: %s", err)
   842  	}
   843  
   844  	src, ok := isrc.(*hgSource)
   845  	if !ok {
   846  		t.Fatalf("expected a hgSource, got a %T", isrc)
   847  	}
   848  
   849  	if err := src.exportRevisionTo(ctx, rev, repoPath); err != nil {
   850  		t.Fatalf("unexpected error: %v", err)
   851  	}
   852  
   853  	_, err = os.Stat(filepath.Join(repoPath, ".hg"))
   854  	if err == nil {
   855  		t.Fatal("expected .hg/ to not exists")
   856  	} else if !os.IsNotExist(err) {
   857  		t.Fatalf("unexpected error: %v", err)
   858  	}
   859  }
   860  
   861  // Fail a test if the specified binaries aren't installed.
   862  func requiresBins(t *testing.T, bins ...string) {
   863  	for _, b := range bins {
   864  		_, err := exec.LookPath(b)
   865  		if err != nil {
   866  			t.Fatalf("%s is not installed", b)
   867  		}
   868  	}
   869  }