Commit 86d2264c authored by Kamil Trzcinski's avatar Kamil Trzcinski

Add tests to support upload mechanism

parent b2c75b57
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"regexp"
"testing"
)
func okHandler(w http.ResponseWriter, r *gitRequest) {
w.WriteHeader(201)
fmt.Fprint(w, "{\"status\":\"ok\"}")
}
func runPreAuthorizeHandler(t *testing.T, suffix string, url *regexp.Regexp, authorizationResponse interface{}, returnCode, expectedCode int) *httptest.ResponseRecorder {
// Prepare test server and backend
ts := testAuthServer(url, returnCode, authorizationResponse)
defer ts.Close()
// Create http request
httpRequest, err := http.NewRequest("GET", "/address", nil)
if err != nil {
t.Fatal(err)
}
request := gitRequest{
Request: httpRequest,
u: newUpstream(ts.URL, nil),
}
response := httptest.NewRecorder()
preAuthorizeHandler(okHandler, suffix)(response, &request)
assertResponseCode(t, response, expectedCode)
return response
}
func TestPreAuthorizeHappyPath(t *testing.T) {
runPreAuthorizeHandler(
t, "/authorize",
regexp.MustCompile(`/authorize\z`),
&authorizationResponse{},
200, 201)
}
func TestPreAuthorizeSuffix(t *testing.T) {
runPreAuthorizeHandler(
t, "/different-authorize",
regexp.MustCompile(`/authorize\z`),
&authorizationResponse{},
200, 404)
}
func TestPreAuthorizeJsonFailure(t *testing.T) {
runPreAuthorizeHandler(
t, "/authorize",
regexp.MustCompile(`/authorize\z`),
"not-json",
200, 500)
}
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"reflect"
"testing"
)
func TestGzipEncoding(t *testing.T) {
resp := httptest.NewRecorder()
var b bytes.Buffer
w := gzip.NewWriter(&b)
fmt.Fprint(w, "test")
w.Close()
body := ioutil.NopCloser(&b)
req, err := http.NewRequest("POST", "http://address/test", body)
if err != nil {
t.Fatal(err)
}
req.Header.Set("Content-Encoding", "gzip")
request := gitRequest{Request: req}
contentEncodingHandler(func(w http.ResponseWriter, r *gitRequest) {
if _, ok := r.Body.(*gzip.Reader); !ok {
t.Fatal("Expected gzip reader for body, but it's:", reflect.TypeOf(r.Body))
}
if r.Header.Get("Content-Encoding") != "" {
t.Fatal("Content-Encoding should be deleted")
}
})(resp, &request)
assertResponseCode(t, resp, 200)
}
func TestNoEncoding(t *testing.T) {
resp := httptest.NewRecorder()
var b bytes.Buffer
body := ioutil.NopCloser(&b)
req, err := http.NewRequest("POST", "http://address/test", body)
if err != nil {
t.Fatal(err)
}
req.Header.Set("Content-Encoding", "")
request := gitRequest{Request: req}
contentEncodingHandler(func(w http.ResponseWriter, r *gitRequest) {
if r.Body != body {
t.Fatal("Expected the same body")
}
if r.Header.Get("Content-Encoding") != "" {
t.Fatal("Content-Encoding should be deleted")
}
})(resp, &request)
assertResponseCode(t, resp, 200)
}
func TestInvalidEncoding(t *testing.T) {
resp := httptest.NewRecorder()
req, err := http.NewRequest("POST", "http://address/test", nil)
if err != nil {
t.Fatal(err)
}
req.Header.Set("Content-Encoding", "application/unknown")
request := gitRequest{Request: req}
contentEncodingHandler(func(w http.ResponseWriter, r *gitRequest) {
t.Fatal("it shouldn't be executed")
})(resp, &request)
assertResponseCode(t, resp, 500)
}
package main
import (
"net/http/httptest"
"testing"
)
func assertResponseCode(t *testing.T, response *httptest.ResponseRecorder, expectedCode int) {
if response.Code != expectedCode {
t.Fatalf("for HTTP request expected to get %d, got %d instead", expectedCode, response.Code)
}
}
...@@ -2,6 +2,7 @@ package main ...@@ -2,6 +2,7 @@ package main
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
...@@ -10,6 +11,7 @@ import ( ...@@ -10,6 +11,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"path" "path"
"regexp"
"testing" "testing"
"time" "time"
) )
...@@ -29,7 +31,7 @@ func TestAllowedClone(t *testing.T) { ...@@ -29,7 +31,7 @@ func TestAllowedClone(t *testing.T) {
} }
// Prepare test server and backend // Prepare test server and backend
ts := testAuthServer(200, gitOkBody(t)) ts := testAuthServer(nil, 200, gitOkBody(t))
defer ts.Close() defer ts.Close()
ws := startWorkhorseServer(ts.URL) ws := startWorkhorseServer(ts.URL)
defer ws.Close() defer ws.Close()
...@@ -51,7 +53,7 @@ func TestDeniedClone(t *testing.T) { ...@@ -51,7 +53,7 @@ func TestDeniedClone(t *testing.T) {
} }
// Prepare test server and backend // Prepare test server and backend
ts := testAuthServer(403, "Access denied") ts := testAuthServer(nil, 403, "Access denied")
defer ts.Close() defer ts.Close()
ws := startWorkhorseServer(ts.URL) ws := startWorkhorseServer(ts.URL)
defer ws.Close() defer ws.Close()
...@@ -69,7 +71,7 @@ func TestAllowedPush(t *testing.T) { ...@@ -69,7 +71,7 @@ func TestAllowedPush(t *testing.T) {
preparePushRepo(t) preparePushRepo(t)
// Prepare the test server and backend // Prepare the test server and backend
ts := testAuthServer(200, gitOkBody(t)) ts := testAuthServer(nil, 200, gitOkBody(t))
defer ts.Close() defer ts.Close()
ws := startWorkhorseServer(ts.URL) ws := startWorkhorseServer(ts.URL)
defer ws.Close() defer ws.Close()
...@@ -84,7 +86,7 @@ func TestDeniedPush(t *testing.T) { ...@@ -84,7 +86,7 @@ func TestDeniedPush(t *testing.T) {
preparePushRepo(t) preparePushRepo(t)
// Prepare the test server and backend // Prepare the test server and backend
ts := testAuthServer(403, "Access denied") ts := testAuthServer(nil, 403, "Access denied")
defer ts.Close() defer ts.Close()
ws := startWorkhorseServer(ts.URL) ws := startWorkhorseServer(ts.URL)
defer ws.Close() defer ws.Close()
...@@ -104,7 +106,7 @@ func TestAllowedDownloadZip(t *testing.T) { ...@@ -104,7 +106,7 @@ func TestAllowedDownloadZip(t *testing.T) {
// Prepare test server and backend // Prepare test server and backend
archiveName := "foobar.zip" archiveName := "foobar.zip"
ts := testAuthServer(200, archiveOkBody(t, archiveName)) ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
defer ts.Close() defer ts.Close()
ws := startWorkhorseServer(ts.URL) ws := startWorkhorseServer(ts.URL)
defer ws.Close() defer ws.Close()
...@@ -123,7 +125,7 @@ func TestAllowedDownloadTar(t *testing.T) { ...@@ -123,7 +125,7 @@ func TestAllowedDownloadTar(t *testing.T) {
// Prepare test server and backend // Prepare test server and backend
archiveName := "foobar.tar" archiveName := "foobar.tar"
ts := testAuthServer(200, archiveOkBody(t, archiveName)) ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
defer ts.Close() defer ts.Close()
ws := startWorkhorseServer(ts.URL) ws := startWorkhorseServer(ts.URL)
defer ws.Close() defer ws.Close()
...@@ -142,7 +144,7 @@ func TestAllowedDownloadTarGz(t *testing.T) { ...@@ -142,7 +144,7 @@ func TestAllowedDownloadTarGz(t *testing.T) {
// Prepare test server and backend // Prepare test server and backend
archiveName := "foobar.tar.gz" archiveName := "foobar.tar.gz"
ts := testAuthServer(200, archiveOkBody(t, archiveName)) ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
defer ts.Close() defer ts.Close()
ws := startWorkhorseServer(ts.URL) ws := startWorkhorseServer(ts.URL)
defer ws.Close() defer ws.Close()
...@@ -161,7 +163,7 @@ func TestAllowedDownloadTarBz2(t *testing.T) { ...@@ -161,7 +163,7 @@ func TestAllowedDownloadTarBz2(t *testing.T) {
// Prepare test server and backend // Prepare test server and backend
archiveName := "foobar.tar.bz2" archiveName := "foobar.tar.bz2"
ts := testAuthServer(200, archiveOkBody(t, archiveName)) ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
defer ts.Close() defer ts.Close()
ws := startWorkhorseServer(ts.URL) ws := startWorkhorseServer(ts.URL)
defer ws.Close() defer ws.Close()
...@@ -180,7 +182,7 @@ func TestAllowedApiDownloadZip(t *testing.T) { ...@@ -180,7 +182,7 @@ func TestAllowedApiDownloadZip(t *testing.T) {
// Prepare test server and backend // Prepare test server and backend
archiveName := "foobar.zip" archiveName := "foobar.zip"
ts := testAuthServer(200, archiveOkBody(t, archiveName)) ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
defer ts.Close() defer ts.Close()
ws := startWorkhorseServer(ts.URL) ws := startWorkhorseServer(ts.URL)
defer ws.Close() defer ws.Close()
...@@ -199,7 +201,7 @@ func TestDownloadCacheHit(t *testing.T) { ...@@ -199,7 +201,7 @@ func TestDownloadCacheHit(t *testing.T) {
// Prepare test server and backend // Prepare test server and backend
archiveName := "foobar.zip" archiveName := "foobar.zip"
ts := testAuthServer(200, archiveOkBody(t, archiveName)) ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
defer ts.Close() defer ts.Close()
ws := startWorkhorseServer(ts.URL) ws := startWorkhorseServer(ts.URL)
defer ws.Close() defer ws.Close()
...@@ -230,7 +232,7 @@ func TestDownloadCacheCreate(t *testing.T) { ...@@ -230,7 +232,7 @@ func TestDownloadCacheCreate(t *testing.T) {
// Prepare test server and backend // Prepare test server and backend
archiveName := "foobar.zip" archiveName := "foobar.zip"
ts := testAuthServer(200, archiveOkBody(t, archiveName)) ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
defer ts.Close() defer ts.Close()
ws := startWorkhorseServer(ts.URL) ws := startWorkhorseServer(ts.URL)
defer ws.Close() defer ws.Close()
...@@ -281,12 +283,47 @@ func newBranch() string { ...@@ -281,12 +283,47 @@ func newBranch() string {
return fmt.Sprintf("branch-%d", time.Now().UnixNano()) return fmt.Sprintf("branch-%d", time.Now().UnixNano())
} }
func testAuthServer(code int, body string) *httptest.Server { func testServerWithHandler(url *regexp.Regexp, handler http.HandlerFunc) *httptest.Server {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if url != nil && !url.MatchString(r.URL.Path) {
log.Println("UPSTREAM", r.Method, r.URL, "DENY")
w.WriteHeader(404)
return
}
if version := r.Header.Get("Gitlab-Workhorse"); version == "" {
log.Println("UPSTREAM", r.Method, r.URL, "DENY")
w.WriteHeader(403)
return
}
handler(w, r)
}))
}
func testAuthServer(url *regexp.Regexp, code int, body interface{}) *httptest.Server {
return testServerWithHandler(url, func(w http.ResponseWriter, r *http.Request) {
// Write pure string
if data, ok := body.(string); ok {
log.Println("UPSTREAM", r.Method, r.URL, code) log.Println("UPSTREAM", r.Method, r.URL, code)
w.WriteHeader(code) w.WriteHeader(code)
fmt.Fprint(w, body) fmt.Fprint(w, data)
})) return
}
// Write json string
data, err := json.Marshal(body)
if err != nil {
log.Println("UPSTREAM", r.Method, r.URL, "FAILURE", err)
w.WriteHeader(503)
fmt.Fprint(w, err)
return
}
log.Println("UPSTREAM", r.Method, r.URL, code)
w.WriteHeader(code)
w.Write(data)
})
} }
func startWorkhorseServer(authBackend string) *httptest.Server { func startWorkhorseServer(authBackend string) *httptest.Server {
...@@ -301,23 +338,26 @@ func runOrFail(t *testing.T, cmd *exec.Cmd) { ...@@ -301,23 +338,26 @@ func runOrFail(t *testing.T, cmd *exec.Cmd) {
} }
} }
func gitOkBody(t *testing.T) string { func gitOkBody(t *testing.T) interface{} {
return fmt.Sprintf(`{"GL_ID":"user-123","RepoPath":"%s"}`, repoPath(t)) return &authorizationResponse{
GL_ID: "user-123",
RepoPath: repoPath(t),
}
} }
func archiveOkBody(t *testing.T, archiveName string) string { func archiveOkBody(t *testing.T, archiveName string) interface{} {
cwd, err := os.Getwd() cwd, err := os.Getwd()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
archivePath := path.Join(cwd, cacheDir, archiveName) archivePath := path.Join(cwd, cacheDir, archiveName)
jsonString := `{
"RepoPath":"%s", return &authorizationResponse{
"ArchivePath":"%s", RepoPath: repoPath(t),
"CommitId":"c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd", ArchivePath: archivePath,
"ArchivePrefix":"foobar123" CommitId: "c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd",
}` ArchivePrefix: "foobar123",
return fmt.Sprintf(jsonString, repoPath(t), archivePath) }
} }
func repoPath(t *testing.T) string { func repoPath(t *testing.T) string {
......
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"net/http/httptest"
"regexp"
"testing"
)
func TestProxyRequest(t *testing.T) {
ts := testServerWithHandler(regexp.MustCompile(`/url/path\z`), func(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
t.Fatal("Expected POST request")
}
if r.Header.Get("Custom-Header") != "test" {
t.Fatal("Missing custom header")
}
var body bytes.Buffer
io.Copy(&body, r.Body)
if body.String() != "REQUEST" {
t.Fatal("Expected REQUEST in request body")
}
w.Header().Set("Custom-Response-Header", "test")
w.WriteHeader(202)
fmt.Fprint(w, "RESPONSE")
})
httpRequest, err := http.NewRequest("POST", ts.URL+"/url/path", bytes.NewBufferString("REQUEST"))
if err != nil {
t.Fatal(err)
}
httpRequest.Header.Set("Custom-Header", "test")
request := gitRequest{
Request: httpRequest,
u: newUpstream(ts.URL, nil),
}
response := httptest.NewRecorder()
proxyRequest(response, &request)
assertResponseCode(t, response, 202)
if response.Body.String() != "RESPONSE" {
t.Fatal("Expected RESPONSE in response body:", response.Body.String())
}
if response.Header().Get("Custom-Response-Header") != "test" {
t.Fatal("Expected custom response header")
}
}
...@@ -59,7 +59,7 @@ func rewriteFormFilesFromMultipart(r *gitRequest, writer *multipart.Writer) (cle ...@@ -59,7 +59,7 @@ func rewriteFormFilesFromMultipart(r *gitRequest, writer *multipart.Writer) (cle
// Add file entry // Add file entry
writer.WriteField(name+".path", file.Name()) writer.WriteField(name+".path", file.Name())
writer.WriteField(name+".file", filename) writer.WriteField(name+".name", filename)
files = append(files, file.Name()) files = append(files, file.Name())
_, err = io.Copy(file, p) _, err = io.Copy(file, p)
......
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/http/httptest"
"os"
"regexp"
"strings"
"testing"
)
func TestUploadTempPathRequirement(t *testing.T) {
response := httptest.NewRecorder()
request := gitRequest{
authorizationResponse: authorizationResponse{
TempPath: "",
},
}
handleFileUploads(response, &request)
assertResponseCode(t, response, 500)
}
func TestUploadHandlerForwardingRawData(t *testing.T) {
ts := testServerWithHandler(regexp.MustCompile(`/url/path\z`), func(w http.ResponseWriter, r *http.Request) {
if r.Method != "PATCH" {
t.Fatal("Expected PATCH request")
}
var body bytes.Buffer
io.Copy(&body, r.Body)
if body.String() != "REQUEST" {
t.Fatal("Expected REQUEST in request body")
}
w.WriteHeader(202)
fmt.Fprint(w, "RESPONSE")
})
httpRequest, err := http.NewRequest("PATCH", ts.URL+"/url/path", bytes.NewBufferString("REQUEST"))
if err != nil {
t.Fatal(err)
}
tempPath, err := ioutil.TempDir("", "uploads")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempPath)
response := httptest.NewRecorder()
request := gitRequest{
Request: httpRequest,
u: newUpstream(ts.URL, nil),
authorizationResponse: authorizationResponse{
TempPath: tempPath,
},
}
handleFileUploads(response, &request)
assertResponseCode(t, response, 202)
if response.Body.String() != "RESPONSE" {
t.Fatal("Expected RESPONSE in response body")
}
}
func TestUploadHandlerRewritingMultiPartData(t *testing.T) {
var filePath string
tempPath, err := ioutil.TempDir("", "uploads")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempPath)
ts := testServerWithHandler(regexp.MustCompile(`/url/path\z`), func(w http.ResponseWriter, r *http.Request) {
if r.Method != "PUT" {
t.Fatal("Expected PUT request")
}
err := r.ParseMultipartForm(100000)
if err != nil {
t.Fatal(err)
}
if len(r.MultipartForm.Value) != 3 {
t.Fatal("Expected to receive exactly 3 values")
}
if len(r.MultipartForm.File) != 0 {
t.Fatal("Expected to not receive any files")
}
if r.FormValue("token") != "test" {
t.Fatal("Expected to receive token")
}
if r.FormValue("file.name") != "my.file" {
t.Fatal("Expected to receive a filename")
}
filePath = r.FormValue("file.path")
if !strings.HasPrefix(r.FormValue("file.path"), tempPath) {
t.Fatal("Expected to the file to be in tempPath")
}
w.WriteHeader(202)
fmt.Fprint(w, "RESPONSE")
})
var buffer bytes.Buffer
writer := multipart.NewWriter(&buffer)
writer.WriteField("token", "test")
file, err := writer.CreateFormFile("file", "my.file")
if err != nil {
t.Fatal(err)
}
fmt.Fprint(file, "test")
writer.Close()
httpRequest, err := http.NewRequest("PUT", ts.URL+"/url/path", nil)
if err != nil {
t.Fatal(err)
}
httpRequest.Body = ioutil.NopCloser(&buffer)
httpRequest.ContentLength = int64(buffer.Len())
httpRequest.Header.Set("Content-Type", writer.FormDataContentType())
response := httptest.NewRecorder()
request := gitRequest{
Request: httpRequest,
u: newUpstream(ts.URL, nil),
authorizationResponse: authorizationResponse{
TempPath: tempPath,
},
}
handleFileUploads(response, &request)
assertResponseCode(t, response, 202)
if _, err := os.Stat(filePath); !os.IsNotExist(err) {
t.Fatal("expected the file to be deleted")
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment