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  }