// stm: #unit package retrievaladapter import ( "context" "testing" "github.com/golang/mock/gomock" "github.com/ipfs/go-cid" "github.com/stretchr/testify/require" "golang.org/x/xerrors" "github.com/filecoin-project/go-fil-markets/retrievalmarket" testnet "github.com/filecoin-project/go-fil-markets/shared_testutil" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/mocks" "github.com/filecoin-project/lotus/chain/actors/builtin/market" "github.com/filecoin-project/lotus/chain/types" ) func TestGetPricingInput(t *testing.T) { //stm: @CHAIN_STATE_MARKET_STORAGE_DEAL_001 ctx := context.Background() tsk := &types.TipSet{} key := tsk.Key() pcid := testnet.GenerateCids(1)[0] deals := []abi.DealID{1, 2} paddedSize := abi.PaddedPieceSize(128) unpaddedSize := paddedSize.Unpadded() tcs := map[string]struct { pieceCid cid.Cid deals []abi.DealID fFnc func(node *mocks.MockFullNode) expectedErrorStr string expectedVerified bool expectedPieceSize abi.UnpaddedPieceSize }{ "error when fails to fetch chain head": { fFnc: func(n *mocks.MockFullNode) { n.EXPECT().ChainHead(gomock.Any()).Return(tsk, xerrors.New("chain head error")).Times(1) }, expectedErrorStr: "chain head error", }, "error when no piece matches": { fFnc: func(n *mocks.MockFullNode) { out1 := &api.MarketDeal{ Proposal: market.DealProposal{ PieceCID: testnet.GenerateCids(1)[0], }, } out2 := &api.MarketDeal{ Proposal: market.DealProposal{ PieceCID: testnet.GenerateCids(1)[0], }, } n.EXPECT().ChainHead(gomock.Any()).Return(tsk, nil).Times(1) gomock.InOrder( n.EXPECT().StateMarketStorageDeal(gomock.Any(), deals[0], key).Return(out1, nil), n.EXPECT().StateMarketStorageDeal(gomock.Any(), deals[1], key).Return(out2, nil), ) }, expectedErrorStr: "failed to find matching piece", }, "error when fails to fetch deal state": { fFnc: func(n *mocks.MockFullNode) { out1 := &api.MarketDeal{ Proposal: market.DealProposal{ PieceCID: pcid, PieceSize: paddedSize, }, } out2 := &api.MarketDeal{ Proposal: market.DealProposal{ PieceCID: testnet.GenerateCids(1)[0], VerifiedDeal: true, }, } n.EXPECT().ChainHead(gomock.Any()).Return(tsk, nil).Times(1) gomock.InOrder( n.EXPECT().StateMarketStorageDeal(gomock.Any(), deals[0], key).Return(out1, xerrors.New("error 1")), n.EXPECT().StateMarketStorageDeal(gomock.Any(), deals[1], key).Return(out2, xerrors.New("error 2")), ) }, expectedErrorStr: "failed to fetch storage deal state", }, "verified is true even if one deal is verified and we get the correct piecesize": { fFnc: func(n *mocks.MockFullNode) { out1 := &api.MarketDeal{ Proposal: market.DealProposal{ PieceCID: pcid, PieceSize: paddedSize, }, } out2 := &api.MarketDeal{ Proposal: market.DealProposal{ PieceCID: testnet.GenerateCids(1)[0], VerifiedDeal: true, }, } n.EXPECT().ChainHead(gomock.Any()).Return(tsk, nil).Times(1) gomock.InOrder( n.EXPECT().StateMarketStorageDeal(gomock.Any(), deals[0], key).Return(out1, nil), n.EXPECT().StateMarketStorageDeal(gomock.Any(), deals[1], key).Return(out2, nil), ) }, expectedPieceSize: unpaddedSize, expectedVerified: true, }, "success even if one deal state fetch errors out but the other deal is verified and has the required piececid": { fFnc: func(n *mocks.MockFullNode) { out1 := &api.MarketDeal{ Proposal: market.DealProposal{ PieceCID: testnet.GenerateCids(1)[0], }, } out2 := &api.MarketDeal{ Proposal: market.DealProposal{ PieceCID: pcid, PieceSize: paddedSize, VerifiedDeal: true, }, } n.EXPECT().ChainHead(gomock.Any()).Return(tsk, nil).Times(1) gomock.InOrder( n.EXPECT().StateMarketStorageDeal(gomock.Any(), deals[0], key).Return(out1, xerrors.New("some error")), n.EXPECT().StateMarketStorageDeal(gomock.Any(), deals[1], key).Return(out2, nil), ) }, expectedPieceSize: unpaddedSize, expectedVerified: true, }, "verified is false if both deals are unverified and we get the correct piece size": { fFnc: func(n *mocks.MockFullNode) { out1 := &api.MarketDeal{ Proposal: market.DealProposal{ PieceCID: pcid, PieceSize: paddedSize, VerifiedDeal: false, }, } out2 := &api.MarketDeal{ Proposal: market.DealProposal{ PieceCID: testnet.GenerateCids(1)[0], VerifiedDeal: false, }, } n.EXPECT().ChainHead(gomock.Any()).Return(tsk, nil).Times(1) gomock.InOrder( n.EXPECT().StateMarketStorageDeal(gomock.Any(), deals[0], key).Return(out1, nil), n.EXPECT().StateMarketStorageDeal(gomock.Any(), deals[1], key).Return(out2, nil), ) }, expectedPieceSize: unpaddedSize, expectedVerified: false, }, } for name, tc := range tcs { tc := tc t.Run(name, func(t *testing.T) { mockCtrl := gomock.NewController(t) // when test is done, assert expectations on all mock objects. defer mockCtrl.Finish() mockFull := mocks.NewMockFullNode(mockCtrl) rpn := &retrievalProviderNode{ full: mockFull, } if tc.fFnc != nil { tc.fFnc(mockFull) } resp, err := rpn.GetRetrievalPricingInput(ctx, pcid, deals) if tc.expectedErrorStr != "" { require.Error(t, err) require.Contains(t, err.Error(), tc.expectedErrorStr) require.Equal(t, retrievalmarket.PricingInput{}, resp) } else { require.NoError(t, err) require.Equal(t, tc.expectedPieceSize, resp.PieceSize) require.Equal(t, tc.expectedVerified, resp.VerifiedDeal) } }) } }