Merge pull request #676 from github/better-server-failure-handling-tests

[wip] better tests for handling server failures
This commit is contained in:
risk danger olson 2015-09-21 14:02:24 -07:00
commit 8e2638b22c
19 changed files with 416 additions and 48 deletions

@ -226,15 +226,14 @@ func (q *TransferQueue) batchApiRoutine() {
startProgress.Do(q.meter.Start)
for _, o := range objects {
if _, ok := o.Rel(q.transferKind); ok {
// This object has an error
if o.Error != nil {
q.errorc <- Error(o.Error)
q.meter.Skip(o.Size)
q.wait.Done()
continue
}
if o.Error != nil {
q.errorc <- Error(o.Error)
q.meter.Skip(o.Size)
q.wait.Done()
continue
}
if _, ok := o.Rel(q.transferKind); ok {
// This object needs to be transferred
if transfer, ok := q.transferables[o.Oid]; ok {
transfer.SetObject(o)

@ -58,4 +58,4 @@ fi
for file in "${testfiles[@]}"; do
echo "0$(cat .$(basename $file).time 2>/dev/null || true) $file"
done | sort -rnk1 | awk '{ print $2 }' | xargs -I % -P $parallel -n 1 /bin/sh -c % --batch
done | sort -rnk1 | awk '{ print $2 }' | xargs -I % -P $parallel -n 1 /bin/bash % --batch

@ -25,6 +25,22 @@ var (
repoDir string
largeObjects = newLfsStorage()
server *httptest.Server
// maps OIDs to content strings. Both the LFS and Storage test servers below
// see OIDs.
oidHandlers map[string]string
// These magic strings tell the test lfs server change their behavior so the
// integration tests can check those use cases. Tests will create objects with
// the magic strings as the contents.
//
// printf "status:lfs:404" > 404.dat
//
contentHandlers = []string{
"status-batch-403", "status-batch-404", "status-batch-410", "status-batch-422", "status-batch-500",
"status-storage-403", "status-storage-404", "status-storage-410", "status-storage-422", "status-storage-500",
"status-legacy-404", "status-legacy-410", "status-legacy-422", "status-legacy-403", "status-legacy-500",
}
)
func main() {
@ -79,6 +95,7 @@ type lfsObject struct {
Oid string `json:"oid,omitempty"`
Size int64 `json:"size,omitempty"`
Actions map[string]lfsLink `json:"actions,omitempty"`
Err *lfsError `json:"error,omitempty"`
}
type lfsLink struct {
@ -86,6 +103,11 @@ type lfsLink struct {
Header map[string]string `json:"header,omitempty"`
}
type lfsError struct {
Code int
Message string
}
// handles any requests with "{name}.server.git/info/lfs" in the path
func lfsHandler(w http.ResponseWriter, r *http.Request) {
repo, err := repoFromLfsUrl(r.URL.Path)
@ -132,6 +154,24 @@ func lfsPostHandler(w http.ResponseWriter, r *http.Request, repo string) {
log.Fatal(err)
}
switch oidHandlers[obj.Oid] {
case "status-legacy-403":
w.WriteHeader(403)
return
case "status-legacy-404":
w.WriteHeader(404)
return
case "status-legacy-410":
w.WriteHeader(410)
return
case "status-legacy-422":
w.WriteHeader(422)
return
case "status-legacy-500":
w.WriteHeader(500)
return
}
res := &lfsObject{
Oid: obj.Oid,
Size: obj.Size,
@ -232,13 +272,28 @@ func lfsBatchHandler(w http.ResponseWriter, r *http.Request, repo string) {
o := lfsObject{
Oid: obj.Oid,
Size: obj.Size,
Actions: map[string]lfsLink{
}
switch oidHandlers[obj.Oid] {
case "status-batch-403":
o.Err = &lfsError{Code: 403, Message: "welp"}
case "status-batch-404":
o.Err = &lfsError{Code: 404, Message: "welp"}
case "status-batch-410":
o.Err = &lfsError{Code: 410, Message: "welp"}
case "status-batch-422":
o.Err = &lfsError{Code: 422, Message: "welp"}
case "status-batch-500":
o.Err = &lfsError{Code: 500, Message: "welp"}
default: // regular 200 response
o.Actions = map[string]lfsLink{
action: lfsLink{
Href: lfsUrl(repo, obj.Oid),
Header: map[string]string{},
},
},
}
}
if testingChunked {
o.Actions[action].Header["Transfer-Encoding"] = "chunked"
}
@ -263,9 +318,30 @@ func lfsBatchHandler(w http.ResponseWriter, r *http.Request, repo string) {
// handles any /storage/{oid} requests
func storageHandler(w http.ResponseWriter, r *http.Request) {
repo := r.URL.Query().Get("r")
log.Printf("storage %s %s repo: %s\n", r.Method, r.URL, repo)
parts := strings.Split(r.URL.Path, "/")
oid := parts[len(parts)-1]
log.Printf("storage %s %s repo: %s\n", r.Method, oid, repo)
switch r.Method {
case "PUT":
switch oidHandlers[oid] {
case "status-storage-403":
w.WriteHeader(403)
return
case "status-storage-404":
w.WriteHeader(404)
return
case "status-storage-410":
w.WriteHeader(410)
return
case "status-storage-422":
w.WriteHeader(422)
return
case "status-storage-500":
w.WriteHeader(500)
return
}
if testingChunkedTransferEncoding(r) {
valid := false
for _, value := range r.TransferEncoding {
@ -461,3 +537,12 @@ func skipIfBadAuth(w http.ResponseWriter, r *http.Request) bool {
log.Printf("Bad auth: %q\n", auth)
return true
}
func init() {
oidHandlers = make(map[string]string)
for _, content := range contentHandlers {
h := sha256.New()
h.Write([]byte(content))
oidHandlers[hex.EncodeToString(h.Sum(nil))] = content
}
}

@ -27,7 +27,7 @@ begin_test "batch error handling"
grep "Tracking \*.dat" track.log
contents="a"
contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ")
contents_oid=$(calc_oid "$contents")
printf "$contents" > a.dat
git add a.dat

@ -21,7 +21,7 @@ begin_test "batch transfer unsupported on server"
grep "Tracking \*.dat" track.log
contents="a"
contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ")
contents_oid=$(calc_oid "$contents")
printf "$contents" > a.dat
git add a.dat

@ -27,7 +27,7 @@ begin_test "batch transfer"
grep "Tracking \*.dat" track.log
contents="a"
contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ")
contents_oid=$(calc_oid "$contents")
printf "$contents" > a.dat
git add a.dat

@ -16,7 +16,7 @@ begin_test "checkout"
contents="something something"
contentsize=19
contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ")
contents_oid=$(calc_oid "$contents")
# Same content everywhere is ok, just one object in lfs db
printf "$contents" > file1.dat

@ -27,7 +27,7 @@ begin_test "chunked transfer encoding batched"
grep "Tracking \*.dat" track.log
contents="a"
contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ")
contents_oid=$(calc_oid "$contents")
printf "$contents" > a.dat
git add a.dat

@ -27,7 +27,7 @@ begin_test "chunked transfer encoding"
grep "Tracking \*.dat" track.log
contents="a"
contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ")
contents_oid=$(calc_oid "$contents")
# Regular Git commands can be used.
printf "$contents" > a.dat

@ -12,7 +12,7 @@ begin_test "commit, delete, then push"
git lfs track "*.dat"
deleted_oid=$(echo "deleted" | shasum -a 256 | cut -f 1 -d " ")
deleted_oid=$(calc_oid "deleted\n")
echo "deleted" > deleted.dat
git add deleted.dat .gitattributes
git commit -m "add deleted file"
@ -21,7 +21,7 @@ begin_test "commit, delete, then push"
assert_pointer "master" "deleted.dat" "$deleted_oid" 8
added_oid=$(echo "added" | shasum -a 256 | cut -f 1 -d " ")
added_oid=$(calc_oid "added\n")
echo "added" > added.dat
git add added.dat
git commit -m "add file"

@ -18,7 +18,7 @@ begin_test "credentials without useHttpPath, with bad path password"
grep "Tracking \*.dat" track.log
contents="a"
contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ")
contents_oid=$(calc_oid "$contents")
printf "$contents" > a.dat
git add a.dat
@ -47,7 +47,7 @@ begin_test "credentials with useHttpPath, with wrong password"
grep "Tracking \*.dat" track.log
contents="a"
contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ")
contents_oid=$(calc_oid "$contents")
printf "$contents" > a.dat
git add a.dat
@ -78,7 +78,7 @@ begin_test "credentials with useHttpPath, with correct password"
# creating new branch does not re-sent any objects existing on other
# remote branches anymore, generate new object, different from prev tests
contents="b"
contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ")
contents_oid=$(calc_oid "$contents")
printf "$contents" > b.dat
git add b.dat

@ -17,7 +17,7 @@ begin_test "fetch"
grep "Tracking \*.dat" track.log
contents="a"
contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ")
contents_oid=$(calc_oid "$contents")
printf "$contents" > a.dat
git add a.dat
@ -43,7 +43,7 @@ begin_test "fetch"
# Add a file in a different branch
git checkout -b newbranch
b="b"
b_oid=$(printf "$b" | shasum -a 256 | cut -f 1 -d " ")
b_oid=$(calc_oid "$b")
printf "$b" > b.dat
git add b.dat
git commit -m "add b.dat"
@ -152,12 +152,12 @@ begin_test "fetch-recent"
content3="filecontent3"
content4="filecontent4"
content5="filecontent5"
oid0=$(printf "$content0" | shasum -a 256 | cut -f 1 -d " ")
oid1=$(printf "$content1" | shasum -a 256 | cut -f 1 -d " ")
oid2=$(printf "$content2" | shasum -a 256 | cut -f 1 -d " ")
oid3=$(printf "$content3" | shasum -a 256 | cut -f 1 -d " ")
oid4=$(printf "$content4" | shasum -a 256 | cut -f 1 -d " ")
oid5=$(printf "$content5" | shasum -a 256 | cut -f 1 -d " ")
oid0=$(calc_oid "$content0")
oid1=$(calc_oid "$content1")
oid2=$(calc_oid "$content2")
oid3=$(calc_oid "$content3")
oid4=$(calc_oid "$content4")
oid5=$(calc_oid "$content5")
echo "[
{
@ -293,7 +293,7 @@ begin_test "fetch-all"
for ((a=0; a < NUMFILES ; a++))
do
content[$a]="filecontent$a"
oid[$a]=$(printf "${content[$a]}" | shasum -a 256 | cut -f 1 -d " ")
oid[$a]=$(calc_oid "${content[$a]}")
done
echo "[

@ -27,7 +27,7 @@ begin_test "happy path"
grep "Tracking \*.dat" track.log
contents="a"
contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ")
contents_oid=$(calc_oid "$contents")
# Regular Git commands can be used.
printf "$contents" > a.dat

@ -204,7 +204,7 @@ begin_test "pre-push with missing pointer which is on server"
clone_repo "$reponame" missing-but-on-server
contents="common data"
contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ")
contents_oid=$(calc_oid "$contents")
git lfs track "*.dat"
printf "$contents" > common1.dat
git add common1.dat
@ -269,7 +269,7 @@ begin_test "pre-push with missing pointer which is on server (BATCH)"
clone_repo "$reponame" missing-but-on-server-batch
contents="common data"
contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ")
contents_oid=$(calc_oid "$contents")
git lfs track "*.dat"
printf "$contents" > common1.dat
git add common1.dat
@ -319,7 +319,7 @@ begin_test "pre-push multiple branches"
for ((a=0; a < NUMFILES ; a++))
do
content[$a]="filecontent$a"
oid[$a]=$(printf "${content[$a]}" | shasum -a 256 | cut -f 1 -d " ")
oid[$a]=$(calc_oid "${content[$a]}")
done
echo "[

@ -17,7 +17,7 @@ begin_test "pull"
grep "Tracking \*.dat" track.log
contents="a"
contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ")
contents_oid=$(calc_oid "$contents")
printf "$contents" > a.dat
git add a.dat

139
test/test-push-failures.sh Executable file

@ -0,0 +1,139 @@
#!/usr/bin/env bash
. "test/testlib.sh"
begin_test "push: upload to bad dns"
(
set -e
reponame="$(basename "$0" ".sh")-bad-dns"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
git lfs track "*.dat"
printf "hi" > good.dat
git add .gitattributes good.dat
git commit -m "welp"
port="$(echo "http://127.0.0.1:63378" | cut -f 3 -d ":")"
git config lfs.url "http://git-lfs-bad-dns:$port"
set +e
GIT_TERMINAL_PROMPT=0 git push origin master
res="$?"
set -e
refute_server_object "$reponame" "$(calc_oid "hi")"
if [ "$res" = "0" ]; then
echo "push successful?"
exit 1
fi
)
end_test
push_fail_test() {
local contents="$1"
set -e
local reponame="$(basename "$0" ".sh")-$contents"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
git lfs track "*.dat"
printf "hi" > good.dat
printf "$contents" > bad.dat
git add .gitattributes good.dat bad.dat
git commit -m "welp"
set +e
git push origin master
res="$?"
set -e
refute_server_object "$reponame" "$(calc_oid "$contents")"
if [ "$res" = "0" ]; then
echo "push successful?"
exit 1
fi
}
begin_test "push: upload file with storage 403"
(
set -e
push_fail_test "status-storage-403"
)
end_test
begin_test "push: upload file with storage 404"
(
set -e
push_fail_test "status-storage-404"
)
end_test
begin_test "push: upload file with storage 410"
(
set -e
push_fail_test "status-storage-410"
)
end_test
begin_test "push: upload file with storage 422"
(
set -e
push_fail_test "status-storage-422"
)
end_test
begin_test "push: upload file with storage 500"
(
set -e
push_fail_test "status-storage-500"
)
end_test
begin_test "push: upload file with api 403"
(
set -e
push_fail_test "status-batch-403"
)
end_test
begin_test "push: upload file with api 404"
(
set -e
push_fail_test "status-batch-404"
)
end_test
begin_test "push: upload file with api 410"
(
set -e
push_fail_test "status-batch-410"
)
end_test
begin_test "push: upload file with api 422"
(
set -e
push_fail_test "status-batch-422"
)
end_test
begin_test "push: upload file with api 500"
(
set -e
push_fail_test "status-batch-500"
)
end_test

141
test/test-push-legacy-failures.sh Executable file

@ -0,0 +1,141 @@
#!/usr/bin/env bash
. "test/testlib.sh"
begin_test "push (legacy): upload to bad dns"
(
set -e
reponame="$(basename "$0" ".sh")-bad-dns"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
git lfs track "*.dat"
printf "hi" > good.dat
git add .gitattributes good.dat
git commit -m "welp"
port="$(echo "http://127.0.0.1:63378" | cut -f 3 -d ":")"
git config lfs.batch false
git config lfs.url "http://git-lfs-bad-dns:$port"
set +e
GIT_TERMINAL_PROMPT=0 git push origin master
res="$?"
set -e
refute_server_object "$reponame" "$(calc_oid "hi")"
if [ "$res" = "0" ]; then
echo "push successful?"
exit 1
fi
)
end_test
push_legacy_fail_test() {
local contents="$1"
set -e
local reponame="$(basename "$0" ".sh")-$contents"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
git config lfs.batch false
git lfs track "*.dat"
printf "hi" > good.dat
printf "$contents" > bad.dat
git add .gitattributes good.dat bad.dat
git commit -m "welp"
set +e
git push origin master
res="$?"
set -e
refute_server_object "$reponame" "$(calc_oid "$contents")"
if [ "$res" = "0" ]; then
echo "push successful?"
exit 1
fi
}
begin_test "push (legacy): upload file with storage 403"
(
set -e
push_legacy_fail_test "status-storage-403"
)
end_test
begin_test "push (legacy): upload file with storage 404"
(
set -e
push_legacy_fail_test "status-storage-404"
)
end_test
begin_test "push (legacy): upload file with storage 410"
(
set -e
push_legacy_fail_test "status-storage-410"
)
end_test
begin_test "push (legacy): upload file with storage 422"
(
set -e
push_legacy_fail_test "status-storage-422"
)
end_test
begin_test "push (legacy): upload file with storage 500"
(
set -e
push_legacy_fail_test "status-storage-500"
)
end_test
begin_test "push (legacy): upload file with api 403"
(
set -e
push_legacy_fail_test "status-legacy-403"
)
end_test
begin_test "push (legacy): upload file with api 404"
(
set -e
push_legacy_fail_test "status-legacy-404"
)
end_test
begin_test "push (legacy): upload file with api 410"
(
set -e
push_legacy_fail_test "status-legacy-410"
)
end_test
begin_test "push (legacy): upload file with api 422"
(
set -e
push_legacy_fail_test "status-legacy-422"
)
end_test
begin_test "push (legacy): upload file with api 500"
(
set -e
push_legacy_fail_test "status-legacy-500"
)
end_test

@ -56,12 +56,12 @@ push_all_setup() {
content4="tagged"
content5="master"
extracontent="extra"
oid1=$(printf "$content1" | shasum -a 256 | cut -f 1 -d " ")
oid2=$(printf "$content2" | shasum -a 256 | cut -f 1 -d " ")
oid3=$(printf "$content3" | shasum -a 256 | cut -f 1 -d " ")
oid4=$(printf "$content4" | shasum -a 256 | cut -f 1 -d " ")
oid5=$(printf "$content5" | shasum -a 256 | cut -f 1 -d " ")
extraoid=$(printf "$extracontent" | shasum -a 256 | cut -f 1 -d " ")
oid1=$(calc_oid "$content1")
oid2=$(calc_oid "$content2")
oid3=$(calc_oid "$content3")
oid4=$(calc_oid "$content4")
oid5=$(calc_oid "$content5")
extraoid=$(calc_oid "$extracontent")
# if the local repo exists, it has already been bootstrapped
[ -d "push-all" ] && exit 0
@ -369,11 +369,11 @@ begin_test "push modified files"
content3="filecontent3"
content4="filecontent4"
content5="filecontent5"
oid1=$(printf "$content1" | shasum -a 256 | cut -f 1 -d " ")
oid2=$(printf "$content2" | shasum -a 256 | cut -f 1 -d " ")
oid3=$(printf "$content3" | shasum -a 256 | cut -f 1 -d " ")
oid4=$(printf "$content4" | shasum -a 256 | cut -f 1 -d " ")
oid5=$(printf "$content5" | shasum -a 256 | cut -f 1 -d " ")
oid1=$(calc_oid "$content1")
oid2=$(calc_oid "$content2")
oid3=$(calc_oid "$content3")
oid4=$(calc_oid "$content4")
oid5=$(calc_oid "$content5")
echo "[
{

@ -323,6 +323,10 @@ comparison_to_operator() {
fi
}
calc_oid() {
printf "$1" | shasum -a 256 | cut -f 1 -d " "
}
# Get a date string with an offset
# Args: One or more date offsets of the form (regex) "[+-]\d+[dmyHM]"
# e.g. +1d = 1 day forward from today