Commit aa15b3a4 authored by Janoš Guljaš's avatar Janoš Guljaš Committed by GitHub

cleanup jsonhttptest package (#577)

parent 24d5b25a
...@@ -41,9 +41,12 @@ func TestBytes(t *testing.T) { ...@@ -41,9 +41,12 @@ func TestBytes(t *testing.T) {
} }
t.Run("upload", func(t *testing.T) { t.Run("upload", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, client, http.MethodPost, resource, bytes.NewReader(content), http.StatusOK, api.BytesPostResponse{ jsonhttptest.Request(t, client, http.MethodPost, resource, http.StatusOK,
jsonhttptest.WithRequestBody(bytes.NewReader(content)),
jsonhttptest.WithExpectedJSONResponse(api.BytesPostResponse{
Reference: swarm.MustParseHexAddress(expHash), Reference: swarm.MustParseHexAddress(expHash),
}) }),
)
}) })
t.Run("download", func(t *testing.T) { t.Run("download", func(t *testing.T) {
...@@ -67,9 +70,11 @@ func TestBytes(t *testing.T) { ...@@ -67,9 +70,11 @@ func TestBytes(t *testing.T) {
}) })
t.Run("not found", func(t *testing.T) { t.Run("not found", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, client, http.MethodGet, resource+"/abcd", nil, http.StatusNotFound, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodGet, resource+"/abcd", http.StatusNotFound,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "not found", Message: "not found",
Code: http.StatusNotFound, Code: http.StatusNotFound,
}) }),
)
}) })
} }
...@@ -132,7 +132,9 @@ func TestBzz(t *testing.T) { ...@@ -132,7 +132,9 @@ func TestBzz(t *testing.T) {
// read file from manifest path // read file from manifest path
rcvdHeader := jsonhttptest.ResponseDirectCheckBinaryResponse(t, client, http.MethodGet, bzzDownloadResource(manifestFileReference.String(), filePath), nil, http.StatusOK, []byte(sampleHtml), nil) rcvdHeader := jsonhttptest.Request(t, client, http.MethodGet, bzzDownloadResource(manifestFileReference.String(), filePath), http.StatusOK,
jsonhttptest.WithExpectedResponse([]byte(sampleHtml)),
)
cd := rcvdHeader.Get("Content-Disposition") cd := rcvdHeader.Get("Content-Disposition")
_, params, err := mime.ParseMediaType(cd) _, params, err := mime.ParseMediaType(cd)
if err != nil { if err != nil {
...@@ -150,11 +152,12 @@ func TestBzz(t *testing.T) { ...@@ -150,11 +152,12 @@ func TestBzz(t *testing.T) {
// check on invalid path // check on invalid path
jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodGet, bzzDownloadResource(manifestFileReference.String(), missingFilePath), nil, http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodGet, bzzDownloadResource(manifestFileReference.String(), missingFilePath), http.StatusBadRequest,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "invalid path address", Message: "invalid path address",
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
}, nil) }),
)
}) })
} }
...@@ -44,30 +44,39 @@ func TestChunkUploadDownload(t *testing.T) { ...@@ -44,30 +44,39 @@ func TestChunkUploadDownload(t *testing.T) {
) )
t.Run("invalid hash", func(t *testing.T) { t.Run("invalid hash", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, client, http.MethodPost, resource(invalidHash), bytes.NewReader(validContent), http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodPost, resource(invalidHash), http.StatusBadRequest,
jsonhttptest.WithRequestBody(bytes.NewReader(validContent)),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "chunk write error", Message: "chunk write error",
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
}) }),
)
// make sure chunk is not retrievable // make sure chunk is not retrievable
_ = request(t, client, http.MethodGet, resource(invalidHash), nil, http.StatusNotFound) _ = request(t, client, http.MethodGet, resource(invalidHash), nil, http.StatusNotFound)
}) })
t.Run("invalid content", func(t *testing.T) { t.Run("invalid content", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, client, http.MethodPost, resource(validHash), bytes.NewReader(invalidContent), http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodPost, resource(invalidHash), http.StatusBadRequest,
jsonhttptest.WithRequestBody(bytes.NewReader(invalidContent)),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "chunk write error", Message: "chunk write error",
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
}) }),
)
// make sure not retrievable // make sure not retrievable
_ = request(t, client, http.MethodGet, resource(validHash), nil, http.StatusNotFound) _ = request(t, client, http.MethodGet, resource(validHash), nil, http.StatusNotFound)
}) })
t.Run("ok", func(t *testing.T) { t.Run("ok", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, client, http.MethodPost, resource(validHash), bytes.NewReader(validContent), http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodPost, resource(validHash), http.StatusOK,
jsonhttptest.WithRequestBody(bytes.NewReader(validContent)),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
// try to fetch the same chunk // try to fetch the same chunk
resp := request(t, client, http.MethodGet, resource(validHash), nil, http.StatusOK) resp := request(t, client, http.MethodGet, resource(validHash), nil, http.StatusOK)
...@@ -82,12 +91,14 @@ func TestChunkUploadDownload(t *testing.T) { ...@@ -82,12 +91,14 @@ func TestChunkUploadDownload(t *testing.T) {
}) })
t.Run("pin-invalid-value", func(t *testing.T) { t.Run("pin-invalid-value", func(t *testing.T) {
headers := make(map[string][]string) jsonhttptest.Request(t, client, http.MethodPost, resource(validHash), http.StatusOK,
headers[api.SwarmPinHeader] = []string{"hdgdh"} jsonhttptest.WithRequestBody(bytes.NewReader(validContent)),
jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, resource(validHash), bytes.NewReader(validContent), http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}, headers) }),
jsonhttptest.WithRequestHeader(api.SwarmPinHeader, "invalid-pin"),
)
// Also check if the chunk is NOT pinned // Also check if the chunk is NOT pinned
if mockValidatingStorer.GetModeSet(validHash) == storage.ModeSetPin { if mockValidatingStorer.GetModeSet(validHash) == storage.ModeSetPin {
...@@ -95,11 +106,13 @@ func TestChunkUploadDownload(t *testing.T) { ...@@ -95,11 +106,13 @@ func TestChunkUploadDownload(t *testing.T) {
} }
}) })
t.Run("pin-header-missing", func(t *testing.T) { t.Run("pin-header-missing", func(t *testing.T) {
headers := make(map[string][]string) jsonhttptest.Request(t, client, http.MethodPost, resource(validHash), http.StatusOK,
jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, resource(validHash), bytes.NewReader(validContent), http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.WithRequestBody(bytes.NewReader(validContent)),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}, headers) }),
)
// Also check if the chunk is NOT pinned // Also check if the chunk is NOT pinned
if mockValidatingStorer.GetModeSet(validHash) == storage.ModeSetPin { if mockValidatingStorer.GetModeSet(validHash) == storage.ModeSetPin {
...@@ -107,12 +120,14 @@ func TestChunkUploadDownload(t *testing.T) { ...@@ -107,12 +120,14 @@ func TestChunkUploadDownload(t *testing.T) {
} }
}) })
t.Run("pin-ok", func(t *testing.T) { t.Run("pin-ok", func(t *testing.T) {
headers := make(map[string][]string) jsonhttptest.Request(t, client, http.MethodPost, resource(validHash), http.StatusOK,
headers[api.SwarmPinHeader] = []string{"True"} jsonhttptest.WithRequestBody(bytes.NewReader(validContent)),
jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, resource(validHash), bytes.NewReader(validContent), http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}, headers) }),
jsonhttptest.WithRequestHeader(api.SwarmPinHeader, "True"),
)
// Also check if the chunk is pinned // Also check if the chunk is pinned
if mockValidatingStorer.GetModePut(validHash) != storage.ModePutUploadPin { if mockValidatingStorer.GetModePut(validHash) != storage.ModePutUploadPin {
......
...@@ -34,23 +34,27 @@ func TestDirs(t *testing.T) { ...@@ -34,23 +34,27 @@ func TestDirs(t *testing.T) {
) )
t.Run("empty request body", func(t *testing.T) { t.Run("empty request body", func(t *testing.T) {
jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, dirUploadResource, bytes.NewReader(nil), http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodPost, dirUploadResource, http.StatusBadRequest,
jsonhttptest.WithRequestBody(bytes.NewReader(nil)),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "could not validate request", Message: "could not validate request",
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
}, http.Header{ }),
"Content-Type": {api.ContentTypeTar}, jsonhttptest.WithRequestHeader("Content-Type", api.ContentTypeTar),
}) )
}) })
t.Run("non tar file", func(t *testing.T) { t.Run("non tar file", func(t *testing.T) {
file := bytes.NewReader([]byte("some data")) file := bytes.NewReader([]byte("some data"))
jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, dirUploadResource, file, http.StatusInternalServerError, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodPost, dirUploadResource, http.StatusInternalServerError,
jsonhttptest.WithRequestBody(file),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "could not store dir", Message: "could not store dir",
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
}, http.Header{ }),
"Content-Type": {api.ContentTypeTar}, jsonhttptest.WithRequestHeader("Content-Type", api.ContentTypeTar),
}) )
}) })
t.Run("wrong content type", func(t *testing.T) { t.Run("wrong content type", func(t *testing.T) {
...@@ -60,12 +64,14 @@ func TestDirs(t *testing.T) { ...@@ -60,12 +64,14 @@ func TestDirs(t *testing.T) {
}}) }})
// submit valid tar, but with wrong content-type // submit valid tar, but with wrong content-type
jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, dirUploadResource, tarReader, http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodPost, dirUploadResource, http.StatusBadRequest,
jsonhttptest.WithRequestBody(tarReader),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "could not validate request", Message: "could not validate request",
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
}, http.Header{ }),
"Content-Type": {"other"}, jsonhttptest.WithRequestHeader("Content-Type", "other"),
}) )
}) })
// valid tars // valid tars
...@@ -137,11 +143,13 @@ func TestDirs(t *testing.T) { ...@@ -137,11 +143,13 @@ func TestDirs(t *testing.T) {
tarReader := tarFiles(t, tc.files) tarReader := tarFiles(t, tc.files)
// verify directory tar upload response // verify directory tar upload response
jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, dirUploadResource, tarReader, http.StatusOK, api.FileUploadResponse{ jsonhttptest.Request(t, client, http.MethodPost, dirUploadResource, http.StatusOK,
jsonhttptest.WithRequestBody(tarReader),
jsonhttptest.WithExpectedJSONResponse(api.FileUploadResponse{
Reference: swarm.MustParseHexAddress(tc.expectedHash), Reference: swarm.MustParseHexAddress(tc.expectedHash),
}, http.Header{ }),
"Content-Type": {api.ContentTypeTar}, jsonhttptest.WithRequestHeader("Content-Type", api.ContentTypeTar),
}) )
// create expected manifest // create expected manifest
expectedManifest := jsonmanifest.NewManifest() expectedManifest := jsonmanifest.NewManifest()
...@@ -156,7 +164,9 @@ func TestDirs(t *testing.T) { ...@@ -156,7 +164,9 @@ func TestDirs(t *testing.T) {
} }
// verify directory upload manifest through files api // verify directory upload manifest through files api
jsonhttptest.ResponseDirectCheckBinaryResponse(t, client, http.MethodGet, fileDownloadResource(tc.expectedHash), nil, http.StatusOK, b, nil) jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(tc.expectedHash), http.StatusOK,
jsonhttptest.WithExpectedResponse(b),
)
}) })
} }
} }
......
...@@ -6,7 +6,6 @@ package api_test ...@@ -6,7 +6,6 @@ package api_test
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
...@@ -35,44 +34,46 @@ func TestFiles(t *testing.T) { ...@@ -35,44 +34,46 @@ func TestFiles(t *testing.T) {
client = newTestServer(t, testServerOptions{ client = newTestServer(t, testServerOptions{
Storer: mock.NewStorer(), Storer: mock.NewStorer(),
Tags: tags.NewTags(), Tags: tags.NewTags(),
Logger: logging.New(ioutil.Discard, 5),
}) })
) )
t.Run("invalid-content-type", func(t *testing.T) { t.Run("invalid-content-type", func(t *testing.T) {
jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, fileUploadResource, bytes.NewReader(simpleData), http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource, http.StatusBadRequest,
jsonhttptest.WithRequestBody(bytes.NewReader(simpleData)),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "invalid content-type header", Message: "invalid content-type header",
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
}, nil) }),
)
}) })
t.Run("multipart-upload", func(t *testing.T) { t.Run("multipart-upload", func(t *testing.T) {
fileName := "simple_file.txt" fileName := "simple_file.txt"
rootHash := "295673cf7aa55d119dd6f82528c91d45b53dd63dc2e4ca4abf4ed8b3a0788085" rootHash := "295673cf7aa55d119dd6f82528c91d45b53dd63dc2e4ca4abf4ed8b3a0788085"
_ = jsonhttptest.ResponseDirectWithMultiPart(t, client, http.MethodPost, fileUploadResource, fileName, simpleData, http.StatusOK, "", api.FileUploadResponse{ jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource, http.StatusOK,
jsonhttptest.WithMultipartRequest(bytes.NewReader(simpleData), len(simpleData), fileName, ""),
jsonhttptest.WithExpectedJSONResponse(api.FileUploadResponse{
Reference: swarm.MustParseHexAddress(rootHash), Reference: swarm.MustParseHexAddress(rootHash),
}) }),
)
}) })
t.Run("encrypt-decrypt", func(t *testing.T) { t.Run("encrypt-decrypt", func(t *testing.T) {
t.Skip("reenable after crypto refactor") t.Skip("reenable after crypto refactor")
fileName := "my-pictures.jpeg" fileName := "my-pictures.jpeg"
headers := make(http.Header)
headers.Add(api.EncryptHeader, "True")
headers.Add("Content-Type", "image/jpeg; charset=utf-8")
_, respBytes := jsonhttptest.ResponseDirectSendHeadersAndDontCheckResponse(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, bytes.NewReader(simpleData), http.StatusOK, headers)
read := bytes.NewReader(respBytes)
// get the reference as everytime it will change because of random encryption key
var resp api.FileUploadResponse var resp api.FileUploadResponse
err := json.NewDecoder(read).Decode(&resp) jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, http.StatusOK,
if err != nil { jsonhttptest.WithRequestBody(bytes.NewReader(simpleData)),
t.Fatal(err) jsonhttptest.WithRequestHeader(api.EncryptHeader, "True"),
} jsonhttptest.WithRequestHeader("Content-Type", "image/jpeg; charset=utf-8"),
jsonhttptest.WithUnmarshalJSONResponse(&resp),
)
rootHash := resp.Reference.String() rootHash := resp.Reference.String()
rcvdHeader := jsonhttptest.ResponseDirectCheckBinaryResponse(t, client, http.MethodGet, fileDownloadResource(rootHash), nil, http.StatusOK, simpleData, nil) rcvdHeader := jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(rootHash), http.StatusOK,
jsonhttptest.WithExpectedResponse(simpleData),
)
cd := rcvdHeader.Get("Content-Disposition") cd := rcvdHeader.Get("Content-Disposition")
_, params, err := mime.ParseMediaType(cd) _, params, err := mime.ParseMediaType(cd)
if err != nil { if err != nil {
...@@ -91,14 +92,17 @@ func TestFiles(t *testing.T) { ...@@ -91,14 +92,17 @@ func TestFiles(t *testing.T) {
rootHash := "f2e761160deda91c1fbfab065a5abf530b0766b3e102b51fbd626ba37c3bc581" rootHash := "f2e761160deda91c1fbfab065a5abf530b0766b3e102b51fbd626ba37c3bc581"
t.Run("binary", func(t *testing.T) { t.Run("binary", func(t *testing.T) {
headers := make(http.Header) jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, http.StatusOK,
headers.Add("Content-Type", "image/jpeg; charset=utf-8") jsonhttptest.WithRequestBody(bytes.NewReader(simpleData)),
jsonhttptest.WithExpectedJSONResponse(api.FileUploadResponse{
_ = jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, bytes.NewReader(simpleData), http.StatusOK, api.FileUploadResponse{
Reference: swarm.MustParseHexAddress(rootHash), Reference: swarm.MustParseHexAddress(rootHash),
}, headers) }),
jsonhttptest.WithRequestHeader("Content-Type", "image/jpeg; charset=utf-8"),
)
rcvdHeader := jsonhttptest.ResponseDirectCheckBinaryResponse(t, client, http.MethodGet, fileDownloadResource(rootHash), nil, http.StatusOK, simpleData, nil) rcvdHeader := jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(rootHash), http.StatusOK,
jsonhttptest.WithExpectedResponse(simpleData),
)
cd := rcvdHeader.Get("Content-Disposition") cd := rcvdHeader.Get("Content-Disposition")
_, params, err := mime.ParseMediaType(cd) _, params, err := mime.ParseMediaType(cd)
if err != nil { if err != nil {
...@@ -113,11 +117,16 @@ func TestFiles(t *testing.T) { ...@@ -113,11 +117,16 @@ func TestFiles(t *testing.T) {
}) })
t.Run("multipart", func(t *testing.T) { t.Run("multipart", func(t *testing.T) {
_ = jsonhttptest.ResponseDirectWithMultiPart(t, client, http.MethodPost, fileUploadResource, fileName, simpleData, http.StatusOK, "image/jpeg; charset=utf-8", api.FileUploadResponse{ jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource, http.StatusOK,
jsonhttptest.WithMultipartRequest(bytes.NewReader(simpleData), len(simpleData), fileName, "image/jpeg; charset=utf-8"),
jsonhttptest.WithExpectedJSONResponse(api.FileUploadResponse{
Reference: swarm.MustParseHexAddress(rootHash), Reference: swarm.MustParseHexAddress(rootHash),
}) }),
)
rcvdHeader := jsonhttptest.ResponseDirectCheckBinaryResponse(t, client, http.MethodGet, fileDownloadResource(rootHash), nil, http.StatusOK, simpleData, nil) rcvdHeader := jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(rootHash), http.StatusOK,
jsonhttptest.WithExpectedResponse(simpleData),
)
cd := rcvdHeader.Get("Content-Disposition") cd := rcvdHeader.Get("Content-Disposition")
_, params, err := mime.ParseMediaType(cd) _, params, err := mime.ParseMediaType(cd)
if err != nil { if err != nil {
...@@ -147,19 +156,22 @@ func TestFiles(t *testing.T) { ...@@ -147,19 +156,22 @@ func TestFiles(t *testing.T) {
</html>` </html>`
t.Run("binary", func(t *testing.T) { t.Run("binary", func(t *testing.T) {
headers := make(http.Header) rcvdHeader := jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, http.StatusOK,
headers.Add("Content-Type", "text/html; charset=utf-8") jsonhttptest.WithRequestBody(strings.NewReader(sampleHtml)),
jsonhttptest.WithExpectedJSONResponse(api.FileUploadResponse{
rcvdHeader := jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, strings.NewReader(sampleHtml), http.StatusOK, api.FileUploadResponse{
Reference: swarm.MustParseHexAddress(rootHash), Reference: swarm.MustParseHexAddress(rootHash),
}, headers) }),
jsonhttptest.WithRequestHeader("Content-Type", "text/html; charset=utf-8"),
)
if rcvdHeader.Get("ETag") != fmt.Sprintf("%q", rootHash) { if rcvdHeader.Get("ETag") != fmt.Sprintf("%q", rootHash) {
t.Fatal("Invalid ETags header received") t.Fatal("Invalid ETags header received")
} }
// try to fetch the same file and check the data // try to fetch the same file and check the data
rcvdHeader = jsonhttptest.ResponseDirectCheckBinaryResponse(t, client, http.MethodGet, fileDownloadResource(rootHash), nil, http.StatusOK, []byte(sampleHtml), nil) rcvdHeader = jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(rootHash), http.StatusOK,
jsonhttptest.WithExpectedResponse([]byte(sampleHtml)),
)
// check the headers // check the headers
cd := rcvdHeader.Get("Content-Disposition") cd := rcvdHeader.Get("Content-Disposition")
...@@ -176,16 +188,21 @@ func TestFiles(t *testing.T) { ...@@ -176,16 +188,21 @@ func TestFiles(t *testing.T) {
}) })
t.Run("multipart", func(t *testing.T) { t.Run("multipart", func(t *testing.T) {
rcvdHeader := jsonhttptest.ResponseDirectWithMultiPart(t, client, http.MethodPost, fileUploadResource, fileName, []byte(sampleHtml), http.StatusOK, "", api.FileUploadResponse{ rcvdHeader := jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource, http.StatusOK,
jsonhttptest.WithMultipartRequest(strings.NewReader(sampleHtml), len(sampleHtml), fileName, ""),
jsonhttptest.WithExpectedJSONResponse(api.FileUploadResponse{
Reference: swarm.MustParseHexAddress(rootHash), Reference: swarm.MustParseHexAddress(rootHash),
}) }),
)
if rcvdHeader.Get("ETag") != fmt.Sprintf("%q", rootHash) { if rcvdHeader.Get("ETag") != fmt.Sprintf("%q", rootHash) {
t.Fatal("Invalid ETags header received") t.Fatal("Invalid ETags header received")
} }
// try to fetch the same file and check the data // try to fetch the same file and check the data
rcvdHeader = jsonhttptest.ResponseDirectCheckBinaryResponse(t, client, http.MethodGet, fileDownloadResource(rootHash), nil, http.StatusOK, []byte(sampleHtml), nil) rcvdHeader = jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(rootHash), http.StatusOK,
jsonhttptest.WithExpectedResponse([]byte(sampleHtml)),
)
// check the headers // check the headers
cd := rcvdHeader.Get("Content-Disposition") cd := rcvdHeader.Get("Content-Disposition")
...@@ -205,14 +222,18 @@ func TestFiles(t *testing.T) { ...@@ -205,14 +222,18 @@ func TestFiles(t *testing.T) {
t.Run("upload-then-download-with-targets", func(t *testing.T) { t.Run("upload-then-download-with-targets", func(t *testing.T) {
fileName := "simple_file.txt" fileName := "simple_file.txt"
rootHash := "19d2e82c076031ec4e456978f839472d2f1b1b969a765420404d8d315a0c6123" rootHash := "19d2e82c076031ec4e456978f839472d2f1b1b969a765420404d8d315a0c6123"
headers := make(http.Header)
headers.Add("Content-Type", "text/html; charset=utf-8")
jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, bytes.NewReader(simpleData), http.StatusOK, api.FileUploadResponse{ jsonhttptest.Request(t, client, http.MethodPost, fileUploadResource+"?name="+fileName, http.StatusOK,
jsonhttptest.WithRequestBody(bytes.NewReader(simpleData)),
jsonhttptest.WithExpectedJSONResponse(api.FileUploadResponse{
Reference: swarm.MustParseHexAddress(rootHash), Reference: swarm.MustParseHexAddress(rootHash),
}, headers) }),
jsonhttptest.WithRequestHeader("Content-Type", "text/html; charset=utf-8"),
)
rcvdHeader := jsonhttptest.ResponseDirectCheckBinaryResponse(t, client, http.MethodGet, fileDownloadResource(rootHash)+"?targets="+targets, nil, http.StatusOK, simpleData, nil) rcvdHeader := jsonhttptest.Request(t, client, http.MethodGet, fileDownloadResource(rootHash)+"?targets="+targets, http.StatusOK,
jsonhttptest.WithExpectedResponse(simpleData),
)
if rcvdHeader.Get(api.TargetsRecoveryHeader) != targets { if rcvdHeader.Get(api.TargetsRecoveryHeader) != targets {
t.Fatalf("targets mismatch. got %s, want %s", rcvdHeader.Get(api.TargetsRecoveryHeader), targets) t.Fatalf("targets mismatch. got %s, want %s", rcvdHeader.Get(api.TargetsRecoveryHeader), targets)
...@@ -318,19 +339,23 @@ func TestRangeRequests(t *testing.T) { ...@@ -318,19 +339,23 @@ func TestRangeRequests(t *testing.T) {
Logger: logging.New(ioutil.Discard, 5), Logger: logging.New(ioutil.Discard, 5),
}) })
jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, upload.uploadEndpoint, upload.reader, http.StatusOK, api.FileUploadResponse{ jsonhttptest.Request(t, client, http.MethodPost, upload.uploadEndpoint, http.StatusOK,
jsonhttptest.WithRequestBody(upload.reader),
jsonhttptest.WithExpectedJSONResponse(api.FileUploadResponse{
Reference: swarm.MustParseHexAddress(upload.reference), Reference: swarm.MustParseHexAddress(upload.reference),
}, http.Header{ }),
"Content-Type": {upload.contentType}, jsonhttptest.WithRequestHeader("Content-Type", upload.contentType),
}) )
for _, tc := range ranges { for _, tc := range ranges {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
rangeHeader, want := createRangeHeader(data, tc.ranges) rangeHeader, want := createRangeHeader(data, tc.ranges)
respHeaders, body := jsonhttptest.ResponseDirectSendHeadersAndDontCheckResponse(t, client, http.MethodGet, upload.downloadEndpoint+"/"+upload.reference+upload.filepath, nil, http.StatusPartialContent, http.Header{ var body []byte
"Range": {rangeHeader}, respHeaders := jsonhttptest.Request(t, client, http.MethodGet, upload.downloadEndpoint+"/"+upload.reference+upload.filepath, http.StatusPartialContent,
}) jsonhttptest.WithRequestHeader("Range", rangeHeader),
jsonhttptest.WithPutResponseBody(&body),
)
got := parseRangeParts(t, respHeaders.Get("Content-Type"), body) got := parseRangeParts(t, respHeaders.Get("Content-Type"), body)
......
...@@ -6,7 +6,6 @@ package api_test ...@@ -6,7 +6,6 @@ package api_test
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"strconv" "strconv"
...@@ -48,14 +47,11 @@ func TestTags(t *testing.T) { ...@@ -48,14 +47,11 @@ func TestTags(t *testing.T) {
) )
t.Run("create-unnamed-tag", func(t *testing.T) { t.Run("create-unnamed-tag", func(t *testing.T) {
tReq := &api.TagRequest{}
b, err := json.Marshal(tReq)
if err != nil {
t.Fatal(err)
}
tr := api.TagResponse{} tr := api.TagResponse{}
jsonhttptest.ResponseUnmarshal(t, client, http.MethodPost, tagsResource, bytes.NewReader(b), http.StatusCreated, &tr) jsonhttptest.Request(t, client, http.MethodPost, tagsResource, http.StatusCreated,
jsonhttptest.WithJSONRequestBody(api.TagRequest{}),
jsonhttptest.WithUnmarshalJSONResponse(&tr),
)
if !strings.Contains(tr.Name, "unnamed_tag_") { if !strings.Contains(tr.Name, "unnamed_tag_") {
t.Fatalf("expected tag name to contain %s but is %s instead", "unnamed_tag_", tr.Name) t.Fatalf("expected tag name to contain %s but is %s instead", "unnamed_tag_", tr.Name)
...@@ -63,16 +59,13 @@ func TestTags(t *testing.T) { ...@@ -63,16 +59,13 @@ func TestTags(t *testing.T) {
}) })
t.Run("create-tag-with-name", func(t *testing.T) { t.Run("create-tag-with-name", func(t *testing.T) {
tReq := &api.TagRequest{
Name: someTagName,
}
b, err := json.Marshal(tReq)
if err != nil {
t.Fatal(err)
}
tr := api.TagResponse{} tr := api.TagResponse{}
jsonhttptest.ResponseUnmarshal(t, client, http.MethodPost, tagsResource, bytes.NewReader(b), http.StatusCreated, &tr) jsonhttptest.Request(t, client, http.MethodPost, tagsResource, http.StatusCreated,
jsonhttptest.WithJSONRequestBody(api.TagRequest{
Name: someTagName,
}),
jsonhttptest.WithUnmarshalJSONResponse(&tr),
)
if tr.Name != someTagName { if tr.Name != someTagName {
t.Fatalf("expected tag name to be %s but is %s instead", someTagName, tr.Name) t.Fatalf("expected tag name to be %s but is %s instead", someTagName, tr.Name)
...@@ -80,85 +73,96 @@ func TestTags(t *testing.T) { ...@@ -80,85 +73,96 @@ func TestTags(t *testing.T) {
}) })
t.Run("create-tag-from-chunk-upload-with-invalid-id", func(t *testing.T) { t.Run("create-tag-from-chunk-upload-with-invalid-id", func(t *testing.T) {
sentHeaders := make(http.Header) jsonhttptest.Request(t, client, http.MethodPost, chunksResource(someHash), http.StatusInternalServerError,
sentHeaders.Set(api.SwarmTagUidHeader, "invalid_id.jpg") // the value should be uint32 jsonhttptest.WithRequestBody(bytes.NewReader(someContent)),
_ = jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, chunksResource(someHash), bytes.NewReader(someContent), http.StatusInternalServerError, jsonhttp.StatusResponse{ jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "cannot get or create tag", Message: "cannot get or create tag",
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
}, sentHeaders) }),
jsonhttptest.WithRequestHeader(api.SwarmTagUidHeader, "invalid_id.jpg"), // the value should be uint32
)
}) })
t.Run("get-invalid-tags", func(t *testing.T) { t.Run("get-invalid-tags", func(t *testing.T) {
// invalid tag // invalid tag
jsonhttptest.ResponseDirect(t, client, http.MethodGet, tagsResource+"/foobar", nil, http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodGet, tagsResource+"/foobar", http.StatusBadRequest,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "invalid id", Message: "invalid id",
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
}) }),
)
// non-existent tag // non-existent tag
jsonhttptest.ResponseDirect(t, client, http.MethodDelete, tagsWithIdResource(uint32(333)), nil, http.StatusNotFound, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodDelete, tagsWithIdResource(uint32(333)), http.StatusNotFound,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "tag not present", Message: "tag not present",
Code: http.StatusNotFound, Code: http.StatusNotFound,
}) }),
)
}) })
t.Run("get-tag-id-from-chunk-upload-without-tag", func(t *testing.T) { t.Run("get-tag-id-from-chunk-upload-without-tag", func(t *testing.T) {
rcvdHeaders := jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, chunksResource(someHash), bytes.NewReader(someContent), http.StatusOK, jsonhttp.StatusResponse{ rcvdHeaders := jsonhttptest.Request(t, client, http.MethodPost, chunksResource(someHash), http.StatusOK,
jsonhttptest.WithRequestBody(bytes.NewReader(someContent)),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}, nil) }),
)
isTagFoundInResponse(t, rcvdHeaders, nil) isTagFoundInResponse(t, rcvdHeaders, nil)
}) })
t.Run("create-tag-and-use-it-to-upload-chunk", func(t *testing.T) { t.Run("create-tag-and-use-it-to-upload-chunk", func(t *testing.T) {
// create a tag using the API // create a tag using the API
b, err := json.Marshal(api.TagResponse{
Name: someTagName,
})
if err != nil {
t.Fatal(err)
}
tr := api.TagResponse{} tr := api.TagResponse{}
jsonhttptest.ResponseUnmarshal(t, client, http.MethodPost, tagsResource, bytes.NewReader(b), http.StatusCreated, &tr) jsonhttptest.Request(t, client, http.MethodPost, tagsResource, http.StatusCreated,
jsonhttptest.WithJSONRequestBody(api.TagResponse{
Name: someTagName,
}),
jsonhttptest.WithUnmarshalJSONResponse(&tr),
)
if tr.Name != someTagName { if tr.Name != someTagName {
t.Fatalf("sent tag name %s does not match received tag name %s", someTagName, tr.Name) t.Fatalf("sent tag name %s does not match received tag name %s", someTagName, tr.Name)
} }
// now upload a chunk and see if we receive a tag with the same id // now upload a chunk and see if we receive a tag with the same id
sentHeaders := make(http.Header) rcvdHeaders := jsonhttptest.Request(t, client, http.MethodPost, chunksResource(someHash), http.StatusOK,
sentHeaders.Set(api.SwarmTagUidHeader, strconv.FormatUint(uint64(tr.Uid), 10)) jsonhttptest.WithRequestBody(bytes.NewReader(someContent)),
rcvdHeaders := jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, chunksResource(someHash), bytes.NewReader(someContent), http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}, sentHeaders) }),
jsonhttptest.WithRequestHeader(api.SwarmTagUidHeader, strconv.FormatUint(uint64(tr.Uid), 10)),
)
isTagFoundInResponse(t, rcvdHeaders, &tr) isTagFoundInResponse(t, rcvdHeaders, &tr)
}) })
t.Run("create-tag-and-use-it-to-upload-multiple-chunks", func(t *testing.T) { t.Run("create-tag-and-use-it-to-upload-multiple-chunks", func(t *testing.T) {
// create a tag using the API // create a tag using the API
b, err := json.Marshal(api.TagResponse{
Name: someTagName,
})
if err != nil {
t.Fatal(err)
}
tr := api.TagResponse{} tr := api.TagResponse{}
jsonhttptest.ResponseUnmarshal(t, client, http.MethodPost, tagsResource, bytes.NewReader(b), http.StatusCreated, &tr) jsonhttptest.Request(t, client, http.MethodPost, tagsResource, http.StatusCreated,
jsonhttptest.WithJSONRequestBody(api.TagResponse{
Name: someTagName,
}),
jsonhttptest.WithUnmarshalJSONResponse(&tr),
)
if tr.Name != someTagName { if tr.Name != someTagName {
t.Fatalf("sent tag name %s does not match received tag name %s", someTagName, tr.Name) t.Fatalf("sent tag name %s does not match received tag name %s", someTagName, tr.Name)
} }
// now upload a chunk and see if we receive a tag with the same id // now upload a chunk and see if we receive a tag with the same id
sentHeaders := make(http.Header) rcvdHeaders := jsonhttptest.Request(t, client, http.MethodPost, chunksResource(someHash), http.StatusOK,
sentHeaders.Set(api.SwarmTagUidHeader, fmt.Sprint(tr.Uid)) jsonhttptest.WithRequestBody(bytes.NewReader(someContent)),
rcvdHeaders := jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, chunksResource(someHash), bytes.NewReader(someContent), http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}, sentHeaders) }),
jsonhttptest.WithRequestHeader(api.SwarmTagUidHeader, fmt.Sprint(tr.Uid)),
)
isTagFoundInResponse(t, rcvdHeaders, &tr) isTagFoundInResponse(t, rcvdHeaders, &tr)
...@@ -166,40 +170,51 @@ func TestTags(t *testing.T) { ...@@ -166,40 +170,51 @@ func TestTags(t *testing.T) {
secondValidHash := swarm.MustParseHexAddress("deadbeaf") secondValidHash := swarm.MustParseHexAddress("deadbeaf")
secondValidContent := []byte("123456") secondValidContent := []byte("123456")
sentHeaders = make(http.Header) rcvdHeaders = jsonhttptest.Request(t, client, http.MethodPost, chunksResource(secondValidHash), http.StatusOK,
sentHeaders.Set(api.SwarmTagUidHeader, fmt.Sprint(tr.Uid)) jsonhttptest.WithRequestBody(bytes.NewReader(secondValidContent)),
rcvdHeaders = jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, chunksResource(secondValidHash), bytes.NewReader(secondValidContent), http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}, sentHeaders) }),
jsonhttptest.WithRequestHeader(api.SwarmTagUidHeader, fmt.Sprint(tr.Uid)),
)
isTagFoundInResponse(t, rcvdHeaders, &tr) isTagFoundInResponse(t, rcvdHeaders, &tr)
}) })
t.Run("get-tag-from-chunk-upload-and-use-it-again", func(t *testing.T) { t.Run("get-tag-from-chunk-upload-and-use-it-again", func(t *testing.T) {
// upload a new chunk and get the generated tag id // upload a new chunk and get the generated tag id
rcvdHeaders := jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, chunksResource(someHash), bytes.NewReader(someContent), http.StatusOK, jsonhttp.StatusResponse{ rcvdHeaders := jsonhttptest.Request(t, client, http.MethodPost, chunksResource(someHash), http.StatusOK,
jsonhttptest.WithRequestBody(bytes.NewReader(someContent)),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}, nil) }),
)
id := isTagFoundInResponse(t, rcvdHeaders, nil) id := isTagFoundInResponse(t, rcvdHeaders, nil)
// see if the tag id is present and has valid values // see if the tag id is present and has valid values
tr := api.TagResponse{} tr := api.TagResponse{}
jsonhttptest.ResponseUnmarshal(t, client, http.MethodGet, tagsWithIdResource(id), nil, http.StatusOK, &tr) jsonhttptest.Request(t, client, http.MethodGet, tagsWithIdResource(id), http.StatusOK,
jsonhttptest.WithUnmarshalJSONResponse(&tr),
)
// now upload another chunk using the same tag id // now upload another chunk using the same tag id
sentHeaders := make(http.Header) jsonhttptest.Request(t, client, http.MethodPost, chunksResource(someHash), http.StatusOK,
sentHeaders.Set(api.SwarmTagUidHeader, fmt.Sprint(tr.Uid)) jsonhttptest.WithRequestBody(bytes.NewReader(someContent)),
_ = jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, chunksResource(someHash), bytes.NewReader(someContent), http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}, sentHeaders) }),
jsonhttptest.WithRequestHeader(api.SwarmTagUidHeader, fmt.Sprint(tr.Uid)),
)
// see if the tag id is present and has valid values // see if the tag id is present and has valid values
tr = api.TagResponse{} tr = api.TagResponse{}
jsonhttptest.ResponseUnmarshal(t, client, http.MethodGet, tagsWithIdResource(id), nil, http.StatusOK, &tr) jsonhttptest.Request(t, client, http.MethodGet, tagsWithIdResource(id), http.StatusOK,
jsonhttptest.WithUnmarshalJSONResponse(&tr),
)
if id != tr.Uid { if id != tr.Uid {
t.Fatalf("expected tag id to be %d but is %d", id, tr.Uid) t.Fatalf("expected tag id to be %d but is %d", id, tr.Uid)
...@@ -210,25 +225,33 @@ func TestTags(t *testing.T) { ...@@ -210,25 +225,33 @@ func TestTags(t *testing.T) {
}) })
t.Run("get-tag-using-id", func(t *testing.T) { t.Run("get-tag-using-id", func(t *testing.T) {
rcvdHeaders := jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, chunksResource(someHash), bytes.NewReader(someContent), http.StatusOK, jsonhttp.StatusResponse{ rcvdHeaders := jsonhttptest.Request(t, client, http.MethodPost, chunksResource(someHash), http.StatusOK,
jsonhttptest.WithRequestBody(bytes.NewReader(someContent)),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}, nil) }),
)
id := isTagFoundInResponse(t, rcvdHeaders, nil) id := isTagFoundInResponse(t, rcvdHeaders, nil)
// request the tag and see if the ID is the same // request the tag and see if the ID is the same
tr := api.TagResponse{} tr := api.TagResponse{}
jsonhttptest.ResponseUnmarshal(t, client, http.MethodGet, tagsWithIdResource(id), nil, http.StatusOK, &tr) jsonhttptest.Request(t, client, http.MethodGet, tagsWithIdResource(id), http.StatusOK,
jsonhttptest.WithUnmarshalJSONResponse(&tr),
)
if id != tr.Uid { if id != tr.Uid {
t.Fatalf("expected tag id to be %d but is %d", id, tr.Uid) t.Fatalf("expected tag id to be %d but is %d", id, tr.Uid)
} }
}) })
t.Run("tag-counters", func(t *testing.T) { t.Run("tag-counters", func(t *testing.T) {
rcvdHeaders := jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, chunksResource(someHash), bytes.NewReader(someContent), http.StatusOK, jsonhttp.StatusResponse{ rcvdHeaders := jsonhttptest.Request(t, client, http.MethodPost, chunksResource(someHash), http.StatusOK,
jsonhttptest.WithRequestBody(bytes.NewReader(someContent)),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}, nil) }),
)
id := isTagFoundInResponse(t, rcvdHeaders, nil) id := isTagFoundInResponse(t, rcvdHeaders, nil)
tagToVerify, err := tag.Get(id) tagToVerify, err := tag.Get(id)
...@@ -245,7 +268,9 @@ func TestTags(t *testing.T) { ...@@ -245,7 +268,9 @@ func TestTags(t *testing.T) {
} }
finalTag := api.TagResponse{} finalTag := api.TagResponse{}
jsonhttptest.ResponseUnmarshal(t, client, http.MethodGet, tagsWithIdResource(id), nil, http.StatusOK, &finalTag) jsonhttptest.Request(t, client, http.MethodGet, tagsWithIdResource(id), http.StatusOK,
jsonhttptest.WithUnmarshalJSONResponse(&finalTag),
)
if tagToVerify.Total != finalTag.Total { if tagToVerify.Total != finalTag.Total {
t.Errorf("tag total count mismatch. got %d want %d", tagToVerify.Total, finalTag.Total) t.Errorf("tag total count mismatch. got %d want %d", tagToVerify.Total, finalTag.Total)
...@@ -266,92 +291,101 @@ func TestTags(t *testing.T) { ...@@ -266,92 +291,101 @@ func TestTags(t *testing.T) {
t.Run("delete-tag-error", func(t *testing.T) { t.Run("delete-tag-error", func(t *testing.T) {
// try to delete invalid tag // try to delete invalid tag
jsonhttptest.ResponseDirect(t, client, http.MethodDelete, tagsResource+"/foobar", nil, http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodDelete, tagsResource+"/foobar", http.StatusBadRequest,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "invalid id", Message: "invalid id",
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
}) }),
)
// try to delete non-existent tag // try to delete non-existent tag
jsonhttptest.ResponseDirect(t, client, http.MethodDelete, tagsWithIdResource(uint32(333)), nil, http.StatusNotFound, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodDelete, tagsWithIdResource(uint32(333)), http.StatusNotFound,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "tag not present", Message: "tag not present",
Code: http.StatusNotFound, Code: http.StatusNotFound,
}) }),
)
}) })
t.Run("delete-tag", func(t *testing.T) { t.Run("delete-tag", func(t *testing.T) {
// create a tag through API // create a tag through API
b, err := json.Marshal(api.TagResponse{
Name: someTagName,
})
if err != nil {
t.Fatal(err)
}
tRes := api.TagResponse{} tRes := api.TagResponse{}
jsonhttptest.ResponseUnmarshal(t, client, http.MethodPost, tagsResource, bytes.NewReader(b), http.StatusCreated, &tRes) jsonhttptest.Request(t, client, http.MethodPost, tagsResource, http.StatusCreated,
jsonhttptest.WithJSONRequestBody(api.TagResponse{
Name: someTagName,
}),
jsonhttptest.WithUnmarshalJSONResponse(&tRes),
)
// delete tag through API // delete tag through API
jsonhttptest.ResponseDirect(t, client, http.MethodDelete, tagsWithIdResource(tRes.Uid), nil, http.StatusNoContent, nil) jsonhttptest.Request(t, client, http.MethodDelete, tagsWithIdResource(tRes.Uid), http.StatusNoContent,
jsonhttptest.WithNoResponseBody(),
)
// try to get tag // try to get tag
jsonhttptest.ResponseDirect(t, client, http.MethodGet, tagsWithIdResource(tRes.Uid), nil, http.StatusNotFound, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodGet, tagsWithIdResource(tRes.Uid), http.StatusNotFound,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "tag not present", Message: "tag not present",
Code: http.StatusNotFound, Code: http.StatusNotFound,
}) }),
)
}) })
t.Run("done-split-error", func(t *testing.T) { t.Run("done-split-error", func(t *testing.T) {
b, err := json.Marshal(api.TagResponse{})
if err != nil {
t.Fatal(err)
}
// invalid tag // invalid tag
jsonhttptest.ResponseDirect(t, client, http.MethodPatch, tagsResource+"/foobar", bytes.NewReader(b), http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodPatch, tagsResource+"/foobar", http.StatusBadRequest,
jsonhttptest.WithJSONRequestBody(api.TagResponse{}),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "invalid id", Message: "invalid id",
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
}) }),
)
// non-existent tag // non-existent tag
jsonhttptest.ResponseDirect(t, client, http.MethodPatch, tagsWithIdResource(uint32(333)), bytes.NewReader(b), http.StatusNotFound, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodPatch, tagsWithIdResource(uint32(333)), http.StatusNotFound,
jsonhttptest.WithJSONRequestBody(api.TagResponse{}),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "tag not present", Message: "tag not present",
Code: http.StatusNotFound, Code: http.StatusNotFound,
}) }),
)
}) })
t.Run("done-split", func(t *testing.T) { t.Run("done-split", func(t *testing.T) {
// create a tag through API // create a tag through API
tResB, err := json.Marshal(api.TagResponse{
Name: someTagName,
})
if err != nil {
t.Fatal(err)
}
tRes := api.TagResponse{} tRes := api.TagResponse{}
jsonhttptest.ResponseUnmarshal(t, client, http.MethodPost, tagsResource, bytes.NewReader(tResB), http.StatusCreated, &tRes) jsonhttptest.Request(t, client, http.MethodPost, tagsResource, http.StatusCreated,
jsonhttptest.WithJSONRequestBody(api.TagResponse{
Name: someTagName,
}),
jsonhttptest.WithUnmarshalJSONResponse(&tRes),
)
tagId := tRes.Uid tagId := tRes.Uid
// generate address to be supplied to the done split // generate address to be supplied to the done split
addr := test.RandomAddress() addr := test.RandomAddress()
tReqB, err := json.Marshal(api.TagRequest{
Address: addr,
})
if err != nil {
t.Fatal(err)
}
// upload content with tag // upload content with tag
sentHeaders := make(http.Header) jsonhttptest.Request(t, client, http.MethodPost, chunksResource(someHash), http.StatusOK,
sentHeaders.Set(api.SwarmTagUidHeader, fmt.Sprint(tagId)) jsonhttptest.WithRequestBody(bytes.NewReader(someContent)),
jsonhttptest.ResponseDirectSendHeadersAndDontCheckResponse(t, client, http.MethodPost, chunksResource(someHash), bytes.NewReader(someContent), http.StatusOK, sentHeaders) jsonhttptest.WithRequestHeader(api.SwarmTagUidHeader, fmt.Sprint(tagId)),
)
// call done split // call done split
jsonhttptest.ResponseDirect(t, client, http.MethodPatch, tagsWithIdResource(tagId), bytes.NewReader(tReqB), http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodPatch, tagsWithIdResource(tagId), http.StatusOK,
jsonhttptest.WithJSONRequestBody(api.TagRequest{
Address: addr,
}),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "ok", Message: "ok",
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
// check tag data // check tag data
jsonhttptest.ResponseUnmarshal(t, client, http.MethodGet, tagsWithIdResource(tagId), nil, http.StatusOK, &tRes) jsonhttptest.Request(t, client, http.MethodGet, tagsWithIdResource(tagId), http.StatusOK,
jsonhttptest.WithUnmarshalJSONResponse(&tRes),
)
if !tRes.Address.Equal(addr) { if !tRes.Address.Equal(addr) {
t.Fatalf("expected tag address to be %s but is %s", addr.String(), tRes.Address.String()) t.Fatalf("expected tag address to be %s but is %s", addr.String(), tRes.Address.String())
} }
...@@ -362,21 +396,22 @@ func TestTags(t *testing.T) { ...@@ -362,21 +396,22 @@ func TestTags(t *testing.T) {
// try different address value // try different address value
addr = test.RandomAddress() addr = test.RandomAddress()
tReqB, err = json.Marshal(api.TagRequest{
Address: addr,
})
if err != nil {
t.Fatal(err)
}
// call done split // call done split
jsonhttptest.ResponseDirect(t, client, http.MethodPatch, tagsWithIdResource(tagId), bytes.NewReader(tReqB), http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, client, http.MethodPatch, tagsWithIdResource(tagId), http.StatusOK,
jsonhttptest.WithJSONRequestBody(api.TagRequest{
Address: addr,
}),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "ok", Message: "ok",
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
// check tag data // check tag data
jsonhttptest.ResponseUnmarshal(t, client, http.MethodGet, tagsWithIdResource(tagId), nil, http.StatusOK, &tRes) jsonhttptest.Request(t, client, http.MethodGet, tagsWithIdResource(tagId), http.StatusOK,
jsonhttptest.WithUnmarshalJSONResponse(&tRes),
)
if !tRes.Address.Equal(addr) { if !tRes.Address.Equal(addr) {
t.Fatalf("expected tag address to be %s but is %s", addr.String(), tRes.Address.String()) t.Fatalf("expected tag address to be %s but is %s", addr.String(), tRes.Address.String())
} }
...@@ -390,9 +425,11 @@ func TestTags(t *testing.T) { ...@@ -390,9 +425,11 @@ func TestTags(t *testing.T) {
expectedHash := swarm.MustParseHexAddress("8e27bb803ff049e8c2f4650357026723220170c15ebf9b635a7026539879a1a8") expectedHash := swarm.MustParseHexAddress("8e27bb803ff049e8c2f4650357026723220170c15ebf9b635a7026539879a1a8")
expectedResponse := api.FileUploadResponse{Reference: expectedHash} expectedResponse := api.FileUploadResponse{Reference: expectedHash}
sentHeaders := make(http.Header) respHeaders := jsonhttptest.Request(t, client, http.MethodPost, filesResource, http.StatusOK,
sentHeaders.Set("Content-Type", "application/octet-stream") jsonhttptest.WithRequestBody(bytes.NewReader([]byte("some data"))),
respHeaders := jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, filesResource, bytes.NewReader([]byte("some data")), http.StatusOK, expectedResponse, sentHeaders) jsonhttptest.WithExpectedJSONResponse(expectedResponse),
jsonhttptest.WithRequestHeader("Content-Type", "application/octet-stream"),
)
tagId, err := strconv.Atoi(respHeaders.Get(api.SwarmTagUidHeader)) tagId, err := strconv.Atoi(respHeaders.Get(api.SwarmTagUidHeader))
if err != nil { if err != nil {
...@@ -401,7 +438,9 @@ func TestTags(t *testing.T) { ...@@ -401,7 +438,9 @@ func TestTags(t *testing.T) {
// check tag data // check tag data
tRes := api.TagResponse{} tRes := api.TagResponse{}
jsonhttptest.ResponseUnmarshal(t, client, http.MethodGet, tagsWithIdResource(uint32(tagId)), nil, http.StatusOK, &tRes) jsonhttptest.Request(t, client, http.MethodGet, tagsWithIdResource(uint32(tagId)), http.StatusOK,
jsonhttptest.WithUnmarshalJSONResponse(&tRes),
)
if !(tRes.Total > 0) { if !(tRes.Total > 0) {
t.Errorf("tag total should be greater than 0 but it is not") t.Errorf("tag total should be greater than 0 but it is not")
...@@ -424,9 +463,11 @@ func TestTags(t *testing.T) { ...@@ -424,9 +463,11 @@ func TestTags(t *testing.T) {
expectedHash := swarm.MustParseHexAddress("9e5acfbfeb7e074d4c79f5f9922e8a25990dad267d0ea7becaaad07b47fb2a87") expectedHash := swarm.MustParseHexAddress("9e5acfbfeb7e074d4c79f5f9922e8a25990dad267d0ea7becaaad07b47fb2a87")
expectedResponse := api.FileUploadResponse{Reference: expectedHash} expectedResponse := api.FileUploadResponse{Reference: expectedHash}
sentHeaders := make(http.Header) respHeaders := jsonhttptest.Request(t, client, http.MethodPost, dirResource, http.StatusOK,
sentHeaders.Set("Content-Type", api.ContentTypeTar) jsonhttptest.WithRequestBody(tarReader),
respHeaders := jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, dirResource, tarReader, http.StatusOK, expectedResponse, sentHeaders) jsonhttptest.WithExpectedJSONResponse(expectedResponse),
jsonhttptest.WithRequestHeader("Content-Type", api.ContentTypeTar),
)
tagId, err := strconv.Atoi(respHeaders.Get(api.SwarmTagUidHeader)) tagId, err := strconv.Atoi(respHeaders.Get(api.SwarmTagUidHeader))
if err != nil { if err != nil {
...@@ -435,7 +476,9 @@ func TestTags(t *testing.T) { ...@@ -435,7 +476,9 @@ func TestTags(t *testing.T) {
// check tag data // check tag data
tRes := api.TagResponse{} tRes := api.TagResponse{}
jsonhttptest.ResponseUnmarshal(t, client, http.MethodGet, tagsWithIdResource(uint32(tagId)), nil, http.StatusOK, &tRes) jsonhttptest.Request(t, client, http.MethodGet, tagsWithIdResource(uint32(tagId)), http.StatusOK,
jsonhttptest.WithUnmarshalJSONResponse(&tRes),
)
if !(tRes.Total > 0) { if !(tRes.Total > 0) {
t.Errorf("tag total should be greater than 0 but it is not") t.Errorf("tag total should be greater than 0 but it is not")
...@@ -451,13 +494,12 @@ func TestTags(t *testing.T) { ...@@ -451,13 +494,12 @@ func TestTags(t *testing.T) {
t.Run("bytes-tags", func(t *testing.T) { t.Run("bytes-tags", func(t *testing.T) {
// create a tag using the API // create a tag using the API
tr := api.TagResponse{} tr := api.TagResponse{}
b, err := json.Marshal(api.TagResponse{ jsonhttptest.Request(t, client, http.MethodPost, tagsResource, http.StatusCreated,
jsonhttptest.WithJSONRequestBody(api.TagResponse{
Name: someTagName, Name: someTagName,
}) }),
if err != nil { jsonhttptest.WithUnmarshalJSONResponse(&tr),
t.Fatal(err) )
}
jsonhttptest.ResponseUnmarshal(t, client, http.MethodPost, tagsResource, bytes.NewReader(b), http.StatusCreated, &tr)
if tr.Name != someTagName { if tr.Name != someTagName {
t.Fatalf("sent tag name %s does not match received tag name %s", someTagName, tr.Name) t.Fatalf("sent tag name %s does not match received tag name %s", someTagName, tr.Name)
} }
...@@ -477,9 +519,13 @@ func TestTags(t *testing.T) { ...@@ -477,9 +519,13 @@ func TestTags(t *testing.T) {
copy(content[swarm.ChunkSize:], dataChunk) copy(content[swarm.ChunkSize:], dataChunk)
copy(content[:swarm.ChunkSize], dataChunk) copy(content[:swarm.ChunkSize], dataChunk)
rcvdHeaders := jsonhttptest.ResponseDirectSendHeadersAndReceiveHeaders(t, client, http.MethodPost, bytesResource, bytes.NewReader(content), http.StatusOK, fileUploadResponse{ rcvdHeaders := jsonhttptest.Request(t, client, http.MethodPost, bytesResource, http.StatusOK,
jsonhttptest.WithRequestBody(bytes.NewReader(content)),
jsonhttptest.WithExpectedJSONResponse(fileUploadResponse{
Reference: rootAddress, Reference: rootAddress,
}, sentHeaders) }),
jsonhttptest.WithRequestHeader(api.SwarmTagUidHeader, strconv.FormatUint(uint64(tr.Uid), 10)),
)
id := isTagFoundInResponse(t, rcvdHeaders, nil) id := isTagFoundInResponse(t, rcvdHeaders, nil)
tagToVerify, err := tag.Get(id) tagToVerify, err := tag.Get(id)
...@@ -492,7 +538,9 @@ func TestTags(t *testing.T) { ...@@ -492,7 +538,9 @@ func TestTags(t *testing.T) {
} }
finalTag := api.TagResponse{} finalTag := api.TagResponse{}
jsonhttptest.ResponseUnmarshal(t, client, http.MethodGet, tagsWithIdResource(id), nil, http.StatusOK, &finalTag) jsonhttptest.Request(t, client, http.MethodGet, tagsWithIdResource(id), http.StatusOK,
jsonhttptest.WithUnmarshalJSONResponse(&finalTag),
)
if finalTag.Total != 0 { if finalTag.Total != 0 {
t.Errorf("tag total count mismatch. got %d want %d", finalTag.Total, 0) t.Errorf("tag total count mismatch. got %d want %d", finalTag.Total, 0)
......
...@@ -48,7 +48,9 @@ func TestBalances(t *testing.T) { ...@@ -48,7 +48,9 @@ func TestBalances(t *testing.T) {
// We expect a list of items unordered by peer: // We expect a list of items unordered by peer:
var got *debugapi.BalancesResponse var got *debugapi.BalancesResponse
jsonhttptest.ResponseUnmarshal(t, testServer.Client, http.MethodGet, "/balances", nil, http.StatusOK, &got) jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/balances", http.StatusOK,
jsonhttptest.WithUnmarshalJSONResponse(&got),
)
if !equalBalances(got, expected) { if !equalBalances(got, expected) {
t.Errorf("got balances: %v, expected: %v", got, expected) t.Errorf("got balances: %v, expected: %v", got, expected)
...@@ -65,10 +67,12 @@ func TestBalancesError(t *testing.T) { ...@@ -65,10 +67,12 @@ func TestBalancesError(t *testing.T) {
AccountingOpts: []mock.Option{mock.WithBalancesFunc(balancesFunc)}, AccountingOpts: []mock.Option{mock.WithBalancesFunc(balancesFunc)},
}) })
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/balances", nil, http.StatusInternalServerError, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/balances", http.StatusInternalServerError,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: debugapi.ErrCantBalances, Message: debugapi.ErrCantBalances,
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
}) }),
)
} }
func TestBalancesPeers(t *testing.T) { func TestBalancesPeers(t *testing.T) {
...@@ -80,10 +84,12 @@ func TestBalancesPeers(t *testing.T) { ...@@ -80,10 +84,12 @@ func TestBalancesPeers(t *testing.T) {
AccountingOpts: []mock.Option{mock.WithBalanceFunc(balanceFunc)}, AccountingOpts: []mock.Option{mock.WithBalanceFunc(balanceFunc)},
}) })
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/balances/"+peer, nil, http.StatusOK, debugapi.BalanceResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/balances/"+peer, http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.BalanceResponse{
Peer: peer, Peer: peer,
Balance: 1000000000000000000, Balance: 1000000000000000000,
}) }),
)
} }
func TestBalancesPeersError(t *testing.T) { func TestBalancesPeersError(t *testing.T) {
...@@ -96,10 +102,12 @@ func TestBalancesPeersError(t *testing.T) { ...@@ -96,10 +102,12 @@ func TestBalancesPeersError(t *testing.T) {
AccountingOpts: []mock.Option{mock.WithBalanceFunc(balanceFunc)}, AccountingOpts: []mock.Option{mock.WithBalanceFunc(balanceFunc)},
}) })
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/balances/"+peer, nil, http.StatusInternalServerError, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/balances/"+peer, http.StatusInternalServerError,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: debugapi.ErrCantBalance, Message: debugapi.ErrCantBalance,
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
}) }),
)
} }
func TestBalancesInvalidAddress(t *testing.T) { func TestBalancesInvalidAddress(t *testing.T) {
...@@ -107,10 +115,12 @@ func TestBalancesInvalidAddress(t *testing.T) { ...@@ -107,10 +115,12 @@ func TestBalancesInvalidAddress(t *testing.T) {
testServer := newTestServer(t, testServerOptions{}) testServer := newTestServer(t, testServerOptions{})
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/balances/"+peer, nil, http.StatusNotFound, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/balances/"+peer, http.StatusNotFound,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: debugapi.ErrInvaliAddress, Message: debugapi.ErrInvaliAddress,
Code: http.StatusNotFound, Code: http.StatusNotFound,
}) }),
)
} }
func equalBalances(a, b *debugapi.BalancesResponse) bool { func equalBalances(a, b *debugapi.BalancesResponse) bool {
......
...@@ -31,31 +31,39 @@ func TestHasChunkHandler(t *testing.T) { ...@@ -31,31 +31,39 @@ func TestHasChunkHandler(t *testing.T) {
} }
t.Run("ok", func(t *testing.T) { t.Run("ok", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/chunks/"+key.String(), nil, http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/chunks/"+key.String(), http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
}) })
t.Run("not found", func(t *testing.T) { t.Run("not found", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/chunks/abbbbb", nil, http.StatusNotFound, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/chunks/abbbbb", http.StatusNotFound,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusNotFound), Message: http.StatusText(http.StatusNotFound),
Code: http.StatusNotFound, Code: http.StatusNotFound,
}) }),
)
}) })
t.Run("bad address", func(t *testing.T) { t.Run("bad address", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/chunks/abcd1100zz", nil, http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/chunks/abcd1100zz", http.StatusBadRequest,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "bad address", Message: "bad address",
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
}) }),
)
}) })
t.Run("remove-chunk", func(t *testing.T) { t.Run("remove-chunk", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodDelete, "/chunks/"+key.String(), nil, http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodDelete, "/chunks/"+key.String(), http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
yes, err := mockStorer.Has(context.Background(), key) yes, err := mockStorer.Has(context.Background(), key)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
...@@ -67,10 +75,12 @@ func TestHasChunkHandler(t *testing.T) { ...@@ -67,10 +75,12 @@ func TestHasChunkHandler(t *testing.T) {
t.Run("remove-not-present-chunk", func(t *testing.T) { t.Run("remove-not-present-chunk", func(t *testing.T) {
notPresentChunkAddress := "deadbeef" notPresentChunkAddress := "deadbeef"
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodDelete, "/chunks/"+notPresentChunkAddress, nil, http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodDelete, "/chunks/"+notPresentChunkAddress, http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
yes, err := mockStorer.Has(context.Background(), swarm.NewAddress([]byte(notPresentChunkAddress))) yes, err := mockStorer.Has(context.Background(), swarm.NewAddress([]byte(notPresentChunkAddress)))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
......
...@@ -33,17 +33,21 @@ func TestAddresses(t *testing.T) { ...@@ -33,17 +33,21 @@ func TestAddresses(t *testing.T) {
}) })
t.Run("ok", func(t *testing.T) { t.Run("ok", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/addresses", nil, http.StatusOK, debugapi.AddressesResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/addresses", http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.AddressesResponse{
Overlay: overlay, Overlay: overlay,
Underlay: addresses, Underlay: addresses,
}) }),
)
}) })
t.Run("post method not allowed", func(t *testing.T) { t.Run("post method not allowed", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodPost, "/addresses", nil, http.StatusMethodNotAllowed, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodPost, "/addresses", http.StatusMethodNotAllowed,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Code: http.StatusMethodNotAllowed, Code: http.StatusMethodNotAllowed,
Message: http.StatusText(http.StatusMethodNotAllowed), Message: http.StatusText(http.StatusMethodNotAllowed),
}) }),
)
}) })
} }
...@@ -56,8 +60,10 @@ func TestAddresses_error(t *testing.T) { ...@@ -56,8 +60,10 @@ func TestAddresses_error(t *testing.T) {
})), })),
}) })
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/addresses", nil, http.StatusInternalServerError, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/addresses", http.StatusInternalServerError,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
Message: testErr.Error(), Message: testErr.Error(),
}) }),
)
} }
...@@ -55,26 +55,32 @@ func TestConnect(t *testing.T) { ...@@ -55,26 +55,32 @@ func TestConnect(t *testing.T) {
}) })
t.Run("ok", func(t *testing.T) { t.Run("ok", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodPost, "/connect"+underlay, nil, http.StatusOK, debugapi.PeerConnectResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodPost, "/connect"+underlay, http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.PeerConnectResponse{
Address: overlay.String(), Address: overlay.String(),
}) }),
)
if testServer.P2PMock.ConnectNotifyCalls() != 1 { if testServer.P2PMock.ConnectNotifyCalls() != 1 {
t.Fatal("connect notify not called") t.Fatal("connect notify not called")
} }
}) })
t.Run("error", func(t *testing.T) { t.Run("error", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodPost, "/connect"+errorUnderlay, nil, http.StatusInternalServerError, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodPost, "/connect"+errorUnderlay, http.StatusInternalServerError,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
Message: testErr.Error(), Message: testErr.Error(),
}) }),
)
}) })
t.Run("get method not allowed", func(t *testing.T) { t.Run("get method not allowed", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/connect"+underlay, nil, http.StatusMethodNotAllowed, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/connect"+underlay, http.StatusMethodNotAllowed,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Code: http.StatusMethodNotAllowed, Code: http.StatusMethodNotAllowed,
Message: http.StatusText(http.StatusMethodNotAllowed), Message: http.StatusText(http.StatusMethodNotAllowed),
}) }),
)
}) })
t.Run("error - add peer", func(t *testing.T) { t.Run("error - add peer", func(t *testing.T) {
...@@ -87,10 +93,12 @@ func TestConnect(t *testing.T) { ...@@ -87,10 +93,12 @@ func TestConnect(t *testing.T) {
})), })),
}) })
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodPost, "/connect"+errorUnderlay, nil, http.StatusInternalServerError, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodPost, "/connect"+errorUnderlay, http.StatusInternalServerError,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
Message: testErr.Error(), Message: testErr.Error(),
}) }),
)
}) })
} }
...@@ -115,31 +123,39 @@ func TestDisconnect(t *testing.T) { ...@@ -115,31 +123,39 @@ func TestDisconnect(t *testing.T) {
}) })
t.Run("ok", func(t *testing.T) { t.Run("ok", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodDelete, "/peers/"+address.String(), nil, http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodDelete, "/peers/"+address.String(), http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Code: http.StatusOK, Code: http.StatusOK,
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
}) }),
)
}) })
t.Run("unknown", func(t *testing.T) { t.Run("unknown", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodDelete, "/peers/"+unknownAdddress.String(), nil, http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodDelete, "/peers/"+unknownAdddress.String(), http.StatusBadRequest,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
Message: "peer not found", Message: "peer not found",
}) }),
)
}) })
t.Run("invalid peer address", func(t *testing.T) { t.Run("invalid peer address", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodDelete, "/peers/invalid-address", nil, http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodDelete, "/peers/invalid-address", http.StatusBadRequest,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
Message: "invalid peer address", Message: "invalid peer address",
}) }),
)
}) })
t.Run("error", func(t *testing.T) { t.Run("error", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodDelete, "/peers/"+errorAddress.String(), nil, http.StatusInternalServerError, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodDelete, "/peers/"+errorAddress.String(), http.StatusInternalServerError,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
Message: testErr.Error(), Message: testErr.Error(),
}) }),
)
}) })
} }
...@@ -152,15 +168,19 @@ func TestPeer(t *testing.T) { ...@@ -152,15 +168,19 @@ func TestPeer(t *testing.T) {
}) })
t.Run("ok", func(t *testing.T) { t.Run("ok", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/peers", nil, http.StatusOK, debugapi.PeersResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/peers", http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.PeersResponse{
Peers: []p2p.Peer{{Address: overlay}}, Peers: []p2p.Peer{{Address: overlay}},
}) }),
)
}) })
t.Run("get method not allowed", func(t *testing.T) { t.Run("get method not allowed", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodPost, "/peers", nil, http.StatusMethodNotAllowed, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodPost, "/peers", http.StatusMethodNotAllowed,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Code: http.StatusMethodNotAllowed, Code: http.StatusMethodNotAllowed,
Message: http.StatusText(http.StatusMethodNotAllowed), Message: http.StatusText(http.StatusMethodNotAllowed),
}) }),
)
}) })
} }
...@@ -45,131 +45,172 @@ func TestPinChunkHandler(t *testing.T) { ...@@ -45,131 +45,172 @@ func TestPinChunkHandler(t *testing.T) {
// bad chunk address // bad chunk address
t.Run("pin-bad-address", func(t *testing.T) { t.Run("pin-bad-address", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodPost, "/chunks-pin/abcd1100zz", nil, http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, debugTestServer.Client, http.MethodPost, "/chunks-pin/abcd1100zz", http.StatusBadRequest,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "bad address", Message: "bad address",
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
}) }),
)
}) })
// list pins without anything pinned // list pins without anything pinned
t.Run("list-pins-zero-pins", func(t *testing.T) { t.Run("list-pins-zero-pins", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodGet, "/chunks-pin", nil, http.StatusOK, debugapi.ListPinnedChunksResponse{ jsonhttptest.Request(t, debugTestServer.Client, http.MethodGet, "/chunks-pin", http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.ListPinnedChunksResponse{
Chunks: []debugapi.PinnedChunk{}, Chunks: []debugapi.PinnedChunk{},
}) }),
)
}) })
// pin a chunk which is not existing // pin a chunk which is not existing
t.Run("pin-absent-chunk", func(t *testing.T) { t.Run("pin-absent-chunk", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodPost, "/chunks-pin/123456", nil, http.StatusNotFound, jsonhttp.StatusResponse{ jsonhttptest.Request(t, debugTestServer.Client, http.MethodPost, "/chunks-pin/123456", http.StatusNotFound,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusNotFound), Message: http.StatusText(http.StatusNotFound),
Code: http.StatusNotFound, Code: http.StatusNotFound,
}) }),
)
}) })
// unpin on a chunk which is not pinned // unpin on a chunk which is not pinned
t.Run("unpin-while-not-pinned", func(t *testing.T) { t.Run("unpin-while-not-pinned", func(t *testing.T) {
// Post a chunk // Post a chunk
jsonhttptest.ResponseDirect(t, bzzTestServer, http.MethodPost, resource(hash), bytes.NewReader(data), http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, bzzTestServer, http.MethodPost, resource(hash), http.StatusOK,
jsonhttptest.WithRequestBody(bytes.NewReader(data)),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodDelete, "/chunks-pin/"+hash.String(), nil, http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, debugTestServer.Client, http.MethodDelete, "/chunks-pin/"+hash.String(), http.StatusBadRequest,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "chunk is not yet pinned", Message: "chunk is not yet pinned",
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
}) }),
)
}) })
// pin a existing chunk first time // pin a existing chunk first time
t.Run("pin-chunk-1", func(t *testing.T) { t.Run("pin-chunk-1", func(t *testing.T) {
// Post a chunk // Post a chunk
jsonhttptest.ResponseDirect(t, bzzTestServer, http.MethodPost, resource(hash), bytes.NewReader(data), http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, bzzTestServer, http.MethodPost, resource(hash), http.StatusOK,
jsonhttptest.WithRequestBody(bytes.NewReader(data)),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodPost, "/chunks-pin/"+hash.String(), nil, http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, debugTestServer.Client, http.MethodPost, "/chunks-pin/"+hash.String(), http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
// Check is the chunk is pinned once // Check is the chunk is pinned once
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), nil, http.StatusOK, debugapi.PinnedChunk{ jsonhttptest.Request(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.PinnedChunk{
Address: swarm.MustParseHexAddress("aabbcc"), Address: swarm.MustParseHexAddress("aabbcc"),
PinCounter: 1, PinCounter: 1,
}) }),
)
}) })
// pin a existing chunk second time // pin a existing chunk second time
t.Run("pin-chunk-2", func(t *testing.T) { t.Run("pin-chunk-2", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodPost, "/chunks-pin/"+hash.String(), nil, http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, debugTestServer.Client, http.MethodPost, "/chunks-pin/"+hash.String(), http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
// Check is the chunk is pinned twice // Check is the chunk is pinned twice
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), nil, http.StatusOK, debugapi.PinnedChunk{ jsonhttptest.Request(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.PinnedChunk{
Address: swarm.MustParseHexAddress("aabbcc"), Address: swarm.MustParseHexAddress("aabbcc"),
PinCounter: 2, PinCounter: 2,
}) }),
)
}) })
// unpin a chunk first time // unpin a chunk first time
t.Run("unpin-chunk-1", func(t *testing.T) { t.Run("unpin-chunk-1", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodDelete, "/chunks-pin/"+hash.String(), nil, http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, debugTestServer.Client, http.MethodDelete, "/chunks-pin/"+hash.String(), http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
// Check is the chunk is pinned once // Check is the chunk is pinned once
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), nil, http.StatusOK, debugapi.PinnedChunk{ jsonhttptest.Request(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.PinnedChunk{
Address: swarm.MustParseHexAddress("aabbcc"), Address: swarm.MustParseHexAddress("aabbcc"),
PinCounter: 1, PinCounter: 1,
}) }),
)
}) })
// unpin a chunk second time // unpin a chunk second time
t.Run("unpin-chunk-2", func(t *testing.T) { t.Run("unpin-chunk-2", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodDelete, "/chunks-pin/"+hash.String(), nil, http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, debugTestServer.Client, http.MethodDelete, "/chunks-pin/"+hash.String(), http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
// Check if the chunk is removed from the pinIndex // Check if the chunk is removed from the pinIndex
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), nil, http.StatusNotFound, jsonhttp.StatusResponse{ jsonhttptest.Request(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), http.StatusNotFound,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusNotFound), Message: http.StatusText(http.StatusNotFound),
Code: http.StatusNotFound, Code: http.StatusNotFound,
}) }),
)
}) })
// Add 2 chunks, pin it and check if they show up in the list // Add 2 chunks, pin it and check if they show up in the list
t.Run("list-chunks", func(t *testing.T) { t.Run("list-chunks", func(t *testing.T) {
// Post a chunk // Post a chunk
jsonhttptest.ResponseDirect(t, bzzTestServer, http.MethodPost, resource(hash), bytes.NewReader(data), http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, bzzTestServer, http.MethodPost, resource(hash), http.StatusOK,
jsonhttptest.WithRequestBody(bytes.NewReader(data)),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodPost, "/chunks-pin/"+hash.String(), nil, http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, debugTestServer.Client, http.MethodPost, "/chunks-pin/"+hash.String(), http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
// post another chunk // post another chunk
hash2 := swarm.MustParseHexAddress("ddeeff") hash2 := swarm.MustParseHexAddress("ddeeff")
data2 := []byte("eagle") data2 := []byte("eagle")
mockValidator.AddPair(hash2, data2) mockValidator.AddPair(hash2, data2)
jsonhttptest.ResponseDirect(t, bzzTestServer, http.MethodPost, resource(hash2), bytes.NewReader(data2), http.StatusOK, jsonhttp.StatusResponse{ jsonhttptest.Request(t, bzzTestServer, http.MethodPost, resource(hash2), http.StatusOK,
jsonhttptest.WithRequestBody(bytes.NewReader(data2)),
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}) }),
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodPost, "/chunks-pin/"+hash2.String(), nil, http.StatusOK, jsonhttp.StatusResponse{ )
jsonhttptest.Request(t, debugTestServer.Client, http.MethodPost, "/chunks-pin/"+hash2.String(), http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusOK), Message: http.StatusText(http.StatusOK),
Code: http.StatusOK, Code: http.StatusOK,
}) }),
)
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodGet, "/chunks-pin", nil, http.StatusOK, debugapi.ListPinnedChunksResponse{ jsonhttptest.Request(t, debugTestServer.Client, http.MethodGet, "/chunks-pin", http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.ListPinnedChunksResponse{
Chunks: []debugapi.PinnedChunk{ Chunks: []debugapi.PinnedChunk{
{ {
Address: swarm.MustParseHexAddress("aabbcc"), Address: swarm.MustParseHexAddress("aabbcc"),
...@@ -180,6 +221,7 @@ func TestPinChunkHandler(t *testing.T) { ...@@ -180,6 +221,7 @@ func TestPinChunkHandler(t *testing.T) {
PinCounter: 1, PinCounter: 1,
}, },
}, },
}) }),
)
}) })
} }
...@@ -41,36 +41,46 @@ func TestPingpong(t *testing.T) { ...@@ -41,36 +41,46 @@ func TestPingpong(t *testing.T) {
}) })
t.Run("ok", func(t *testing.T) { t.Run("ok", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, ts.Client, http.MethodPost, "/pingpong/"+peerID.String(), nil, http.StatusOK, debugapi.PingpongResponse{ jsonhttptest.Request(t, ts.Client, http.MethodPost, "/pingpong/"+peerID.String(), http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.PingpongResponse{
RTT: rtt.String(), RTT: rtt.String(),
}) }),
)
}) })
t.Run("peer not found", func(t *testing.T) { t.Run("peer not found", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, ts.Client, http.MethodPost, "/pingpong/"+unknownPeerID.String(), nil, http.StatusNotFound, jsonhttp.StatusResponse{ jsonhttptest.Request(t, ts.Client, http.MethodPost, "/pingpong/"+unknownPeerID.String(), http.StatusNotFound,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Code: http.StatusNotFound, Code: http.StatusNotFound,
Message: "peer not found", Message: "peer not found",
}) }),
)
}) })
t.Run("invalid peer address", func(t *testing.T) { t.Run("invalid peer address", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, ts.Client, http.MethodPost, "/pingpong/invalid-address", nil, http.StatusBadRequest, jsonhttp.StatusResponse{ jsonhttptest.Request(t, ts.Client, http.MethodPost, "/pingpong/invalid-address", http.StatusBadRequest,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
Message: "invalid peer address", Message: "invalid peer address",
}) }),
)
}) })
t.Run("error", func(t *testing.T) { t.Run("error", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, ts.Client, http.MethodPost, "/pingpong/"+errorPeerID.String(), nil, http.StatusInternalServerError, jsonhttp.StatusResponse{ jsonhttptest.Request(t, ts.Client, http.MethodPost, "/pingpong/"+errorPeerID.String(), http.StatusInternalServerError,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
Message: http.StatusText(http.StatusInternalServerError), // do not leak internal error Message: http.StatusText(http.StatusInternalServerError), // do not leak internal error
}) }),
)
}) })
t.Run("get method not allowed", func(t *testing.T) { t.Run("get method not allowed", func(t *testing.T) {
jsonhttptest.ResponseDirect(t, ts.Client, http.MethodGet, "/pingpong/"+peerID.String(), nil, http.StatusMethodNotAllowed, jsonhttp.StatusResponse{ jsonhttptest.Request(t, ts.Client, http.MethodGet, "/pingpong/"+peerID.String(), http.StatusMethodNotAllowed,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Code: http.StatusMethodNotAllowed, Code: http.StatusMethodNotAllowed,
Message: http.StatusText(http.StatusMethodNotAllowed), Message: http.StatusText(http.StatusMethodNotAllowed),
}) }),
)
}) })
} }
...@@ -15,15 +15,19 @@ import ( ...@@ -15,15 +15,19 @@ import (
func TestHealth(t *testing.T) { func TestHealth(t *testing.T) {
testServer := newTestServer(t, testServerOptions{}) testServer := newTestServer(t, testServerOptions{})
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/health", nil, http.StatusOK, debugapi.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/health", http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.StatusResponse{
Status: "ok", Status: "ok",
}) }),
)
} }
func TestReadiness(t *testing.T) { func TestReadiness(t *testing.T) {
testServer := newTestServer(t, testServerOptions{}) testServer := newTestServer(t, testServerOptions{})
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/readiness", nil, http.StatusOK, debugapi.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/readiness", http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.StatusResponse{
Status: "ok", Status: "ok",
}) }),
)
} }
...@@ -27,9 +27,11 @@ func TestTopologyOK(t *testing.T) { ...@@ -27,9 +27,11 @@ func TestTopologyOK(t *testing.T) {
TopologyOpts: []topmock.Option{topmock.WithMarshalJSONFunc(marshalFunc)}, TopologyOpts: []topmock.Option{topmock.WithMarshalJSONFunc(marshalFunc)},
}) })
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/topology", nil, http.StatusOK, topologyResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/topology", http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(topologyResponse{
Topology: "abcd", Topology: "abcd",
}) }),
)
} }
func TestTopologyError(t *testing.T) { func TestTopologyError(t *testing.T) {
...@@ -40,8 +42,10 @@ func TestTopologyError(t *testing.T) { ...@@ -40,8 +42,10 @@ func TestTopologyError(t *testing.T) {
TopologyOpts: []topmock.Option{topmock.WithMarshalJSONFunc(marshalFunc)}, TopologyOpts: []topmock.Option{topmock.WithMarshalJSONFunc(marshalFunc)},
}) })
jsonhttptest.ResponseDirect(t, testServer.Client, http.MethodGet, "/topology", nil, http.StatusInternalServerError, jsonhttp.StatusResponse{ jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/topology", http.StatusInternalServerError,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: "error", Message: "error",
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
}) }),
)
} }
...@@ -25,9 +25,11 @@ func TestGetWelcomeMessage(t *testing.T) { ...@@ -25,9 +25,11 @@ func TestGetWelcomeMessage(t *testing.T) {
return DefaultTestWelcomeMessage return DefaultTestWelcomeMessage
}))}) }))})
jsonhttptest.ResponseDirect(t, srv.Client, http.MethodGet, "/welcome-message", nil, http.StatusOK, debugapi.WelcomeMessageResponse{ jsonhttptest.Request(t, srv.Client, http.MethodGet, "/welcome-message", http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.WelcomeMessageResponse{
WelcomeMesssage: DefaultTestWelcomeMessage, WelcomeMesssage: DefaultTestWelcomeMessage,
}) }),
)
} }
func TestSetWelcomeMessage(t *testing.T) { func TestSetWelcomeMessage(t *testing.T) {
...@@ -81,7 +83,10 @@ func TestSetWelcomeMessage(t *testing.T) { ...@@ -81,7 +83,10 @@ func TestSetWelcomeMessage(t *testing.T) {
Message: tC.wantMessage, Message: tC.wantMessage,
Code: tC.wantStatus, Code: tC.wantStatus,
} }
jsonhttptest.ResponseDirect(t, srv.Client, http.MethodPost, testURL, body, tC.wantStatus, wantResponse) jsonhttptest.Request(t, srv.Client, http.MethodPost, testURL, tC.wantStatus,
jsonhttptest.WithRequestBody(body),
jsonhttptest.WithExpectedJSONResponse(wantResponse),
)
if !tC.wantFail { if !tC.wantFail {
got := srv.P2PMock.GetWelcomeMessage() got := srv.P2PMock.GetWelcomeMessage()
if got != tC.message { if got != tC.message {
...@@ -113,7 +118,10 @@ func TestSetWelcomeMessageInternalServerError(t *testing.T) { ...@@ -113,7 +118,10 @@ func TestSetWelcomeMessageInternalServerError(t *testing.T) {
Message: testError.Error(), Message: testError.Error(),
Code: wantCode, Code: wantCode,
} }
jsonhttptest.ResponseDirect(t, srv.Client, http.MethodPost, testURL, body, wantCode, wantResp) jsonhttptest.Request(t, srv.Client, http.MethodPost, testURL, wantCode,
jsonhttptest.WithRequestBody(body),
jsonhttptest.WithExpectedJSONResponse(wantResp),
)
}) })
} }
...@@ -6,6 +6,7 @@ package jsonhttptest ...@@ -6,6 +6,7 @@ package jsonhttptest
import ( import (
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
...@@ -15,172 +16,238 @@ import ( ...@@ -15,172 +16,238 @@ import (
"net/textproto" "net/textproto"
"strconv" "strconv"
"testing" "testing"
"github.com/ethersphere/bee/pkg/jsonhttp"
) )
func ResponseDirect(t *testing.T, client *http.Client, method, url string, body io.Reader, responseCode int, response interface{}) { // Request is a testing helper function that makes an HTTP request using
// provided client with provided method and url. It performs a validation on
// expected response code and additional options. It returns response headers if
// the request and all validation are successful. In case of any error, testing
// Errorf or Fatal functions will be called.
func Request(t testing.TB, client *http.Client, method, url string, responseCode int, opts ...Option) http.Header {
t.Helper() t.Helper()
resp := request(t, client, method, url, body, responseCode, nil) o := new(options)
defer resp.Body.Close() for _, opt := range opts {
if err := opt.apply(o); err != nil {
got, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal(err) t.Fatal(err)
} }
got = bytes.TrimSpace(got)
if response == nil && len(got) == 0 {
return
} }
want, err := json.Marshal(response)
if err != nil {
t.Error(err)
}
if !bytes.Equal(got, want) {
t.Errorf("got response %s, want %s", string(got), string(want))
}
}
func ResponseDirectWithMultiPart(t *testing.T, client *http.Client, method, url, fileName string, data []byte, req, err := http.NewRequest(method, url, o.requestBody)
responseCode int, contentType string, response interface{}) http.Header {
body := bytes.NewBuffer(nil)
mw := multipart.NewWriter(body)
hdr := make(textproto.MIMEHeader)
hdr.Set("Content-Disposition", fmt.Sprintf("form-data; name=%q", fileName))
hdr.Set("Content-Type", contentType)
hdr.Set("Content-Length", strconv.FormatInt(int64(len(data)), 10))
part, err := mw.CreatePart(hdr)
if err != nil { if err != nil {
t.Error(err) t.Fatal(err)
} }
_, err = io.Copy(part, bytes.NewReader(data)) req.Header = o.requestHeaders
if err != nil { if o.ctx != nil {
t.Error(err) req = req.WithContext(o.ctx)
} }
err = mw.Close() resp, err := client.Do(req)
if err != nil { if err != nil {
t.Error(err) t.Fatal(err)
} }
defer resp.Body.Close()
req, err := http.NewRequest(method, url, body) if resp.StatusCode != responseCode {
if err != nil { t.Errorf("got response status %s, want %v %s", resp.Status, responseCode, http.StatusText(responseCode))
t.Error(err)
} }
req.Header.Set("Content-Type", fmt.Sprintf("multipart/form-data; boundary=%q", mw.Boundary()))
res, err := client.Do(req) if o.expectedResponse != nil {
got, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
t.Error(err) t.Fatal(err)
} }
defer res.Body.Close()
if res.StatusCode != responseCode { if !bytes.Equal(got, o.expectedResponse) {
t.Errorf("got response status %s, want %v %s", res.Status, responseCode, http.StatusText(responseCode)) t.Errorf("got response %q, want %q", string(got), string(o.expectedResponse))
}
return resp.Header
} }
got, err := ioutil.ReadAll(res.Body) if o.expectedJSONResponse != nil {
if v := resp.Header.Get("Content-Type"); v != jsonhttp.DefaultContentTypeHeader {
t.Errorf("got content type %q, want %q", v, jsonhttp.DefaultContentTypeHeader)
}
got, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
got = bytes.TrimSpace(got) got = bytes.TrimSpace(got)
want, err := json.Marshal(response) want, err := json.Marshal(o.expectedJSONResponse)
if err != nil { if err != nil {
t.Error(err) t.Fatal(err)
} }
if !bytes.Equal(got, want) { if !bytes.Equal(got, want) {
t.Errorf("got response %s, want %s", string(got), string(want)) t.Errorf("got json response %q, want %q", string(got), string(want))
}
return resp.Header
} }
return res.Header if o.unmarshalResponse != nil {
} if err := json.NewDecoder(resp.Body).Decode(&o.unmarshalResponse); err != nil {
func ResponseDirectCheckBinaryResponse(t *testing.T, client *http.Client, method, url string, body io.Reader, responseCode int, t.Fatal(err)
response []byte, headers http.Header) http.Header { }
t.Helper() return resp.Header
}
resp := request(t, client, method, url, body, responseCode, headers) if o.responseBody != nil {
defer resp.Body.Close()
got, err := ioutil.ReadAll(resp.Body) got, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
got = bytes.TrimSpace(got) *o.responseBody = got
}
if !bytes.Equal(got, response) { if o.noResponseBody {
t.Errorf("got response %s, want %s", string(got), string(response)) got, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
if len(got) > 0 {
t.Errorf("got response body %q, want none", string(got))
}
} }
return resp.Header return resp.Header
} }
func ResponseDirectSendHeadersAndReceiveHeaders(t *testing.T, client *http.Client, method, url string, body io.Reader, responseCode int, // WithContext sets a context to the request made by the Request function.
response interface{}, headers http.Header) http.Header { func WithContext(ctx context.Context) Option {
t.Helper() return optionFunc(func(o *options) error {
o.ctx = ctx
return nil
})
}
resp := request(t, client, method, url, body, responseCode, headers) // WithRequestBody writes a request body to the request made by the Request
defer resp.Body.Close() // function.
func WithRequestBody(body io.Reader) Option {
return optionFunc(func(o *options) error {
o.requestBody = body
return nil
})
}
got, err := ioutil.ReadAll(resp.Body) // WithJSONRequestBody writes a request JSON-encoded body to the request made by
// the Request function.
func WithJSONRequestBody(r interface{}) Option {
return optionFunc(func(o *options) error {
b, err := json.Marshal(r)
if err != nil { if err != nil {
t.Fatal(err) return fmt.Errorf("json encode request body: %w", err)
} }
got = bytes.TrimSpace(got) o.requestBody = bytes.NewReader(b)
return nil
})
}
want, err := json.Marshal(response) // WithMultipartRequest writes a multipart request with a single file in it to
// the request made by the Request function.
func WithMultipartRequest(body io.Reader, length int, filename, contentType string) Option {
return optionFunc(func(o *options) error {
buf := bytes.NewBuffer(nil)
mw := multipart.NewWriter(buf)
hdr := make(textproto.MIMEHeader)
if filename != "" {
hdr.Set("Content-Disposition", fmt.Sprintf("form-data; name=%q", filename))
}
if contentType != "" {
hdr.Set("Content-Type", contentType)
}
if length > 0 {
hdr.Set("Content-Length", strconv.Itoa(length))
}
part, err := mw.CreatePart(hdr)
if err != nil { if err != nil {
t.Error(err) return fmt.Errorf("create multipart part: %w", err)
} }
if _, err = io.Copy(part, body); err != nil {
if !bytes.Equal(got, want) { return fmt.Errorf("copy file data to multipart part: %w", err)
t.Errorf("got response %s, want %s", string(got), string(want))
} }
if err := mw.Close(); err != nil {
return resp.Header return fmt.Errorf("close multipart writer: %w", err)
}
o.requestBody = buf
if o.requestHeaders == nil {
o.requestHeaders = make(http.Header)
}
o.requestHeaders.Set("Content-Type", fmt.Sprintf("multipart/form-data; boundary=%q", mw.Boundary()))
return nil
})
} }
// ResponseDirectSendHeadersAndDontCheckResponse sends a request with the given headers and does not check for the returned reference. // WithRequestHeader adds a single header to the request made by the Request
// this is useful in tests which does not know the return reference, for ex: when encryption flag is set // function. To add multiple headers call multiple times this option when as
func ResponseDirectSendHeadersAndDontCheckResponse(t *testing.T, client *http.Client, method, url string, body io.Reader, responseCode int, headers http.Header) (http.Header, []byte) { // arguments to the Request function.
t.Helper() func WithRequestHeader(key, value string) Option {
return optionFunc(func(o *options) error {
resp := request(t, client, method, url, body, responseCode, headers) if o.requestHeaders == nil {
defer resp.Body.Close() o.requestHeaders = make(http.Header)
}
o.requestHeaders.Add(key, value)
return nil
})
}
got, err := ioutil.ReadAll(resp.Body) // WithExpectedResponse validates that the response from the request in the
if err != nil { // Request function matches completely bytes provided here.
t.Fatal(err) func WithExpectedResponse(response []byte) Option {
} return optionFunc(func(o *options) error {
got = bytes.TrimSpace(got) o.expectedResponse = response
return nil
})
}
return resp.Header, got // WithExpectedJSONResponse validates that the response from the request in the
// Request function matches JSON-encoded body provided here.
func WithExpectedJSONResponse(response interface{}) Option {
return optionFunc(func(o *options) error {
o.expectedJSONResponse = response
return nil
})
} }
func ResponseUnmarshal(t *testing.T, client *http.Client, method, url string, body io.Reader, responseCode int, response interface{}) { // WithUnmarshalJSONResponse unmarshals response body from the request in the
t.Helper() // Request function to the provided response. Response must be a pointer.
func WithUnmarshalJSONResponse(response interface{}) Option {
return optionFunc(func(o *options) error {
o.unmarshalResponse = response
return nil
})
}
resp := request(t, client, method, url, body, responseCode, nil) // WithPutResponseBody replaces the data in the provided byte slice with the
defer resp.Body.Close() // data from the response body of the request in the Request function.
func WithPutResponseBody(b *[]byte) Option {
return optionFunc(func(o *options) error {
o.responseBody = b
return nil
})
}
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { // WithNoResponseBody ensures that there is no data sent by the response of the
t.Fatal(err) // request in the Request function.
} func WithNoResponseBody() Option {
return optionFunc(func(o *options) error {
o.noResponseBody = true
return nil
})
} }
func request(t *testing.T, client *http.Client, method, url string, body io.Reader, responseCode int, headers http.Header) *http.Response { type options struct {
t.Helper() ctx context.Context
requestBody io.Reader
requestHeaders http.Header
expectedResponse []byte
expectedJSONResponse interface{}
unmarshalResponse interface{}
responseBody *[]byte
noResponseBody bool
}
req, err := http.NewRequest(method, url, body) type Option interface {
if err != nil { apply(*options) error
t.Fatal(err)
}
req.Header = headers
resp, err := client.Do(req)
if err != nil {
t.Fatal(err)
}
if resp.StatusCode != responseCode {
t.Errorf("got response status %s, want %v %s", resp.Status, responseCode, http.StatusText(responseCode))
}
return resp
} }
type optionFunc func(*options) error
func (f optionFunc) apply(r *options) error { return f(r) }
...@@ -5,7 +5,14 @@ ...@@ -5,7 +5,14 @@
package jsonhttptest_test package jsonhttptest_test
import ( import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil" "io/ioutil"
"mime"
"mime/multipart"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"strings" "strings"
...@@ -15,62 +22,316 @@ import ( ...@@ -15,62 +22,316 @@ import (
"github.com/ethersphere/bee/pkg/jsonhttp/jsonhttptest" "github.com/ethersphere/bee/pkg/jsonhttp/jsonhttptest"
) )
func TestResponse(t *testing.T) { func TestRequest_statusCode(t *testing.T) {
c, endpoint := newClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
}))
assert(t, "", "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodGet, endpoint, http.StatusBadRequest)
})
assert(t, `got response status 400 Bad Request, want 200 OK`, "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodGet, endpoint, http.StatusOK)
})
}
func TestRequest_method(t *testing.T) {
c, endpoint := newClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
}))
assert(t, "", "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodGet, endpoint, http.StatusOK)
})
assert(t, "", "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodPost, endpoint, http.StatusMethodNotAllowed)
})
}
func TestRequest_url(t *testing.T) {
c, endpoint := newClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
w.WriteHeader(http.StatusNotFound)
}
}))
assert(t, "", "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodGet, endpoint, http.StatusOK)
})
assert(t, "", "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodPost, endpoint+"/bzz", http.StatusNotFound)
})
}
func TestRequest_responseHeader(t *testing.T) {
headerName := "Swarm-Header"
headerValue := "somevalue"
var gotValue string
c, endpoint := newClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set(headerName, headerValue)
}))
assert(t, "", "", func(m *mock) {
gotValue = jsonhttptest.Request(m, c, http.MethodGet, endpoint, http.StatusOK).Get(headerName)
})
if gotValue != headerValue {
t.Errorf("got header %q, want %q", gotValue, headerValue)
}
}
func TestWithContext(t *testing.T) {
c, endpoint := newClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
ctx, cancel := context.WithCancel(context.Background())
cancel() // cancel the context to detect the fatal error
assert(t, "", fmt.Sprintf("Get %q: context canceled", endpoint), func(m *mock) {
jsonhttptest.Request(m, c, http.MethodGet, endpoint, http.StatusOK,
jsonhttptest.WithContext(ctx),
)
})
}
func TestWithRequestBody(t *testing.T) {
wantBody := []byte("somebody")
var gotBody []byte
c, endpoint := newClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var err error
gotBody, err = ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}))
assert(t, "", "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodPost, endpoint, http.StatusOK,
jsonhttptest.WithRequestBody(bytes.NewReader(wantBody)),
)
})
if !bytes.Equal(gotBody, wantBody) {
t.Errorf("got body %q, want %q", string(gotBody), string(wantBody))
}
}
func TestWithJSONRequestBody(t *testing.T) {
type response struct { type response struct {
Message string `json:"message"` Message string `json:"message"`
} }
message := "text" message := "text"
wantMethod, wantPath, wantBody := http.MethodPatch, "/testing", "request body" wantBody := response{
var gotMethod, gotPath, gotBody string Message: message,
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { }
gotMethod = r.Method var gotBody response
gotPath = r.URL.Path c, endpoint := newClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
b, err := ioutil.ReadAll(r.Body) v, err := ioutil.ReadAll(r.Body)
if err != nil { if err != nil {
jsonhttp.InternalServerError(w, err) jsonhttp.InternalServerError(w, err)
return return
} }
gotBody = string(b) if err := json.Unmarshal(v, &gotBody); err != nil {
jsonhttp.Created(w, response{ jsonhttp.BadRequest(w, err)
Message: message, return
}
}))
assert(t, "", "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodPost, endpoint, http.StatusOK,
jsonhttptest.WithJSONRequestBody(wantBody),
)
}) })
if gotBody.Message != message {
t.Errorf("got message %q, want %q", gotBody.Message, message)
}
}
func TestWithMultipartRequest(t *testing.T) {
wantBody := []byte("somebody")
filename := "swarm.jpg"
contentType := "image/jpeg"
var gotBody []byte
var gotContentDisposition, gotContentType string
c, endpoint := newClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mediaType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
jsonhttp.BadRequest(w, err)
return
}
if strings.HasPrefix(mediaType, "multipart/") {
mr := multipart.NewReader(r.Body, params["boundary"])
p, err := mr.NextPart()
if err != nil {
if err == io.EOF {
return
}
jsonhttp.BadRequest(w, err)
return
}
gotContentDisposition = p.Header.Get("Content-Disposition")
gotContentType = p.Header.Get("Content-Type")
gotBody, err = ioutil.ReadAll(p)
if err != nil {
jsonhttp.BadRequest(w, err)
return
}
}
})) }))
defer s.Close()
c := s.Client() assert(t, "", "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodPost, endpoint, http.StatusOK,
jsonhttptest.WithMultipartRequest(bytes.NewReader(wantBody), len(wantBody), filename, contentType),
)
})
if !bytes.Equal(gotBody, wantBody) {
t.Errorf("got body %q, want %q", string(gotBody), string(wantBody))
}
if gotContentType != contentType {
t.Errorf("got content type %q, want %q", gotContentType, contentType)
}
if contentDisposition := fmt.Sprintf("form-data; name=%q", filename); gotContentDisposition != contentDisposition {
t.Errorf("got content disposition %q, want %q", gotContentDisposition, contentDisposition)
}
}
t.Run("direct", func(t *testing.T) { func TestWithRequestHeader(t *testing.T) {
jsonhttptest.ResponseDirect(t, c, wantMethod, s.URL+wantPath, strings.NewReader(wantBody), http.StatusCreated, response{ headerName := "Swarm-Header"
Message: message, headerValue := "somevalue"
var gotValue string
c, endpoint := newClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotValue = r.Header.Get(headerName)
}))
assert(t, "", "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodPost, endpoint, http.StatusOK,
jsonhttptest.WithRequestHeader(headerName, headerValue),
)
}) })
if gotValue != headerValue {
t.Errorf("got header %q, want %q", gotValue, headerValue)
}
}
func TestWithExpectedResponse(t *testing.T) {
body := []byte("something to want")
if gotMethod != wantMethod { c, endpoint := newClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
t.Errorf("got method %s, want %s", gotMethod, wantMethod) _, err := w.Write(body)
if err != nil {
jsonhttp.InternalServerError(w, err)
} }
if gotPath != wantPath { }))
t.Errorf("got path %s, want %s", gotPath, wantPath)
assert(t, "", "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodGet, endpoint, http.StatusOK,
jsonhttptest.WithExpectedResponse(body),
)
})
assert(t, `got response "something to want", want "invalid"`, "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodGet, endpoint, http.StatusOK,
jsonhttptest.WithExpectedResponse([]byte("invalid")),
)
})
}
func TestWithExpectedJSONResponse(t *testing.T) {
type response struct {
Message string `json:"message"`
} }
if gotBody != wantBody {
t.Errorf("got body %s, want %s", gotBody, wantBody) want := response{
Message: "text",
} }
c, endpoint := newClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
jsonhttp.OK(w, want)
}))
assert(t, "", "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodGet, endpoint, http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(want),
)
}) })
t.Run("unmarshal", func(t *testing.T) { assert(t, `got json response "{\"message\":\"text\"}", want "{\"message\":\"invalid\"}"`, "", func(m *mock) {
var r response jsonhttptest.Request(m, c, http.MethodGet, endpoint, http.StatusOK,
jsonhttptest.ResponseUnmarshal(t, c, wantMethod, s.URL+wantPath, strings.NewReader(wantBody), http.StatusCreated, &r) jsonhttptest.WithExpectedJSONResponse(response{
Message: "invalid",
}),
)
})
}
func TestWithUnmarhalJSONResponse(t *testing.T) {
message := "text"
if gotMethod != wantMethod { c, endpoint := newClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
t.Errorf("got method %s, want %s", gotMethod, wantMethod) jsonhttp.OK(w, message)
}))
var r jsonhttp.StatusResponse
assert(t, "", "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodGet, endpoint, http.StatusOK,
jsonhttptest.WithUnmarshalJSONResponse(&r),
)
})
if r.Message != message {
t.Errorf("got message %q, want %q", r.Message, message)
} }
if gotPath != wantPath { }
t.Errorf("got path %s, want %s", gotPath, wantPath)
func TestWithPutResponseBody(t *testing.T) {
wantBody := []byte("somebody")
c, endpoint := newClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, err := w.Write(wantBody)
if err != nil {
jsonhttp.InternalServerError(w, err)
} }
if gotBody != wantBody { }))
t.Errorf("got body %s, want %s", gotBody, wantBody)
var gotBody []byte
assert(t, "", "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodGet, endpoint, http.StatusOK,
jsonhttptest.WithPutResponseBody(&gotBody),
)
})
if !bytes.Equal(gotBody, wantBody) {
t.Errorf("got body %q, want %q", string(gotBody), string(wantBody))
} }
if r.Message != message { }
t.Errorf("got messag %s, want %s", r.Message, message)
func TestWithNoResponseBody(t *testing.T) {
c, endpoint := newClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
fmt.Fprint(w, "not found")
} }
}))
assert(t, "", "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodGet, endpoint, http.StatusOK,
jsonhttptest.WithNoResponseBody(),
)
}) })
assert(t, `got response body "not found", want none`, "", func(m *mock) {
jsonhttptest.Request(m, c, http.MethodGet, endpoint+"/bzz", http.StatusOK,
jsonhttptest.WithNoResponseBody(),
)
})
}
func newClient(t *testing.T, handler http.Handler) (c *http.Client, endpoint string) {
s := httptest.NewServer(handler)
t.Cleanup(s.Close)
return s.Client(), s.URL
} }
// Copyright 2020 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package jsonhttptest_test
import (
"errors"
"fmt"
"testing"
)
// assert is a test helper that validates a functionality of another helper
// function by mocking Errorf, Fatal and Helper methods on testing.TB.
func assert(t *testing.T, wantError, wantFatal string, f func(m *mock)) {
t.Helper()
defer func() {
if v := recover(); v != nil {
if err, ok := v.(error); ok && errors.Is(err, errFailed) {
return // execution of the goroutine is stopped by a mock Fatal function
}
t.Fatalf("panic: %v", v)
}
}()
m := &mock{
wantError: wantError,
wantFatal: wantFatal,
}
f(m)
if !m.isHelper { // Request function is tested and it must be always a helper
t.Error("not a helper function")
}
if m.gotError != m.wantError {
t.Errorf("got error %q, want %q", m.gotError, m.wantError)
}
if m.gotFatal != m.wantFatal {
t.Errorf("got error %v, want %v", m.gotFatal, m.wantFatal)
}
}
// mock provides the same interface as testing.TB with overridden Errorf, Fatal
// and Heleper methods.
type mock struct {
testing.TB
isHelper bool
gotError string
wantError string
gotFatal string
wantFatal string
}
func (m *mock) Helper() {
m.isHelper = true
}
func (m *mock) Errorf(format string, args ...interface{}) {
m.gotError = fmt.Sprintf(format, args...)
}
func (m *mock) Fatal(args ...interface{}) {
m.gotFatal = fmt.Sprint(args...)
panic(errFailed) // terminate the goroutine to detect it in the assert function
}
var errFailed = errors.New("failed")
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