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