func TestCertVerifyDisabledGlobalEnv(t *testing.T) { empty := config.NewFrom(config.Values{}) assert.False(t, isCertVerificationDisabledForHost(empty, "anyhost.com")) cfg := config.NewFrom(config.Values{ Os: map[string]string{ "GIT_SSL_NO_VERIFY": "1", }, }) assert.True(t, isCertVerificationDisabledForHost(cfg, "anyhost.com")) }
func TestCommandEnabledFromEnvironmentVariables(t *testing.T) { cfg := config.NewFrom(config.Values{ Os: map[string]string{"GITLFSLOCKSENABLED": "1"}, }) assert.True(t, isCommandEnabled(cfg, "locks")) }
func TestCustomTransferUploadConfig(t *testing.T) { path := "/path/to/binary" args := "-c 1 --whatever" cfg := config.NewFrom(config.Values{ Git: map[string]string{ "lfs.customtransfer.testupload.path": path, "lfs.customtransfer.testupload.args": args, "lfs.customtransfer.testupload.concurrent": "false", "lfs.customtransfer.testupload.direction": "upload", }, }) m := ConfigureManifest(NewManifest(), cfg) d := m.NewDownloadAdapter("testupload") assert.NotNil(t, d, "Download adapter should always be created") cd, _ := d.(*customAdapter) assert.Nil(t, cd, "Download adapter should NOT be custom (default to basic)") u := m.NewUploadAdapter("testupload") assert.NotNil(t, u, "Upload adapter should be present") cu, _ := u.(*customAdapter) assert.NotNil(t, cu, "Upload adapter should be customAdapter") assert.Equal(t, cu.path, path, "Path should be correct") assert.Equal(t, cu.args, args, "args should be correct") assert.Equal(t, cu.concurrent, false, "concurrent should be set") }
func TestCustomTransferBothConfig(t *testing.T) { path := "/path/to/binary" args := "-c 1 --whatever --yeah" cfg := config.NewFrom(config.Values{ Git: map[string]string{ "lfs.customtransfer.testboth.path": path, "lfs.customtransfer.testboth.args": args, "lfs.customtransfer.testboth.concurrent": "yes", "lfs.customtransfer.testboth.direction": "both", }, }) m := ConfigureManifest(NewManifest(), cfg) d := m.NewDownloadAdapter("testboth") assert.NotNil(t, d, "Download adapter should be present") cd, _ := d.(*customAdapter) assert.NotNil(t, cd, "Download adapter should be customAdapter") assert.Equal(t, cd.path, path, "Path should be correct") assert.Equal(t, cd.args, args, "args should be correct") assert.Equal(t, cd.concurrent, true, "concurrent should be set") u := m.NewUploadAdapter("testboth") assert.NotNil(t, u, "Upload adapter should be present") cu, _ := u.(*customAdapter) assert.NotNil(t, cu, "Upload adapter should be customAdapter") assert.Equal(t, cu.path, path, "Path should be correct") assert.Equal(t, cu.args, args, "args should be correct") assert.Equal(t, cu.concurrent, true, "concurrent should be set") }
func TestUploadApiError(t *testing.T) { SetupTestCredentialsFunc() repo := test.NewRepo(t) repo.Pushd() defer func() { repo.Popd() repo.Cleanup() RestoreCredentialsFunc() }() mux := http.NewServeMux() server := httptest.NewServer(mux) tmp := tempdir(t) defer server.Close() defer os.RemoveAll(tmp) postCalled := false mux.HandleFunc("/media/objects", func(w http.ResponseWriter, r *http.Request) { postCalled = true w.WriteHeader(404) }) cfg := config.NewFrom(config.Values{ Git: map[string]string{ "lfs.url": server.URL + "/media", }, }) oidPath, _ := lfs.LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11") if err := ioutil.WriteFile(oidPath, []byte("test"), 0744); err != nil { t.Fatal(err) } oid := filepath.Base(oidPath) stat, _ := os.Stat(oidPath) _, _, err := api.BatchOrLegacySingle(cfg, &api.ObjectResource{Oid: oid, Size: stat.Size()}, "upload", []string{"basic"}) if err == nil { t.Fatal(err) } if errors.IsFatalError(err) { t.Fatal("should not panic") } if isDockerConnectionError(err) { return } expected := "LFS: " + fmt.Sprintf(httputil.GetDefaultError(404), server.URL+"/media/objects") if err.Error() != expected { t.Fatalf("Expected: %s\nGot: %s", expected, err.Error()) } if !postCalled { t.Errorf("POST not called") } }
func TestCertVerifyDisabledGlobalConfig(t *testing.T) { def := config.New() assert.False(t, isCertVerificationDisabledForHost(def, "anyhost.com")) cfg := config.NewFrom(config.Values{ Git: map[string]string{"http.sslverify": "false"}, }) assert.True(t, isCertVerificationDisabledForHost(cfg, "anyhost.com")) }
func TestCertFromSSLCAInfoConfig(t *testing.T) { tempfile, err := ioutil.TempFile("", "testcert") assert.Nil(t, err, "Error creating temp cert file") defer os.Remove(tempfile.Name()) _, err = tempfile.WriteString(testCert) assert.Nil(t, err, "Error writing temp cert file") tempfile.Close() // Test http.<url>.sslcainfo for _, hostName := range sslCAInfoConfigHostNames { hostKey := fmt.Sprintf("http.https://%v.sslcainfo", hostName) cfg := config.NewFrom(config.Values{ Git: map[string]string{hostKey: tempfile.Name()}, }) for _, matchedHostTest := range sslCAInfoMatchedHostTests { pool := getRootCAsForHost(cfg, matchedHostTest.hostName) var shouldOrShouldnt string if matchedHostTest.shouldMatch { shouldOrShouldnt = "should" } else { shouldOrShouldnt = "should not" } assert.Equal(t, matchedHostTest.shouldMatch, pool != nil, "Cert lookup for \"%v\" %v have succeeded with \"%v\"", matchedHostTest.hostName, shouldOrShouldnt, hostKey) } } // Test http.sslcainfo cfg := config.NewFrom(config.Values{ Git: map[string]string{"http.sslcainfo": tempfile.Name()}, }) // Should match any host at all for _, matchedHostTest := range sslCAInfoMatchedHostTests { pool := getRootCAsForHost(cfg, matchedHostTest.hostName) assert.NotNil(t, pool) } }
func TestCertVerifyDisabledHostConfig(t *testing.T) { def := config.New() assert.False(t, isCertVerificationDisabledForHost(def, "specifichost.com")) assert.False(t, isCertVerificationDisabledForHost(def, "otherhost.com")) cfg := config.NewFrom(config.Values{ Git: map[string]string{ "http.https://specifichost.com/.sslverify": "false", }, }) assert.True(t, isCertVerificationDisabledForHost(cfg, "specifichost.com")) assert.False(t, isCertVerificationDisabledForHost(cfg, "otherhost.com")) }
func TestSSHGetExeAndArgsSshCommandArgs(t *testing.T) { cfg := config.NewFrom(config.Values{ Os: map[string]string{ "GIT_SSH_COMMAND": "sshcmd --args 1", }, }) endpoint := cfg.Endpoint("download") endpoint.SshUserAndHost = "*****@*****.**" exe, args := sshGetExeAndArgs(cfg, endpoint) assert.Equal(t, "sshcmd", exe) assert.Equal(t, []string{"--args", "1", "*****@*****.**"}, args) }
func TestSSHGetExeAndArgsSshCustomPort(t *testing.T) { cfg := config.NewFrom(config.Values{ Os: map[string]string{ "GIT_SSH_COMMAND": "", "GIT_SSH": "", }, }) endpoint := cfg.Endpoint("download") endpoint.SshUserAndHost = "*****@*****.**" endpoint.SshPort = "8888" exe, args := sshGetExeAndArgs(cfg, endpoint) assert.Equal(t, "ssh", exe) assert.Equal(t, []string{"-p", "8888", "*****@*****.**"}, args) }
func TestSSHGetExeAndArgsTortoisePlinkCommand(t *testing.T) { plink := filepath.Join("Users", "joebloggs", "bin", "tortoiseplink.exe") cfg := config.NewFrom(config.Values{ Os: map[string]string{ "GIT_SSH_COMMAND": plink, }, }) endpoint := cfg.Endpoint("download") endpoint.SshUserAndHost = "*****@*****.**" exe, args := sshGetExeAndArgs(cfg, endpoint) assert.Equal(t, plink, exe) assert.Equal(t, []string{"-batch", "*****@*****.**"}, args) }
func TestProxyFromEnvironment(t *testing.T) { cfg := config.NewFrom(config.Values{ Os: map[string]string{ "HTTPS_PROXY": "https://proxy-from-env:8080", }, }) req, err := http.NewRequest("GET", "https://some-host.com:123/foo/bar", nil) if err != nil { t.Fatal(err) } proxyURL, err := ProxyFromGitConfigOrEnvironment(cfg)(req) assert.Equal(t, "proxy-from-env:8080", proxyURL.Host) assert.Nil(t, err) }
func TestSSHGetExeAndArgsPlinkCustomPort(t *testing.T) { plink := filepath.Join("Users", "joebloggs", "bin", "plink") cfg := config.NewFrom(config.Values{ Os: map[string]string{ "GIT_SSH_COMMAND": "", "GIT_SSH": plink, }, }) endpoint := cfg.Endpoint("download") endpoint.SshUserAndHost = "*****@*****.**" endpoint.SshPort = "8888" exe, args := sshGetExeAndArgs(cfg, endpoint) assert.Equal(t, plink, exe) assert.Equal(t, []string{"-P", "8888", "*****@*****.**"}, args) }
func TestDownloadAPIError(t *testing.T) { SetupTestCredentialsFunc() defer func() { RestoreCredentialsFunc() }() mux := http.NewServeMux() server := httptest.NewServer(mux) defer server.Close() tmp := tempdir(t) defer os.RemoveAll(tmp) mux.HandleFunc("/media/objects/oid", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(404) }) cfg := config.NewFrom(config.Values{ Git: map[string]string{ "lfs.batch": "false", "lfs.url": server.URL + "/media", }, }) _, _, err := api.BatchOrLegacySingle(cfg, &api.ObjectResource{Oid: "oid"}, "download", []string{"basic"}) if err == nil { t.Fatal("no error?") } if errors.IsFatalError(err) { t.Fatal("should not panic") } if isDockerConnectionError(err) { return } expected := fmt.Sprintf(httputil.GetDefaultError(404), server.URL+"/media/objects/oid") if err.Error() != expected { t.Fatalf("Expected: %s\nGot: %s", expected, err.Error()) } }
func TestCertFromSSLCAPathConfig(t *testing.T) { tempdir, err := ioutil.TempDir("", "testcertdir") assert.Nil(t, err, "Error creating temp cert dir") defer os.RemoveAll(tempdir) err = ioutil.WriteFile(filepath.Join(tempdir, "cert1.pem"), []byte(testCert), 0644) assert.Nil(t, err, "Error creating cert file") cfg := config.NewFrom(config.Values{ Git: map[string]string{"http.sslcapath": tempdir}, }) // Should match any host at all for _, matchedHostTest := range sslCAInfoMatchedHostTests { pool := getRootCAsForHost(cfg, matchedHostTest.hostName) assert.NotNil(t, pool) } }
func TestProxyNoProxy(t *testing.T) { cfg := config.NewFrom(config.Values{ Git: map[string]string{ "http.proxy": "https://proxy-from-git-config:8080", }, Os: map[string]string{ "NO_PROXY": "some-host", }, }) req, err := http.NewRequest("GET", "https://some-host:8080", nil) if err != nil { t.Fatal(err) } proxyUrl, err := ProxyFromGitConfigOrEnvironment(cfg)(req) assert.Nil(t, proxyUrl) assert.Nil(t, err) }
func testAdapterRegButBasicOnly(t *testing.T) { cfg := config.NewFrom(config.Values{ Git: map[string]string{"lfs.basictransfersonly": "yes"}, }) m := ConfigureManifest(NewManifest(), cfg) assert := assert.New(t) m.RegisterNewTransferAdapterFunc("test", Upload, newTestAdapter) m.RegisterNewTransferAdapterFunc("test", Download, newTestAdapter) // Will still be created if we ask for them assert.NotNil(m.NewUploadAdapter("test")) assert.NotNil(m.NewDownloadAdapter("test")) // But list will exclude ld := m.GetDownloadAdapterNames() assert.Equal([]string{BasicAdapterName}, ld) lu := m.GetUploadAdapterNames() assert.Equal([]string{BasicAdapterName}, lu) }
func TestCertFromSSLCAInfoEnv(t *testing.T) { tempfile, err := ioutil.TempFile("", "testcert") assert.Nil(t, err, "Error creating temp cert file") defer os.Remove(tempfile.Name()) _, err = tempfile.WriteString(testCert) assert.Nil(t, err, "Error writing temp cert file") tempfile.Close() cfg := config.NewFrom(config.Values{ Os: map[string]string{ "GIT_SSL_CAINFO": tempfile.Name(), }, }) // Should match any host at all for _, matchedHostTest := range sslCAInfoMatchedHostTests { pool := getRootCAsForHost(cfg, matchedHostTest.hostName) assert.NotNil(t, pool) } }
func TestCustomTransferBasicConfig(t *testing.T) { path := "/path/to/binary" cfg := config.NewFrom(config.Values{ Git: map[string]string{"lfs.customtransfer.testsimple.path": path}, }) m := ConfigureManifest(NewManifest(), cfg) u := m.NewUploadAdapter("testsimple") assert.NotNil(t, u, "Upload adapter should be present") cu, _ := u.(*customAdapter) assert.NotNil(t, cu, "Upload adapter should be customAdapter") assert.Equal(t, cu.path, path, "Path should be correct") assert.Equal(t, cu.args, "", "args should be blank") assert.Equal(t, cu.concurrent, true, "concurrent should be defaulted") d := m.NewDownloadAdapter("testsimple") assert.NotNil(t, d, "Download adapter should be present") cd, _ := u.(*customAdapter) assert.NotNil(t, cd, "Download adapter should be customAdapter") assert.Equal(t, cd.path, path, "Path should be correct") assert.Equal(t, cd.args, "", "args should be blank") assert.Equal(t, cd.concurrent, true, "concurrent should be defaulted") }
func checkGetCredentials(t *testing.T, getCredsFunc func(*config.Configuration, *http.Request) (Creds, error), checks []*getCredentialCheck) { for _, check := range checks { t.Logf("Checking %q", check.Desc) cfg := config.NewFrom(config.Values{ Git: check.Config, }) cfg.CurrentRemote = check.CurrentRemote req, err := http.NewRequest(check.Method, check.Href, nil) if err != nil { t.Errorf("[%s] %s", check.Desc, err) continue } for key, value := range check.Header { req.Header.Set(key, value) } creds, err := getCredsFunc(cfg, req) if err != nil { t.Errorf("[%s] %s", check.Desc, err) continue } if check.ExpectCreds() { if creds == nil { t.Errorf("[%s], no credentials returned", check.Desc) continue } if value := creds["protocol"]; len(check.Protocol) > 0 && value != check.Protocol { t.Errorf("[%s] bad protocol: %q, expected: %q", check.Desc, value, check.Protocol) } if value := creds["host"]; len(check.Host) > 0 && value != check.Host { t.Errorf("[%s] bad host: %q, expected: %q", check.Desc, value, check.Host) } if value := creds["username"]; len(check.Username) > 0 && value != check.Username { t.Errorf("[%s] bad username: %q, expected: %q", check.Desc, value, check.Username) } if value := creds["password"]; len(check.Password) > 0 && value != check.Password { t.Errorf("[%s] bad password: %q, expected: %q", check.Desc, value, check.Password) } if value := creds["path"]; len(check.Path) > 0 && value != check.Path { t.Errorf("[%s] bad path: %q, expected: %q", check.Desc, value, check.Path) } } else { if creds != nil { t.Errorf("[%s], unexpected credentials: %v // %v", check.Desc, creds, check) continue } } reqAuth := req.Header.Get("Authorization") if check.SkipAuth { } else if len(check.Authorization) > 0 { if reqAuth != check.Authorization { t.Errorf("[%s] Unexpected Authorization header: %s", check.Desc, reqAuth) } } else { rawtoken := fmt.Sprintf("%s:%s", check.Username, check.Password) expected := "Basic " + strings.TrimSpace(base64.StdEncoding.EncodeToString([]byte(rawtoken))) if reqAuth != expected { t.Errorf("[%s] Bad Authorization. Expected '%s', got '%s'", check.Desc, expected, reqAuth) } } } }
func TestUploadVerifyError(t *testing.T) { SetupTestCredentialsFunc() repo := test.NewRepo(t) repo.Pushd() defer func() { repo.Popd() repo.Cleanup() RestoreCredentialsFunc() }() mux := http.NewServeMux() server := httptest.NewServer(mux) tmp := tempdir(t) defer server.Close() defer os.RemoveAll(tmp) postCalled := false verifyCalled := false mux.HandleFunc("/media/objects", func(w http.ResponseWriter, r *http.Request) { t.Logf("Server: %s %s", r.Method, r.URL) if r.Method != "POST" { w.WriteHeader(405) return } if r.Header.Get("Accept") != api.MediaType { t.Errorf("Invalid Accept") } if r.Header.Get("Content-Type") != api.MediaType { t.Errorf("Invalid Content-Type") } buf := &bytes.Buffer{} tee := io.TeeReader(r.Body, buf) reqObj := &api.ObjectResource{} err := json.NewDecoder(tee).Decode(reqObj) t.Logf("request header: %v", r.Header) t.Logf("request body: %s", buf.String()) if err != nil { t.Fatal(err) } if reqObj.Oid != "988881adc9fc3655077dc2d4d757d480b5ea0e11" { t.Errorf("invalid oid from request: %s", reqObj.Oid) } if reqObj.Size != 4 { t.Errorf("invalid size from request: %d", reqObj.Size) } obj := &api.ObjectResource{ Oid: reqObj.Oid, Size: reqObj.Size, Actions: map[string]*api.LinkRelation{ "upload": &api.LinkRelation{ Href: server.URL + "/upload", Header: map[string]string{"A": "1"}, }, "verify": &api.LinkRelation{ Href: server.URL + "/verify", Header: map[string]string{"B": "2"}, }, }, } by, err := json.Marshal(obj) if err != nil { t.Fatal(err) } postCalled = true head := w.Header() head.Set("Content-Type", api.MediaType) head.Set("Content-Length", strconv.Itoa(len(by))) w.WriteHeader(202) w.Write(by) }) mux.HandleFunc("/verify", func(w http.ResponseWriter, r *http.Request) { verifyCalled = true w.WriteHeader(404) }) cfg := config.NewFrom(config.Values{ Git: map[string]string{ "lfs.url": server.URL + "/media", }, }) oidPath, _ := lfs.LocalMediaPath("988881adc9fc3655077dc2d4d757d480b5ea0e11") if err := ioutil.WriteFile(oidPath, []byte("test"), 0744); err != nil { t.Fatal(err) } oid := filepath.Base(oidPath) stat, _ := os.Stat(oidPath) o, _, err := api.BatchOrLegacySingle(cfg, &api.ObjectResource{Oid: oid, Size: stat.Size()}, "upload", []string{"basic"}) if err != nil { if isDockerConnectionError(err) { return } t.Fatal(err) } err = api.VerifyUpload(cfg, o) if err == nil { t.Fatal("verify should fail") } if errors.IsFatalError(err) { t.Fatal("should not panic") } expected := fmt.Sprintf(httputil.GetDefaultError(404), server.URL+"/verify") if err.Error() != expected { t.Fatalf("Expected: %s\nGot: %s", expected, err.Error()) } if !postCalled { t.Errorf("POST not called") } if !verifyCalled { t.Errorf("verify not called") } }
package commands import ( "testing" "github.com/github/git-lfs/config" "github.com/stretchr/testify/assert" ) var ( testcfg = config.NewFrom(config.Values{ Git: map[string]string{ "lfs.fetchinclude": "/default/include", "lfs.fetchexclude": "/default/exclude", }, }) ) func TestDetermineIncludeExcludePathsReturnsCleanedPaths(t *testing.T) { inc := "/some/include" exc := "/some/exclude" i, e := determineIncludeExcludePaths(testcfg, &inc, &exc) assert.Equal(t, []string{"/some/include"}, i) assert.Equal(t, []string{"/some/exclude"}, e) } func TestDetermineIncludeExcludePathsReturnsEmptyPaths(t *testing.T) { inc := "" exc := "" i, e := determineIncludeExcludePaths(testcfg, &inc, &exc)
// nearly identical to TestSuccessfulDownload // called multiple times to return different 3xx status codes func TestSuccessfulDownloadWithRedirects(t *testing.T) { SetupTestCredentialsFunc() defer func() { RestoreCredentialsFunc() }() mux := http.NewServeMux() server := httptest.NewServer(mux) defer server.Close() tmp := tempdir(t) defer os.RemoveAll(tmp) // all of these should work for GET requests redirectCodes := []int{301, 302, 303, 307} redirectIndex := 0 mux.HandleFunc("/redirect/objects/oid", func(w http.ResponseWriter, r *http.Request) { t.Logf("Server: %s %s", r.Method, r.URL) t.Logf("request header: %v", r.Header) if r.Method != "GET" { w.WriteHeader(405) return } w.Header().Set("Location", server.URL+"/redirect2/objects/oid") w.WriteHeader(redirectCodes[redirectIndex]) t.Logf("redirect with %d", redirectCodes[redirectIndex]) }) mux.HandleFunc("/redirect2/objects/oid", func(w http.ResponseWriter, r *http.Request) { t.Logf("Server: %s %s", r.Method, r.URL) t.Logf("request header: %v", r.Header) if r.Method != "GET" { w.WriteHeader(405) return } w.Header().Set("Location", server.URL+"/media/objects/oid") w.WriteHeader(redirectCodes[redirectIndex]) t.Logf("redirect again with %d", redirectCodes[redirectIndex]) redirectIndex += 1 }) mux.HandleFunc("/media/objects/oid", func(w http.ResponseWriter, r *http.Request) { t.Logf("Server: %s %s", r.Method, r.URL) t.Logf("request header: %v", r.Header) if r.Method != "GET" { w.WriteHeader(405) return } if r.Header.Get("Accept") != api.MediaType { t.Error("Invalid Accept") } if r.Header.Get("Authorization") != expectedAuth(t, server) { t.Error("Invalid Authorization") } obj := &api.ObjectResource{ Oid: "oid", Size: 4, Actions: map[string]*api.LinkRelation{ "download": &api.LinkRelation{ Href: server.URL + "/download", Header: map[string]string{"A": "1"}, }, }, } by, err := json.Marshal(obj) if err != nil { t.Fatal(err) } head := w.Header() head.Set("Content-Type", api.MediaType) head.Set("Content-Length", strconv.Itoa(len(by))) w.WriteHeader(200) w.Write(by) }) cfg := config.NewFrom(config.Values{ Git: map[string]string{ "lfs.batch": "false", "lfs.url": server.URL + "/redirect", }, }) for _, redirect := range redirectCodes { obj, _, err := api.BatchOrLegacySingle(cfg, &api.ObjectResource{Oid: "oid"}, "download", []string{"basic"}) if err != nil { if isDockerConnectionError(err) { return } t.Fatalf("unexpected error for %d status: %s", redirect, err) } if obj.Size != 4 { t.Errorf("unexpected size for %d status: %d", redirect, obj.Size) } } }
func TestCommandEnabledDisabledByDefault(t *testing.T) { cfg := config.NewFrom(config.Values{}) assert.False(t, isCommandEnabled(cfg, "locks")) }
// nearly identical to TestSuccessfulDownload // the api request returns a custom Authorization header func TestSuccessfulDownloadWithAuthorization(t *testing.T) { SetupTestCredentialsFunc() defer func() { RestoreCredentialsFunc() }() mux := http.NewServeMux() server := httptest.NewServer(mux) defer server.Close() tmp := tempdir(t) defer os.RemoveAll(tmp) mux.HandleFunc("/media/objects/oid", func(w http.ResponseWriter, r *http.Request) { t.Logf("Server: %s %s", r.Method, r.URL) t.Logf("request header: %v", r.Header) if r.Method != "GET" { w.WriteHeader(405) return } if r.Header.Get("Accept") != api.MediaType { t.Error("Invalid Accept") } if r.Header.Get("Authorization") != expectedAuth(t, server) { t.Error("Invalid Authorization") } obj := &api.ObjectResource{ Oid: "oid", Size: 4, Actions: map[string]*api.LinkRelation{ "download": &api.LinkRelation{ Href: server.URL + "/download", Header: map[string]string{ "A": "1", "Authorization": "custom", }, }, }, } by, err := json.Marshal(obj) if err != nil { t.Fatal(err) } head := w.Header() head.Set("Content-Type", "application/json; charset=utf-8") head.Set("Content-Length", strconv.Itoa(len(by))) w.WriteHeader(200) w.Write(by) }) cfg := config.NewFrom(config.Values{ Git: map[string]string{ "lfs.batch": "false", "lfs.url": server.URL + "/media", }, }) obj, _, err := api.BatchOrLegacySingle(cfg, &api.ObjectResource{Oid: "oid"}, "download", []string{"basic"}) if err != nil { if isDockerConnectionError(err) { return } t.Fatalf("unexpected error: %s", err) } if obj.Size != 4 { t.Errorf("unexpected size: %d", obj.Size) } }