From b0dcfeb8a04c096f2be6b80adbbd8acea983e4a8 Mon Sep 17 00:00:00 2001 From: Gui Iribarren Date: Tue, 4 Apr 2023 14:43:15 -0300 Subject: [PATCH] e2etest: implement VochainTest interface to separate Setup, Run and Teardown --- cmd/end2endtest/account.go | 66 +++++++++++++++++++++-------------- cmd/end2endtest/main.go | 52 ++++++++++++++++++++++----- cmd/end2endtest/plaintext.go | 40 +++++++++++++-------- cmd/end2endtest/zkweighted.go | 40 +++++++++++++-------- 4 files changed, 133 insertions(+), 65 deletions(-) diff --git a/cmd/end2endtest/account.go b/cmd/end2endtest/account.go index db9c7f73e..83f65cdbb 100644 --- a/cmd/end2endtest/account.go +++ b/cmd/end2endtest/account.go @@ -4,14 +4,12 @@ import ( "context" "encoding/hex" "fmt" - "net/url" "os" "strings" "time" "github.com/ethereum/go-ethereum/common" "github.com/google/go-cmp/cmp" - "github.com/google/uuid" apipkg "go.vocdoni.io/dvote/api" "go.vocdoni.io/dvote/apiclient" "go.vocdoni.io/dvote/crypto/ethereum" @@ -23,7 +21,7 @@ import ( func init() { ops = append(ops, operation{ - fn: testTokenTxs, + test: &E2ETokenTxs{}, name: "tokentxs", description: "Tests all token related transactions", example: os.Args[0] + " --operation=tokentxs " + @@ -31,51 +29,67 @@ func init() { }) } -func testTokenTxs(c config) { +var _ VochainTest = (*E2ETokenTxs)(nil) + +type E2ETokenTxs struct { + api *apiclient.HTTPclient + config *config + + alice, bob *ethereum.SignKeys + aliceFP *models.FaucetPackage +} + +func (t *E2ETokenTxs) Setup(api *apiclient.HTTPclient, config *config) error { + t.api = api + t.config = config // create alice signer - alice := ðereum.SignKeys{} - if err := alice.Generate(); err != nil { - log.Fatal(err) + t.alice = ethereum.NewSignKeys() + err := t.alice.Generate() + if err != nil { + return err } // create bob signer - bob := ðereum.SignKeys{} - if err := bob.Generate(); err != nil { - log.Fatal(err) - } - - // Connect to the API host - hostURL, err := url.Parse(c.host) + t.bob = ethereum.NewSignKeys() + err = t.bob.Generate() if err != nil { - log.Fatal(err) + return err } - log.Debugw("connecting to API", "host", hostURL.String()) - token := uuid.New() - api, err := apiclient.NewHTTPclient(hostURL, &token) + // get faucet package for alice + t.aliceFP, err = getFaucetPackage(t.config, t.alice.Address().Hex()) if err != nil { - log.Fatal(err) + return err } + return nil +} + +func (t *E2ETokenTxs) Teardown() error { + // nothing to do here + return nil +} + +func (t *E2ETokenTxs) Run() (duration time.Duration, err error) { + start := time.Now() + // check transaction cost - if err := testGetTxCost(api); err != nil { + if err := testGetTxCost(t.api); err != nil { log.Fatal(err) } - fp, err := getFaucetPackage(c, alice.Address().Hex()) - if err != nil { - log.Fatal(err) - } // check create and set account - if err := testCreateAndSetAccount(api, fp, alice, bob); err != nil { + if err := testCreateAndSetAccount(t.api, t.aliceFP, t.alice, t.bob); err != nil { log.Fatal(err) } // check send tokens - if err := testSendTokens(api, alice, bob); err != nil { + if err := testSendTokens(t.api, t.alice, t.bob); err != nil { log.Fatal(err) } + + return time.Since(start), nil } func testGetTxCost(api *apiclient.HTTPclient) error { diff --git a/cmd/end2endtest/main.go b/cmd/end2endtest/main.go index 7d72c6419..f9d04d3a9 100644 --- a/cmd/end2endtest/main.go +++ b/cmd/end2endtest/main.go @@ -2,10 +2,12 @@ package main import ( "fmt" + "net/url" "os" "path/filepath" "time" + "github.com/google/uuid" flag "github.com/spf13/pflag" "go.vocdoni.io/dvote/crypto/ethereum" "go.vocdoni.io/dvote/internal" @@ -21,8 +23,14 @@ import ( // * how many times to retry opening a connection to an endpoint before giving up const retries = 10 +type VochainTest interface { + Setup(api *apiclient.HTTPclient, config *config) error + Run() (duration time.Duration, err error) + Teardown() error +} + type operation struct { - fn func(c config) + test VochainTest name, description, example string } @@ -55,10 +63,10 @@ func main() { // For the sake of including the version in the log, it's also included in a log line later on. fmt.Fprintf(os.Stderr, "vocdoni version %q\n", internal.Version) - c := config{} + c := &config{} flag.StringVar(&c.host, "host", "https://api-dev.vocdoni.net/v2", "API host to connect to") flag.StringVar(&c.logLevel, "logLevel", "info", "log level (debug, info, warn, error, fatal)") - flag.StringVar(&c.operation, "operation", "vtest", + flag.StringVar(&c.operation, "operation", "", fmt.Sprintf("set operation mode: %v", opNames())) flag.StringSliceVarP(&c.accountPrivKeys, "accountPrivKey", "k", []string{}, "account private key (optional)") @@ -104,18 +112,44 @@ func main() { log.Infof("privkey %x = account %s", ak.PrivateKey(), ak.AddressString()) } - found := false + var test VochainTest for _, op := range ops { if op.name == c.operation { - op.fn(c) - found = true + test = op.test } } - - if !found { + if test == nil { log.Fatal("no valid operation mode specified") } + api, err := NewAPIclient(c.host) + if err != nil { + log.Fatal(err) + } + + err = test.Setup(api, c) + if err != nil { + log.Fatal(err) + } + + duration, err := test.Run() + if err != nil { + log.Fatal(err) + } + log.Infow("test finished", "duration", duration.String()) +} + +// NewAPIclient connects to the API host and returns the handle +func NewAPIclient(host string) (*apiclient.HTTPclient, error) { + hostURL, err := url.Parse(host) + if err != nil { + log.Fatal(err) + } + + log.Debugf("connecting to %s", hostURL.String()) + + token := uuid.New() + return apiclient.NewHTTPclient(hostURL, &token) } func privKeyToSigner(key string) (*ethereum.SignKeys, error) { @@ -129,7 +163,7 @@ func privKeyToSigner(key string) (*ethereum.SignKeys, error) { return skey, nil } -func getFaucetPackage(c config, account string) (*models.FaucetPackage, error) { +func getFaucetPackage(c *config, account string) (*models.FaucetPackage, error) { if c.faucet == "" { return nil, fmt.Errorf("need to pass a valid --faucet") } diff --git a/cmd/end2endtest/plaintext.go b/cmd/end2endtest/plaintext.go index 75bf441bd..6cc2529b5 100644 --- a/cmd/end2endtest/plaintext.go +++ b/cmd/end2endtest/plaintext.go @@ -6,13 +6,11 @@ import ( "errors" "fmt" "math/big" - "net/url" "os" "strings" "sync" "time" - "github.com/google/uuid" vapi "go.vocdoni.io/dvote/api" "go.vocdoni.io/dvote/apiclient" "go.vocdoni.io/dvote/crypto/ethereum" @@ -24,26 +22,36 @@ import ( func init() { ops = append(ops, operation{ - fn: plaintextElectionTest, + test: &E2EPlaintextElection{}, name: "plaintextelection", description: "Publishes a census and a non-anonymous, non-secret election, emits N votes and verifies the results", example: os.Args[0] + " --operation=plaintextelection --votes=1000", }) } -func plaintextElectionTest(c config) { - // Connect to the API host - hostURL, err := url.Parse(c.host) - if err != nil { - log.Fatal(err) - } - log.Debugf("connecting to %s", hostURL.String()) +var _ VochainTest = (*E2EPlaintextElection)(nil) - token := uuid.New() - api, err := apiclient.NewHTTPclient(hostURL, &token) - if err != nil { - log.Fatal(err) - } +type E2EPlaintextElection struct { + api *apiclient.HTTPclient + config *config +} + +func (t *E2EPlaintextElection) Setup(api *apiclient.HTTPclient, config *config) error { + t.api = api + t.config = config + return nil +} + +func (t *E2EPlaintextElection) Teardown() error { + // nothing to do here + return nil +} + +func (t *E2EPlaintextElection) Run() (duration time.Duration, err error) { + start := time.Now() + + c := t.config + api := t.api // Set the account in the API client, so we can sign transactions if err := api.SetAccount(hex.EncodeToString(c.accountKeys[0].PrivateKey())); err != nil { @@ -369,4 +377,6 @@ func plaintextElectionTest(c config) { } log.Infof("election %s status is RESULTS", electionID.String()) log.Infof("election results: %v", election.Results) + + return time.Since(start), nil } diff --git a/cmd/end2endtest/zkweighted.go b/cmd/end2endtest/zkweighted.go index 84af7b81d..299cd2c07 100644 --- a/cmd/end2endtest/zkweighted.go +++ b/cmd/end2endtest/zkweighted.go @@ -4,13 +4,11 @@ import ( "context" "fmt" "math/big" - "net/url" "os" "strings" "sync" "time" - "github.com/google/uuid" vapi "go.vocdoni.io/dvote/api" "go.vocdoni.io/dvote/apiclient" "go.vocdoni.io/dvote/crypto/ethereum" @@ -23,7 +21,7 @@ import ( func init() { ops = append(ops, operation{ - fn: anonElectionTest, + test: &E2EAnonElection{}, name: "anonelection", description: "Performs a complete test of anonymous election, from creating a census to voting and validating votes", example: os.Args[0] + " --operation=anonelection --votes=1000 " + @@ -31,19 +29,29 @@ func init() { }) } -func anonElectionTest(c config) { - // Connect to the API host - hostURL, err := url.Parse(c.host) - if err != nil { - log.Fatal(err) - } - log.Debugf("connecting to %s", hostURL.String()) +var _ VochainTest = (*E2EAnonElection)(nil) - token := uuid.New() - api, err := apiclient.NewHTTPclient(hostURL, &token) - if err != nil { - log.Fatal(err) - } +type E2EAnonElection struct { + api *apiclient.HTTPclient + config *config +} + +func (t *E2EAnonElection) Setup(api *apiclient.HTTPclient, config *config) error { + t.api = api + t.config = config + return nil +} + +func (t *E2EAnonElection) Teardown() error { + // nothing to do here + return nil +} + +func (t *E2EAnonElection) Run() (duration time.Duration, err error) { + start := time.Now() + + c := t.config + api := t.api // Set the account in the API client, so we can sign transactions if err := api.SetAccount(c.accountPrivKeys[0]); err != nil { @@ -361,4 +369,6 @@ func anonElectionTest(c config) { } log.Infof("election %s status is RESULTS", electionID.String()) log.Infof("election results: %v", election.Results) + + return time.Since(start), nil }