get test working with a git and lfs server
This commit is contained in:
parent
5fc4fde5fb
commit
e2afd37e7c
242
tests/cmd/lfstest-gitserver.go
Normal file
242
tests/cmd/lfstest-gitserver.go
Normal file
@ -0,0 +1,242 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
repoDir string
|
||||
largeObjects = make(map[string][]byte)
|
||||
server *httptest.Server
|
||||
)
|
||||
|
||||
func main() {
|
||||
// should be run from project root
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
repoDir = filepath.Join(wd, "tests", "remote")
|
||||
|
||||
mux := http.NewServeMux()
|
||||
server = httptest.NewServer(mux)
|
||||
stopch := make(chan bool)
|
||||
|
||||
mux.HandleFunc("/shutdown", func(w http.ResponseWriter, r *http.Request) {
|
||||
stopch <- true
|
||||
})
|
||||
|
||||
mux.HandleFunc("/storage/", storageHandler)
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.Contains(r.URL.Path, "/info/lfs") {
|
||||
log.Printf("git lfs %s %s\n", r.Method, r.URL)
|
||||
lfsHandler(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("git http-backend %s %s\n", r.Method, r.URL)
|
||||
gitHandler(w, r)
|
||||
})
|
||||
|
||||
urlname := os.Getenv("LFSTEST_URL")
|
||||
if len(urlname) == 0 {
|
||||
urlname = "lfstest-gitserver"
|
||||
}
|
||||
|
||||
file, err := os.Create(urlname)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
file.Write([]byte(server.URL))
|
||||
file.Close()
|
||||
log.Println(server.URL)
|
||||
|
||||
defer func() {
|
||||
os.RemoveAll(urlname)
|
||||
}()
|
||||
|
||||
<-stopch
|
||||
log.Println("done")
|
||||
}
|
||||
|
||||
type lfsObject struct {
|
||||
Oid string `json:"oid,omitempty"`
|
||||
Size int64 `json:"size,omitempty"`
|
||||
Links map[string]lfsLink `json:"_links,omitempty"`
|
||||
}
|
||||
|
||||
type lfsLink struct {
|
||||
Href string `json:"href"`
|
||||
Header map[string]string `json:"header,omitempty"`
|
||||
}
|
||||
|
||||
// handles any requests with "{name}.server.git/info/lfs" in the path
|
||||
func lfsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/vnd.git-lfs+json")
|
||||
if r.Method == "POST" {
|
||||
lfsPostHandler(w, r)
|
||||
} else {
|
||||
lfsGetHandler(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func lfsPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
buf := &bytes.Buffer{}
|
||||
tee := io.TeeReader(r.Body, buf)
|
||||
obj := &lfsObject{}
|
||||
err := json.NewDecoder(tee).Decode(obj)
|
||||
io.Copy(ioutil.Discard, r.Body)
|
||||
r.Body.Close()
|
||||
|
||||
log.Println("REQUEST")
|
||||
log.Println(buf.String())
|
||||
log.Printf("OID: %s\n", obj.Oid)
|
||||
log.Printf("Size: %d\n", obj.Size)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
res := &lfsObject{
|
||||
Links: map[string]lfsLink{
|
||||
"upload": lfsLink{
|
||||
Href: server.URL + "/storage/" + obj.Oid,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
by, err := json.Marshal(res)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Println("RESPONSE: 202")
|
||||
log.Println(string(by))
|
||||
|
||||
w.WriteHeader(202)
|
||||
w.Write(by)
|
||||
}
|
||||
|
||||
func lfsGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
parts := strings.Split(r.URL.Path, "/")
|
||||
oid := parts[len(parts)-1]
|
||||
|
||||
if by, ok := largeObjects[oid]; ok {
|
||||
obj := &lfsObject{
|
||||
Oid: oid,
|
||||
Size: int64(len(by)),
|
||||
Links: map[string]lfsLink{
|
||||
"download": lfsLink{
|
||||
Href: server.URL + "/storage/" + oid,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
by, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Println("RESPONSE: 200")
|
||||
log.Println(string(by))
|
||||
|
||||
w.WriteHeader(200)
|
||||
w.Write(by)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(404)
|
||||
}
|
||||
|
||||
// handles any /storage/{oid} requests
|
||||
func storageHandler(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("storage %s %s\n", r.Method, r.URL)
|
||||
switch r.Method {
|
||||
case "PUT":
|
||||
hash := sha256.New()
|
||||
buf := &bytes.Buffer{}
|
||||
io.Copy(io.MultiWriter(hash, buf), r.Body)
|
||||
oid := hex.EncodeToString(hash.Sum(nil))
|
||||
if !strings.HasSuffix(r.URL.Path, "/"+oid) {
|
||||
w.WriteHeader(403)
|
||||
return
|
||||
}
|
||||
|
||||
largeObjects[oid] = buf.Bytes()
|
||||
|
||||
case "GET":
|
||||
parts := strings.Split(r.URL.Path, "/")
|
||||
oid := parts[len(parts)-1]
|
||||
|
||||
if by, ok := largeObjects[oid]; ok {
|
||||
w.Write(by)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(404)
|
||||
default:
|
||||
w.WriteHeader(500)
|
||||
}
|
||||
}
|
||||
|
||||
func gitHandler(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
io.Copy(ioutil.Discard, r.Body)
|
||||
r.Body.Close()
|
||||
}()
|
||||
|
||||
cmd := exec.Command("git", "http-backend")
|
||||
cmd.Env = []string{
|
||||
fmt.Sprintf("GIT_PROJECT_ROOT=%s", repoDir),
|
||||
fmt.Sprintf("GIT_HTTP_EXPORT_ALL="),
|
||||
fmt.Sprintf("PATH_INFO=%s", r.URL.Path),
|
||||
fmt.Sprintf("QUERY_STRING=%s", r.URL.RawQuery),
|
||||
fmt.Sprintf("REQUEST_METHOD=%s", r.Method),
|
||||
fmt.Sprintf("CONTENT_TYPE=%s", r.Header.Get("Content-Type")),
|
||||
}
|
||||
|
||||
buffer := &bytes.Buffer{}
|
||||
cmd.Stdin = r.Body
|
||||
cmd.Stdout = buffer
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
text := textproto.NewReader(bufio.NewReader(buffer))
|
||||
|
||||
code, _, _ := text.ReadCodeLine(-1)
|
||||
|
||||
if code != 0 {
|
||||
w.WriteHeader(code)
|
||||
}
|
||||
|
||||
headers, _ := text.ReadMIMEHeader()
|
||||
head := w.Header()
|
||||
for key, values := range headers {
|
||||
for _, value := range values {
|
||||
head.Add(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
io.Copy(w, text.R)
|
||||
}
|
@ -2,6 +2,19 @@
|
||||
# this should run from the git-lfs project root.
|
||||
set -e
|
||||
|
||||
wait_for_file() {
|
||||
local filename=$1
|
||||
for ((n=30; n>0; n--)); do
|
||||
if [ -s $filename ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# cleanup
|
||||
rm -rf "tests/remote"
|
||||
rm -rf "tests/local"
|
||||
@ -13,6 +26,12 @@ echo "compile git-lfs"
|
||||
script/bootstrap
|
||||
GITLFS="`pwd`/bin/git-lfs"
|
||||
|
||||
echo "spin up test server"
|
||||
LFSTEST_URL=tests/remote/url go run tests/cmd/lfstest-gitserver.go &
|
||||
wait_for_file tests/remote/url
|
||||
GITSERVER=$(cat tests/remote/url)
|
||||
echo $GITSERVER
|
||||
|
||||
echo "set up 'remote' git repository"
|
||||
REPONAME="$(basename "$0")"
|
||||
REPODIR="`pwd`/tests/remote/$REPONAME.git"
|
||||
@ -26,11 +45,17 @@ echo "set up 'local' test directory with git clone"
|
||||
cd $ROOTDIR
|
||||
TESTDIR="$(mktemp -d "`pwd`/tests/local/XXXXXX")"
|
||||
cd $TESTDIR
|
||||
git clone $GITSERVER/$REPONAME repo
|
||||
cd repo
|
||||
|
||||
echo "start the test"
|
||||
|
||||
out=$($GITLFS track "*.dat")
|
||||
echo "$out"
|
||||
echo "$out" | grep "dat"
|
||||
|
||||
echo "ok"
|
||||
# only run if this test complete
|
||||
rm -rf $TESTDIR
|
||||
|
||||
# run after the entire test run regardless of success or failure
|
||||
curl $GITSERVER/shutdown
|
||||
|
Loading…
Reference in New Issue
Block a user