Merge pull request #6464 from filecoin-project/refactor/itest-cli
Refactor cli test to kit2
This commit is contained in:
commit
a0894a866d
@ -10,16 +10,15 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/filecoin-project/lotus/extern/storage-sealing/sealiface"
|
"github.com/filecoin-project/lotus/extern/storage-sealing/sealiface"
|
||||||
"github.com/filecoin-project/lotus/itests/kit"
|
"github.com/filecoin-project/lotus/itests/kit2"
|
||||||
"github.com/filecoin-project/lotus/markets/storageadapter"
|
"github.com/filecoin-project/lotus/markets/storageadapter"
|
||||||
"github.com/filecoin-project/lotus/node"
|
"github.com/filecoin-project/lotus/node"
|
||||||
"github.com/filecoin-project/lotus/node/impl"
|
|
||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBatchDealInput(t *testing.T) {
|
func TestBatchDealInput(t *testing.T) {
|
||||||
kit.QuietMiningLogs()
|
kit2.QuietMiningLogs()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
blockTime = 10 * time.Millisecond
|
blockTime = 10 * time.Millisecond
|
||||||
@ -32,13 +31,13 @@ func TestBatchDealInput(t *testing.T) {
|
|||||||
|
|
||||||
run := func(piece, deals, expectSectors int) func(t *testing.T) {
|
run := func(piece, deals, expectSectors int) func(t *testing.T) {
|
||||||
return func(t *testing.T) {
|
return func(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
publishPeriod := 10 * time.Second
|
publishPeriod := 10 * time.Second
|
||||||
maxDealsPerMsg := uint64(deals)
|
maxDealsPerMsg := uint64(deals)
|
||||||
|
|
||||||
// Set max deals per publish deals message to maxDealsPerMsg
|
// Set max deals per publish deals message to maxDealsPerMsg
|
||||||
minerDef := []kit.StorageMiner{{
|
opts := kit2.ConstructorOpts(node.Options(
|
||||||
Full: 0,
|
|
||||||
Opts: node.Options(
|
|
||||||
node.Override(
|
node.Override(
|
||||||
new(*storageadapter.DealPublisher),
|
new(*storageadapter.DealPublisher),
|
||||||
storageadapter.NewDealPublisher(nil, storageadapter.PublishMsgConfig{
|
storageadapter.NewDealPublisher(nil, storageadapter.PublishMsgConfig{
|
||||||
@ -56,26 +55,16 @@ func TestBatchDealInput(t *testing.T) {
|
|||||||
}, nil
|
}, nil
|
||||||
}, nil
|
}, nil
|
||||||
}),
|
}),
|
||||||
),
|
))
|
||||||
Preseal: kit.PresealGenesis,
|
client, miner, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), opts)
|
||||||
}}
|
ens.InterconnectAll().BeginMining(blockTime)
|
||||||
|
dh := kit2.NewDealHarness(t, client, miner)
|
||||||
// Create a connect client and miner node
|
|
||||||
n, sn := kit.MockMinerBuilder(t, kit.OneFull, minerDef)
|
|
||||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
|
||||||
miner := sn[0]
|
|
||||||
|
|
||||||
blockMiner := kit.ConnectAndStartMining(t, blockTime, miner, client)
|
|
||||||
t.Cleanup(blockMiner.Stop)
|
|
||||||
|
|
||||||
dh := kit.NewDealHarness(t, client, miner)
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
err := miner.MarketSetAsk(ctx, big.Zero(), big.Zero(), 200, 128, 32<<30)
|
err := miner.MarketSetAsk(ctx, big.Zero(), big.Zero(), 200, 128, 32<<30)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
checkNoPadding := func() {
|
checkNoPadding := func() {
|
||||||
sl, err := sn[0].SectorsList(ctx)
|
sl, err := miner.SectorsList(ctx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
sort.Slice(sl, func(i, j int) bool {
|
sort.Slice(sl, func(i, j int) bool {
|
||||||
@ -83,7 +72,7 @@ func TestBatchDealInput(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
for _, snum := range sl {
|
for _, snum := range sl {
|
||||||
si, err := sn[0].SectorsStatus(ctx, snum, false)
|
si, err := miner.SectorsStatus(ctx, snum, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// fmt.Printf("S %d: %+v %s\n", snum, si.Deals, si.State)
|
// fmt.Printf("S %d: %+v %s\n", snum, si.Deals, si.State)
|
||||||
@ -98,7 +87,7 @@ func TestBatchDealInput(t *testing.T) {
|
|||||||
|
|
||||||
// Starts a deal and waits until it's published
|
// Starts a deal and waits until it's published
|
||||||
runDealTillSeal := func(rseed int) {
|
runDealTillSeal := func(rseed int) {
|
||||||
res, _, _, err := kit.CreateImportFile(ctx, client, rseed, piece)
|
res, _, _, err := kit2.CreateImportFile(ctx, client, rseed, piece)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
deal := dh.StartDeal(ctx, res.Root, false, dealStartEpoch)
|
deal := dh.StartDeal(ctx, res.Root, false, dealStartEpoch)
|
||||||
@ -122,7 +111,7 @@ func TestBatchDealInput(t *testing.T) {
|
|||||||
|
|
||||||
checkNoPadding()
|
checkNoPadding()
|
||||||
|
|
||||||
sl, err := sn[0].SectorsList(ctx)
|
sl, err := miner.SectorsList(ctx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(sl), expectSectors)
|
require.Equal(t, len(sl), expectSectors)
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
package itests
|
package itests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/cli"
|
"github.com/filecoin-project/lotus/cli"
|
||||||
"github.com/filecoin-project/lotus/itests/kit"
|
"github.com/filecoin-project/lotus/itests/kit2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestClient does a basic test to exercise the client CLI commands.
|
// TestClient does a basic test to exercise the client CLI commands.
|
||||||
func TestClient(t *testing.T) {
|
func TestClient(t *testing.T) {
|
||||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||||
kit.QuietMiningLogs()
|
kit2.QuietMiningLogs()
|
||||||
|
|
||||||
blocktime := 5 * time.Millisecond
|
blockTime := 5 * time.Millisecond
|
||||||
ctx := context.Background()
|
client, _, ens := kit2.EnsembleMinimal(t, kit2.MockProofs(), kit2.ThroughRPC())
|
||||||
clientNode, _ := kit.StartOneNodeOneMiner(ctx, t, blocktime)
|
ens.InterconnectAll().BeginMining(blockTime)
|
||||||
kit.RunClientTest(t, cli.Commands, clientNode)
|
kit2.RunClientTest(t, cli.Commands, *client)
|
||||||
}
|
}
|
||||||
|
146
itests/kit2/client.go
Normal file
146
itests/kit2/client.go
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
package kit2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
lcli "github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RunClientTest exercises some of the Client CLI commands
|
||||||
|
func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode TestFullNode) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Create mock CLI
|
||||||
|
mockCLI := NewMockCLI(ctx, t, cmds)
|
||||||
|
clientCLI := mockCLI.Client(clientNode.ListenAddr)
|
||||||
|
|
||||||
|
// Get the Miner address
|
||||||
|
addrs, err := clientNode.StateListMiners(ctx, types.EmptyTSK)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, addrs, 1)
|
||||||
|
|
||||||
|
minerAddr := addrs[0]
|
||||||
|
fmt.Println("Miner:", minerAddr)
|
||||||
|
|
||||||
|
// client query-ask <Miner addr>
|
||||||
|
out := clientCLI.RunCmd("client", "query-ask", minerAddr.String())
|
||||||
|
require.Regexp(t, regexp.MustCompile("Ask:"), out)
|
||||||
|
|
||||||
|
// Create a deal (non-interactive)
|
||||||
|
// client deal --start-epoch=<start epoch> <cid> <Miner addr> 1000000attofil <duration>
|
||||||
|
res, _, _, err := CreateImportFile(ctx, clientNode, 1, 0)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
startEpoch := fmt.Sprintf("--start-epoch=%d", 2<<12)
|
||||||
|
dataCid := res.Root
|
||||||
|
price := "1000000attofil"
|
||||||
|
duration := fmt.Sprintf("%d", build.MinDealDuration)
|
||||||
|
out = clientCLI.RunCmd("client", "deal", startEpoch, dataCid.String(), minerAddr.String(), price, duration)
|
||||||
|
fmt.Println("client deal", out)
|
||||||
|
|
||||||
|
// Create a deal (interactive)
|
||||||
|
// client deal
|
||||||
|
// <cid>
|
||||||
|
// <duration> (in days)
|
||||||
|
// <miner addr>
|
||||||
|
// "no" (verified Client)
|
||||||
|
// "yes" (confirm deal)
|
||||||
|
res, _, _, err = CreateImportFile(ctx, clientNode, 2, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
dataCid2 := res.Root
|
||||||
|
duration = fmt.Sprintf("%d", build.MinDealDuration/builtin.EpochsInDay)
|
||||||
|
cmd := []string{"client", "deal"}
|
||||||
|
interactiveCmds := []string{
|
||||||
|
dataCid2.String(),
|
||||||
|
duration,
|
||||||
|
minerAddr.String(),
|
||||||
|
"no",
|
||||||
|
"yes",
|
||||||
|
}
|
||||||
|
out = clientCLI.RunInteractiveCmd(cmd, interactiveCmds)
|
||||||
|
fmt.Println("client deal:\n", out)
|
||||||
|
|
||||||
|
// Wait for provider to start sealing deal
|
||||||
|
dealStatus := ""
|
||||||
|
for {
|
||||||
|
// client list-deals
|
||||||
|
out = clientCLI.RunCmd("client", "list-deals")
|
||||||
|
fmt.Println("list-deals:\n", out)
|
||||||
|
|
||||||
|
lines := strings.Split(out, "\n")
|
||||||
|
require.GreaterOrEqual(t, len(lines), 2)
|
||||||
|
re := regexp.MustCompile(`\s+`)
|
||||||
|
parts := re.Split(lines[1], -1)
|
||||||
|
if len(parts) < 4 {
|
||||||
|
require.Fail(t, "bad list-deals output format")
|
||||||
|
}
|
||||||
|
dealStatus = parts[3]
|
||||||
|
fmt.Println(" Deal status:", dealStatus)
|
||||||
|
|
||||||
|
st := CategorizeDealState(dealStatus)
|
||||||
|
require.NotEqual(t, TestDealStateFailed, st)
|
||||||
|
if st == TestDealStateComplete {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the first file from the Miner
|
||||||
|
// client retrieve <cid> <file path>
|
||||||
|
tmpdir, err := ioutil.TempDir(os.TempDir(), "test-cli-Client")
|
||||||
|
require.NoError(t, err)
|
||||||
|
path := filepath.Join(tmpdir, "outfile.dat")
|
||||||
|
out = clientCLI.RunCmd("client", "retrieve", dataCid.String(), path)
|
||||||
|
fmt.Println("retrieve:\n", out)
|
||||||
|
require.Regexp(t, regexp.MustCompile("Success"), out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateImportFile(ctx context.Context, client api.FullNode, rseed int, size int) (res *api.ImportRes, path string, data []byte, err error) {
|
||||||
|
data, path, err = createRandomFile(rseed, size)
|
||||||
|
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, path, data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createRandomFile(rseed, size int) ([]byte, string, error) {
|
||||||
|
if size == 0 {
|
||||||
|
size = 1600
|
||||||
|
}
|
||||||
|
data := make([]byte, size)
|
||||||
|
rand.New(rand.NewSource(int64(rseed))).Read(data)
|
||||||
|
|
||||||
|
dir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-")
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
path := filepath.Join(dir, "sourcefile.dat")
|
||||||
|
err = ioutil.WriteFile(path, data, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, path, nil
|
||||||
|
}
|
141
itests/kit2/mockcli.go
Normal file
141
itests/kit2/mockcli.go
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package kit2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/multiformats/go-multiaddr"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
lcli "github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockCLI struct {
|
||||||
|
t *testing.T
|
||||||
|
cmds []*lcli.Command
|
||||||
|
cctx *lcli.Context
|
||||||
|
out *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMockCLI(ctx context.Context, 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{
|
||||||
|
Flags: []lcli.Flag{
|
||||||
|
&lcli.StringFlag{
|
||||||
|
Name: "api-url",
|
||||||
|
Hidden: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Commands: cmds,
|
||||||
|
}
|
||||||
|
|
||||||
|
var out bytes.Buffer
|
||||||
|
app.Writer = &out
|
||||||
|
app.Setup()
|
||||||
|
|
||||||
|
cctx := lcli.NewContext(app, &flag.FlagSet{}, nil)
|
||||||
|
cctx.Context = ctx
|
||||||
|
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}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockCLIClient runs commands against a particular node
|
||||||
|
type MockCLIClient struct {
|
||||||
|
t *testing.T
|
||||||
|
cmds []*lcli.Command
|
||||||
|
addr multiaddr.Multiaddr
|
||||||
|
cctx *lcli.Context
|
||||||
|
out *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MockCLIClient) RunCmd(input ...string) string {
|
||||||
|
out, err := c.RunCmdRaw(input...)
|
||||||
|
require.NoError(c.t, err, "output:\n%s", out)
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
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=<node api listener address>
|
||||||
|
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(lcli.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 *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 {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MockCLIClient) RunInteractiveCmd(cmd []string, interactive []string) string {
|
||||||
|
c.toStdin(strings.Join(interactive, "\n") + "\n")
|
||||||
|
return c.RunCmd(cmd...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MockCLIClient) toStdin(s string) {
|
||||||
|
c.cctx.App.Metadata["stdin"] = bytes.NewBufferString(s)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user