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

feat: new txtar command adduser #1471

Merged
merged 14 commits into from
Jan 10, 2024
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(""), "---")
}
4 changes: 4 additions & 0 deletions gno.land/pkg/integration/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
// - `--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`.
//
// Logging:
//
// Gnoland logs aren't forwarded to stdout to avoid overwhelming the tests with too much
Expand Down
104 changes: 100 additions & 4 deletions gno.land/pkg/integration/testing_integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import (
"context"
"errors"
"fmt"
"hash/crc32"
"os"
Expand All @@ -10,15 +11,20 @@
"strings"
"testing"

"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"
)

const numTestAccounts int = 4

type tSeqShim struct{ *testing.T }

// noop Parallel method allow us to run test sequentially
Expand Down Expand Up @@ -71,6 +77,10 @@
// 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 @@ -107,12 +117,25 @@
env.Values["_logger"] = logger
}

// Setup "test1" default account
// test1 must be created outside of the loop below because it is already included in genesis so
// attempting to recreate results in it getting overwritten and breaking existing tests that
// rely on its address being static.
kb.CreateAccount(DefaultAccount_Name, DefaultAccount_Seed, "", "", 0, 0)

env.Setenv("USER_SEED_"+DefaultAccount_Name, DefaultAccount_Seed)
env.Setenv("USER_ADDR_"+DefaultAccount_Name, DefaultAccount_Address)

// Create test accounts starting from test2.
for i := 1; i < numTestAccounts; i++ {
accountName := "test" + strconv.Itoa(i+1)

balance, err := createAccount(env, kb, accountName)
if err != nil {
return fmt.Errorf("error creating account %s: %w", accountName, err)
}

Check warning on line 134 in gno.land/pkg/integration/testing_integration.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/integration/testing_integration.go#L133-L134

Added lines #L133 - L134 were not covered by tests

newUserBalances = append(newUserBalances, balance)
}

env.Setenv("GNOROOT", gnoRootDir)
env.Setenv("GNOHOME", gnoHomeDir)

Expand All @@ -126,15 +149,15 @@
}

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 +167,16 @@

// 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 +244,42 @@

tsValidateError(ts, "gnokey", neg, err)
},
// 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
}

Check warning on line 252 in gno.land/pkg/integration/testing_integration.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/integration/testing_integration.go#L248-L252

Added lines #L248 - L252 were not covered by tests

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

Check warning on line 256 in gno.land/pkg/integration/testing_integration.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/integration/testing_integration.go#L254-L256

Added lines #L254 - L256 were not covered by tests

kb, err := keys.NewKeyBaseFromDir(gnoHomeDir)
if err != nil {
ts.Fatalf("unable to get keybase")
}

Check warning on line 261 in gno.land/pkg/integration/testing_integration.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/integration/testing_integration.go#L258-L261

Added lines #L258 - L261 were not covered by tests

balance, err := createAccount(ts, kb, args[0])
if err != nil {
ts.Fatalf("error creating account %s: %s", args[0], err)
}

Check warning on line 266 in gno.land/pkg/integration/testing_integration.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/integration/testing_integration.go#L263-L266

Added lines #L263 - L266 were not covered by tests

newUserBalances = append(newUserBalances, balance)

Check warning on line 268 in gno.land/pkg/integration/testing_integration.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/integration/testing_integration.go#L268

Added line #L268 was not covered by tests
},
},
}
}

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 Expand Up @@ -273,3 +338,34 @@
}
}
}

type envSetter interface {
Setenv(key, value string)
}

// createAccount creates a new account with the given name and adds it to the keybase.
func createAccount(env envSetter, kb keys.Keybase, accountName string) (balance gnoland.Balance, err error) {
entropy, err := bip39.NewEntropy(256)
if err != nil {
return balance, fmt.Errorf("error creating entropy: %w", err)
}

Check warning on line 351 in gno.land/pkg/integration/testing_integration.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/integration/testing_integration.go#L350-L351

Added lines #L350 - L351 were not covered by tests

mnemonic, err := bip39.NewMnemonic(entropy)
if err != nil {
return balance, fmt.Errorf("error generating mnemonic: %w", err)
}

Check warning on line 356 in gno.land/pkg/integration/testing_integration.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/integration/testing_integration.go#L355-L356

Added lines #L355 - L356 were not covered by tests

var keyInfo keys.Info
if keyInfo, err = kb.CreateAccount(accountName, mnemonic, "", "", 0, 0); err != nil {
return balance, fmt.Errorf("unable to create account: %w", err)
}

Check warning on line 361 in gno.land/pkg/integration/testing_integration.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/integration/testing_integration.go#L360-L361

Added lines #L360 - L361 were not covered by tests

address := keyInfo.GetAddress()
env.Setenv("USER_SEED_"+accountName, mnemonic)
env.Setenv("USER_ADDR_"+accountName, address.String())

return gnoland.Balance{
Address: address,
Amount: std.Coins{std.NewCoin("ugnot", 1000000000000000000)},
}, nil
}
Loading