Skip to content

Commit

Permalink
e2etest: implement VochainTest interface to separate Setup, Run and T…
Browse files Browse the repository at this point in the history
…eardown
  • Loading branch information
altergui committed Apr 4, 2023
1 parent f1451a4 commit b0dcfeb
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 65 deletions.
66 changes: 40 additions & 26 deletions cmd/end2endtest/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -23,59 +21,75 @@ 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 " +
"--host http://127.0.0.1:9090/v2",
})
}

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 := &ethereum.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 := &ethereum.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 {
Expand Down
52 changes: 43 additions & 9 deletions cmd/end2endtest/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
}
Expand Down Expand Up @@ -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)")
Expand Down Expand Up @@ -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) {
Expand All @@ -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")
}
Expand Down
40 changes: 25 additions & 15 deletions cmd/end2endtest/plaintext.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 {
Expand Down Expand Up @@ -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
}
40 changes: 25 additions & 15 deletions cmd/end2endtest/zkweighted.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -23,27 +21,37 @@ 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 " +
"--oracleKey=6aae1d165dd9776c580b8fdaf8622e39c5f943c715e20690080bbfce2c760223",
})
}

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 {
Expand Down Expand Up @@ -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
}

0 comments on commit b0dcfeb

Please sign in to comment.