Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lotus-lite: CLI tests for lotus client commands #4497

Merged
merged 1 commit into from
Oct 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/api_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ type GatewayAPI interface {
StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*MarketDeal, error)
StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error)
StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error)
StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error)
StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*MsgLookup, error)
}
5 changes: 5 additions & 0 deletions api/apistruct/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ type GatewayStruct struct {
StateMarketBalance func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error)
StateMarketStorageDeal func(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error)
StateNetworkVersion func(ctx context.Context, tsk types.TipSetKey) (stnetwork.Version, error)
StateVerifiedClientStatus func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error)
StateWaitMsg func(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error)
}
}
Expand Down Expand Up @@ -1547,6 +1548,10 @@ func (g GatewayStruct) StateNetworkVersion(ctx context.Context, tsk types.TipSet
return g.Internal.StateNetworkVersion(ctx, tsk)
}

func (g GatewayStruct) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) {
return g.Internal.StateVerifiedClientStatus(ctx, addr, tsk)
}

func (g GatewayStruct) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) {
return g.Internal.StateWaitMsg(ctx, msg, confidence)
}
Expand Down
38 changes: 23 additions & 15 deletions api/test/deals.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,21 +106,7 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
}

func MakeDeal(t *testing.T, ctx context.Context, rseed int, client api.FullNode, miner TestStorageNode, carExport, fastRet bool) {
data := make([]byte, 1600)
rand.New(rand.NewSource(int64(rseed))).Read(data)

dir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-")
if err != nil {
t.Fatal(err)
}

path := filepath.Join(dir, "sourcefile.dat")
err = ioutil.WriteFile(path, data, 0644)
if err != nil {
t.Fatal(err)
}

res, err := client.ClientImport(ctx, api.FileRef{Path: path})
res, data, err := CreateClientFile(ctx, client, rseed)
if err != nil {
t.Fatal(err)
}
Expand All @@ -141,6 +127,28 @@ func MakeDeal(t *testing.T, ctx context.Context, rseed int, client api.FullNode,
testRetrieval(t, ctx, client, fcid, &info.PieceCID, carExport, data)
}

func CreateClientFile(ctx context.Context, client api.FullNode, rseed int) (*api.ImportRes, []byte, error) {
data := make([]byte, 1600)
rand.New(rand.NewSource(int64(rseed))).Read(data)

dir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-")
if err != nil {
return nil, nil, err
}

path := filepath.Join(dir, "sourcefile.dat")
err = ioutil.WriteFile(path, data, 0644)
if err != nil {
return nil, nil, err
}

res, err := client.ClientImport(ctx, api.FileRef{Path: path})
if err != nil {
return nil, nil, err
}
return res, data, nil
}

func TestFastRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {

ctx := context.Background()
Expand Down
74 changes: 39 additions & 35 deletions cli/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ var clientDealCmd = &cli.Command{
}
defer closer()
ctx := ReqContext(cctx)
afmt := NewAppFmt(cctx.App)

if cctx.NArg() != 4 {
return xerrors.New("expected 4 args: dataCid, miner, price, duration")
Expand Down Expand Up @@ -462,7 +463,7 @@ var clientDealCmd = &cli.Command{
return err
}

fmt.Println(encoder.Encode(*proposal))
afmt.Println(encoder.Encode(*proposal))

return nil
},
Expand All @@ -477,6 +478,7 @@ func interactiveDeal(cctx *cli.Context) error {
ctx := ReqContext(cctx)
ctx, cancel := context.WithCancel(ctx)
defer cancel()
afmt := NewAppFmt(cctx.App)

state := "import"
gib := types.NewInt(1 << 30)
Expand Down Expand Up @@ -517,10 +519,10 @@ func interactiveDeal(cctx *cli.Context) error {
}

printErr := func(err error) {
fmt.Printf("%s %s\n", color.RedString("Error:"), err.Error())
afmt.Printf("%s %s\n", color.RedString("Error:"), err.Error())
}

cs := readline.NewCancelableStdin(os.Stdin)
cs := readline.NewCancelableStdin(afmt.Stdin)
go func() {
<-ctx.Done()
cs.Close() // nolint:errcheck
Expand All @@ -537,7 +539,7 @@ uiLoop:

switch state {
case "import":
fmt.Print("Data CID (from " + color.YellowString("lotus client import") + "): ")
afmt.Print("Data CID (from " + color.YellowString("lotus client import") + "): ")

_cidStr, _, err := rl.ReadLine()
cidStr := string(_cidStr)
Expand All @@ -560,7 +562,7 @@ uiLoop:

state = "duration"
case "duration":
fmt.Print("Deal duration (days): ")
afmt.Print("Deal duration (days): ")

_daystr, _, err := rl.ReadLine()
daystr := string(_daystr)
Expand Down Expand Up @@ -605,7 +607,7 @@ uiLoop:
continue
}

fmt.Print("\nMake this a verified deal? (yes/no): ")
afmt.Print("\nMake this a verified deal? (yes/no): ")

_yn, _, err := rl.ReadLine()
yn := string(_yn)
Expand All @@ -619,13 +621,13 @@ uiLoop:
case "no":
verified = false
default:
fmt.Println("Type in full 'yes' or 'no'")
afmt.Println("Type in full 'yes' or 'no'")
continue
}

state = "miner"
case "miner":
fmt.Print("Miner Addresses (f0.. f0..), none to find: ")
afmt.Print("Miner Addresses (f0.. f0..), none to find: ")

_maddrsStr, _, err := rl.ReadLine()
maddrsStr := string(_maddrsStr)
Expand Down Expand Up @@ -664,11 +666,11 @@ uiLoop:
candidateAsks = append(candidateAsks, ask)
}

fmt.Printf("Found %d candidate asks\n", len(candidateAsks))
afmt.Printf("Found %d candidate asks\n", len(candidateAsks))
state = "find-budget"
case "find-budget":
fmt.Printf("Proposing from %s, Current Balance: %s\n", a, types.FIL(fromBal))
fmt.Print("Maximum budget (FIL): ") // TODO: Propose some default somehow?
afmt.Printf("Proposing from %s, Current Balance: %s\n", a, types.FIL(fromBal))
afmt.Print("Maximum budget (FIL): ") // TODO: Propose some default somehow?

_budgetStr, _, err := rl.ReadLine()
budgetStr := string(_budgetStr)
Expand Down Expand Up @@ -698,10 +700,10 @@ uiLoop:
}
}
candidateAsks = goodAsks
fmt.Printf("%d asks within budget\n", len(candidateAsks))
afmt.Printf("%d asks within budget\n", len(candidateAsks))
state = "find-count"
case "find-count":
fmt.Print("Deals to make (1): ")
afmt.Print("Deals to make (1): ")
dealcStr, _, err := rl.ReadLine()
if err != nil {
printErr(xerrors.Errorf("reading deal count: %w", err))
Expand Down Expand Up @@ -780,12 +782,12 @@ uiLoop:
case "confirm":
// TODO: do some more or epochs math (round to miner PP, deal start buffer)

fmt.Printf("-----\n")
fmt.Printf("Proposing from %s\n", a)
fmt.Printf("\tBalance: %s\n", types.FIL(fromBal))
fmt.Printf("\n")
fmt.Printf("Piece size: %s (Payload size: %s)\n", units.BytesSize(float64(ds.PieceSize)), units.BytesSize(float64(ds.PayloadSize)))
fmt.Printf("Duration: %s\n", dur)
afmt.Printf("-----\n")
afmt.Printf("Proposing from %s\n", a)
afmt.Printf("\tBalance: %s\n", types.FIL(fromBal))
afmt.Printf("\n")
afmt.Printf("Piece size: %s (Payload size: %s)\n", units.BytesSize(float64(ds.PieceSize)), units.BytesSize(float64(ds.PayloadSize)))
afmt.Printf("Duration: %s\n", dur)

pricePerGib := big.Zero()
for _, a := range ask {
Expand All @@ -804,20 +806,20 @@ uiLoop:

if len(ask) > 1 {
totalPrice := types.BigMul(epochPrice, types.NewInt(uint64(epochs)))
fmt.Printf("Miner %s (Power:%s) price: ~%s (%s per epoch)\n", color.YellowString(a.Miner.String()), color.GreenString(types.SizeStr(mpow.MinerPower.QualityAdjPower)), color.BlueString(types.FIL(totalPrice).String()), types.FIL(epochPrice))
afmt.Printf("Miner %s (Power:%s) price: ~%s (%s per epoch)\n", color.YellowString(a.Miner.String()), color.GreenString(types.SizeStr(mpow.MinerPower.QualityAdjPower)), color.BlueString(types.FIL(totalPrice).String()), types.FIL(epochPrice))
}
}

// TODO: price is based on PaddedPieceSize, right?
epochPrice := types.BigDiv(types.BigMul(pricePerGib, types.NewInt(uint64(ds.PieceSize))), gib)
totalPrice := types.BigMul(epochPrice, types.NewInt(uint64(epochs)))

fmt.Printf("Total price: ~%s (%s per epoch)\n", color.CyanString(types.FIL(totalPrice).String()), types.FIL(epochPrice))
fmt.Printf("Verified: %v\n", verified)
afmt.Printf("Total price: ~%s (%s per epoch)\n", color.CyanString(types.FIL(totalPrice).String()), types.FIL(epochPrice))
afmt.Printf("Verified: %v\n", verified)

state = "accept"
case "accept":
fmt.Print("\nAccept (yes/no): ")
afmt.Print("\nAccept (yes/no): ")

_yn, _, err := rl.ReadLine()
yn := string(_yn)
Expand All @@ -830,7 +832,7 @@ uiLoop:
}

