Commit 8b240282 authored by Janoš Guljaš's avatar Janoš Guljaš Committed by GitHub

improve list and get pinned chunks api endpoints and tests (#233)

parent 58bc639b
......@@ -5,8 +5,10 @@
package debugapi
type (
StatusResponse = statusResponse
PeerConnectResponse = peerConnectResponse
PeersResponse = peersResponse
AddressesResponse = addressesResponse
StatusResponse = statusResponse
PeerConnectResponse = peerConnectResponse
PeersResponse = peersResponse
AddressesResponse = addressesResponse
PinnedChunk = pinnedChunk
ListPinnedChunksResponse = listPinnedChunksResponse
)
......@@ -5,7 +5,7 @@
package debugapi
import (
"context"
"errors"
"net/http"
"github.com/ethersphere/bee/pkg/jsonhttp"
......@@ -29,7 +29,7 @@ func (s *server) pinChunk(w http.ResponseWriter, r *http.Request) {
has, err := s.Storer.Has(r.Context(), addr)
if err != nil {
s.Logger.Debugf("debug api: pin chunk: localstore has: %v", err)
jsonhttp.BadRequest(w, err)
jsonhttp.InternalServerError(w, err)
return
}
......@@ -60,7 +60,7 @@ func (s *server) unpinChunk(w http.ResponseWriter, r *http.Request) {
has, err := s.Storer.Has(r.Context(), addr)
if err != nil {
s.Logger.Debugf("debug api: pin chunk: localstore has: %v", err)
jsonhttp.BadRequest(w, err)
jsonhttp.InternalServerError(w, err)
return
}
......@@ -85,13 +85,64 @@ func (s *server) unpinChunk(w http.ResponseWriter, r *http.Request) {
jsonhttp.OK(w, nil)
}
type pinnedChunk struct {
Address swarm.Address `json:"address"`
PinCounter uint64 `json:"pinCounter"`
}
type listPinnedChunksResponse struct {
Chunks []pinnedChunk `json:"chunks"`
}
// listPinnedChunks lists all the chunk address and pin counters that are currently pinned.
func (s *server) listPinnedChunks(w http.ResponseWriter, r *http.Request) {
pinnedChunks, err := s.Storer.PinnedChunks(context.Background(), swarm.NewAddress(nil))
pinnedChunks, err := s.Storer.PinnedChunks(r.Context(), swarm.NewAddress(nil))
if err != nil {
s.Logger.Debugf("debug-api: pin chunk: listing pinned chunks: %v", err)
jsonhttp.InternalServerError(w, err)
return
}
chunks := make([]pinnedChunk, len(pinnedChunks))
for i, c := range pinnedChunks {
chunks[i] = pinnedChunk(*c)
}
jsonhttp.OK(w, listPinnedChunksResponse{
Chunks: chunks,
})
}
func (s *server) getPinnedChunk(w http.ResponseWriter, r *http.Request) {
addr, err := swarm.ParseHexAddress(mux.Vars(r)["address"])
if err != nil {
s.Logger.Debugf("debug api: pin chunk: parse chunk ddress: %v", err)
jsonhttp.BadRequest(w, "bad address")
return
}
has, err := s.Storer.Has(r.Context(), addr)
if err != nil {
s.Logger.Debugf("debug api: pin chunk: localstore has: %v", err)
jsonhttp.BadRequest(w, err)
return
}
if !has {
jsonhttp.NotFound(w, nil)
return
}
pinCounter, err := s.Storer.PinInfo(addr)
if err != nil {
s.Logger.Debugf("debug-api: pin chunk: listing pinned chunks error: %v", err)
if errors.Is(err, storage.ErrNotFound) {
jsonhttp.NotFound(w, nil)
return
}
s.Logger.Debugf("debug-api: pin chunk: listing pinned chunks: %v", err)
jsonhttp.InternalServerError(w, err)
return
}
jsonhttp.OK(w, pinnedChunks)
jsonhttp.OK(w, pinnedChunk{
Address: addr,
PinCounter: pinCounter,
})
}
......@@ -9,6 +9,7 @@ import (
"net/http"
"testing"
"github.com/ethersphere/bee/pkg/debugapi"
"github.com/ethersphere/bee/pkg/jsonhttp"
"github.com/ethersphere/bee/pkg/jsonhttp/jsonhttptest"
"github.com/ethersphere/bee/pkg/storage/mock"
......@@ -78,9 +79,9 @@ func TestPinChunkHandler(t *testing.T) {
})
// Check is the chunk is pinned once
jsonhttptest.ResponseDirectWithJson(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), nil, http.StatusOK, jsonhttp.StatusResponse{
Message: `{"Address":"aabbcc","PinCounter":1}`,
Code: http.StatusOK,
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), nil, http.StatusOK, debugapi.PinnedChunk{
Address: swarm.MustParseHexAddress("aabbcc"),
PinCounter: 1,
})
})
......@@ -93,9 +94,9 @@ func TestPinChunkHandler(t *testing.T) {
})
// Check is the chunk is pinned twice
jsonhttptest.ResponseDirectWithJson(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), nil, http.StatusOK, jsonhttp.StatusResponse{
Message: `{"Address":"aabbcc","PinCounter":2}`,
Code: http.StatusOK,
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), nil, http.StatusOK, debugapi.PinnedChunk{
Address: swarm.MustParseHexAddress("aabbcc"),
PinCounter: 2,
})
})
......@@ -107,9 +108,9 @@ func TestPinChunkHandler(t *testing.T) {
})
// Check is the chunk is pinned once
jsonhttptest.ResponseDirectWithJson(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), nil, http.StatusOK, jsonhttp.StatusResponse{
Message: `{"Address":"aabbcc","PinCounter":1}`,
Code: http.StatusOK,
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), nil, http.StatusOK, debugapi.PinnedChunk{
Address: swarm.MustParseHexAddress("aabbcc"),
PinCounter: 1,
})
})
......@@ -121,9 +122,9 @@ func TestPinChunkHandler(t *testing.T) {
})
// Check if the chunk is removed from the pinIndex
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), nil, http.StatusInternalServerError, jsonhttp.StatusResponse{
Message: "pin chunks: leveldb: not found",
Code: http.StatusInternalServerError,
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodGet, "/chunks-pin/"+hash.String(), nil, http.StatusNotFound, jsonhttp.StatusResponse{
Message: http.StatusText(http.StatusNotFound),
Code: http.StatusNotFound,
})
})
......@@ -153,10 +154,17 @@ func TestPinChunkHandler(t *testing.T) {
Code: http.StatusOK,
})
jsonhttptest.ResponseDirectWithJson(t, debugTestServer.Client, http.MethodGet, "/chunks-pin", nil, http.StatusOK, jsonhttp.StatusResponse{
Message: `{"Address":"aabbcc","PinCounter":1},{"Address":"ddeeff","PinCounter":1}`,
Code: http.StatusOK,
jsonhttptest.ResponseDirect(t, debugTestServer.Client, http.MethodGet, "/chunks-pin", nil, http.StatusOK, debugapi.ListPinnedChunksResponse{
Chunks: []debugapi.PinnedChunk{
{
Address: swarm.MustParseHexAddress("aabbcc"),
PinCounter: 1,
},
{
Address: swarm.MustParseHexAddress("ddeeff"),
PinCounter: 1,
},
},
})
})
}
......@@ -57,9 +57,9 @@ func (s *server) setupRouting() {
"GET": http.HandlerFunc(s.hasChunkHandler),
})
router.Handle("/chunks-pin/{address}", jsonhttp.MethodHandler{
"GET": http.HandlerFunc(s.getPinnedChunk),
"POST": http.HandlerFunc(s.pinChunk),
"DELETE": http.HandlerFunc(s.unpinChunk),
"GET": http.HandlerFunc(s.listPinnedChunks),
})
router.Handle("/chunks-pin", jsonhttp.MethodHandler{
"GET": http.HandlerFunc(s.listPinnedChunks),
......
......@@ -11,8 +11,6 @@ import (
"io/ioutil"
"net/http"
"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{}) {
......@@ -37,35 +35,6 @@ func ResponseDirect(t *testing.T, client *http.Client, method, url string, body
}
}
// ResponseDirectWithJson checks for responses in json format. It is useful in cases where the response is json.
func ResponseDirectWithJson(t *testing.T, client *http.Client, method, url string, body io.Reader, responseCode int, response interface{}) {
t.Helper()
resp := request(t, client, method, url, body, responseCode, nil)
defer resp.Body.Close()
got, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
got = bytes.TrimSpace(got)
want, err := json.Marshal(response)
if err != nil {
t.Error(err)
}
var wantJson jsonhttp.StatusResponse
err = json.Unmarshal(want, &wantJson)
if err != nil {
t.Error(err)
}
wantString := "[" + wantJson.Message + "]"
if wantString != string(got) {
t.Errorf("got response %s, want %s", string(got), wantString)
}
}
func ResponseDirectWithHeaders(t *testing.T, client *http.Client, method, url string, body io.Reader, responseCode int,
response interface{}, headers http.Header) {
t.Helper()
......
......@@ -7,11 +7,13 @@ package localstore
import (
"bytes"
"context"
"errors"
"fmt"
"github.com/ethersphere/bee/pkg/shed"
"github.com/ethersphere/bee/pkg/storage"
"github.com/ethersphere/bee/pkg/swarm"
"github.com/syndtr/goleveldb/leveldb"
)
const (
......@@ -60,6 +62,9 @@ func (db *DB) PinInfo(address swarm.Address) (uint64, error) {
}
out, err := db.pinIndex.Get(it)
if err != nil {
if errors.Is(err, leveldb.ErrNotFound) {
return 0, storage.ErrNotFound
}
return 0, err
}
return out.PinCounter, nil
......
......@@ -116,7 +116,7 @@ func TestPinInfo(t *testing.T) {
}
_, err = db.PinInfo(swarm.NewAddress(chunk.Address().Bytes()))
if err != nil {
if !errors.Is(err, leveldb.ErrNotFound) {
if !errors.Is(err, storage.ErrNotFound) {
t.Fatal(err)
}
}
......
......@@ -166,7 +166,7 @@ func (m *MockStorer) PinInfo(address swarm.Address) (uint64, error) {
return m.pinnedCounter[i], nil
}
}
return 0, errors.New("could not find address")
return 0, storage.ErrNotFound
}
func (m *MockStorer) Close() error {
......
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