lotus/storage/paths/remote_test.go

883 lines
25 KiB
Go
Raw Normal View History

2021-12-15 14:30:42 +00:00
//stm: #unit
package paths_test
2021-05-20 11:01:25 +00:00
import (
"context"
"encoding/json"
2021-05-20 11:01:25 +00:00
"fmt"
"io"
2021-05-20 11:01:25 +00:00
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
2021-05-20 11:01:25 +00:00
"testing"
"github.com/golang/mock/gomock"
"github.com/google/uuid"
"github.com/gorilla/mux"
logging "github.com/ipfs/go-log/v2"
"github.com/stretchr/testify/require"
"golang.org/x/xerrors"
2021-05-20 11:01:25 +00:00
"github.com/filecoin-project/go-state-types/abi"
2022-06-14 15:00:51 +00:00
"github.com/filecoin-project/specs-storage/storage"
"github.com/filecoin-project/lotus/node/repo"
"github.com/filecoin-project/lotus/storage/paths"
"github.com/filecoin-project/lotus/storage/paths/mocks"
"github.com/filecoin-project/lotus/storage/sealer/partialfile"
"github.com/filecoin-project/lotus/storage/sealer/storiface"
2021-05-20 11:01:25 +00:00
)
const metaFile = "sectorstore.json"
func createTestStorage(t *testing.T, p string, seal bool, att ...*paths.Local) storiface.ID {
if err := os.MkdirAll(p, 0755); err != nil {
if !os.IsExist(err) {
require.NoError(t, err)
}
}
cfg := &paths.LocalStorageMeta{
2022-01-18 10:57:04 +00:00
ID: storiface.ID(uuid.New().String()),
Weight: 10,
CanSeal: seal,
CanStore: !seal,
}
b, err := json.MarshalIndent(cfg, "", " ")
require.NoError(t, err)
require.NoError(t, ioutil.WriteFile(filepath.Join(p, metaFile), b, 0644))
for _, s := range att {
require.NoError(t, s.OpenPath(context.Background(), p))
}
return cfg.ID
}
func TestMoveShared(t *testing.T) {
logging.SetAllLoggers(logging.LevelDebug)
index := paths.NewIndex()
ctx := context.Background()
dir := t.TempDir()
openRepo := func(dir string) repo.LockedRepo {
r, err := repo.NewFS(dir)
require.NoError(t, err)
require.NoError(t, r.Init(repo.Worker))
lr, err := r.Lock(repo.Worker)
require.NoError(t, err)
t.Cleanup(func() {
_ = lr.Close()
})
err = lr.SetStorage(func(config *paths.StorageConfig) {
*config = paths.StorageConfig{}
})
require.NoError(t, err)
return lr
}
// setup two repos with two storage paths:
// repo 1 with both paths
// repo 2 with one path (shared)
lr1 := openRepo(filepath.Join(dir, "l1"))
lr2 := openRepo(filepath.Join(dir, "l2"))
mux1 := mux.NewRouter()
mux2 := mux.NewRouter()
hs1 := httptest.NewServer(mux1)
hs2 := httptest.NewServer(mux2)
ls1, err := paths.NewLocal(ctx, lr1, index, []string{hs1.URL + "/remote"})
require.NoError(t, err)
ls2, err := paths.NewLocal(ctx, lr2, index, []string{hs2.URL + "/remote"})
require.NoError(t, err)
dirStor := filepath.Join(dir, "stor")
dirSeal := filepath.Join(dir, "seal")
id1 := createTestStorage(t, dirStor, false, ls1, ls2)
id2 := createTestStorage(t, dirSeal, true, ls1)
rs1 := paths.NewRemote(ls1, index, nil, 20, &paths.DefaultPartialFileHandler{})
rs2 := paths.NewRemote(ls2, index, nil, 20, &paths.DefaultPartialFileHandler{})
_ = rs2
mux1.PathPrefix("/").Handler(&paths.FetchHandler{Local: ls1, PfHandler: &paths.DefaultPartialFileHandler{}})
mux2.PathPrefix("/").Handler(&paths.FetchHandler{Local: ls2, PfHandler: &paths.DefaultPartialFileHandler{}})
// add a sealed replica file to the sealing (non-shared) path
s1ref := storage.SectorRef{
ID: abi.SectorID{
Miner: 12,
Number: 1,
},
ProofType: abi.RegisteredSealProof_StackedDrg2KiBV1,
}
sp, sid, err := rs1.AcquireSector(ctx, s1ref, storiface.FTNone, storiface.FTSealed, storiface.PathSealing, storiface.AcquireMove)
require.NoError(t, err)
2022-01-18 10:57:04 +00:00
require.Equal(t, id2, storiface.ID(sid.Sealed))
data := make([]byte, 2032)
data[1] = 54
require.NoError(t, ioutil.WriteFile(sp.Sealed, data, 0666))
fmt.Println("write to ", sp.Sealed)
2022-01-18 10:57:04 +00:00
require.NoError(t, index.StorageDeclareSector(ctx, storiface.ID(sid.Sealed), s1ref.ID, storiface.FTSealed, true))
// move to the shared path from the second node (remote move / delete)
require.NoError(t, rs2.MoveStorage(ctx, s1ref, storiface.FTSealed))
// check that the file still exists
sp, sid, err = rs2.AcquireSector(ctx, s1ref, storiface.FTSealed, storiface.FTNone, storiface.PathStorage, storiface.AcquireMove)
require.NoError(t, err)
2022-01-18 10:57:04 +00:00
require.Equal(t, id1, storiface.ID(sid.Sealed))
fmt.Println("read from ", sp.Sealed)
read, err := ioutil.ReadFile(sp.Sealed)
require.NoError(t, err)
require.EqualValues(t, data, read)
}
2021-05-20 11:01:25 +00:00
func TestReader(t *testing.T) {
2021-12-15 14:30:42 +00:00
//stm: @STORAGE_INFO_001
2021-05-20 11:01:25 +00:00
logging.SetAllLoggers(logging.LevelDebug)
bz := []byte("Hello World")
pfPath := "path"
emptyPartialFile := &partialfile.PartialFile{}
2021-06-03 04:45:23 +00:00
sectorSize := abi.SealProofInfos[1].SectorSize
ft := storiface.FTUnsealed
2021-05-20 11:01:25 +00:00
sectorRef := storage.SectorRef{
ID: abi.SectorID{
Miner: 123,
Number: 123,
},
ProofType: 1,
}
offset := abi.PaddedPieceSize(100)
size := abi.PaddedPieceSize(1000)
ctx := context.Background()
tcs := map[string]struct {
2022-06-14 18:31:17 +00:00
storeFnc func(s *mocks.MockStore)
pfFunc func(s *mocks.MockPartialFileHandler)
indexFnc func(s *mocks.MockSectorIndex, serverURL string)
2021-05-20 11:01:25 +00:00
needHttpServer bool
getAllocatedReturnCode int
getSectorReturnCode int
serverUrl string
// expectation
errStr string
expectedNonNilReader bool
expectedSectorBytes []byte
}{
// -------- have the unsealed file locally
"fails when error while acquiring unsealed file": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
2021-05-20 11:01:25 +00:00
mockSectorAcquire(l, sectorRef, pfPath, xerrors.New("acquire error"))
},
errStr: "acquire error",
},
"fails when error while opening local partial (unsealed) file": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
2021-05-20 11:01:25 +00:00
mockSectorAcquire(l, sectorRef, pfPath, nil)
},
2022-06-14 18:31:17 +00:00
pfFunc: func(pf *mocks.MockPartialFileHandler) {
2021-05-20 11:01:25 +00:00
mockPartialFileOpen(pf, sectorSize, pfPath, xerrors.New("pf open error"))
},
errStr: "pf open error",
},
"fails when error while checking if local unsealed file has piece": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
2021-05-20 11:01:25 +00:00
mockSectorAcquire(l, sectorRef, pfPath, nil)
},
2022-06-14 18:31:17 +00:00
pfFunc: func(pf *mocks.MockPartialFileHandler) {
2021-05-20 11:01:25 +00:00
mockPartialFileOpen(pf, sectorSize, pfPath, nil)
mockCheckAllocation(pf, offset, size, emptyPartialFile,
true, xerrors.New("piece check error"))
},
errStr: "piece check error",
},
"fails when error while closing local unsealed file that does not have the piece": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
2021-05-20 11:01:25 +00:00
mockSectorAcquire(l, sectorRef, pfPath, nil)
},
2022-06-14 18:31:17 +00:00
pfFunc: func(pf *mocks.MockPartialFileHandler) {
2021-05-20 11:01:25 +00:00
mockPartialFileOpen(pf, sectorSize, pfPath, nil)
mockCheckAllocation(pf, offset, size, emptyPartialFile,
false, nil)
pf.EXPECT().Close(emptyPartialFile).Return(xerrors.New("close error")).Times(1)
},
errStr: "close error",
},
"fails when error while fetching reader for the local unsealed file that has the unsealed piece": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
2021-05-20 11:01:25 +00:00
mockSectorAcquire(l, sectorRef, pfPath, nil)
},
2022-06-14 18:31:17 +00:00
pfFunc: func(pf *mocks.MockPartialFileHandler) {
2021-05-20 11:01:25 +00:00
mockPartialFileOpen(pf, sectorSize, pfPath, nil)
mockCheckAllocation(pf, offset, size, emptyPartialFile,
true, nil)
mockPfReader(pf, emptyPartialFile, offset, size, nil, xerrors.New("reader error"))
},
errStr: "reader error",
},
// ------------------- don't have the unsealed file locally
"fails when error while finding sector": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
2021-05-20 11:01:25 +00:00
mockSectorAcquire(l, sectorRef, "", nil)
},
2022-06-14 18:31:17 +00:00
indexFnc: func(in *mocks.MockSectorIndex, _ string) {
2021-05-20 11:01:25 +00:00
in.EXPECT().StorageFindSector(gomock.Any(), sectorRef.ID, storiface.FTUnsealed, gomock.Any(),
false).Return(nil, xerrors.New("find sector error"))
},
errStr: "find sector error",
},
"fails when no worker has unsealed file": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
2021-05-20 11:01:25 +00:00
mockSectorAcquire(l, sectorRef, "", nil)
},
2022-06-14 18:31:17 +00:00
indexFnc: func(in *mocks.MockSectorIndex, _ string) {
2021-05-20 11:01:25 +00:00
in.EXPECT().StorageFindSector(gomock.Any(), sectorRef.ID, storiface.FTUnsealed, gomock.Any(),
false).Return(nil, nil)
},
errStr: storiface.ErrSectorNotFound.Error(),
},
// --- nil reader when local unsealed file does NOT have unsealed piece
"nil reader when local unsealed file does not have the unsealed piece and remote sector also dosen't have the unsealed piece": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
2021-05-20 11:01:25 +00:00
mockSectorAcquire(l, sectorRef, pfPath, nil)
},
2022-06-14 18:31:17 +00:00
pfFunc: func(pf *mocks.MockPartialFileHandler) {
2021-05-20 11:01:25 +00:00
mockPartialFileOpen(pf, sectorSize, pfPath, nil)
mockCheckAllocation(pf, offset, size, emptyPartialFile,
false, nil)
pf.EXPECT().Close(emptyPartialFile).Return(nil).Times(1)
2021-05-20 11:01:25 +00:00
},
2022-06-14 18:31:17 +00:00
indexFnc: func(in *mocks.MockSectorIndex, url string) {
2022-01-18 10:57:04 +00:00
si := storiface.SectorStorageInfo{
URLs: []string{url},
}
in.EXPECT().StorageFindSector(gomock.Any(), sectorRef.ID, storiface.FTUnsealed, gomock.Any(),
2022-01-18 10:57:04 +00:00
false).Return([]storiface.SectorStorageInfo{si}, nil).Times(1)
},
needHttpServer: true,
getAllocatedReturnCode: 500,
2021-05-20 11:01:25 +00:00
},
// ---- nil reader when none of the remote unsealed file has unsealed piece
"nil reader when none of the worker has the unsealed piece": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
2021-05-20 11:01:25 +00:00
mockSectorAcquire(l, sectorRef, "", nil)
},
2022-06-14 18:31:17 +00:00
indexFnc: func(in *mocks.MockSectorIndex, url string) {
2022-01-18 10:57:04 +00:00
si := storiface.SectorStorageInfo{
2021-05-20 11:01:25 +00:00
URLs: []string{url},
}
in.EXPECT().StorageFindSector(gomock.Any(), sectorRef.ID, storiface.FTUnsealed, gomock.Any(),
2022-01-18 10:57:04 +00:00
false).Return([]storiface.SectorStorageInfo{si}, nil).Times(1)
2021-05-20 11:01:25 +00:00
},
needHttpServer: true,
getAllocatedReturnCode: 500,
},
"nil reader when none of the worker is able to serve the unsealed piece even though they have it": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
2021-05-20 11:01:25 +00:00
mockSectorAcquire(l, sectorRef, "", nil)
},
2022-06-14 18:31:17 +00:00
indexFnc: func(in *mocks.MockSectorIndex, url string) {
2022-01-18 10:57:04 +00:00
si := storiface.SectorStorageInfo{
2021-05-20 11:01:25 +00:00
URLs: []string{url},
}
in.EXPECT().StorageFindSector(gomock.Any(), sectorRef.ID, storiface.FTUnsealed, gomock.Any(),
2022-01-18 10:57:04 +00:00
false).Return([]storiface.SectorStorageInfo{si}, nil).Times(1)
2021-05-20 11:01:25 +00:00
},
needHttpServer: true,
getSectorReturnCode: 500,
getAllocatedReturnCode: 200,
},
// ---- Success for local unsealed file
"successfully fetches reader for piece from local unsealed file": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
2021-05-20 11:01:25 +00:00
mockSectorAcquire(l, sectorRef, pfPath, nil)
},
2022-06-14 18:31:17 +00:00
pfFunc: func(pf *mocks.MockPartialFileHandler) {
2021-05-20 11:01:25 +00:00
mockPartialFileOpen(pf, sectorSize, pfPath, nil)
mockCheckAllocation(pf, offset, size, emptyPartialFile,
true, nil)
f, err := ioutil.TempFile("", "TestReader-")
require.NoError(t, err)
_, err = f.Write(bz)
require.NoError(t, err)
require.NoError(t, f.Close())
f, err = os.Open(f.Name())
require.NoError(t, err)
mockPfReader(pf, emptyPartialFile, offset, size, f, nil)
},
expectedNonNilReader: true,
expectedSectorBytes: bz,
},
// --- Success for remote unsealed file
// --- Success for remote unsealed file
"successfully fetches reader from remote unsealed piece when local unsealed file does NOT have the unsealed Piece": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
mockSectorAcquire(l, sectorRef, pfPath, nil)
},
2022-06-14 18:31:17 +00:00
pfFunc: func(pf *mocks.MockPartialFileHandler) {
mockPartialFileOpen(pf, sectorSize, pfPath, nil)
mockCheckAllocation(pf, offset, size, emptyPartialFile,
false, nil)
pf.EXPECT().Close(emptyPartialFile).Return(nil).Times(1)
},
2022-06-14 18:31:17 +00:00
indexFnc: func(in *mocks.MockSectorIndex, url string) {
2022-01-18 10:57:04 +00:00
si := storiface.SectorStorageInfo{
URLs: []string{url},
}
in.EXPECT().StorageFindSector(gomock.Any(), sectorRef.ID, storiface.FTUnsealed, gomock.Any(),
2022-01-18 10:57:04 +00:00
false).Return([]storiface.SectorStorageInfo{si}, nil).Times(1)
},
needHttpServer: true,
getSectorReturnCode: 200,
getAllocatedReturnCode: 200,
expectedSectorBytes: bz,
expectedNonNilReader: true,
},
2021-05-20 11:01:25 +00:00
"successfully fetches reader for piece from remote unsealed piece": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
2021-05-20 11:01:25 +00:00
mockSectorAcquire(l, sectorRef, "", nil)
},
2022-06-14 18:31:17 +00:00
indexFnc: func(in *mocks.MockSectorIndex, url string) {
2022-01-18 10:57:04 +00:00
si := storiface.SectorStorageInfo{
2021-05-20 11:01:25 +00:00
URLs: []string{url},
}
in.EXPECT().StorageFindSector(gomock.Any(), sectorRef.ID, storiface.FTUnsealed, gomock.Any(),
2022-01-18 10:57:04 +00:00
false).Return([]storiface.SectorStorageInfo{si}, nil).Times(1)
2021-05-20 11:01:25 +00:00
},
needHttpServer: true,
getSectorReturnCode: 200,
getAllocatedReturnCode: 200,
expectedSectorBytes: bz,
expectedNonNilReader: true,
},
}
for name, tc := range tcs {
tc := tc
t.Run(name, func(t *testing.T) {
// create go mock controller here
mockCtrl := gomock.NewController(t)
// when test is done, assert expectations on all mock objects.
defer mockCtrl.Finish()
// create them mocks
2022-06-14 18:31:17 +00:00
lstore := mocks.NewMockStore(mockCtrl)
pfhandler := mocks.NewMockPartialFileHandler(mockCtrl)
index := mocks.NewMockSectorIndex(mockCtrl)
2021-05-20 11:01:25 +00:00
if tc.storeFnc != nil {
tc.storeFnc(lstore)
}
if tc.pfFunc != nil {
tc.pfFunc(pfhandler)
}
if tc.needHttpServer {
// run http server
ts := httptest.NewServer(&mockHttpServer{
expectedSectorName: storiface.SectorName(sectorRef.ID),
expectedFileType: ft.String(),
expectedOffset: fmt.Sprintf("%d", offset.Unpadded()),
expectedSize: fmt.Sprintf("%d", size.Unpadded()),
expectedSectorType: fmt.Sprintf("%d", sectorRef.ProofType),
getAllocatedReturnCode: tc.getAllocatedReturnCode,
2021-06-03 04:45:23 +00:00
getSectorReturnCode: tc.getSectorReturnCode,
getSectorBytes: tc.expectedSectorBytes,
2021-05-20 11:01:25 +00:00
})
defer ts.Close()
tc.serverUrl = fmt.Sprintf("%s/remote/%s/%s", ts.URL, ft.String(), storiface.SectorName(sectorRef.ID))
}
if tc.indexFnc != nil {
tc.indexFnc(index, tc.serverUrl)
}
remoteStore := paths.NewRemote(lstore, index, nil, 6000, pfhandler)
2021-05-20 11:01:25 +00:00
rdg, err := remoteStore.Reader(ctx, sectorRef, offset, size)
var rd io.ReadCloser
2021-05-20 11:01:25 +00:00
if tc.errStr != "" {
if rdg == nil {
require.Error(t, err)
require.Nil(t, rdg)
require.Contains(t, err.Error(), tc.errStr)
} else {
rd, err = rdg(0)
require.Error(t, err)
require.Nil(t, rd)
require.Contains(t, err.Error(), tc.errStr)
}
2021-05-20 11:01:25 +00:00
} else {
require.NoError(t, err)
}
if !tc.expectedNonNilReader {
require.Nil(t, rd)
} else {
require.NotNil(t, rdg)
rd, err := rdg(0)
require.NoError(t, err)
2021-05-20 11:01:25 +00:00
defer func() {
require.NoError(t, rd.Close())
}()
if f, ok := rd.(*os.File); ok {
require.NoError(t, os.Remove(f.Name()))
}
bz, err := ioutil.ReadAll(rd)
require.NoError(t, err)
require.Equal(t, tc.expectedSectorBytes, bz)
}
})
}
}
func TestCheckIsUnsealed(t *testing.T) {
logging.SetAllLoggers(logging.LevelDebug)
pfPath := "path"
ft := storiface.FTUnsealed
emptyPartialFile := &partialfile.PartialFile{}
sectorRef := storage.SectorRef{
ID: abi.SectorID{
Miner: 123,
Number: 123,
},
ProofType: 1,
}
sectorSize := abi.SealProofInfos[1].SectorSize
offset := abi.PaddedPieceSize(100)
size := abi.PaddedPieceSize(1000)
ctx := context.Background()
tcs := map[string]struct {
2022-06-14 18:31:17 +00:00
storeFnc func(s *mocks.MockStore)
pfFunc func(s *mocks.MockPartialFileHandler)
indexFnc func(s *mocks.MockSectorIndex, serverURL string)
needHttpServer bool
getAllocatedReturnCode int
serverUrl string
// expectation
errStr string
expectedIsUnealed bool
}{
// -------- have the unsealed file locally
"fails when error while acquiring unsealed file": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
mockSectorAcquire(l, sectorRef, pfPath, xerrors.New("acquire error"))
},
errStr: "acquire error",
},
"fails when error while opening local partial (unsealed) file": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
mockSectorAcquire(l, sectorRef, pfPath, nil)
},
2022-06-14 18:31:17 +00:00
pfFunc: func(pf *mocks.MockPartialFileHandler) {
mockPartialFileOpen(pf, sectorSize, pfPath, xerrors.New("pf open error"))
},
errStr: "pf open error",
},
"fails when error while checking if local unsealed file has piece": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
mockSectorAcquire(l, sectorRef, pfPath, nil)
},
2022-06-14 18:31:17 +00:00
pfFunc: func(pf *mocks.MockPartialFileHandler) {
mockPartialFileOpen(pf, sectorSize, pfPath, nil)
mockCheckAllocation(pf, offset, size, emptyPartialFile,
true, xerrors.New("piece check error"))
},
errStr: "piece check error",
},
"fails when error while closing local unsealed file": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
mockSectorAcquire(l, sectorRef, pfPath, nil)
},
2022-06-14 18:31:17 +00:00
pfFunc: func(pf *mocks.MockPartialFileHandler) {
mockPartialFileOpen(pf, sectorSize, pfPath, nil)
mockCheckAllocation(pf, offset, size, emptyPartialFile,
false, nil)
pf.EXPECT().Close(emptyPartialFile).Return(xerrors.New("close error")).Times(1)
},
errStr: "close error",
},
// ------------------- don't have the unsealed file locally
"fails when error while finding sector": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
mockSectorAcquire(l, sectorRef, "", nil)
},
2022-06-14 18:31:17 +00:00
indexFnc: func(in *mocks.MockSectorIndex, _ string) {
in.EXPECT().StorageFindSector(gomock.Any(), sectorRef.ID, storiface.FTUnsealed, gomock.Any(),
false).Return(nil, xerrors.New("find sector error"))
},
errStr: "find sector error",
},
"false when no worker has unsealed file": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
mockSectorAcquire(l, sectorRef, "", nil)
},
2022-06-14 18:31:17 +00:00
indexFnc: func(in *mocks.MockSectorIndex, _ string) {
in.EXPECT().StorageFindSector(gomock.Any(), sectorRef.ID, storiface.FTUnsealed, gomock.Any(),
false).Return(nil, nil)
},
},
// false when local unsealed file does NOT have unsealed piece
"false when local unsealed file does not have the piece and remote sector too dosen't have the piece": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
mockSectorAcquire(l, sectorRef, pfPath, nil)
},
2022-06-14 18:31:17 +00:00
pfFunc: func(pf *mocks.MockPartialFileHandler) {
mockPartialFileOpen(pf, sectorSize, pfPath, nil)
mockCheckAllocation(pf, offset, size, emptyPartialFile,
false, nil)
pf.EXPECT().Close(emptyPartialFile).Return(nil).Times(1)
},
2022-06-14 18:31:17 +00:00
indexFnc: func(in *mocks.MockSectorIndex, url string) {
2022-01-18 10:57:04 +00:00
si := storiface.SectorStorageInfo{
URLs: []string{url},
}
in.EXPECT().StorageFindSector(gomock.Any(), sectorRef.ID, storiface.FTUnsealed, gomock.Any(),
2022-01-18 10:57:04 +00:00
false).Return([]storiface.SectorStorageInfo{si}, nil).Times(1)
},
needHttpServer: true,
getAllocatedReturnCode: 500,
},
"false when none of the worker has the unsealed piece": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
mockSectorAcquire(l, sectorRef, "", nil)
},
2022-06-14 18:31:17 +00:00
indexFnc: func(in *mocks.MockSectorIndex, url string) {
2022-01-18 10:57:04 +00:00
si := storiface.SectorStorageInfo{
URLs: []string{url},
}
in.EXPECT().StorageFindSector(gomock.Any(), sectorRef.ID, storiface.FTUnsealed, gomock.Any(),
2022-01-18 10:57:04 +00:00
false).Return([]storiface.SectorStorageInfo{si}, nil).Times(1)
},
needHttpServer: true,
getAllocatedReturnCode: 500,
},
// ---- Success for local unsealed file
"true when local unsealed file has the piece": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
mockSectorAcquire(l, sectorRef, pfPath, nil)
},
2022-06-14 18:31:17 +00:00
pfFunc: func(pf *mocks.MockPartialFileHandler) {
mockPartialFileOpen(pf, sectorSize, pfPath, nil)
mockCheckAllocation(pf, offset, size, emptyPartialFile,
true, nil)
pf.EXPECT().Close(emptyPartialFile).Return(nil).Times(1)
},
expectedIsUnealed: true,
},
// --- Success for remote unsealed file
"true if we have a remote unsealed piece": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
mockSectorAcquire(l, sectorRef, "", nil)
},
2022-06-14 18:31:17 +00:00
indexFnc: func(in *mocks.MockSectorIndex, url string) {
2022-01-18 10:57:04 +00:00
si := storiface.SectorStorageInfo{
URLs: []string{url},
}
in.EXPECT().StorageFindSector(gomock.Any(), sectorRef.ID, storiface.FTUnsealed, gomock.Any(),
2022-01-18 10:57:04 +00:00
false).Return([]storiface.SectorStorageInfo{si}, nil).Times(1)
},
needHttpServer: true,
getAllocatedReturnCode: 200,
expectedIsUnealed: true,
},
"true when local unsealed file does NOT have the unsealed Piece but remote sector has the unsealed piece": {
2022-06-14 18:31:17 +00:00
storeFnc: func(l *mocks.MockStore) {
mockSectorAcquire(l, sectorRef, pfPath, nil)
},
2022-06-14 18:31:17 +00:00
pfFunc: func(pf *mocks.MockPartialFileHandler) {
mockPartialFileOpen(pf, sectorSize, pfPath, nil)
mockCheckAllocation(pf, offset, size, emptyPartialFile,
false, nil)
pf.EXPECT().Close(emptyPartialFile).Return(nil).Times(1)
},
2022-06-14 18:31:17 +00:00
indexFnc: func(in *mocks.MockSectorIndex, url string) {
2022-01-18 10:57:04 +00:00
si := storiface.SectorStorageInfo{
URLs: []string{url},
}
in.EXPECT().StorageFindSector(gomock.Any(), sectorRef.ID, storiface.FTUnsealed, gomock.Any(),
2022-01-18 10:57:04 +00:00
false).Return([]storiface.SectorStorageInfo{si}, nil).Times(1)
},
needHttpServer: true,
getAllocatedReturnCode: 200,
expectedIsUnealed: true,
},
}
for name, tc := range tcs {
tc := tc
t.Run(name, func(t *testing.T) {
// create go mock controller here
mockCtrl := gomock.NewController(t)
// when test is done, assert expectations on all mock objects.
defer mockCtrl.Finish()
// create them mocks
2022-06-14 18:31:17 +00:00
lstore := mocks.NewMockStore(mockCtrl)
pfhandler := mocks.NewMockPartialFileHandler(mockCtrl)
index := mocks.NewMockSectorIndex(mockCtrl)
if tc.storeFnc != nil {
tc.storeFnc(lstore)
}
if tc.pfFunc != nil {
tc.pfFunc(pfhandler)
}
if tc.needHttpServer {
// run http server
ts := httptest.NewServer(&mockHttpServer{
expectedSectorName: storiface.SectorName(sectorRef.ID),
expectedFileType: ft.String(),
expectedOffset: fmt.Sprintf("%d", offset.Unpadded()),
expectedSize: fmt.Sprintf("%d", size.Unpadded()),
expectedSectorType: fmt.Sprintf("%d", sectorRef.ProofType),
getAllocatedReturnCode: tc.getAllocatedReturnCode,
})
defer ts.Close()
tc.serverUrl = fmt.Sprintf("%s/remote/%s/%s", ts.URL, ft.String(), storiface.SectorName(sectorRef.ID))
}
if tc.indexFnc != nil {
tc.indexFnc(index, tc.serverUrl)
}
remoteStore := paths.NewRemote(lstore, index, nil, 6000, pfhandler)
isUnsealed, err := remoteStore.CheckIsUnsealed(ctx, sectorRef, offset, size)
if tc.errStr != "" {
require.Error(t, err)
require.False(t, isUnsealed)
require.Contains(t, err.Error(), tc.errStr)
} else {
require.NoError(t, err)
}
require.Equal(t, tc.expectedIsUnealed, isUnsealed)
})
}
}
2022-06-14 18:31:17 +00:00
func mockSectorAcquire(l *mocks.MockStore, sectorRef storage.SectorRef, pfPath string, err error) {
2021-05-20 11:01:25 +00:00
l.EXPECT().AcquireSector(gomock.Any(), sectorRef, storiface.FTUnsealed,
storiface.FTNone, storiface.PathStorage, storiface.AcquireMove).Return(storiface.SectorPaths{
Unsealed: pfPath,
},
storiface.SectorPaths{}, err).Times(1)
}
2022-06-14 18:31:17 +00:00
func mockPartialFileOpen(pf *mocks.MockPartialFileHandler, sectorSize abi.SectorSize, pfPath string, err error) {
2021-05-20 11:01:25 +00:00
pf.EXPECT().OpenPartialFile(abi.PaddedPieceSize(sectorSize), pfPath).Return(&partialfile.PartialFile{},
err).Times(1)
}
2022-06-14 18:31:17 +00:00
func mockCheckAllocation(pf *mocks.MockPartialFileHandler, offset, size abi.PaddedPieceSize, file *partialfile.PartialFile,
2021-05-20 11:01:25 +00:00
out bool, err error) {
pf.EXPECT().HasAllocated(file, storiface.UnpaddedByteIndex(offset.Unpadded()),
size.Unpadded()).Return(out, err).Times(1)
}
2022-06-14 18:31:17 +00:00
func mockPfReader(pf *mocks.MockPartialFileHandler, file *partialfile.PartialFile, offset, size abi.PaddedPieceSize,
2021-05-20 11:01:25 +00:00
outFile *os.File, err error) {
pf.EXPECT().Reader(file, storiface.PaddedByteIndex(offset), size).Return(outFile, err)
}
type mockHttpServer struct {
expectedSectorName string
expectedFileType string
expectedOffset string
expectedSize string
expectedSectorType string
getAllocatedReturnCode int
2021-06-03 04:45:23 +00:00
getSectorReturnCode int
getSectorBytes []byte
2021-05-20 11:01:25 +00:00
}
func (m *mockHttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
mux := mux.NewRouter()
2021-06-03 04:45:23 +00:00
mux.HandleFunc("/remote/{type}/{id}", m.getSector).Methods("GET")
2021-05-20 11:01:25 +00:00
mux.HandleFunc("/remote/{type}/{id}/{spt}/allocated/{offset}/{size}", m.getAllocated).Methods("GET")
mux.ServeHTTP(w, r)
}
func (m *mockHttpServer) getAllocated(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
if vars["id"] != m.expectedSectorName {
w.WriteHeader(http.StatusBadRequest)
return
}
if vars["type"] != m.expectedFileType {
w.WriteHeader(http.StatusBadRequest)
return
}
if vars["spt"] != m.expectedSectorType {
w.WriteHeader(http.StatusBadRequest)
return
}
if vars["offset"] != m.expectedOffset {
w.WriteHeader(http.StatusBadRequest)
return
}
if vars["size"] != m.expectedSize {
w.WriteHeader(http.StatusBadRequest)
return
}
w.WriteHeader(m.getAllocatedReturnCode)
}
2021-06-03 04:45:23 +00:00
func (m *mockHttpServer) getSector(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
if vars["id"] != m.expectedSectorName {
w.WriteHeader(http.StatusBadRequest)
return
}
if vars["type"] != m.expectedFileType {
w.WriteHeader(http.StatusBadRequest)
return
}
w.WriteHeader(m.getSectorReturnCode)
_, _ = w.Write(m.getSectorBytes)
}