if yn != "yes" {
fmt.Println("Type in full 'yes' or 'no'")
afmt.Println("Type in full 'yes' or 'no'")
continue
}

Expand Down Expand Up @@ -861,7 +863,7 @@ uiLoop:
return err
}

fmt.Printf("Deal (%s) CID: %s\n", maddr, color.GreenString(encoder.Encode(*proposal)))
afmt.Printf("Deal (%s) CID: %s\n", maddr, color.GreenString(encoder.Encode(*proposal)))
}

return nil
Expand Down Expand Up @@ -975,6 +977,7 @@ var clientRetrieveCmd = &cli.Command{
}
defer closer()
ctx := ReqContext(cctx)
afmt := NewAppFmt(cctx.App)

var payer address.Address
if cctx.String("from") != "" {
Expand Down Expand Up @@ -1083,14 +1086,14 @@ var clientRetrieveCmd = &cli.Command{
select {
case evt, ok := <-updates:
if ok {
fmt.Printf("> Recv: %s, Paid %s, %s (%s)\n",
afmt.Printf("> Recv: %s, Paid %s, %s (%s)\n",
types.SizeStr(types.NewInt(evt.BytesReceived)),
types.FIL(evt.FundsSpent),
retrievalmarket.ClientEvents[evt.Event],
retrievalmarket.DealStatuses[evt.Status],
)
} else {
fmt.Println("Success")
afmt.Println("Success")
return nil
}

Expand Down Expand Up @@ -1269,8 +1272,9 @@ var clientQueryAskCmd = &cli.Command{
},
},
Action: func(cctx *cli.Context) error {
afmt := NewAppFmt(cctx.App)
if cctx.NArg() != 1 {
fmt.Println("Usage: query-ask [minerAddress]")
afmt.Println("Usage: query-ask [minerAddress]")
return nil
}

Expand Down Expand Up @@ -1311,23 +1315,23 @@ var clientQueryAskCmd = &cli.Command{
return err
}

fmt.Printf("Ask: %s\n", maddr)
fmt.Printf("Price per GiB: %s\n", types.FIL(ask.Price))
fmt.Printf("Verified Price per GiB: %s\n", types.FIL(ask.VerifiedPrice))
fmt.Printf("Max Piece size: %s\n", types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize))))
afmt.Printf("Ask: %s\n", maddr)
afmt.Printf("Price per GiB: %s\n", types.FIL(ask.Price))
afmt.Printf("Verified Price per GiB: %s\n", types.FIL(ask.VerifiedPrice))
afmt.Printf("Max Piece size: %s\n", types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize))))

