Skip to content

feat: new txtar command adduser #1471

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

Merged
merged 14 commits into from
Jan 10, 2024
Merged
5 changes: 5 additions & 0 deletions gno.land/cmd/gnoland/testdata/adduser-err.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
gnoland start

# should fail if user is added after node is started
! adduser test5
stderr '"adduser" error: adduser must be used before starting node'
30 changes: 30 additions & 0 deletions gno.land/cmd/gnoland/testdata/adduser.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
adduser test8

## start a new node
gnoland start

## add bar.gno package located in $WORK directory as gno.land/r/foobar/bar
gnokey maketx addpkg -pkgdir $WORK/bar -pkgpath gno.land/r/foobar/bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test8

## execute Render
gnokey maketx run -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test8 $WORK/script/script.gno

## compare render
stdout 'main: --- hello from foo ---'
stdout 'OK!'
stdout 'GAS WANTED: 200000'
stdout 'GAS USED: '

-- bar/bar.gno --
package bar

func Render(path string) string {
return "hello from foo"
}

-- script/script.gno --
package main
import "gno.land/r/foobar/bar"
func main() {
println("main: ---", bar.Render(""), "---")
}
8 changes: 8 additions & 0 deletions gno.land/pkg/integration/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
// - `--remote`, `--insecure-password-stdin`, and `--home` flags are set automatically to
// communicate with the gnoland node.
//
// 3. `adduser`:
// - Creates a new user in the default keybase directory
// - Must be run before `gnoland start`.
//
// 4. `sleep`:
// - Sleeps for a specified duration string, parsed by `time.ParseDuration`.
// - Defaults to 1 second if no duration is specified.
//
// Logging:
//
// Gnoland logs aren't forwarded to stdout to avoid overwhelming the tests with too much
Expand Down
86 changes: 84 additions & 2 deletions gno.land/pkg/integration/testing_integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,25 @@ package integration

import (
"context"
"errors"
"fmt"
"hash/crc32"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"time"

"github.com/gnolang/gno/gno.land/pkg/gnoland"
"github.com/gnolang/gno/gnovm/pkg/gnoenv"
"github.com/gnolang/gno/tm2/pkg/bft/node"
"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/crypto/bip39"
"github.com/gnolang/gno/tm2/pkg/crypto/keys"
"github.com/gnolang/gno/tm2/pkg/crypto/keys/client"
"github.com/gnolang/gno/tm2/pkg/log"
"github.com/gnolang/gno/tm2/pkg/std"
"github.com/rogpeppe/go-internal/testscript"
)

Expand Down Expand Up @@ -71,6 +76,10 @@ func setupGnolandTestScript(t *testing.T, txtarDir string) testscript.Params {
// Testscripts run concurrently by default, so we need to be prepared for that.
nodes := map[string]*testNode{}

// Track new user balances added via the `adduser` command. These are added to the genesis
// state when the node is started.
var newUserBalances []gnoland.Balance

updateScripts, _ := strconv.ParseBool(os.Getenv("UPDATE_SCRIPTS"))
persistWorkDir, _ := strconv.ParseBool(os.Getenv("TESTWORK"))
return testscript.Params{
Expand Down Expand Up @@ -126,15 +135,15 @@ func setupGnolandTestScript(t *testing.T, txtarDir string) testscript.Params {
}

logger := ts.Value("_logger").(log.Logger) // grab logger
sid := ts.Getenv("SID") // grab session id
sid := getNodeSID(ts) // grab session id

var cmd string
cmd, args = args[0], args[1:]

var err error
switch cmd {
case "start":
if _, ok := nodes[sid]; ok {
if nodeIsRunning(nodes, sid) {
err = fmt.Errorf("node already started")
break
}
Expand All @@ -144,6 +153,16 @@ func setupGnolandTestScript(t *testing.T, txtarDir string) testscript.Params {

// Generate config and node
cfg, _ := TestingNodeConfig(t, gnoRootDir)

// Add balances for users added via the `adduser` command.
genesis := cfg.Genesis
genesisState := gnoland.GnoGenesisState{
Balances: genesis.AppState.(gnoland.GnoGenesisState).Balances,
Txs: genesis.AppState.(gnoland.GnoGenesisState).Txs,
}
genesisState.Balances = append(genesisState.Balances, newUserBalances...)
cfg.Genesis.AppState = genesisState

n, remoteAddr := TestingInMemoryNode(t, logger, cfg)

// Register cleanup
Expand Down Expand Up @@ -211,10 +230,73 @@ func setupGnolandTestScript(t *testing.T, txtarDir string) testscript.Params {

tsValidateError(ts, "gnokey", neg, err)
},
"sleep": func(ts *testscript.TestScript, neg bool, args []string) {
d := time.Second
if len(args) > 0 {
var err error
if d, err = time.ParseDuration(args[0]); err != nil {
ts.Fatalf("unable to parse duration %q: %s", args[1], err)
}
}

time.Sleep(d)
},
// adduser commands must be executed before starting the node; it errors out otherwise.
"adduser": func(ts *testscript.TestScript, neg bool, args []string) {
if nodeIsRunning(nodes, getNodeSID(ts)) {
tsValidateError(ts, "adduser", neg, errors.New("adduser must be used before starting node"))
return
}

if len(args) == 0 {
ts.Fatalf("new user name required")
}

entropy, err := bip39.NewEntropy(256)
if err != nil {
ts.Fatalf("error creating entropy: %v", err)
}

mnemonic, err := bip39.NewMnemonic(entropy)
if err != nil {
ts.Fatalf("error generating mnemonic: %v", err)
}

accountName := args[0]
kb, err := keys.NewKeyBaseFromDir(gnoHomeDir)
if err != nil {
ts.Fatalf("unable to fetch keybase: %v", err)
}

var keyInfo keys.Info
if keyInfo, err = kb.CreateAccount(accountName, mnemonic, "", "", 0, 0); err != nil {
ts.Fatalf("unable to create account: %v", err)
}

address := keyInfo.GetAddress()
newUserBalances = append(
newUserBalances,
gnoland.Balance{
Address: address,
Amount: std.Coins{std.NewCoin("ugnot", 1000000000000000000)},
},
)
ts.Setenv("USER_SEED_"+accountName, mnemonic)
ts.Setenv("USER_ADDR_"+accountName, address.String())
},
},
}
}

func getNodeSID(ts *testscript.TestScript) string {
return ts.Getenv("SID")
}

func nodeIsRunning(nodes map[string]*testNode, sid string) bool {
_, ok := nodes[sid]
return ok
}

func getTestingLogger(env *testscript.Env, logname string) (log.Logger, error) {
var path string

Expand Down