github.com/rhatdan/docker@v0.7.7-0.20180119204836-47a0dcbcd20a/builder/remotecontext/git/gitutils_test.go (about)

     1  package git
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"net/url"
     9  	"os"
    10  	"os/exec"
    11  	"path/filepath"
    12  	"runtime"
    13  	"strings"
    14  	"testing"
    15  
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestParseRemoteURL(t *testing.T) {
    21  	dir, err := parseRemoteURL("git://github.com/user/repo.git")
    22  	require.NoError(t, err)
    23  	assert.NotEmpty(t, dir)
    24  	assert.Equal(t, gitRepo{"git://github.com/user/repo.git", "master", ""}, dir)
    25  
    26  	dir, err = parseRemoteURL("git://github.com/user/repo.git#mybranch:mydir/mysubdir/")
    27  	require.NoError(t, err)
    28  	assert.NotEmpty(t, dir)
    29  	assert.Equal(t, gitRepo{"git://github.com/user/repo.git", "mybranch", "mydir/mysubdir/"}, dir)
    30  
    31  	dir, err = parseRemoteURL("https://github.com/user/repo.git")
    32  	require.NoError(t, err)
    33  	assert.NotEmpty(t, dir)
    34  	assert.Equal(t, gitRepo{"https://github.com/user/repo.git", "master", ""}, dir)
    35  
    36  	dir, err = parseRemoteURL("https://github.com/user/repo.git#mybranch:mydir/mysubdir/")
    37  	require.NoError(t, err)
    38  	assert.NotEmpty(t, dir)
    39  	assert.Equal(t, gitRepo{"https://github.com/user/repo.git", "mybranch", "mydir/mysubdir/"}, dir)
    40  
    41  	dir, err = parseRemoteURL("git@github.com:user/repo.git")
    42  	require.NoError(t, err)
    43  	assert.NotEmpty(t, dir)
    44  	assert.Equal(t, gitRepo{"git@github.com:user/repo.git", "master", ""}, dir)
    45  
    46  	dir, err = parseRemoteURL("git@github.com:user/repo.git#mybranch:mydir/mysubdir/")
    47  	require.NoError(t, err)
    48  	assert.NotEmpty(t, dir)
    49  	assert.Equal(t, gitRepo{"git@github.com:user/repo.git", "mybranch", "mydir/mysubdir/"}, dir)
    50  }
    51  
    52  func TestCloneArgsSmartHttp(t *testing.T) {
    53  	mux := http.NewServeMux()
    54  	server := httptest.NewServer(mux)
    55  	serverURL, _ := url.Parse(server.URL)
    56  
    57  	serverURL.Path = "/repo.git"
    58  
    59  	mux.HandleFunc("/repo.git/info/refs", func(w http.ResponseWriter, r *http.Request) {
    60  		q := r.URL.Query().Get("service")
    61  		w.Header().Set("Content-Type", fmt.Sprintf("application/x-%s-advertisement", q))
    62  	})
    63  
    64  	args := fetchArgs(serverURL.String(), "master")
    65  	exp := []string{"fetch", "--depth", "1", "origin", "master"}
    66  	assert.Equal(t, exp, args)
    67  }
    68  
    69  func TestCloneArgsDumbHttp(t *testing.T) {
    70  	mux := http.NewServeMux()
    71  	server := httptest.NewServer(mux)
    72  	serverURL, _ := url.Parse(server.URL)
    73  
    74  	serverURL.Path = "/repo.git"
    75  
    76  	mux.HandleFunc("/repo.git/info/refs", func(w http.ResponseWriter, r *http.Request) {
    77  		w.Header().Set("Content-Type", "text/plain")
    78  	})
    79  
    80  	args := fetchArgs(serverURL.String(), "master")
    81  	exp := []string{"fetch", "origin", "master"}
    82  	assert.Equal(t, exp, args)
    83  }
    84  
    85  func TestCloneArgsGit(t *testing.T) {
    86  	args := fetchArgs("git://github.com/docker/docker", "master")
    87  	exp := []string{"fetch", "--depth", "1", "origin", "master"}
    88  	assert.Equal(t, exp, args)
    89  }
    90  
    91  func gitGetConfig(name string) string {
    92  	b, err := git([]string{"config", "--get", name}...)
    93  	if err != nil {
    94  		// since we are interested in empty or non empty string,
    95  		// we can safely ignore the err here.
    96  		return ""
    97  	}
    98  	return strings.TrimSpace(string(b))
    99  }
   100  
   101  func TestCheckoutGit(t *testing.T) {
   102  	root, err := ioutil.TempDir("", "docker-build-git-checkout")
   103  	require.NoError(t, err)
   104  	defer os.RemoveAll(root)
   105  
   106  	autocrlf := gitGetConfig("core.autocrlf")
   107  	if !(autocrlf == "true" || autocrlf == "false" ||
   108  		autocrlf == "input" || autocrlf == "") {
   109  		t.Logf("unknown core.autocrlf value: \"%s\"", autocrlf)
   110  	}
   111  	eol := "\n"
   112  	if autocrlf == "true" {
   113  		eol = "\r\n"
   114  	}
   115  
   116  	gitDir := filepath.Join(root, "repo")
   117  	_, err = git("init", gitDir)
   118  	require.NoError(t, err)
   119  
   120  	_, err = gitWithinDir(gitDir, "config", "user.email", "test@docker.com")
   121  	require.NoError(t, err)
   122  
   123  	_, err = gitWithinDir(gitDir, "config", "user.name", "Docker test")
   124  	require.NoError(t, err)
   125  
   126  	err = ioutil.WriteFile(filepath.Join(gitDir, "Dockerfile"), []byte("FROM scratch"), 0644)
   127  	require.NoError(t, err)
   128  
   129  	subDir := filepath.Join(gitDir, "subdir")
   130  	require.NoError(t, os.Mkdir(subDir, 0755))
   131  
   132  	err = ioutil.WriteFile(filepath.Join(subDir, "Dockerfile"), []byte("FROM scratch\nEXPOSE 5000"), 0644)
   133  	require.NoError(t, err)
   134  
   135  	if runtime.GOOS != "windows" {
   136  		if err = os.Symlink("../subdir", filepath.Join(gitDir, "parentlink")); err != nil {
   137  			t.Fatal(err)
   138  		}
   139  
   140  		if err = os.Symlink("/subdir", filepath.Join(gitDir, "absolutelink")); err != nil {
   141  			t.Fatal(err)
   142  		}
   143  	}
   144  
   145  	_, err = gitWithinDir(gitDir, "add", "-A")
   146  	require.NoError(t, err)
   147  
   148  	_, err = gitWithinDir(gitDir, "commit", "-am", "First commit")
   149  	require.NoError(t, err)
   150  
   151  	_, err = gitWithinDir(gitDir, "checkout", "-b", "test")
   152  	require.NoError(t, err)
   153  
   154  	err = ioutil.WriteFile(filepath.Join(gitDir, "Dockerfile"), []byte("FROM scratch\nEXPOSE 3000"), 0644)
   155  	require.NoError(t, err)
   156  
   157  	err = ioutil.WriteFile(filepath.Join(subDir, "Dockerfile"), []byte("FROM busybox\nEXPOSE 5000"), 0644)
   158  	require.NoError(t, err)
   159  
   160  	_, err = gitWithinDir(gitDir, "add", "-A")
   161  	require.NoError(t, err)
   162  
   163  	_, err = gitWithinDir(gitDir, "commit", "-am", "Branch commit")
   164  	require.NoError(t, err)
   165  
   166  	_, err = gitWithinDir(gitDir, "checkout", "master")
   167  	require.NoError(t, err)
   168  
   169  	// set up submodule
   170  	subrepoDir := filepath.Join(root, "subrepo")
   171  	_, err = git("init", subrepoDir)
   172  	require.NoError(t, err)
   173  
   174  	_, err = gitWithinDir(subrepoDir, "config", "user.email", "test@docker.com")
   175  	require.NoError(t, err)
   176  
   177  	_, err = gitWithinDir(subrepoDir, "config", "user.name", "Docker test")
   178  	require.NoError(t, err)
   179  
   180  	err = ioutil.WriteFile(filepath.Join(subrepoDir, "subfile"), []byte("subcontents"), 0644)
   181  	require.NoError(t, err)
   182  
   183  	_, err = gitWithinDir(subrepoDir, "add", "-A")
   184  	require.NoError(t, err)
   185  
   186  	_, err = gitWithinDir(subrepoDir, "commit", "-am", "Subrepo initial")
   187  	require.NoError(t, err)
   188  
   189  	cmd := exec.Command("git", "submodule", "add", subrepoDir, "sub") // this command doesn't work with --work-tree
   190  	cmd.Dir = gitDir
   191  	require.NoError(t, cmd.Run())
   192  
   193  	_, err = gitWithinDir(gitDir, "add", "-A")
   194  	require.NoError(t, err)
   195  
   196  	_, err = gitWithinDir(gitDir, "commit", "-am", "With submodule")
   197  	require.NoError(t, err)
   198  
   199  	type singleCase struct {
   200  		frag      string
   201  		exp       string
   202  		fail      bool
   203  		submodule bool
   204  	}
   205  
   206  	cases := []singleCase{
   207  		{"", "FROM scratch", false, true},
   208  		{"master", "FROM scratch", false, true},
   209  		{":subdir", "FROM scratch" + eol + "EXPOSE 5000", false, false},
   210  		{":nosubdir", "", true, false},   // missing directory error
   211  		{":Dockerfile", "", true, false}, // not a directory error
   212  		{"master:nosubdir", "", true, false},
   213  		{"master:subdir", "FROM scratch" + eol + "EXPOSE 5000", false, false},
   214  		{"master:../subdir", "", true, false},
   215  		{"test", "FROM scratch" + eol + "EXPOSE 3000", false, false},
   216  		{"test:", "FROM scratch" + eol + "EXPOSE 3000", false, false},
   217  		{"test:subdir", "FROM busybox" + eol + "EXPOSE 5000", false, false},
   218  	}
   219  
   220  	if runtime.GOOS != "windows" {
   221  		// Windows GIT (2.7.1 x64) does not support parentlink/absolutelink. Sample output below
   222  		// 	git --work-tree .\repo --git-dir .\repo\.git add -A
   223  		//	error: readlink("absolutelink"): Function not implemented
   224  		// 	error: unable to index file absolutelink
   225  		// 	fatal: adding files failed
   226  		cases = append(cases, singleCase{frag: "master:absolutelink", exp: "FROM scratch" + eol + "EXPOSE 5000", fail: false})
   227  		cases = append(cases, singleCase{frag: "master:parentlink", exp: "FROM scratch" + eol + "EXPOSE 5000", fail: false})
   228  	}
   229  
   230  	for _, c := range cases {
   231  		ref, subdir := getRefAndSubdir(c.frag)
   232  		r, err := cloneGitRepo(gitRepo{remote: gitDir, ref: ref, subdir: subdir})
   233  
   234  		if c.fail {
   235  			assert.Error(t, err)
   236  			continue
   237  		}
   238  		require.NoError(t, err)
   239  		defer os.RemoveAll(r)
   240  		if c.submodule {
   241  			b, err := ioutil.ReadFile(filepath.Join(r, "sub/subfile"))
   242  			require.NoError(t, err)
   243  			assert.Equal(t, "subcontents", string(b))
   244  		} else {
   245  			_, err := os.Stat(filepath.Join(r, "sub/subfile"))
   246  			require.Error(t, err)
   247  			require.True(t, os.IsNotExist(err))
   248  		}
   249  
   250  		b, err := ioutil.ReadFile(filepath.Join(r, "Dockerfile"))
   251  		require.NoError(t, err)
   252  		assert.Equal(t, c.exp, string(b))
   253  	}
   254  }
   255  
   256  func TestValidGitTransport(t *testing.T) {
   257  	gitUrls := []string{
   258  		"git://github.com/docker/docker",
   259  		"git@github.com:docker/docker.git",
   260  		"git@bitbucket.org:atlassianlabs/atlassian-docker.git",
   261  		"https://github.com/docker/docker.git",
   262  		"http://github.com/docker/docker.git",
   263  		"http://github.com/docker/docker.git#branch",
   264  		"http://github.com/docker/docker.git#:dir",
   265  	}
   266  	incompleteGitUrls := []string{
   267  		"github.com/docker/docker",
   268  	}
   269  
   270  	for _, url := range gitUrls {
   271  		if !isGitTransport(url) {
   272  			t.Fatalf("%q should be detected as valid Git prefix", url)
   273  		}
   274  	}
   275  
   276  	for _, url := range incompleteGitUrls {
   277  		if isGitTransport(url) {
   278  			t.Fatalf("%q should not be detected as valid Git prefix", url)
   279  		}
   280  	}
   281  }