From b097a5fb0c8c36cf2ea913c5a7e28fd5e0351d89 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Mon, 26 Oct 2020 12:01:33 +0100 Subject: [PATCH] refactor: share code between CLI tests --- cli/paych_test.go | 295 ++++++++++++------------------------------- cli/test/client.go | 14 +- cli/test/mockcli.go | 70 ++++++---- cli/test/multisig.go | 12 +- cli/test/net.go | 46 +++++++ 5 files changed, 188 insertions(+), 249 deletions(-) diff --git a/cli/paych_test.go b/cli/paych_test.go index 77a6e61eb..777574105 100644 --- a/cli/paych_test.go +++ b/cli/paych_test.go @@ -1,9 +1,7 @@ package cli import ( - "bytes" "context" - "flag" "fmt" "os" "regexp" @@ -12,24 +10,21 @@ import ( "testing" "time" - "github.com/stretchr/testify/require" - "github.com/urfave/cli/v2" + clitest "github.com/filecoin-project/lotus/cli/test" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - cbor "github.com/ipfs/go-ipld-cbor" - "github.com/multiformats/go-multiaddr" - "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/actors/policy" + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/stretchr/testify/require" "github.com/filecoin-project/lotus/api/apibstore" "github.com/filecoin-project/lotus/api/test" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/types" - builder "github.com/filecoin-project/lotus/node/test" ) func init() { @@ -45,21 +40,21 @@ func TestPaymentChannels(t *testing.T) { blocktime := 5 * time.Millisecond ctx := context.Background() - nodes, addrs := startTwoNodesOneMiner(ctx, t, blocktime) + nodes, addrs := clitest.StartTwoNodesOneMiner(ctx, t, blocktime) paymentCreator := nodes[0] paymentReceiver := nodes[1] creatorAddr := addrs[0] receiverAddr := addrs[1] // Create mock CLI - mockCLI := newMockCLI(t) - creatorCLI := mockCLI.client(paymentCreator.ListenAddr) - receiverCLI := mockCLI.client(paymentReceiver.ListenAddr) + mockCLI := clitest.NewMockCLI(t, Commands) + creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) + receiverCLI := mockCLI.Client(paymentReceiver.ListenAddr) // creator: paych add-funds channelAmt := "100000" - cmd := []string{creatorAddr.String(), receiverAddr.String(), channelAmt} - chstr := creatorCLI.runCmd(paychAddFundsCmd, cmd) + cmd := []string{"paych", "add-funds", creatorAddr.String(), receiverAddr.String(), channelAmt} + chstr := creatorCLI.RunCmd(cmd) chAddr, err := address.NewFromString(chstr) require.NoError(t, err) @@ -67,16 +62,16 @@ func TestPaymentChannels(t *testing.T) { // creator: paych voucher create voucherAmt := 100 vamt := strconv.Itoa(voucherAmt) - cmd = []string{chAddr.String(), vamt} - voucher := creatorCLI.runCmd(paychVoucherCreateCmd, cmd) + cmd = []string{"paych", "voucher", "create", chAddr.String(), vamt} + voucher := creatorCLI.RunCmd(cmd) // receiver: paych voucher add - cmd = []string{chAddr.String(), voucher} - receiverCLI.runCmd(paychVoucherAddCmd, cmd) + cmd = []string{"paych", "voucher", "add", chAddr.String(), voucher} + receiverCLI.RunCmd(cmd) // creator: paych settle - cmd = []string{chAddr.String()} - creatorCLI.runCmd(paychSettleCmd, cmd) + cmd = []string{"paych", "settle", chAddr.String()} + creatorCLI.RunCmd(cmd) // Wait for the chain to reach the settle height chState := getPaychState(ctx, t, paymentReceiver, chAddr) @@ -85,8 +80,8 @@ func TestPaymentChannels(t *testing.T) { waitForHeight(ctx, t, paymentReceiver, sa) // receiver: paych collect - cmd = []string{chAddr.String()} - receiverCLI.runCmd(paychCloseCmd, cmd) + cmd = []string{"paych", "collect", chAddr.String()} + receiverCLI.RunCmd(cmd) } type voucherSpec struct { @@ -101,17 +96,18 @@ func TestPaymentChannelStatus(t *testing.T) { blocktime := 5 * time.Millisecond ctx := context.Background() - nodes, addrs := startTwoNodesOneMiner(ctx, t, blocktime) + nodes, addrs := clitest.StartTwoNodesOneMiner(ctx, t, blocktime) paymentCreator := nodes[0] creatorAddr := addrs[0] receiverAddr := addrs[1] // Create mock CLI - mockCLI := newMockCLI(t) - creatorCLI := mockCLI.client(paymentCreator.ListenAddr) + mockCLI := clitest.NewMockCLI(t, Commands) + creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) - cmd := []string{creatorAddr.String(), receiverAddr.String()} - out := creatorCLI.runCmd(paychStatusByFromToCmd, cmd) + // creator: paych status-by-from-to + cmd := []string{"paych", "status-by-from-to", creatorAddr.String(), receiverAddr.String()} + out := creatorCLI.RunCmd(cmd) fmt.Println(out) noChannelState := "Channel does not exist" require.Regexp(t, regexp.MustCompile(noChannelState), out) @@ -120,14 +116,14 @@ func TestPaymentChannelStatus(t *testing.T) { create := make(chan string) go func() { // creator: paych add-funds - cmd := []string{creatorAddr.String(), receiverAddr.String(), fmt.Sprintf("%d", channelAmt)} - create <- creatorCLI.runCmd(paychAddFundsCmd, cmd) + cmd := []string{"paych", "add-funds", creatorAddr.String(), receiverAddr.String(), fmt.Sprintf("%d", channelAmt)} + create <- creatorCLI.RunCmd(cmd) }() // Wait for the output to stop being "Channel does not exist" for regexp.MustCompile(noChannelState).MatchString(out) { - cmd := []string{creatorAddr.String(), receiverAddr.String()} - out = creatorCLI.runCmd(paychStatusByFromToCmd, cmd) + cmd := []string{"paych", "status-by-from-to", creatorAddr.String(), receiverAddr.String()} + out = creatorCLI.RunCmd(cmd) } fmt.Println(out) @@ -147,8 +143,8 @@ func TestPaymentChannelStatus(t *testing.T) { // Wait for create channel to complete chstr := <-create - cmd = []string{chstr} - out = creatorCLI.runCmd(paychStatusCmd, cmd) + cmd = []string{"paych", "status", chstr} + out = creatorCLI.RunCmd(cmd) fmt.Println(out) // Output should have the channel address require.Regexp(t, regexp.MustCompile("Channel.*"+chstr), out) @@ -160,11 +156,11 @@ func TestPaymentChannelStatus(t *testing.T) { // creator: paych voucher create voucherAmt := uint64(10) - cmd = []string{chAddr.String(), fmt.Sprintf("%d", voucherAmt)} - creatorCLI.runCmd(paychVoucherCreateCmd, cmd) + cmd = []string{"paych", "voucher", "create", chAddr.String(), fmt.Sprintf("%d", voucherAmt)} + creatorCLI.RunCmd(cmd) - cmd = []string{chstr} - out = creatorCLI.runCmd(paychStatusCmd, cmd) + cmd = []string{"paych", "status", chstr} + out = creatorCLI.RunCmd(cmd) fmt.Println(out) voucherAmtAtto := types.BigMul(types.NewInt(voucherAmt), types.NewInt(build.FilecoinPrecision)) voucherAmtStr := fmt.Sprintf("%d", voucherAmtAtto) @@ -179,21 +175,21 @@ func TestPaymentChannelVouchers(t *testing.T) { blocktime := 5 * time.Millisecond ctx := context.Background() - nodes, addrs := startTwoNodesOneMiner(ctx, t, blocktime) + nodes, addrs := clitest.StartTwoNodesOneMiner(ctx, t, blocktime) paymentCreator := nodes[0] paymentReceiver := nodes[1] creatorAddr := addrs[0] receiverAddr := addrs[1] // Create mock CLI - mockCLI := newMockCLI(t) - creatorCLI := mockCLI.client(paymentCreator.ListenAddr) - receiverCLI := mockCLI.client(paymentReceiver.ListenAddr) + mockCLI := clitest.NewMockCLI(t, Commands) + creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) + receiverCLI := mockCLI.Client(paymentReceiver.ListenAddr) // creator: paych add-funds channelAmt := "100000" - cmd := []string{creatorAddr.String(), receiverAddr.String(), channelAmt} - chstr := creatorCLI.runCmd(paychAddFundsCmd, cmd) + cmd := []string{"paych", "add-funds", creatorAddr.String(), receiverAddr.String(), channelAmt} + chstr := creatorCLI.RunCmd(cmd) chAddr, err := address.NewFromString(chstr) require.NoError(t, err) @@ -203,39 +199,39 @@ func TestPaymentChannelVouchers(t *testing.T) { // creator: paych voucher create // Note: implied --lane=0 voucherAmt1 := 100 - cmd = []string{chAddr.String(), strconv.Itoa(voucherAmt1)} - voucher1 := creatorCLI.runCmd(paychVoucherCreateCmd, cmd) + cmd = []string{"paych", "voucher", "create", chAddr.String(), strconv.Itoa(voucherAmt1)} + voucher1 := creatorCLI.RunCmd(cmd) vouchers = append(vouchers, voucherSpec{serialized: voucher1, lane: 0, amt: voucherAmt1}) // creator: paych voucher create --lane=5 lane5 := "--lane=5" voucherAmt2 := 50 - cmd = []string{lane5, chAddr.String(), strconv.Itoa(voucherAmt2)} - voucher2 := creatorCLI.runCmd(paychVoucherCreateCmd, cmd) + cmd = []string{"paych", "voucher", "create", lane5, chAddr.String(), strconv.Itoa(voucherAmt2)} + voucher2 := creatorCLI.RunCmd(cmd) vouchers = append(vouchers, voucherSpec{serialized: voucher2, lane: 5, amt: voucherAmt2}) // creator: paych voucher create --lane=5 voucherAmt3 := 70 - cmd = []string{lane5, chAddr.String(), strconv.Itoa(voucherAmt3)} - voucher3 := creatorCLI.runCmd(paychVoucherCreateCmd, cmd) + cmd = []string{"paych", "voucher", "create", lane5, chAddr.String(), strconv.Itoa(voucherAmt3)} + voucher3 := creatorCLI.RunCmd(cmd) vouchers = append(vouchers, voucherSpec{serialized: voucher3, lane: 5, amt: voucherAmt3}) // creator: paych voucher create --lane=5 voucherAmt4 := 80 - cmd = []string{lane5, chAddr.String(), strconv.Itoa(voucherAmt4)} - voucher4 := creatorCLI.runCmd(paychVoucherCreateCmd, cmd) + cmd = []string{"paych", "voucher", "create", lane5, chAddr.String(), strconv.Itoa(voucherAmt4)} + voucher4 := creatorCLI.RunCmd(cmd) vouchers = append(vouchers, voucherSpec{serialized: voucher4, lane: 5, amt: voucherAmt4}) // creator: paych voucher list --export - cmd = []string{"--export", chAddr.String()} - list := creatorCLI.runCmd(paychVoucherListCmd, cmd) + cmd = []string{"paych", "voucher", "list", "--export", chAddr.String()} + list := creatorCLI.RunCmd(cmd) // Check that voucher list output is correct on creator checkVoucherOutput(t, list, vouchers) // creator: paych voucher best-spendable - cmd = []string{"--export", chAddr.String()} - bestSpendable := creatorCLI.runCmd(paychVoucherBestSpendableCmd, cmd) + cmd = []string{"paych", "voucher", "best-spendable", "--export", chAddr.String()} + bestSpendable := creatorCLI.RunCmd(cmd) // Check that best spendable output is correct on creator bestVouchers := []voucherSpec{ @@ -245,31 +241,31 @@ func TestPaymentChannelVouchers(t *testing.T) { checkVoucherOutput(t, bestSpendable, bestVouchers) // receiver: paych voucher add - cmd = []string{chAddr.String(), voucher1} - receiverCLI.runCmd(paychVoucherAddCmd, cmd) + cmd = []string{"paych", "voucher", "add", chAddr.String(), voucher1} + receiverCLI.RunCmd(cmd) // receiver: paych voucher add - cmd = []string{chAddr.String(), voucher2} - receiverCLI.runCmd(paychVoucherAddCmd, cmd) + cmd = []string{"paych", "voucher", "add", chAddr.String(), voucher2} + receiverCLI.RunCmd(cmd) // receiver: paych voucher add - cmd = []string{chAddr.String(), voucher3} - receiverCLI.runCmd(paychVoucherAddCmd, cmd) + cmd = []string{"paych", "voucher", "add", chAddr.String(), voucher3} + receiverCLI.RunCmd(cmd) // receiver: paych voucher add - cmd = []string{chAddr.String(), voucher4} - receiverCLI.runCmd(paychVoucherAddCmd, cmd) + cmd = []string{"paych", "voucher", "add", chAddr.String(), voucher4} + receiverCLI.RunCmd(cmd) // receiver: paych voucher list --export - cmd = []string{"--export", chAddr.String()} - list = receiverCLI.runCmd(paychVoucherListCmd, cmd) + cmd = []string{"paych", "voucher", "list", "--export", chAddr.String()} + list = receiverCLI.RunCmd(cmd) // Check that voucher list output is correct on receiver checkVoucherOutput(t, list, vouchers) // receiver: paych voucher best-spendable - cmd = []string{"--export", chAddr.String()} - bestSpendable = receiverCLI.runCmd(paychVoucherBestSpendableCmd, cmd) + cmd = []string{"paych", "voucher", "best-spendable", "--export", chAddr.String()} + bestSpendable = receiverCLI.RunCmd(cmd) // Check that best spendable output is correct on receiver bestVouchers = []voucherSpec{ @@ -279,12 +275,12 @@ func TestPaymentChannelVouchers(t *testing.T) { checkVoucherOutput(t, bestSpendable, bestVouchers) // receiver: paych voucher submit - cmd = []string{chAddr.String(), voucher1} - receiverCLI.runCmd(paychVoucherSubmitCmd, cmd) + cmd = []string{"paych", "voucher", "submit", chAddr.String(), voucher1} + receiverCLI.RunCmd(cmd) // receiver: paych voucher best-spendable - cmd = []string{"--export", chAddr.String()} - bestSpendable = receiverCLI.runCmd(paychVoucherBestSpendableCmd, cmd) + cmd = []string{"paych", "voucher", "best-spendable", "--export", chAddr.String()} + bestSpendable = receiverCLI.RunCmd(cmd) // Check that best spendable output no longer includes submitted voucher bestVouchers = []voucherSpec{ @@ -295,12 +291,12 @@ func TestPaymentChannelVouchers(t *testing.T) { // There are three vouchers in lane 5: 50, 70, 80 // Submit the voucher for 50. Best spendable should still be 80. // receiver: paych voucher submit - cmd = []string{chAddr.String(), voucher2} - receiverCLI.runCmd(paychVoucherSubmitCmd, cmd) + cmd = []string{"paych", "voucher", "submit", chAddr.String(), voucher2} + receiverCLI.RunCmd(cmd) // receiver: paych voucher best-spendable - cmd = []string{"--export", chAddr.String()} - bestSpendable = receiverCLI.runCmd(paychVoucherBestSpendableCmd, cmd) + cmd = []string{"paych", "voucher", "best-spendable", "--export", chAddr.String()} + bestSpendable = receiverCLI.RunCmd(cmd) // Check that best spendable output still includes the voucher for 80 bestVouchers = []voucherSpec{ @@ -310,12 +306,12 @@ func TestPaymentChannelVouchers(t *testing.T) { // Submit the voucher for 80 // receiver: paych voucher submit - cmd = []string{chAddr.String(), voucher4} - receiverCLI.runCmd(paychVoucherSubmitCmd, cmd) + cmd = []string{"paych", "voucher", "submit", chAddr.String(), voucher4} + receiverCLI.RunCmd(cmd) // receiver: paych voucher best-spendable - cmd = []string{"--export", chAddr.String()} - bestSpendable = receiverCLI.runCmd(paychVoucherBestSpendableCmd, cmd) + cmd = []string{"paych", "voucher", "best-spendable", "--export", chAddr.String()} + bestSpendable = receiverCLI.RunCmd(cmd) // Check that best spendable output no longer includes submitted voucher bestVouchers = []voucherSpec{} @@ -329,19 +325,19 @@ func TestPaymentChannelVoucherCreateShortfall(t *testing.T) { blocktime := 5 * time.Millisecond ctx := context.Background() - nodes, addrs := startTwoNodesOneMiner(ctx, t, blocktime) + nodes, addrs := clitest.StartTwoNodesOneMiner(ctx, t, blocktime) paymentCreator := nodes[0] creatorAddr := addrs[0] receiverAddr := addrs[1] // Create mock CLI - mockCLI := newMockCLI(t) - creatorCLI := mockCLI.client(paymentCreator.ListenAddr) + mockCLI := clitest.NewMockCLI(t, Commands) + creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) // creator: paych add-funds channelAmt := 100 - cmd := []string{creatorAddr.String(), receiverAddr.String(), fmt.Sprintf("%d", channelAmt)} - chstr := creatorCLI.runCmd(paychAddFundsCmd, cmd) + cmd := []string{"paych", "add-funds", creatorAddr.String(), receiverAddr.String(), fmt.Sprintf("%d", channelAmt)} + chstr := creatorCLI.RunCmd(cmd) chAddr, err := address.NewFromString(chstr) require.NoError(t, err) @@ -349,15 +345,15 @@ func TestPaymentChannelVoucherCreateShortfall(t *testing.T) { // creator: paych voucher create --lane=1 voucherAmt1 := 60 lane1 := "--lane=1" - cmd = []string{lane1, chAddr.String(), strconv.Itoa(voucherAmt1)} - voucher1 := creatorCLI.runCmd(paychVoucherCreateCmd, cmd) + cmd = []string{"paych", "voucher", "create", lane1, chAddr.String(), strconv.Itoa(voucherAmt1)} + voucher1 := creatorCLI.RunCmd(cmd) fmt.Println(voucher1) // creator: paych voucher create --lane=2 lane2 := "--lane=2" voucherAmt2 := 70 - cmd = []string{lane2, chAddr.String(), strconv.Itoa(voucherAmt2)} - _, err = creatorCLI.runCmdRaw(paychVoucherCreateCmd, cmd) + cmd = []string{"paych", "voucher", "create", lane2, chAddr.String(), strconv.Itoa(voucherAmt2)} + _, err = creatorCLI.RunCmdRaw(cmd) // Should fail because channel doesn't have required amount require.Error(t, err) @@ -388,129 +384,6 @@ func checkVoucherOutput(t *testing.T, list string, vouchers []voucherSpec) { } } -func startTwoNodesOneMiner(ctx context.Context, t *testing.T, blocktime time.Duration) ([]test.TestNode, []address.Address) { - n, sn := builder.RPCMockSbBuilder(t, test.TwoFull, test.OneMiner) - - paymentCreator := n[0] - paymentReceiver := n[1] - miner := sn[0] - - // Get everyone connected - addrs, err := paymentCreator.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := paymentReceiver.NetConnect(ctx, addrs); err != nil { - t.Fatal(err) - } - - if err := miner.NetConnect(ctx, addrs); err != nil { - t.Fatal(err) - } - - // Start mining blocks - bm := test.NewBlockMiner(ctx, t, miner, blocktime) - bm.MineBlocks() - - // Send some funds to register the receiver - receiverAddr, err := paymentReceiver.WalletNew(ctx, types.KTSecp256k1) - if err != nil { - t.Fatal(err) - } - - test.SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18)) - - // Get the creator's address - creatorAddr, err := paymentCreator.WalletDefaultAddress(ctx) - if err != nil { - t.Fatal(err) - } - - // Create mock CLI - return n, []address.Address{creatorAddr, receiverAddr} -} - -type mockCLI struct { - t *testing.T - cctx *cli.Context - out *bytes.Buffer -} - -// TODO: refactor to use the methods in cli/test/mockcli.go -func newMockCLI(t *testing.T) *mockCLI { - // Create a CLI App with an --api-url flag so that we can specify which node - // the command should be executed against - app := cli.NewApp() - app.Flags = []cli.Flag{ - &cli.StringFlag{ - Name: "api-url", - Hidden: true, - }, - } - var out bytes.Buffer - app.Writer = &out - app.Setup() - - cctx := cli.NewContext(app, &flag.FlagSet{}, nil) - return &mockCLI{t: t, cctx: cctx, out: &out} -} - -func (c *mockCLI) client(addr multiaddr.Multiaddr) *mockCLIClient { - return &mockCLIClient{t: c.t, addr: addr, cctx: c.cctx, out: c.out} -} - -// mockCLIClient runs commands against a particular node -type mockCLIClient struct { - t *testing.T - addr multiaddr.Multiaddr - cctx *cli.Context - out *bytes.Buffer -} - -func (c *mockCLIClient) runCmd(cmd *cli.Command, input []string) string { - out, err := c.runCmdRaw(cmd, input) - require.NoError(c.t, err) - - return out -} - -func (c *mockCLIClient) runCmdRaw(cmd *cli.Command, input []string) (string, error) { - // prepend --api-url= - apiFlag := "--api-url=" + c.addr.String() - input = append([]string{apiFlag}, input...) - - fs := c.flagSet(cmd) - err := fs.Parse(input) - require.NoError(c.t, err) - - err = cmd.Action(cli.NewContext(c.cctx.App, fs, c.cctx)) - - // Get the output - str := strings.TrimSpace(c.out.String()) - c.out.Reset() - return str, err -} - -func (c *mockCLIClient) flagSet(cmd *cli.Command) *flag.FlagSet { - // Apply app level flags (so we can process --api-url flag) - fs := &flag.FlagSet{} - for _, f := range c.cctx.App.Flags { - err := f.Apply(fs) - if err != nil { - c.t.Fatal(err) - } - } - // Apply command level flags - for _, f := range cmd.Flags { - err := f.Apply(fs) - if err != nil { - c.t.Fatal(err) - } - } - return fs -} - // waitForHeight waits for the node to reach the given chain epoch func waitForHeight(ctx context.Context, t *testing.T, node test.TestNode, height abi.ChainEpoch) { atHeight := make(chan struct{}) diff --git a/cli/test/client.go b/cli/test/client.go index 3a5146219..aefc97479 100644 --- a/cli/test/client.go +++ b/cli/test/client.go @@ -25,8 +25,8 @@ func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode test.TestNode) defer cancel() // Create mock CLI - mockCLI := newMockCLI(t, cmds) - clientCLI := mockCLI.client(clientNode.ListenAddr) + mockCLI := NewMockCLI(t, cmds) + clientCLI := mockCLI.Client(clientNode.ListenAddr) // Get the miner address addrs, err := clientNode.StateListMiners(ctx, types.EmptyTSK) @@ -40,7 +40,7 @@ func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode test.TestNode) cmd := []string{ "client", "query-ask", minerAddr.String(), } - out := clientCLI.runCmd(cmd) + out := clientCLI.RunCmd(cmd) require.Regexp(t, regexp.MustCompile("Ask:"), out) // Create a deal (non-interactive) @@ -53,7 +53,7 @@ func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode test.TestNode) cmd = []string{ "client", "deal", dataCid.String(), minerAddr.String(), price, duration, } - out = clientCLI.runCmd(cmd) + out = clientCLI.RunCmd(cmd) fmt.Println("client deal", out) // Create a deal (interactive) @@ -77,7 +77,7 @@ func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode test.TestNode) "no", "yes", } - out = clientCLI.runInteractiveCmd(cmd, interactiveCmds) + out = clientCLI.RunInteractiveCmd(cmd, interactiveCmds) fmt.Println("client deal:\n", out) // Wait for provider to start sealing deal @@ -85,7 +85,7 @@ func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode test.TestNode) for dealStatus != "StorageDealSealing" { // client list-deals cmd = []string{"client", "list-deals"} - out = clientCLI.runCmd(cmd) + out = clientCLI.RunCmd(cmd) fmt.Println("list-deals:\n", out) lines := strings.Split(out, "\n") @@ -109,7 +109,7 @@ func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode test.TestNode) cmd = []string{ "client", "retrieve", dataCid.String(), path, } - out = clientCLI.runCmd(cmd) + out = clientCLI.RunCmd(cmd) fmt.Println("retrieve:\n", out) require.Regexp(t, regexp.MustCompile("Success"), out) } diff --git a/cli/test/mockcli.go b/cli/test/mockcli.go index c7eb70092..dc6d6fd4a 100644 --- a/cli/test/mockcli.go +++ b/cli/test/mockcli.go @@ -11,14 +11,14 @@ import ( lcli "github.com/urfave/cli/v2" ) -type mockCLI struct { +type MockCLI struct { t *testing.T cmds []*lcli.Command cctx *lcli.Context out *bytes.Buffer } -func newMockCLI(t *testing.T, cmds []*lcli.Command) *mockCLI { +func NewMockCLI(t *testing.T, cmds []*lcli.Command) *MockCLI { // Create a CLI App with an --api-url flag so that we can specify which node // the command should be executed against app := &lcli.App{ @@ -36,15 +36,15 @@ func newMockCLI(t *testing.T, cmds []*lcli.Command) *mockCLI { app.Setup() cctx := lcli.NewContext(app, &flag.FlagSet{}, nil) - return &mockCLI{t: t, cmds: cmds, cctx: cctx, out: &out} + return &MockCLI{t: t, cmds: cmds, cctx: cctx, out: &out} } -func (c *mockCLI) client(addr multiaddr.Multiaddr) *mockCLIClient { - return &mockCLIClient{t: c.t, cmds: c.cmds, addr: addr, cctx: c.cctx, out: c.out} +func (c *MockCLI) Client(addr multiaddr.Multiaddr) *MockCLIClient { + return &MockCLIClient{t: c.t, cmds: c.cmds, addr: addr, cctx: c.cctx, out: c.out} } -// mockCLIClient runs commands against a particular node -type mockCLIClient struct { +// MockCLIClient runs commands against a particular node +type MockCLIClient struct { t *testing.T cmds []*lcli.Command addr multiaddr.Multiaddr @@ -52,7 +52,7 @@ type mockCLIClient struct { out *bytes.Buffer } -func (c *mockCLIClient) run(cmd []string, params []string, args []string) string { +func (c *MockCLIClient) run(cmd []string, params []string, args []string) string { // Add parameter --api-url= apiFlag := "--api-url=" + c.addr.String() params = append([]string{apiFlag}, params...) @@ -66,28 +66,48 @@ func (c *mockCLIClient) run(cmd []string, params []string, args []string) string return str } -func (c *mockCLIClient) runCmd(input []string) string { - cmd := c.cmdByNameSub(input[0], input[1]) - out, err := c.runCmdRaw(cmd, input[2:]) +func (c *MockCLIClient) RunCmd(input []string) string { + out, err := c.RunCmdRaw(input) require.NoError(c.t, err) return out } -func (c *mockCLIClient) cmdByNameSub(name string, sub string) *lcli.Command { - for _, c := range c.cmds { - if c.Name == name { - for _, s := range c.Subcommands { - if s.Name == sub { - return s - } - } +// Given an input, find the corresponding command or sub-command. +// eg "paych add-funds" +func (c *MockCLIClient) cmdByNameSub(input []string) (*lcli.Command, []string) { + name := input[0] + for _, cmd := range c.cmds { + if cmd.Name == name { + return c.findSubcommand(cmd, input[1:]) } } - return nil + return nil, []string{} } -func (c *mockCLIClient) runCmdRaw(cmd *lcli.Command, input []string) (string, error) { +func (c *MockCLIClient) findSubcommand(cmd *lcli.Command, input []string) (*lcli.Command, []string) { + // If there are no sub-commands, return the current command + if len(cmd.Subcommands) == 0 { + return cmd, input + } + + // Check each sub-command for a match against the name + subName := input[0] + for _, subCmd := range cmd.Subcommands { + if subCmd.Name == subName { + // Found a match, recursively search for sub-commands + return c.findSubcommand(subCmd, input[1:]) + } + } + return nil, []string{} +} + +func (c *MockCLIClient) RunCmdRaw(input []string) (string, error) { + cmd, input := c.cmdByNameSub(input) + if cmd == nil { + panic("Could not find command " + input[0] + " " + input[1]) + } + // prepend --api-url= apiFlag := "--api-url=" + c.addr.String() input = append([]string{apiFlag}, input...) @@ -104,7 +124,7 @@ func (c *mockCLIClient) runCmdRaw(cmd *lcli.Command, input []string) (string, er return str, err } -func (c *mockCLIClient) flagSet(cmd *lcli.Command) *flag.FlagSet { +func (c *MockCLIClient) flagSet(cmd *lcli.Command) *flag.FlagSet { // Apply app level flags (so we can process --api-url flag) fs := &flag.FlagSet{} for _, f := range c.cctx.App.Flags { @@ -123,11 +143,11 @@ func (c *mockCLIClient) flagSet(cmd *lcli.Command) *flag.FlagSet { return fs } -func (c *mockCLIClient) runInteractiveCmd(cmd []string, interactive []string) string { +func (c *MockCLIClient) RunInteractiveCmd(cmd []string, interactive []string) string { c.toStdin(strings.Join(interactive, "\n") + "\n") - return c.runCmd(cmd) + return c.RunCmd(cmd) } -func (c *mockCLIClient) toStdin(s string) { +func (c *MockCLIClient) toStdin(s string) { c.cctx.App.Metadata["stdin"] = bytes.NewBufferString(s) } diff --git a/cli/test/multisig.go b/cli/test/multisig.go index d2c0238d2..f7c0d88d7 100644 --- a/cli/test/multisig.go +++ b/cli/test/multisig.go @@ -18,8 +18,8 @@ func RunMultisigTest(t *testing.T, cmds []*lcli.Command, clientNode test.TestNod ctx := context.Background() // Create mock CLI - mockCLI := newMockCLI(t, cmds) - clientCLI := mockCLI.client(clientNode.ListenAddr) + mockCLI := NewMockCLI(t, cmds) + clientCLI := mockCLI.Client(clientNode.ListenAddr) // Create some wallets on the node to use for testing multisig var walletAddrs []address.Address @@ -48,7 +48,7 @@ func RunMultisigTest(t *testing.T, cmds []*lcli.Command, clientNode test.TestNod walletAddrs[1].String(), walletAddrs[2].String(), } - out := clientCLI.runCmd(cmd) + out := clientCLI.RunCmd(cmd) fmt.Println(out) // Extract msig robust address from output @@ -68,12 +68,12 @@ func RunMultisigTest(t *testing.T, cmds []*lcli.Command, clientNode test.TestNod msigRobustAddr, walletAddrs[3].String(), } - out = clientCLI.runCmd(cmd) + out = clientCLI.RunCmd(cmd) fmt.Println(out) // msig inspect cmd = []string{"msig", "inspect", "--vesting", "--decode-params", msigRobustAddr} - out = clientCLI.runCmd(cmd) + out = clientCLI.RunCmd(cmd) fmt.Println(out) // Expect correct balance @@ -96,6 +96,6 @@ func RunMultisigTest(t *testing.T, cmds []*lcli.Command, clientNode test.TestNod walletAddrs[3].String(), "false", } - out = clientCLI.runCmd(cmd) + out = clientCLI.RunCmd(cmd) fmt.Println(out) } diff --git a/cli/test/net.go b/cli/test/net.go index d13993d16..836b81a8f 100644 --- a/cli/test/net.go +++ b/cli/test/net.go @@ -5,6 +5,9 @@ import ( "testing" "time" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api/test" test2 "github.com/filecoin-project/lotus/node/test" @@ -39,3 +42,46 @@ func StartOneNodeOneMiner(ctx context.Context, t *testing.T, blocktime time.Dura // Create mock CLI return full, fullAddr } + +func StartTwoNodesOneMiner(ctx context.Context, t *testing.T, blocktime time.Duration) ([]test.TestNode, []address.Address) { + n, sn := test2.RPCMockSbBuilder(t, test.TwoFull, test.OneMiner) + + fullNode1 := n[0] + fullNode2 := n[1] + miner := sn[0] + + // Get everyone connected + addrs, err := fullNode1.NetAddrsListen(ctx) + if err != nil { + t.Fatal(err) + } + + if err := fullNode2.NetConnect(ctx, addrs); err != nil { + t.Fatal(err) + } + + if err := miner.NetConnect(ctx, addrs); err != nil { + t.Fatal(err) + } + + // Start mining blocks + bm := test.NewBlockMiner(ctx, t, miner, blocktime) + bm.MineBlocks() + + // Send some funds to register the second node + fullNodeAddr2, err := fullNode2.WalletNew(ctx, types.KTSecp256k1) + if err != nil { + t.Fatal(err) + } + + test.SendFunds(ctx, t, fullNode1, fullNodeAddr2, abi.NewTokenAmount(1e18)) + + // Get the first node's address + fullNodeAddr1, err := fullNode1.WalletDefaultAddress(ctx) + if err != nil { + t.Fatal(err) + } + + // Create mock CLI + return n, []address.Address{fullNodeAddr1, fullNodeAddr2} +}