github.com/psexton/git-lfs@v2.1.1-0.20170517224304-289a18b2bc53+incompatible/git/git_test.go (about)

     1  package git_test // to avoid import cycles
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"sort"
     8  	"testing"
     9  	"time"
    10  
    11  	. "github.com/git-lfs/git-lfs/git"
    12  	"github.com/git-lfs/git-lfs/test"
    13  	"github.com/stretchr/testify/assert"
    14  )
    15  
    16  func TestCurrentRefAndCurrentRemoteRef(t *testing.T) {
    17  	repo := test.NewRepo(t)
    18  	repo.Pushd()
    19  	defer func() {
    20  		repo.Popd()
    21  		repo.Cleanup()
    22  	}()
    23  
    24  	// test commits; we'll just modify the same file each time since we're
    25  	// only interested in branches
    26  	inputs := []*test.CommitInput{
    27  		{ // 0
    28  			Files: []*test.FileInput{
    29  				{Filename: "file1.txt", Size: 20},
    30  			},
    31  		},
    32  		{ // 1
    33  			NewBranch: "branch2",
    34  			Files: []*test.FileInput{
    35  				{Filename: "file1.txt", Size: 25},
    36  			},
    37  		},
    38  		{ // 2
    39  			ParentBranches: []string{"master"}, // back on master
    40  			Files: []*test.FileInput{
    41  				{Filename: "file1.txt", Size: 30},
    42  			},
    43  		},
    44  		{ // 3
    45  			NewBranch: "branch3",
    46  			Files: []*test.FileInput{
    47  				{Filename: "file1.txt", Size: 32},
    48  			},
    49  		},
    50  	}
    51  	outputs := repo.AddCommits(inputs)
    52  	// last commit was on branch3
    53  	ref, err := CurrentRef()
    54  	assert.Nil(t, err)
    55  	assert.Equal(t, &Ref{"branch3", RefTypeLocalBranch, outputs[3].Sha}, ref)
    56  	test.RunGitCommand(t, true, "checkout", "master")
    57  	ref, err = CurrentRef()
    58  	assert.Nil(t, err)
    59  	assert.Equal(t, &Ref{"master", RefTypeLocalBranch, outputs[2].Sha}, ref)
    60  	// Check remote
    61  	repo.AddRemote("origin")
    62  	test.RunGitCommand(t, true, "push", "-u", "origin", "master:someremotebranch")
    63  	ref, err = CurrentRemoteRef()
    64  	assert.Nil(t, err)
    65  	assert.Equal(t, &Ref{"origin/someremotebranch", RefTypeRemoteBranch, outputs[2].Sha}, ref)
    66  
    67  	refname, err := RemoteRefNameForCurrentBranch()
    68  	assert.Nil(t, err)
    69  	assert.Equal(t, "refs/remotes/origin/someremotebranch", refname)
    70  
    71  	remote, err := RemoteForCurrentBranch()
    72  	assert.Nil(t, err)
    73  	assert.Equal(t, "origin", remote)
    74  
    75  	ref, err = ResolveRef(outputs[2].Sha)
    76  	assert.Nil(t, err)
    77  	assert.Equal(t, &Ref{outputs[2].Sha, RefTypeOther, outputs[2].Sha}, ref)
    78  }
    79  
    80  func TestRecentBranches(t *testing.T) {
    81  	repo := test.NewRepo(t)
    82  	repo.Pushd()
    83  	defer func() {
    84  		repo.Popd()
    85  		repo.Cleanup()
    86  	}()
    87  
    88  	now := time.Now()
    89  	// test commits; we'll just modify the same file each time since we're
    90  	// only interested in branches & dates
    91  	inputs := []*test.CommitInput{
    92  		{ // 0
    93  			CommitDate: now.AddDate(0, 0, -20),
    94  			Files: []*test.FileInput{
    95  				{Filename: "file1.txt", Size: 20},
    96  			},
    97  		},
    98  		{ // 1
    99  			CommitDate: now.AddDate(0, 0, -15),
   100  			NewBranch:  "excluded_branch", // new branch & tag but too old
   101  			Tags:       []string{"excluded_tag"},
   102  			Files: []*test.FileInput{
   103  				{Filename: "file1.txt", Size: 25},
   104  			},
   105  		},
   106  		{ // 2
   107  			CommitDate:     now.AddDate(0, 0, -12),
   108  			ParentBranches: []string{"master"}, // back on master
   109  			Files: []*test.FileInput{
   110  				{Filename: "file1.txt", Size: 30},
   111  			},
   112  		},
   113  		{ // 3
   114  			CommitDate: now.AddDate(0, 0, -6),
   115  			NewBranch:  "included_branch", // new branch within 7 day limit
   116  			Files: []*test.FileInput{
   117  				{Filename: "file1.txt", Size: 32},
   118  			},
   119  		},
   120  		{ // 4
   121  			CommitDate: now.AddDate(0, 0, -3),
   122  			NewBranch:  "included_branch_2", // new branch within 7 day limit
   123  			Files: []*test.FileInput{
   124  				{Filename: "file1.txt", Size: 36},
   125  			},
   126  		},
   127  		{ // 5
   128  			// Final commit, current date/time
   129  			ParentBranches: []string{"master"}, // back on master
   130  			Files: []*test.FileInput{
   131  				{Filename: "file1.txt", Size: 21},
   132  			},
   133  		},
   134  	}
   135  	outputs := repo.AddCommits(inputs)
   136  
   137  	// Add a couple of remotes and push some branches
   138  	repo.AddRemote("origin")
   139  	repo.AddRemote("upstream")
   140  
   141  	test.RunGitCommand(t, true, "push", "origin", "master")
   142  	test.RunGitCommand(t, true, "push", "origin", "excluded_branch")
   143  	test.RunGitCommand(t, true, "push", "origin", "included_branch")
   144  	test.RunGitCommand(t, true, "push", "upstream", "master")
   145  	test.RunGitCommand(t, true, "push", "upstream", "included_branch_2")
   146  
   147  	// Recent, local only
   148  	refs, err := RecentBranches(now.AddDate(0, 0, -7), false, "")
   149  	assert.Equal(t, nil, err)
   150  	expectedRefs := []*Ref{
   151  		&Ref{"master", RefTypeLocalBranch, outputs[5].Sha},
   152  		&Ref{"included_branch_2", RefTypeLocalBranch, outputs[4].Sha},
   153  		&Ref{"included_branch", RefTypeLocalBranch, outputs[3].Sha},
   154  	}
   155  	assert.Equal(t, expectedRefs, refs, "Refs should be correct")
   156  
   157  	// Recent, remotes too (all of them)
   158  	refs, err = RecentBranches(now.AddDate(0, 0, -7), true, "")
   159  	assert.Equal(t, nil, err)
   160  	expectedRefs = []*Ref{
   161  		&Ref{"master", RefTypeLocalBranch, outputs[5].Sha},
   162  		&Ref{"included_branch_2", RefTypeLocalBranch, outputs[4].Sha},
   163  		&Ref{"included_branch", RefTypeLocalBranch, outputs[3].Sha},
   164  		&Ref{"upstream/master", RefTypeRemoteBranch, outputs[5].Sha},
   165  		&Ref{"upstream/included_branch_2", RefTypeRemoteBranch, outputs[4].Sha},
   166  		&Ref{"origin/master", RefTypeRemoteBranch, outputs[5].Sha},
   167  		&Ref{"origin/included_branch", RefTypeRemoteBranch, outputs[3].Sha},
   168  	}
   169  	// Need to sort for consistent comparison
   170  	sort.Sort(test.RefsByName(expectedRefs))
   171  	sort.Sort(test.RefsByName(refs))
   172  	assert.Equal(t, expectedRefs, refs, "Refs should be correct")
   173  
   174  	// Recent, only single remote
   175  	refs, err = RecentBranches(now.AddDate(0, 0, -7), true, "origin")
   176  	assert.Equal(t, nil, err)
   177  	expectedRefs = []*Ref{
   178  		&Ref{"master", RefTypeLocalBranch, outputs[5].Sha},
   179  		&Ref{"origin/master", RefTypeRemoteBranch, outputs[5].Sha},
   180  		&Ref{"included_branch_2", RefTypeLocalBranch, outputs[4].Sha},
   181  		&Ref{"included_branch", RefTypeLocalBranch, outputs[3].Sha},
   182  		&Ref{"origin/included_branch", RefTypeRemoteBranch, outputs[3].Sha},
   183  	}
   184  	// Need to sort for consistent comparison
   185  	sort.Sort(test.RefsByName(expectedRefs))
   186  	sort.Sort(test.RefsByName(refs))
   187  	assert.Equal(t, expectedRefs, refs, "Refs should be correct")
   188  }
   189  
   190  func TestResolveEmptyCurrentRef(t *testing.T) {
   191  	repo := test.NewRepo(t)
   192  	repo.Pushd()
   193  	defer func() {
   194  		repo.Popd()
   195  		repo.Cleanup()
   196  	}()
   197  
   198  	_, err := CurrentRef()
   199  	assert.NotEqual(t, nil, err)
   200  }
   201  
   202  func TestWorkTrees(t *testing.T) {
   203  
   204  	// Only git 2.5+
   205  	if !Config.IsGitVersionAtLeast("2.5.0") {
   206  		return
   207  	}
   208  
   209  	repo := test.NewRepo(t)
   210  	repo.Pushd()
   211  	defer func() {
   212  		repo.Popd()
   213  		repo.Cleanup()
   214  	}()
   215  
   216  	// test commits; we'll just modify the same file each time since we're
   217  	// only interested in branches & dates
   218  	inputs := []*test.CommitInput{
   219  		{ // 0
   220  			Files: []*test.FileInput{
   221  				{Filename: "file1.txt", Size: 20},
   222  			},
   223  		},
   224  		{ // 1
   225  			NewBranch: "branch2",
   226  			Files: []*test.FileInput{
   227  				{Filename: "file1.txt", Size: 25},
   228  			},
   229  		},
   230  		{ // 2
   231  			NewBranch:      "branch3",
   232  			ParentBranches: []string{"master"}, // back on master
   233  			Files: []*test.FileInput{
   234  				{Filename: "file1.txt", Size: 30},
   235  			},
   236  		},
   237  		{ // 3
   238  			NewBranch:      "branch4",
   239  			ParentBranches: []string{"master"}, // back on master
   240  			Files: []*test.FileInput{
   241  				{Filename: "file1.txt", Size: 40},
   242  			},
   243  		},
   244  	}
   245  	outputs := repo.AddCommits(inputs)
   246  	// Checkout master again otherwise can't create a worktree from branch4 if we're on it here
   247  	test.RunGitCommand(t, true, "checkout", "master")
   248  
   249  	// We can create worktrees as subfolders for convenience
   250  	// Each one is checked out to a different branch
   251  	// Note that we *won't* create one for branch3
   252  	test.RunGitCommand(t, true, "worktree", "add", "branch2_wt", "branch2")
   253  	test.RunGitCommand(t, true, "worktree", "add", "branch4_wt", "branch4")
   254  
   255  	refs, err := GetAllWorkTreeHEADs(filepath.Join(repo.Path, ".git"))
   256  	assert.Equal(t, nil, err)
   257  	expectedRefs := []*Ref{
   258  		&Ref{"master", RefTypeLocalBranch, outputs[0].Sha},
   259  		&Ref{"branch2", RefTypeLocalBranch, outputs[1].Sha},
   260  		&Ref{"branch4", RefTypeLocalBranch, outputs[3].Sha},
   261  	}
   262  	// Need to sort for consistent comparison
   263  	sort.Sort(test.RefsByName(expectedRefs))
   264  	sort.Sort(test.RefsByName(refs))
   265  	assert.Equal(t, expectedRefs, refs, "Refs should be correct")
   266  }
   267  
   268  func TestVersionCompare(t *testing.T) {
   269  	assert.True(t, IsVersionAtLeast("2.6.0", "2.6.0"))
   270  	assert.True(t, IsVersionAtLeast("2.6.0", "2.6"))
   271  	assert.True(t, IsVersionAtLeast("2.6.0", "2"))
   272  	assert.True(t, IsVersionAtLeast("2.6.10", "2.6.5"))
   273  	assert.True(t, IsVersionAtLeast("2.8.1", "2.7.2"))
   274  
   275  	assert.False(t, IsVersionAtLeast("1.6.0", "2"))
   276  	assert.False(t, IsVersionAtLeast("2.5.0", "2.6"))
   277  	assert.False(t, IsVersionAtLeast("2.5.0", "2.5.1"))
   278  	assert.False(t, IsVersionAtLeast("2.5.2", "2.5.10"))
   279  }
   280  
   281  func TestGitAndRootDirs(t *testing.T) {
   282  	repo := test.NewRepo(t)
   283  	repo.Pushd()
   284  	defer func() {
   285  		repo.Popd()
   286  		repo.Cleanup()
   287  	}()
   288  
   289  	git, root, err := GitAndRootDirs()
   290  	if err != nil {
   291  		t.Fatal(err)
   292  	}
   293  
   294  	expected, err := os.Stat(git)
   295  	if err != nil {
   296  		t.Fatal(err)
   297  	}
   298  
   299  	actual, err := os.Stat(filepath.Join(root, ".git"))
   300  	if err != nil {
   301  		t.Fatal(err)
   302  	}
   303  
   304  	assert.True(t, os.SameFile(expected, actual))
   305  }
   306  
   307  func TestGetTrackedFiles(t *testing.T) {
   308  	repo := test.NewRepo(t)
   309  	repo.Pushd()
   310  	defer func() {
   311  		repo.Popd()
   312  		repo.Cleanup()
   313  	}()
   314  
   315  	// test commits; we'll just modify the same file each time since we're
   316  	// only interested in branches
   317  	inputs := []*test.CommitInput{
   318  		{ // 0
   319  			Files: []*test.FileInput{
   320  				{Filename: "file1.txt", Size: 20},
   321  				{Filename: "file2.txt", Size: 20},
   322  				{Filename: "folder1/file10.txt", Size: 20},
   323  				{Filename: "folder1/anotherfile.txt", Size: 20},
   324  			},
   325  		},
   326  		{ // 1
   327  			Files: []*test.FileInput{
   328  				{Filename: "file3.txt", Size: 20},
   329  				{Filename: "file4.txt", Size: 20},
   330  				{Filename: "folder2/something.txt", Size: 20},
   331  				{Filename: "folder2/folder3/deep.txt", Size: 20},
   332  			},
   333  		},
   334  	}
   335  	repo.AddCommits(inputs)
   336  
   337  	tracked, err := GetTrackedFiles("*.txt")
   338  	assert.Nil(t, err)
   339  	sort.Strings(tracked) // for direct comparison
   340  	fulllist := []string{"file1.txt", "file2.txt", "file3.txt", "file4.txt", "folder1/anotherfile.txt", "folder1/file10.txt", "folder2/folder3/deep.txt", "folder2/something.txt"}
   341  	assert.Equal(t, fulllist, tracked)
   342  
   343  	tracked, err = GetTrackedFiles("*file*.txt")
   344  	assert.Nil(t, err)
   345  	sort.Strings(tracked)
   346  	sublist := []string{"file1.txt", "file2.txt", "file3.txt", "file4.txt", "folder1/anotherfile.txt", "folder1/file10.txt"}
   347  	assert.Equal(t, sublist, tracked)
   348  
   349  	tracked, err = GetTrackedFiles("folder1/*")
   350  	assert.Nil(t, err)
   351  	sort.Strings(tracked)
   352  	sublist = []string{"folder1/anotherfile.txt", "folder1/file10.txt"}
   353  	assert.Equal(t, sublist, tracked)
   354  
   355  	tracked, err = GetTrackedFiles("folder2/*")
   356  	assert.Nil(t, err)
   357  	sort.Strings(tracked)
   358  	sublist = []string{"folder2/folder3/deep.txt", "folder2/something.txt"}
   359  	assert.Equal(t, sublist, tracked)
   360  
   361  	// relative dir
   362  	os.Chdir("folder1")
   363  	tracked, err = GetTrackedFiles("*.txt")
   364  	assert.Nil(t, err)
   365  	sort.Strings(tracked)
   366  	sublist = []string{"anotherfile.txt", "file10.txt"}
   367  	assert.Equal(t, sublist, tracked)
   368  	os.Chdir("..")
   369  
   370  	// absolute paths only includes matches in repo root
   371  	tracked, err = GetTrackedFiles("/*.txt")
   372  	assert.Nil(t, err)
   373  	sort.Strings(tracked)
   374  	assert.Equal(t, []string{"file1.txt", "file2.txt", "file3.txt", "file4.txt"}, tracked)
   375  
   376  	// Test includes staged but uncommitted files
   377  	ioutil.WriteFile("z_newfile.txt", []byte("Hello world"), 0644)
   378  	test.RunGitCommand(t, true, "add", "z_newfile.txt")
   379  	tracked, err = GetTrackedFiles("*.txt")
   380  	assert.Nil(t, err)
   381  	sort.Strings(tracked)
   382  	fulllist = append(fulllist, "z_newfile.txt")
   383  	assert.Equal(t, fulllist, tracked)
   384  
   385  	// Test includes modified files (not staged)
   386  	ioutil.WriteFile("file1.txt", []byte("Modifications"), 0644)
   387  	tracked, err = GetTrackedFiles("*.txt")
   388  	assert.Nil(t, err)
   389  	sort.Strings(tracked)
   390  	assert.Equal(t, fulllist, tracked)
   391  
   392  	// Test includes modified files (staged)
   393  	test.RunGitCommand(t, true, "add", "file1.txt")
   394  	tracked, err = GetTrackedFiles("*.txt")
   395  	assert.Nil(t, err)
   396  	sort.Strings(tracked)
   397  	assert.Equal(t, fulllist, tracked)
   398  
   399  	// Test excludes deleted files (not committed)
   400  	test.RunGitCommand(t, true, "rm", "file2.txt")
   401  	tracked, err = GetTrackedFiles("*.txt")
   402  	assert.Nil(t, err)
   403  	sort.Strings(tracked)
   404  	deletedlist := []string{"file1.txt", "file3.txt", "file4.txt", "folder1/anotherfile.txt", "folder1/file10.txt", "folder2/folder3/deep.txt", "folder2/something.txt", "z_newfile.txt"}
   405  	assert.Equal(t, deletedlist, tracked)
   406  
   407  }
   408  
   409  func TestLocalRefs(t *testing.T) {
   410  	repo := test.NewRepo(t)
   411  	repo.Pushd()
   412  	defer func() {
   413  		repo.Popd()
   414  		repo.Cleanup()
   415  	}()
   416  
   417  	repo.AddCommits([]*test.CommitInput{
   418  		{
   419  			Files: []*test.FileInput{
   420  				{Filename: "file1.txt", Size: 20},
   421  			},
   422  		},
   423  		{
   424  			NewBranch:      "branch",
   425  			ParentBranches: []string{"master"},
   426  			Files: []*test.FileInput{
   427  				{Filename: "file1.txt", Size: 20},
   428  			},
   429  		},
   430  	})
   431  
   432  	test.RunGitCommand(t, true, "tag", "v1")
   433  
   434  	refs, err := LocalRefs()
   435  	if err != nil {
   436  		t.Fatal(err)
   437  	}
   438  
   439  	actual := make(map[string]bool)
   440  	for _, r := range refs {
   441  		t.Logf("REF: %s", r.Name)
   442  		switch r.Type {
   443  		case RefTypeHEAD:
   444  			t.Errorf("Local HEAD ref: %v", r)
   445  		case RefTypeOther:
   446  			t.Errorf("Stash or unknown ref: %v", r)
   447  		case RefTypeRemoteBranch, RefTypeRemoteTag:
   448  			t.Errorf("Remote ref: %v", r)
   449  		default:
   450  			actual[r.Name] = true
   451  		}
   452  	}
   453  
   454  	expected := []string{"master", "branch", "v1"}
   455  	found := 0
   456  	for _, refname := range expected {
   457  		if actual[refname] {
   458  			found += 1
   459  		} else {
   460  			t.Errorf("could not find ref %q", refname)
   461  		}
   462  	}
   463  
   464  	if found != len(expected) {
   465  		t.Errorf("Unexpected local refs: %v", actual)
   466  	}
   467  }
   468  
   469  func TestGetFilesChanges(t *testing.T) {
   470  	repo := test.NewRepo(t)
   471  	repo.Pushd()
   472  	defer func() {
   473  		repo.Popd()
   474  		repo.Cleanup()
   475  	}()
   476  
   477  	commits := repo.AddCommits([]*test.CommitInput{
   478  		{
   479  			Files: []*test.FileInput{
   480  				{Filename: "file1.txt", Size: 20},
   481  			},
   482  		},
   483  		{
   484  			Files: []*test.FileInput{
   485  				{Filename: "file1.txt", Size: 25},
   486  				{Filename: "file2.txt", Size: 20},
   487  				{Filename: "folder/file3.txt", Size: 10},
   488  			},
   489  			Tags: []string{"tag1"},
   490  		},
   491  		{
   492  			NewBranch:      "abranch",
   493  			ParentBranches: []string{"master"},
   494  			Files: []*test.FileInput{
   495  				{Filename: "file1.txt", Size: 30},
   496  				{Filename: "file4.txt", Size: 40},
   497  			},
   498  		},
   499  	})
   500  
   501  	expected0to1 := []string{"file1.txt", "file2.txt", "folder/file3.txt"}
   502  	expected1to2 := []string{"file1.txt", "file4.txt"}
   503  	expected0to2 := []string{"file1.txt", "file2.txt", "file4.txt", "folder/file3.txt"}
   504  	// Test 2 SHAs
   505  	changes, err := GetFilesChanged(commits[0].Sha, commits[1].Sha)
   506  	assert.Nil(t, err)
   507  	assert.Equal(t, expected0to1, changes)
   508  	// Test SHA & tag
   509  	changes, err = GetFilesChanged(commits[0].Sha, "tag1")
   510  	assert.Nil(t, err)
   511  	assert.Equal(t, expected0to1, changes)
   512  	// Test SHA & branch
   513  	changes, err = GetFilesChanged(commits[0].Sha, "abranch")
   514  	assert.Nil(t, err)
   515  	assert.Equal(t, expected0to2, changes)
   516  	// Test tag & branch
   517  	changes, err = GetFilesChanged("tag1", "abranch")
   518  	assert.Nil(t, err)
   519  	assert.Equal(t, expected1to2, changes)
   520  	// Test fail
   521  	_, err = GetFilesChanged("tag1", "nonexisting")
   522  	assert.NotNil(t, err)
   523  	_, err = GetFilesChanged("nonexisting", "tag1")
   524  	assert.NotNil(t, err)
   525  	// Test Single arg version
   526  	changes, err = GetFilesChanged(commits[1].Sha, "")
   527  	assert.Nil(t, err)
   528  	assert.Equal(t, expected0to1, changes)
   529  	changes, err = GetFilesChanged("abranch", "")
   530  	assert.Nil(t, err)
   531  	assert.Equal(t, expected1to2, changes)
   532  
   533  }
   534  
   535  func TestValidateRemoteURL(t *testing.T) {
   536  	assert.Nil(t, ValidateRemoteURL("https://github.com/git-lfs/git-lfs"))
   537  	assert.Nil(t, ValidateRemoteURL("http://github.com/git-lfs/git-lfs"))
   538  	assert.Nil(t, ValidateRemoteURL("git://github.com/git-lfs/git-lfs"))
   539  	assert.Nil(t, ValidateRemoteURL("ssh://git@github.com/git-lfs/git-lfs"))
   540  	assert.Nil(t, ValidateRemoteURL("ssh://git@github.com:22/git-lfs/git-lfs"))
   541  	assert.Nil(t, ValidateRemoteURL("git@github.com:git-lfs/git-lfs"))
   542  	assert.Nil(t, ValidateRemoteURL("git@server:/absolute/path.git"))
   543  	assert.NotNil(t, ValidateRemoteURL("ftp://git@github.com/git-lfs/git-lfs"))
   544  }