size := cctx.Int64("size")
if size == 0 {
return nil
}
perEpoch := types.BigDiv(types.BigMul(ask.Price, types.NewInt(uint64(size))), types.NewInt(1<<30))
fmt.Printf("Price per Block: %s\n", types.FIL(perEpoch))
afmt.Printf("Price per Block: %s\n", types.FIL(perEpoch))

duration := cctx.Int64("duration")
if duration == 0 {
return nil
}
fmt.Printf("Total Price: %s\n", types.FIL(types.BigMul(perEpoch, types.NewInt(uint64(duration)))))
afmt.Printf("Total Price: %s\n", types.FIL(types.BigMul(perEpoch, types.NewInt(uint64(duration)))))

return nil
},
Expand Down Expand Up @@ -1410,7 +1414,7 @@ var clientListDeals = &cli.Command{
}
}

return outputStorageDeals(ctx, os.Stdout, api, localDeals, cctx.Bool("verbose"), cctx.Bool("color"), showFailed)
return outputStorageDeals(ctx, cctx.App.Writer, api, localDeals, cctx.Bool("verbose"), cctx.Bool("color"), showFailed)
},
}

Expand Down
22 changes: 22 additions & 0 deletions cli/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cli

import (
"context"
"os"
"testing"
"time"

clitest "github.com/filecoin-project/lotus/cli/test"
)

// TestClient does a basic test to exercise the client CLI
// commands
func TestClient(t *testing.T) {
_ = os.Setenv("BELLMAN_NO_GPU", "1")
clitest.QuietMiningLogs()

blocktime := 5 * time.Millisecond
ctx := context.Background()
clientNode, _ := clitest.StartOneNodeOneMiner(ctx, t, blocktime)
clitest.RunClientTest(t, Commands, clientNode)
}
Loading