package http
import (
"crypto/tls"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"net/http/cgi"
"net/url"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
. "gopkg.in/check.v1"
"gopkg.in/src-d/go-git-fixtures.v3"
)
func Test(t *testing.T) { TestingT(t) }
type ClientSuite struct {
Endpoint *transport.Endpoint
EmptyAuth transport.AuthMethod
}
var _ = Suite(&ClientSuite{})
func (s *ClientSuite) SetUpSuite(c *C) {
var err error
s.Endpoint, err = transport.NewEndpoint(
"https://github.com/git-fixtures/basic",
)
c.Assert(err, IsNil)
}
func (s *UploadPackSuite) TestNewClient(c *C) {
roundTripper := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
cl := &http.Client{Transport: roundTripper}
r, ok := NewClient(cl).(*client)
c.Assert(ok, Equals, true)
c.Assert(r.c, Equals, cl)
}
func (s *ClientSuite) TestNewBasicAuth(c *C) {
a := &BasicAuth{"foo", "qux"}
c.Assert(a.Name(), Equals, "http-basic-auth")
c.Assert(a.String(), Equals, "http-basic-auth - foo:*******")
}
func (s *ClientSuite) TestNewTokenAuth(c *C) {
a := &TokenAuth{"OAUTH-TOKEN-TEXT"}
c.Assert(a.Name(), Equals, "http-token-auth")
c.Assert(a.String(), Equals, "http-token-auth - *******")
// Check header is set correctly
req, err := http.NewRequest("GET", "https://github.com/git-fixtures/basic", nil)
c.Assert(err, Equals, nil)
a.setAuth(req)
c.Assert(req.Header.Get("Authorization"), Equals, "Bearer OAUTH-TOKEN-TEXT")
}
func (s *ClientSuite) TestNewErrOK(c *C) {
res := &http.Response{StatusCode: http.StatusOK}
err := NewErr(res)
c.Assert(err, IsNil)
}
func (s *ClientSuite) TestNewErrUnauthorized(c *C) {
s.testNewHTTPError(c, http.StatusUnauthorized, "authentication required")
}
func (s *ClientSuite) TestNewErrForbidden(c *C) {
s.testNewHTTPError(c, http.StatusForbidden, "authorization failed")
}
func (s *ClientSuite) TestNewErrNotFound(c *C) {
s.testNewHTTPError(c, http.StatusNotFound, "repository not found")
}
func (s *ClientSuite) TestNewHTTPError40x(c *C) {
s.testNewHTTPError(c, http.StatusPaymentRequired,
"unexpected client error.*")
}
func (s *ClientSuite) testNewHTTPError(c *C, code int, msg string) {
req, _ := http.NewRequest("GET", "foo", nil)
res := &http.Response{
StatusCode: code,
Request: req,
}
err := NewErr(res)
c.Assert(err, NotNil)
c.Assert(err, ErrorMatches, msg)
}
func (s *ClientSuite) TestSetAuth(c *C) {
auth := &BasicAuth{}
r, err := DefaultClient.NewUploadPackSession(s.Endpoint, auth)
c.Assert(err, IsNil)
c.Assert(auth, Equals, r.(*upSession).auth)
}
type mockAuth struct{}
func (*mockAuth) Name() string { return "" }
func (*mockAuth) String() string { return "" }
func (s *ClientSuite) TestSetAuthWrongType(c *C) {
_, err := DefaultClient.NewUploadPackSession(s.Endpoint, &mockAuth{})
c.Assert(err, Equals, transport.ErrInvalidAuthMethod)
}
func (s *ClientSuite) TestModifyEndpointIfRedirect(c *C) {
sess := &session{endpoint: nil}
u, _ := url.Parse("https://example.com/info/refs")
res := &http.Response{Request: &http.Request{URL: u}}
c.Assert(func() {
sess.ModifyEndpointIfRedirect(res)
}, PanicMatches, ".*nil pointer dereference.*")
sess = &session{endpoint: nil}
// no-op - should return and not panic
sess.ModifyEndpointIfRedirect(&http.Response{})
data := []struct {
url string
endpoint *transport.Endpoint
expected *transport.Endpoint
}{
{"https://example.com/foo/bar", nil, nil},
{"https://example.com/foo.git/info/refs",
&transport.Endpoint{},
&transport.Endpoint{Protocol: "https", Host: "example.com", Path: "/foo.git"}},
{"https://example.com:8080/foo.git/info/refs",
&transport.Endpoint{},
&transport.Endpoint{Protocol: "https", Host: "example.com", Port: 8080, Path: "/foo.git"}},
}
for _, d := range data {
u, _ := url.Parse(d.url)
sess := &session{endpoint: d.endpoint}
sess.ModifyEndpointIfRedirect(&http.Response{
Request: &http.Request{URL: u},
})
c.Assert(d.endpoint, DeepEquals, d.expected)
}
}
type BaseSuite struct {
fixtures.Suite
base string
host string
port int
}
func (s *BaseSuite) SetUpTest(c *C) {
l, err := net.Listen("tcp", "localhost:0")
c.Assert(err, IsNil)
base, err := ioutil.TempDir(os.TempDir(), fmt.Sprintf("go-git-http-%d", s.port))
c.Assert(err, IsNil)
s.port = l.Addr().(*net.TCPAddr).Port
s.base = filepath.Join(base, s.host)
err = os.MkdirAll(s.base, 0755)
c.Assert(err, IsNil)
cmd := exec.Command("git", "--exec-path")
out, err := cmd.CombinedOutput()
c.Assert(err, IsNil)
server := &http.Server{
Handler: &cgi.Handler{
Path: filepath.Join(strings.Trim(string(out), "\n"), "git-http-backend"),
Env: []string{"GIT_HTTP_EXPORT_ALL=true", fmt.Sprintf("GIT_PROJECT_ROOT=%s", s.base)},
},
}
go func() {
log.Fatal(server.Serve(l))
}()
}
func (s *BaseSuite) prepareRepository(c *C, f *fixtures.Fixture, name string) *transport.Endpoint {
fs := f.DotGit()
err := fixtures.EnsureIsBare(fs)
c.Assert(err, IsNil)
path := filepath.Join(s.base, name)
err = os.Rename(fs.Root(), path)
c.Assert(err, IsNil)
return s.newEndpoint(c, name)
}
func (s *BaseSuite) newEndpoint(c *C, name string) *transport.Endpoint {
ep, err := transport.NewEndpoint(fmt.Sprintf("http://localhost:%d/%s", s.port, name))
c.Assert(err, IsNil)
return ep
}
func (s *BaseSuite) TearDownTest(c *C) {
err := os.RemoveAll(s.base)
c.Assert(err, IsNil)
}