test http handler
This commit is contained in:
parent
db5c88196d
commit
759d8f090b
@ -364,7 +364,7 @@ var runCmd = &cli.Command{
|
||||
|
||||
remote := stores.NewRemote(localStore, nodeApi, sminfo.AuthHeader(), cctx.Int("parallel-fetch-limit"))
|
||||
|
||||
fh := &stores.FetchHandler{Local: localStore}
|
||||
fh := &stores.FetchHandler{Local: localStore, PfHandler: &stores.DefaultPartialFileHandler{}}
|
||||
remoteHandler := func(w http.ResponseWriter, r *http.Request) {
|
||||
if !auth.HasPerm(r.Context(), nil, api.PermAdmin) {
|
||||
w.WriteHeader(401)
|
||||
|
2
extern/sector-storage/manager.go
vendored
2
extern/sector-storage/manager.go
vendored
@ -114,7 +114,7 @@ func New(ctx context.Context, lstor *stores.Local, stor *stores.Remote, ls store
|
||||
ls: ls,
|
||||
storage: stor,
|
||||
localStore: lstor,
|
||||
remoteHnd: &stores.FetchHandler{Local: lstor},
|
||||
remoteHnd: &stores.FetchHandler{Local: lstor, PfHandler: &stores.DefaultPartialFileHandler{}},
|
||||
index: si,
|
||||
|
||||
sched: newScheduler(),
|
||||
|
38
extern/sector-storage/stores/http_handler.go
vendored
38
extern/sector-storage/stores/http_handler.go
vendored
@ -21,8 +21,23 @@ import (
|
||||
|
||||
var log = logging.Logger("stores")
|
||||
|
||||
var _ partialFileHandler = &DefaultPartialFileHandler{}
|
||||
|
||||
// DefaultPartialFileHandler is the default implementation of the partialFileHandler interface.
|
||||
// This is probably the only implementation we'll ever use because the purpose of the
|
||||
// interface to is to mock out partial file related functionality during testing.
|
||||
type DefaultPartialFileHandler struct{}
|
||||
|
||||
func (d *DefaultPartialFileHandler) OpenPartialFile(maxPieceSize abi.PaddedPieceSize, path string) (*partialfile.PartialFile, error) {
|
||||
return partialfile.OpenPartialFile(maxPieceSize, path)
|
||||
}
|
||||
func (d *DefaultPartialFileHandler) HasAllocated(pf *partialfile.PartialFile, offset storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize) (bool, error) {
|
||||
return pf.HasAllocated(offset, size)
|
||||
}
|
||||
|
||||
type FetchHandler struct {
|
||||
*Local
|
||||
Local Store
|
||||
PfHandler partialFileHandler
|
||||
}
|
||||
|
||||
func (handler *FetchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // /remote/
|
||||
@ -88,7 +103,7 @@ func (handler *FetchHandler) remoteGetSector(w http.ResponseWriter, r *http.Requ
|
||||
|
||||
paths, _, err := handler.Local.AcquireSector(r.Context(), si, ft, storiface.FTNone, storiface.PathStorage, storiface.AcquireMove)
|
||||
if err != nil {
|
||||
log.Errorf("%+v", err)
|
||||
log.Errorf("AcquireSector: %+v", err)
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
@ -104,7 +119,7 @@ func (handler *FetchHandler) remoteGetSector(w http.ResponseWriter, r *http.Requ
|
||||
|
||||
stat, err := os.Stat(path)
|
||||
if err != nil {
|
||||
log.Errorf("%+v", err)
|
||||
log.Errorf("os.Stat: %+v", err)
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
@ -131,6 +146,7 @@ func (handler *FetchHandler) remoteGetSector(w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.WriteHeader(200)
|
||||
// will do a ranged read over the file at the given path if the caller has asked for a ranged read in the request headers.
|
||||
http.ServeFile(w, r, path)
|
||||
}
|
||||
@ -156,7 +172,7 @@ func (handler *FetchHandler) remoteDeleteSector(w http.ResponseWriter, r *http.R
|
||||
return
|
||||
}
|
||||
|
||||
if err := handler.Remove(r.Context(), id, ft, false); err != nil {
|
||||
if err := handler.Local.Remove(r.Context(), id, ft, false); err != nil {
|
||||
log.Errorf("%+v", err)
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
@ -172,14 +188,14 @@ func (handler *FetchHandler) remoteGetAllocated(w http.ResponseWriter, r *http.R
|
||||
|
||||
id, err := storiface.ParseSectorID(vars["id"])
|
||||
if err != nil {
|
||||
log.Errorf("%+v", err)
|
||||
log.Errorf("parsing sectorID: %+v", err)
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
|
||||
ft, err := ftFromString(vars["type"])
|
||||
if err != nil {
|
||||
log.Errorf("%+v", err)
|
||||
log.Errorf("ftFromString: %+v", err)
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
@ -198,7 +214,7 @@ func (handler *FetchHandler) remoteGetAllocated(w http.ResponseWriter, r *http.R
|
||||
spt := abi.RegisteredSealProof(spti)
|
||||
ssize, err := spt.SectorSize()
|
||||
if err != nil {
|
||||
log.Errorf("%+v", err)
|
||||
log.Errorf("spt.SectorSize(): %+v", err)
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
@ -211,7 +227,7 @@ func (handler *FetchHandler) remoteGetAllocated(w http.ResponseWriter, r *http.R
|
||||
}
|
||||
szi, err := strconv.ParseInt(vars["size"], 10, 64)
|
||||
if err != nil {
|
||||
log.Errorf("parsing spt: %+v", err)
|
||||
log.Errorf("parsing size: %+v", err)
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
@ -228,7 +244,7 @@ func (handler *FetchHandler) remoteGetAllocated(w http.ResponseWriter, r *http.R
|
||||
// return error if we do NOT have it.
|
||||
paths, _, err := handler.Local.AcquireSector(r.Context(), si, ft, storiface.FTNone, storiface.PathStorage, storiface.AcquireMove)
|
||||
if err != nil {
|
||||
log.Errorf("%+v", err)
|
||||
log.Errorf("AcquireSector: %+v", err)
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
@ -241,7 +257,7 @@ func (handler *FetchHandler) remoteGetAllocated(w http.ResponseWriter, r *http.R
|
||||
}
|
||||
|
||||
// open the Unsealed file and check if it has the Unsealed sector for the piece at the given offset and size.
|
||||
pf, err := partialfile.OpenPartialFile(abi.PaddedPieceSize(ssize), path)
|
||||
pf, err := handler.PfHandler.OpenPartialFile(abi.PaddedPieceSize(ssize), path)
|
||||
if err != nil {
|
||||
log.Error("opening partial file: ", err)
|
||||
w.WriteHeader(500)
|
||||
@ -253,7 +269,7 @@ func (handler *FetchHandler) remoteGetAllocated(w http.ResponseWriter, r *http.R
|
||||
}
|
||||
}()
|
||||
|
||||
has, err := pf.HasAllocated(storiface.UnpaddedByteIndex(offi), abi.UnpaddedPieceSize(szi))
|
||||
has, err := handler.PfHandler.HasAllocated(pf, storiface.UnpaddedByteIndex(offi), abi.UnpaddedPieceSize(szi))
|
||||
if err != nil {
|
||||
log.Error("has allocated: ", err)
|
||||
w.WriteHeader(500)
|
||||
|
437
extern/sector-storage/stores/http_handler_test.go
vendored
Normal file
437
extern/sector-storage/stores/http_handler_test.go
vendored
Normal file
@ -0,0 +1,437 @@
|
||||
package stores_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/partialfile"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/stores/mocks"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
|
||||
"github.com/filecoin-project/specs-storage/storage"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func TestRemoteGetAllocated(t *testing.T) {
|
||||
|
||||
emptyPartialFile := &partialfile.PartialFile{}
|
||||
pfPath := "path"
|
||||
expectedSectorRef := storage.SectorRef{
|
||||
ID: abi.SectorID{
|
||||
123,
|
||||
123,
|
||||
},
|
||||
ProofType: 0,
|
||||
}
|
||||
|
||||
validSectorName := fmt.Sprintf("s-t0%d-%d", 123, 123)
|
||||
validSectorFileType := storiface.FTUnsealed.String()
|
||||
validSectorType := "1"
|
||||
sectorSize := abi.SealProofInfos[1].SectorSize
|
||||
|
||||
validOffset := "100"
|
||||
validOffsetInt := 100
|
||||
|
||||
validSize := "1000"
|
||||
validSizeInt := 1000
|
||||
|
||||
type pieceInfo struct {
|
||||
sectorName string
|
||||
fileType string
|
||||
sectorType string
|
||||
|
||||
// piece info
|
||||
offset string
|
||||
size string
|
||||
}
|
||||
validPieceInfo := pieceInfo{
|
||||
sectorName: validSectorName,
|
||||
fileType: validSectorFileType,
|
||||
sectorType: validSectorType,
|
||||
offset: validOffset,
|
||||
size: validSize,
|
||||
}
|
||||
|
||||
tcs := map[string]struct {
|
||||
piFnc func(pi *pieceInfo)
|
||||
storeFnc func(s *mocks.Store)
|
||||
pfFunc func(s *mocks.PartialFileHandler)
|
||||
|
||||
// expectation
|
||||
expectedStatusCode int
|
||||
}{
|
||||
"fails when sector name is invalid": {
|
||||
piFnc: func(pi *pieceInfo) {
|
||||
pi.sectorName = "invalid"
|
||||
},
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
},
|
||||
"fails when file type is invalid": {
|
||||
piFnc: func(pi *pieceInfo) {
|
||||
pi.fileType = "invalid"
|
||||
},
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
},
|
||||
"fails when sector proof type is invalid": {
|
||||
piFnc: func(pi *pieceInfo) {
|
||||
pi.sectorType = "invalid"
|
||||
},
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
},
|
||||
"fails when offset is invalid": {
|
||||
piFnc: func(pi *pieceInfo) {
|
||||
pi.offset = "invalid"
|
||||
},
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
},
|
||||
"fails when size is invalid": {
|
||||
piFnc: func(pi *pieceInfo) {
|
||||
pi.size = "invalid"
|
||||
},
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
},
|
||||
"fails when errors out during acquiring unsealed sector file": {
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
storeFnc: func(l *mocks.Store) {
|
||||
l.On("AcquireSector", mock.Anything, expectedSectorRef, storiface.FTUnsealed,
|
||||
storiface.FTNone, storiface.PathStorage, storiface.AcquireMove).Return(storiface.SectorPaths{
|
||||
Unsealed: "path",
|
||||
},
|
||||
storiface.SectorPaths{}, xerrors.New("some error"))
|
||||
},
|
||||
},
|
||||
"fails when unsealed sector file is not found locally": {
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
storeFnc: func(l *mocks.Store) {
|
||||
|
||||
l.On("AcquireSector", mock.Anything, expectedSectorRef, storiface.FTUnsealed,
|
||||
storiface.FTNone, storiface.PathStorage, storiface.AcquireMove).Return(storiface.SectorPaths{},
|
||||
storiface.SectorPaths{}, nil)
|
||||
},
|
||||
},
|
||||
"fails when partial file is not found locally": {
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
storeFnc: func(l *mocks.Store) {
|
||||
// will return emppty paths
|
||||
|
||||
l.On("AcquireSector", mock.Anything, expectedSectorRef, storiface.FTUnsealed,
|
||||
storiface.FTNone, storiface.PathStorage, storiface.AcquireMove).Return(storiface.SectorPaths{
|
||||
Unsealed: pfPath,
|
||||
},
|
||||
storiface.SectorPaths{}, nil)
|
||||
},
|
||||
|
||||
pfFunc: func(pf *mocks.PartialFileHandler) {
|
||||
//OpenPartialFile(maxPieceSize abi.PaddedPieceSize, path string)
|
||||
pf.On("OpenPartialFile", abi.PaddedPieceSize(sectorSize), pfPath).Return(&partialfile.PartialFile{},
|
||||
xerrors.New("some error"))
|
||||
},
|
||||
},
|
||||
|
||||
"fails when determining partial file allocation returns an error": {
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
storeFnc: func(l *mocks.Store) {
|
||||
// will return emppty paths
|
||||
|
||||
l.On("AcquireSector", mock.Anything, expectedSectorRef, storiface.FTUnsealed,
|
||||
storiface.FTNone, storiface.PathStorage, storiface.AcquireMove).Return(storiface.SectorPaths{
|
||||
Unsealed: pfPath,
|
||||
},
|
||||
storiface.SectorPaths{}, nil)
|
||||
},
|
||||
|
||||
pfFunc: func(pf *mocks.PartialFileHandler) {
|
||||
pf.On("OpenPartialFile", abi.PaddedPieceSize(sectorSize), pfPath).Return(emptyPartialFile,
|
||||
nil)
|
||||
pf.On("HasAllocated", emptyPartialFile, storiface.UnpaddedByteIndex(validOffsetInt),
|
||||
abi.UnpaddedPieceSize(validSizeInt)).Return(true, xerrors.New("some error"))
|
||||
},
|
||||
},
|
||||
"StatusRequestedRangeNotSatisfiable when piece is NOT allocated in partial file": {
|
||||
expectedStatusCode: http.StatusRequestedRangeNotSatisfiable,
|
||||
storeFnc: func(l *mocks.Store) {
|
||||
// will return emppty paths
|
||||
|
||||
l.On("AcquireSector", mock.Anything, expectedSectorRef, storiface.FTUnsealed,
|
||||
storiface.FTNone, storiface.PathStorage, storiface.AcquireMove).Return(storiface.SectorPaths{
|
||||
Unsealed: pfPath,
|
||||
},
|
||||
storiface.SectorPaths{}, nil)
|
||||
},
|
||||
|
||||
pfFunc: func(pf *mocks.PartialFileHandler) {
|
||||
pf.On("OpenPartialFile", abi.PaddedPieceSize(sectorSize), pfPath).Return(emptyPartialFile,
|
||||
nil)
|
||||
pf.On("HasAllocated", emptyPartialFile, storiface.UnpaddedByteIndex(validOffsetInt),
|
||||
abi.UnpaddedPieceSize(validSizeInt)).Return(false, nil)
|
||||
},
|
||||
},
|
||||
"OK when piece is allocated in partial file": {
|
||||
expectedStatusCode: http.StatusOK,
|
||||
storeFnc: func(l *mocks.Store) {
|
||||
// will return emppty paths
|
||||
|
||||
l.On("AcquireSector", mock.Anything, expectedSectorRef, storiface.FTUnsealed,
|
||||
storiface.FTNone, storiface.PathStorage, storiface.AcquireMove).Return(storiface.SectorPaths{
|
||||
Unsealed: pfPath,
|
||||
},
|
||||
storiface.SectorPaths{}, nil)
|
||||
},
|
||||
|
||||
pfFunc: func(pf *mocks.PartialFileHandler) {
|
||||
pf.On("OpenPartialFile", abi.PaddedPieceSize(sectorSize), pfPath).Return(emptyPartialFile,
|
||||
nil)
|
||||
pf.On("HasAllocated", emptyPartialFile, storiface.UnpaddedByteIndex(validOffsetInt),
|
||||
abi.UnpaddedPieceSize(validSizeInt)).Return(true, nil)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range tcs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
lstore := &mocks.Store{}
|
||||
pfhandler := &mocks.PartialFileHandler{}
|
||||
|
||||
handler := &stores.FetchHandler{
|
||||
lstore,
|
||||
pfhandler,
|
||||
}
|
||||
|
||||
// run http server
|
||||
ts := httptest.NewServer(handler)
|
||||
defer ts.Close()
|
||||
|
||||
pi := validPieceInfo
|
||||
if tc.piFnc != nil {
|
||||
tc.piFnc(&pi)
|
||||
}
|
||||
|
||||
if tc.storeFnc != nil {
|
||||
tc.storeFnc(lstore)
|
||||
}
|
||||
if tc.pfFunc != nil {
|
||||
tc.pfFunc(pfhandler)
|
||||
}
|
||||
|
||||
// call remoteGetAllocated
|
||||
url := fmt.Sprintf("%s/remote/%s/%s/%s/allocated/%s/%s",
|
||||
ts.URL,
|
||||
pi.fileType,
|
||||
pi.sectorName,
|
||||
pi.sectorType,
|
||||
pi.offset,
|
||||
pi.size)
|
||||
resp, err := http.Get(url)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
// assert expected status code
|
||||
require.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
||||
|
||||
// assert expectations on the mocks
|
||||
lstore.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoteGetSector(t *testing.T) {
|
||||
str := "hello-world"
|
||||
fileBytes := []byte(str)
|
||||
|
||||
validSectorName := fmt.Sprintf("s-t0%d-%d", 123, 123)
|
||||
validSectorFileType := storiface.FTUnsealed.String()
|
||||
expectedSectorRef := storage.SectorRef{
|
||||
ID: abi.SectorID{
|
||||
123,
|
||||
123,
|
||||
},
|
||||
ProofType: 0,
|
||||
}
|
||||
|
||||
type sectorInfo struct {
|
||||
sectorName string
|
||||
fileType string
|
||||
}
|
||||
validSectorInfo := sectorInfo{
|
||||
sectorName: validSectorName,
|
||||
fileType: validSectorFileType,
|
||||
}
|
||||
|
||||
tcs := map[string]struct {
|
||||
siFnc func(pi *sectorInfo)
|
||||
storeFnc func(s *mocks.Store, path string)
|
||||
|
||||
// reading a file or a dir
|
||||
isDir bool
|
||||
|
||||
// expectation
|
||||
noResponseBytes bool
|
||||
expectedContentType string
|
||||
expectedStatusCode int
|
||||
expectedResponseBytes []byte
|
||||
}{
|
||||
"fails when sector name is invalid": {
|
||||
siFnc: func(si *sectorInfo) {
|
||||
si.sectorName = "invalid"
|
||||
},
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
noResponseBytes: true,
|
||||
},
|
||||
"fails when file type is invalid": {
|
||||
siFnc: func(si *sectorInfo) {
|
||||
si.fileType = "invalid"
|
||||
},
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
noResponseBytes: true,
|
||||
},
|
||||
"fails when error while acquiring sector file": {
|
||||
storeFnc: func(l *mocks.Store, _ string) {
|
||||
l.On("AcquireSector", mock.Anything, expectedSectorRef, storiface.FTUnsealed,
|
||||
storiface.FTNone, storiface.PathStorage, storiface.AcquireMove).Return(storiface.SectorPaths{
|
||||
Unsealed: "path",
|
||||
},
|
||||
storiface.SectorPaths{}, xerrors.New("some error"))
|
||||
},
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
noResponseBytes: true,
|
||||
},
|
||||
"fails when acquired sector file path is empty": {
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
storeFnc: func(l *mocks.Store, _ string) {
|
||||
|
||||
l.On("AcquireSector", mock.Anything, expectedSectorRef, storiface.FTUnsealed,
|
||||
storiface.FTNone, storiface.PathStorage, storiface.AcquireMove).Return(storiface.SectorPaths{},
|
||||
storiface.SectorPaths{}, nil)
|
||||
},
|
||||
noResponseBytes: true,
|
||||
},
|
||||
"fails when acquired file does not exist": {
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
storeFnc: func(l *mocks.Store, _ string) {
|
||||
|
||||
l.On("AcquireSector", mock.Anything, expectedSectorRef, storiface.FTUnsealed,
|
||||
storiface.FTNone, storiface.PathStorage, storiface.AcquireMove).Return(storiface.SectorPaths{
|
||||
Unsealed: "path",
|
||||
},
|
||||
storiface.SectorPaths{}, nil)
|
||||
},
|
||||
noResponseBytes: true,
|
||||
},
|
||||
"successfully read a sector file": {
|
||||
storeFnc: func(l *mocks.Store, path string) {
|
||||
|
||||
l.On("AcquireSector", mock.Anything, expectedSectorRef, storiface.FTUnsealed,
|
||||
storiface.FTNone, storiface.PathStorage, storiface.AcquireMove).Return(storiface.SectorPaths{
|
||||
Unsealed: path,
|
||||
},
|
||||
storiface.SectorPaths{}, nil)
|
||||
},
|
||||
|
||||
noResponseBytes: false,
|
||||
expectedContentType: "application/octet-stream",
|
||||
expectedStatusCode: 200,
|
||||
expectedResponseBytes: fileBytes,
|
||||
},
|
||||
"successfully read a sector dir": {
|
||||
storeFnc: func(l *mocks.Store, path string) {
|
||||
|
||||
l.On("AcquireSector", mock.Anything, expectedSectorRef, storiface.FTUnsealed,
|
||||
storiface.FTNone, storiface.PathStorage, storiface.AcquireMove).Return(storiface.SectorPaths{
|
||||
Unsealed: path,
|
||||
},
|
||||
storiface.SectorPaths{}, nil)
|
||||
},
|
||||
|
||||
isDir: true,
|
||||
noResponseBytes: false,
|
||||
expectedContentType: "application/x-tar",
|
||||
expectedStatusCode: 200,
|
||||
expectedResponseBytes: fileBytes,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range tcs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
var path string
|
||||
|
||||
if !tc.isDir {
|
||||
// create file
|
||||
tempFile, err := ioutil.TempFile("", "TestRemoteGetSector-")
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(tempFile.Name())
|
||||
_, err = tempFile.Write(fileBytes)
|
||||
require.NoError(t, err)
|
||||
path = tempFile.Name()
|
||||
} else {
|
||||
// create dir with a file
|
||||
tempFile2, err := ioutil.TempFile("", "TestRemoteGetSector-")
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(tempFile2.Name())
|
||||
stat, err := os.Stat(tempFile2.Name())
|
||||
require.NoError(t, err)
|
||||
tempDir, err := ioutil.TempDir("", "TestRemoteGetSector-")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(tempDir)
|
||||
require.NoError(t, os.Rename(tempFile2.Name(), filepath.Join(tempDir, stat.Name())))
|
||||
|
||||
path = tempDir
|
||||
}
|
||||
|
||||
lstore := &mocks.Store{}
|
||||
pfhandler := &mocks.PartialFileHandler{}
|
||||
|
||||
handler := &stores.FetchHandler{
|
||||
lstore,
|
||||
pfhandler,
|
||||
}
|
||||
|
||||
// run http server
|
||||
ts := httptest.NewServer(handler)
|
||||
defer ts.Close()
|
||||
|
||||
si := validSectorInfo
|
||||
if tc.siFnc != nil {
|
||||
tc.siFnc(&si)
|
||||
}
|
||||
|
||||
if tc.storeFnc != nil {
|
||||
tc.storeFnc(lstore, path)
|
||||
}
|
||||
|
||||
// call remoteGetAllocated
|
||||
url := fmt.Sprintf("%s/remote/%s/%s",
|
||||
ts.URL,
|
||||
si.fileType,
|
||||
si.sectorName,
|
||||
)
|
||||
resp, err := http.Get(url)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
bz, err := ioutil.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
// assert expected status code
|
||||
require.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
||||
|
||||
if !tc.noResponseBytes {
|
||||
if !tc.isDir {
|
||||
require.EqualValues(t, tc.expectedResponseBytes, bz)
|
||||
}
|
||||
}
|
||||
|
||||
require.Equal(t, tc.expectedContentType, resp.Header.Get("Content-Type"))
|
||||
|
||||
// assert expectations on the mocks
|
||||
lstore.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
12
extern/sector-storage/stores/interface.go
vendored
12
extern/sector-storage/stores/interface.go
vendored
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/partialfile"
|
||||
|
||||
"github.com/filecoin-project/specs-storage/storage"
|
||||
|
||||
@ -11,6 +12,17 @@ import (
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
|
||||
)
|
||||
|
||||
// PartialFileHandler helps mock out the partial file functionality during testing.
|
||||
type partialFileHandler interface {
|
||||
// OpenPartialFile opens and returns a partial file at the given path and also verifies it has the given
|
||||
// size
|
||||
OpenPartialFile(maxPieceSize abi.PaddedPieceSize, path string) (*partialfile.PartialFile, error)
|
||||
|
||||
// HasAllocated returns true if the given partialfile has an unsealed piece starting at the given offset with the given size.
|
||||
// returns false otherwise.
|
||||
HasAllocated(pf *partialfile.PartialFile, offset storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize) (bool, error)
|
||||
}
|
||||
|
||||
type Store interface {
|
||||
AcquireSector(ctx context.Context, s storage.SectorRef, existing storiface.SectorFileType, allocate storiface.SectorFileType, sealing storiface.PathType, op storiface.AcquireMode) (paths storiface.SectorPaths, stores storiface.SectorPaths, err error)
|
||||
Remove(ctx context.Context, s abi.SectorID, types storiface.SectorFileType, force bool) error
|
||||
|
61
extern/sector-storage/stores/mocks/PartialFileHandler.go
vendored
Normal file
61
extern/sector-storage/stores/mocks/PartialFileHandler.go
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
// Code generated by mockery 2.7.5. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
abi "github.com/filecoin-project/go-state-types/abi"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
partialfile "github.com/filecoin-project/lotus/extern/sector-storage/partialfile"
|
||||
|
||||
storiface "github.com/filecoin-project/lotus/extern/sector-storage/storiface"
|
||||
)
|
||||
|
||||
// PartialFileHandler is an autogenerated mock type for the PartialFileHandler type
|
||||
type PartialFileHandler struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// HasAllocated provides a mock function with given fields: pf, offset, size
|
||||
func (_m *PartialFileHandler) HasAllocated(pf *partialfile.PartialFile, offset storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize) (bool, error) {
|
||||
ret := _m.Called(pf, offset, size)
|
||||
|
||||
var r0 bool
|
||||
if rf, ok := ret.Get(0).(func(*partialfile.PartialFile, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) bool); ok {
|
||||
r0 = rf(pf, offset, size)
|
||||
} else {
|
||||
r0 = ret.Get(0).(bool)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*partialfile.PartialFile, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) error); ok {
|
||||
r1 = rf(pf, offset, size)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// OpenPartialFile provides a mock function with given fields: maxPieceSize, path
|
||||
func (_m *PartialFileHandler) OpenPartialFile(maxPieceSize abi.PaddedPieceSize, path string) (*partialfile.PartialFile, error) {
|
||||
ret := _m.Called(maxPieceSize, path)
|
||||
|
||||
var r0 *partialfile.PartialFile
|
||||
if rf, ok := ret.Get(0).(func(abi.PaddedPieceSize, string) *partialfile.PartialFile); ok {
|
||||
r0 = rf(maxPieceSize, path)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*partialfile.PartialFile)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(abi.PaddedPieceSize, string) error); ok {
|
||||
r1 = rf(maxPieceSize, path)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
115
extern/sector-storage/stores/mocks/Store.go
vendored
Normal file
115
extern/sector-storage/stores/mocks/Store.go
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
// Code generated by mockery 2.7.5. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
abi "github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
fsutil "github.com/filecoin-project/lotus/extern/sector-storage/fsutil"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
storage "github.com/filecoin-project/specs-storage/storage"
|
||||
|
||||
stores "github.com/filecoin-project/lotus/extern/sector-storage/stores"
|
||||
|
||||
storiface "github.com/filecoin-project/lotus/extern/sector-storage/storiface"
|
||||
)
|
||||
|
||||
// Store is an autogenerated mock type for the Store type
|
||||
type Store struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// AcquireSector provides a mock function with given fields: ctx, s, existing, allocate, sealing, op
|
||||
func (_m *Store) AcquireSector(ctx context.Context, s storage.SectorRef, existing storiface.SectorFileType, allocate storiface.SectorFileType, sealing storiface.PathType, op storiface.AcquireMode) (storiface.SectorPaths, storiface.SectorPaths, error) {
|
||||
ret := _m.Called(ctx, s, existing, allocate, sealing, op)
|
||||
|
||||
var r0 storiface.SectorPaths
|
||||
if rf, ok := ret.Get(0).(func(context.Context, storage.SectorRef, storiface.SectorFileType, storiface.SectorFileType, storiface.PathType, storiface.AcquireMode) storiface.SectorPaths); ok {
|
||||
r0 = rf(ctx, s, existing, allocate, sealing, op)
|
||||
} else {
|
||||
r0 = ret.Get(0).(storiface.SectorPaths)
|
||||
}
|
||||
|
||||
var r1 storiface.SectorPaths
|
||||
if rf, ok := ret.Get(1).(func(context.Context, storage.SectorRef, storiface.SectorFileType, storiface.SectorFileType, storiface.PathType, storiface.AcquireMode) storiface.SectorPaths); ok {
|
||||
r1 = rf(ctx, s, existing, allocate, sealing, op)
|
||||
} else {
|
||||
r1 = ret.Get(1).(storiface.SectorPaths)
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, storage.SectorRef, storiface.SectorFileType, storiface.SectorFileType, storiface.PathType, storiface.AcquireMode) error); ok {
|
||||
r2 = rf(ctx, s, existing, allocate, sealing, op)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// FsStat provides a mock function with given fields: ctx, id
|
||||
func (_m *Store) FsStat(ctx context.Context, id stores.ID) (fsutil.FsStat, error) {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
var r0 fsutil.FsStat
|
||||
if rf, ok := ret.Get(0).(func(context.Context, stores.ID) fsutil.FsStat); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
r0 = ret.Get(0).(fsutil.FsStat)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, stores.ID) error); ok {
|
||||
r1 = rf(ctx, id)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MoveStorage provides a mock function with given fields: ctx, s, types
|
||||
func (_m *Store) MoveStorage(ctx context.Context, s storage.SectorRef, types storiface.SectorFileType) error {
|
||||
ret := _m.Called(ctx, s, types)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, storage.SectorRef, storiface.SectorFileType) error); ok {
|
||||
r0 = rf(ctx, s, types)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Remove provides a mock function with given fields: ctx, s, types, force
|
||||
func (_m *Store) Remove(ctx context.Context, s abi.SectorID, types storiface.SectorFileType, force bool) error {
|
||||
ret := _m.Called(ctx, s, types, force)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, abi.SectorID, storiface.SectorFileType, bool) error); ok {
|
||||
r0 = rf(ctx, s, types, force)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// RemoveCopies provides a mock function with given fields: ctx, s, types
|
||||
func (_m *Store) RemoveCopies(ctx context.Context, s abi.SectorID, types storiface.SectorFileType) error {
|
||||
ret := _m.Called(ctx, s, types)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, abi.SectorID, storiface.SectorFileType) error); ok {
|
||||
r0 = rf(ctx, s, types)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
Loading…
Reference in New Issue
Block a user