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

support procedural test style for VM-defined workloads #1667

Merged
merged 43 commits into from
Nov 3, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
6f2fc50
initial revision.
tsachiherman Oct 16, 2024
1833c3f
lint
tsachiherman Oct 17, 2024
a4f51a1
update
tsachiherman Oct 17, 2024
8e22542
merge
tsachiherman Oct 17, 2024
fe528f5
update
tsachiherman Oct 17, 2024
baf90fd
update
tsachiherman Oct 17, 2024
ee7974c
lint
tsachiherman Oct 17, 2024
0b935bb
update
tsachiherman Oct 17, 2024
83afa8d
update
tsachiherman Oct 18, 2024
2523292
Merge branch 'main' into tsachi/proc-testing
tsachiherman Oct 23, 2024
1716ecf
Merge branch 'main' into tsachi/proc-testing
tsachiherman Oct 24, 2024
b681a95
stage
tsachiherman Oct 24, 2024
9fcc4dc
update
tsachiherman Oct 24, 2024
62048d7
update
tsachiherman Oct 24, 2024
3f7f35c
lint
tsachiherman Oct 24, 2024
bb6ca7b
Merge branch 'main' into tsachi/proc-testing
tsachiherman Oct 24, 2024
b27c3e7
try to fix chainid
tsachiherman Oct 24, 2024
c55e886
move test registry instance to be created at the vm level.
tsachiherman Oct 25, 2024
53d05e2
lint
tsachiherman Oct 25, 2024
848a8b9
update
tsachiherman Oct 25, 2024
32b6cff
update
tsachiherman Oct 25, 2024
69625eb
lint
tsachiherman Oct 25, 2024
f06bcf8
update
tsachiherman Oct 25, 2024
834bf53
Merge branch 'main' into tsachi/proc-testing
tsachiherman Oct 25, 2024
128d5fc
lint
tsachiherman Oct 25, 2024
93541c0
Merge branch 'main' into tsachi/proc-testing
tsachiherman Oct 27, 2024
c4621d6
update per CR
tsachiherman Oct 27, 2024
bb12aa7
sync e2e tests
tsachiherman Oct 27, 2024
473a08d
Update tests/workload/network.go
tsachiherman Oct 28, 2024
66d5493
update per CR
tsachiherman Oct 28, 2024
4c55dc3
Merge branch 'tsachi/proc-testing' of github.com:ava-labs/hypersdk in…
tsachiherman Oct 28, 2024
83231c7
update per CR
tsachiherman Oct 29, 2024
4bc7424
use ginkgo.Serial instead of mutex'ing.
tsachiherman Oct 29, 2024
f087929
lint
tsachiherman Oct 29, 2024
23f5b79
Merge branch 'main' into tsachi/proc-testing
tsachiherman Oct 29, 2024
782f4b2
Merge branch 'main' into tsachi/proc-testing
tsachiherman Oct 30, 2024
920c45a
avoid re-calc of txid
tsachiherman Oct 31, 2024
e5bb823
Merge branch 'tsachi/proc-testing' of github.com:ava-labs/hypersdk in…
tsachiherman Oct 31, 2024
5471cac
update per CR
tsachiherman Nov 1, 2024
2e7261f
Merge branch 'main' into tsachi/proc-testing
tsachiherman Nov 1, 2024
4021021
fix lint
tsachiherman Nov 1, 2024
a346111
fix comment per lint
tsachiherman Nov 1, 2024
3b5d436
update per CR
tsachiherman Nov 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions examples/morpheusvm/tests/e2e/transfer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package e2e_test

import (
"context"
"time"

"github.com/stretchr/testify/require"

"github.com/ava-labs/hypersdk/api/jsonrpc"
"github.com/ava-labs/hypersdk/auth"
"github.com/ava-labs/hypersdk/chain"
"github.com/ava-labs/hypersdk/crypto/ed25519"
"github.com/ava-labs/hypersdk/examples/morpheusvm/actions"
"github.com/ava-labs/hypersdk/examples/morpheusvm/vm"
"github.com/ava-labs/hypersdk/tests/workload"

he2e "github.com/ava-labs/hypersdk/tests/e2e"
tsachiherman marked this conversation as resolved.
Show resolved Hide resolved
ginkgo "github.com/onsi/ginkgo/v2"
)

var _ = he2e.RegisterTest("Transfer Transaction", func(t ginkgo.FullGinkgoTInterface, tn workload.TestNetwork) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm concerned this test doesn't add any real value to a hypersdk VM developer. If anything, it adds less value than the current workload tests because the user doesn't have fine grained controls of what a "confirmed" transaction is. In the workload tests, at least devs can define their custom confirmation logic. In these e2e tests all a user gets back is whether or not the transaction was found in the block.

require := require.New(t)

uri := tn.URIs()[0]
other, err := ed25519.GeneratePrivateKey()
require.NoError(err)
aother := auth.NewED25519Address(other.PublicKey())

lcli := vm.NewJSONRPCClient(uri)
parser, err := lcli.Parser(context.Background())
require.NoError(err)

spendingKey, err := tn.WorkloadFactory().GetSpendingKey()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in these custom e2e tests, we only use the workloadfactory for this one method. This means if the user wants to only create custom e2e tests they need to also define the workloadfactory interface which is quite confusing 😅

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe its worth adding some of the further work you mentioned to this PR. If the GenesisKeys are added to the test network then we wouldn't need to couple the WorkloadFactory here

require.NoError(err)

cli := jsonrpc.NewJSONRPCClient(uri)
_, tx, _, err := cli.GenerateTransaction(
context.Background(),
parser,
[]chain.Action{&actions.Transfer{
To: aother,
Value: 1,
}},
auth.NewED25519Factory(ed25519.PrivateKey(spendingKey.Bytes)),
)

require.NoError(err)

timeoutCtx, timeoutCtxFnc := context.WithDeadline(context.Background(), time.Now().Add(2*time.Second))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have a const txCheckInterval. I think it makes sense to either pass the const in here or remove the const completely and pass in a value from the test.

defer timeoutCtxFnc()

require.NoError(tn.SubmitTxs(timeoutCtx, uri, []*chain.Transaction{tx}))
require.NoError(tn.ConfirmTxs(timeoutCtx, uri, []*chain.Transaction{tx}))
return nil
})
58 changes: 58 additions & 0 deletions examples/morpheusvm/tests/integration/transfer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package integration_test

import (
"context"
"time"

"github.com/stretchr/testify/require"

"github.com/ava-labs/hypersdk/api/jsonrpc"
"github.com/ava-labs/hypersdk/auth"
"github.com/ava-labs/hypersdk/chain"
"github.com/ava-labs/hypersdk/crypto/ed25519"
"github.com/ava-labs/hypersdk/examples/morpheusvm/actions"
"github.com/ava-labs/hypersdk/examples/morpheusvm/vm"
"github.com/ava-labs/hypersdk/tests/integration"
"github.com/ava-labs/hypersdk/tests/workload"

ginkgo "github.com/onsi/ginkgo/v2"
)

var _ = integration.RegisterTest("Transfer Transaction", func(t ginkgo.FullGinkgoTInterface, tn workload.TestNetwork) error {
aaronbuchwald marked this conversation as resolved.
Show resolved Hide resolved
require := require.New(t)

uri := tn.URIs()[0]
other, err := ed25519.GeneratePrivateKey()
require.NoError(err)
aother := auth.NewED25519Address(other.PublicKey())

lcli := vm.NewJSONRPCClient(uri)
parser, err := lcli.Parser(context.Background())
require.NoError(err)

spendingKey, err := tn.WorkloadFactory().GetSpendingKey()
require.NoError(err)

cli := jsonrpc.NewJSONRPCClient(uri)
_, tx, _, err := cli.GenerateTransaction(
context.Background(),
parser,
[]chain.Action{&actions.Transfer{
To: aother,
Value: 1,
}},
auth.NewED25519Factory(ed25519.PrivateKey(spendingKey.Bytes)),
)

require.NoError(err)

timeoutCtx, timeoutCtxFnc := context.WithDeadline(context.Background(), time.Now().Add(2*time.Second))
defer timeoutCtxFnc()

require.NoError(tn.SubmitTxs(timeoutCtx, uri, []*chain.Transaction{tx}))
require.NoError(tn.ConfirmTxs(timeoutCtx, uri, []*chain.Transaction{tx}))
return nil
})
7 changes: 7 additions & 0 deletions examples/morpheusvm/tests/workload/workload.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ func New(minBlockGap int64) (*genesis.DefaultGenesis, workload.TxWorkloadFactory
}, spamKey, nil
}

func (f *workloadFactory) GetSpendingKey() (*auth.PrivateKey, error) {
return &auth.PrivateKey{
Address: ed25519Addrs[0],
Bytes: ed25519PrivKeys[0][:],
}, nil
}

func (f *workloadFactory) NewSizedTxWorkload(uri string, size int) (workload.TxWorkloadIterator, error) {
cli := jsonrpc.NewJSONRPCClient(uri)
lcli := vm.NewJSONRPCClient(uri)
Expand Down
21 changes: 21 additions & 0 deletions tests/e2e/e2e.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"github.com/ava-labs/hypersdk/api/state"
"github.com/ava-labs/hypersdk/auth"
"github.com/ava-labs/hypersdk/chain"
"github.com/ava-labs/hypersdk/tests/registry"
"github.com/ava-labs/hypersdk/tests/workload"
"github.com/ava-labs/hypersdk/throughput"
"github.com/ava-labs/hypersdk/utils"
Expand All @@ -34,6 +35,8 @@
expectedABI abi.ABI
spamKey *auth.PrivateKey
spamHelper throughput.SpamHelper
testRegistry registry.Registry
testNetwork workload.TestNetwork

Check failure on line 39 in tests/e2e/e2e.go

View workflow job for this annotation

GitHub Actions / hypersdk-lint

var `testNetwork` is unused (unused)
)

func SetWorkload(name string, factory workload.TxWorkloadFactory, abi abi.ABI, chainParser chain.Parser, sh throughput.SpamHelper, key *auth.PrivateKey) {
Expand Down Expand Up @@ -256,6 +259,24 @@
})
})

var _ = ginkgo.Describe("[Custom VM Tests]", func() {
tc := e2e.NewTestContext()
require := require.New(tc)

for _, test := range testRegistry.List() {
ginkgo.It(test.Name, func() {
baseURIs := getE2EBaseURIs(tc)
testNetwork := &Network{uris: baseURIs}
require.NoError(test.Fnc(ginkgo.GinkgoT(), testNetwork), "Test %s failed with an error", test.Name)
})
}
})

func RegisterTest(name string, f registry.TestFunc) bool {
testRegistry.Add(name, f)
return true
}

func getE2EURIs(tc tests.TestContext, blockchainID ids.ID) []string {
nodeURIs := e2e.GetEnv(tc).GetNetwork().GetNodeURIs()
uris := make([]string, 0, len(nodeURIs))
Expand Down
81 changes: 81 additions & 0 deletions tests/e2e/network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package e2e

import (
"context"
"errors"
"time"

"github.com/ava-labs/hypersdk/api/indexer"
"github.com/ava-labs/hypersdk/chain"
"github.com/ava-labs/hypersdk/tests/workload"
)

var (
ErrUnableToConfirmTx = errors.New("unable to confirm transaction")
ErrInvalidURI = errors.New("invalid uri")
)

const (
txCheckInterval = 100 * time.Millisecond
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the const i mentioned earlier

)

type Network struct {
tsachiherman marked this conversation as resolved.
Show resolved Hide resolved
uris []string
}

func (n *Network) ConfirmTxs(ctx context.Context, uri string, txs []*chain.Transaction) error {

Check failure on line 29 in tests/e2e/network.go

View workflow job for this annotation

GitHub Actions / hypersdk-lint

unused-receiver: method receiver 'n' is not referenced in method's body, consider removing or renaming it as _ (revive)
// this is the wrong way. for integration, we wante to test the block content directly.
// instance, err := n.getInstance(uri)
// if err != nil {
// return err
// }
// expectBlk(instance)(false)

indexerCli := indexer.NewClient(uri)
for _, tx := range txs {
success, _, err := indexerCli.WaitForTransaction(ctx, txCheckInterval, tx.ID())
if err != nil {
return err
}
if !success {
return ErrUnableToConfirmTx
}
}
return nil
}

func (n *Network) SubmitTxs(ctx context.Context, uri string, txs []*chain.Transaction) error {

Check failure on line 50 in tests/e2e/network.go

View workflow job for this annotation

GitHub Actions / hypersdk-lint

unused-parameter: parameter 'ctx' seems to be unused, consider removing or renaming it as _ (revive)

Check failure on line 50 in tests/e2e/network.go

View workflow job for this annotation

GitHub Actions / hypersdk-lint

unused-parameter: parameter 'uri' seems to be unused, consider removing or renaming it as _ (revive)

Check failure on line 50 in tests/e2e/network.go

View workflow job for this annotation

GitHub Actions / hypersdk-lint

unused-parameter: parameter 'txs' seems to be unused, consider removing or renaming it as _ (revive)

Check failure on line 50 in tests/e2e/network.go

View workflow job for this annotation

GitHub Actions / hypersdk-lint

unused-receiver: method receiver 'n' is not referenced in method's body, consider removing or renaming it as _ (revive)
/*instance, err := n.getInstance(uri)
if err != nil {
return err
}
for _, tx := range txs {
_, err := instance.cli.SubmitTx(ctx, tx.Bytes())
if err != nil {
return err
}
}*/
return nil
}

func (n *Network) URIs() []string {
return n.uris
}

func (n *Network) WorkloadFactory() workload.TxWorkloadFactory {

Check failure on line 68 in tests/e2e/network.go

View workflow job for this annotation

GitHub Actions / hypersdk-lint

unused-receiver: method receiver 'n' is not referenced in method's body, consider removing or renaming it as _ (revive)
return txWorkloadFactory
}

/*
func (n *Network) getInstance(uri string) (instance, error) {
for _, instance := range instances {
if instance.routerServer.URL == uri {
return instance, nil
}
}
return instance{}, ErrInvalidURI
}
*/
21 changes: 21 additions & 0 deletions tests/integration/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/ava-labs/hypersdk/extension/externalsubscriber"
"github.com/ava-labs/hypersdk/fees"
"github.com/ava-labs/hypersdk/pubsub"
"github.com/ava-labs/hypersdk/tests/registry"
"github.com/ava-labs/hypersdk/tests/workload"
"github.com/ava-labs/hypersdk/vm"

Expand All @@ -58,6 +59,8 @@ var (
sendAppGossipCounter int
uris []string
blocks []snowman.Block
testNetwork workload.TestNetwork
testRegistry registry.Registry

networkID uint32

Expand Down Expand Up @@ -116,9 +119,16 @@ func Setup(
require.NoError(err)
parser = createdParser

// find all callers named NetworkTest...(signature)

setInstances()
}

func RegisterTest(name string, f registry.TestFunc) bool {
testRegistry.Add(name, f)
return true
}

func setInstances() {
require := require.New(ginkgo.GinkgoT())

Expand Down Expand Up @@ -265,6 +275,8 @@ func setInstances() {
uris[i] = inst.routerServer.URL
}

testNetwork = &Network{uris: uris}

blocks = []snowman.Block{}

log.Info("created instances", zap.Int("count", len(instances)))
Expand Down Expand Up @@ -648,6 +660,15 @@ var _ = ginkgo.Describe("[Tx Processing]", ginkgo.Serial, func() {
})
})

var _ = ginkgo.Describe("[Custom VM Tests]", func() {
require := require.New(ginkgo.GinkgoT())
for _, test := range testRegistry.List() {
ginkgo.It(test.Name, func() {
require.NoError(test.Fnc(ginkgo.GinkgoT(), testNetwork), "Test %s failed with an error", test.Name)
})
}
})

func expectBlk(i instance) func(add bool) []*chain.Result {
require := require.New(ginkgo.GinkgoT())

Expand Down
79 changes: 79 additions & 0 deletions tests/integration/network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package integration

import (
"context"
"errors"
"time"

"github.com/ava-labs/hypersdk/api/indexer"
"github.com/ava-labs/hypersdk/chain"
"github.com/ava-labs/hypersdk/tests/workload"
)

var (
ErrUnableToConfirmTx = errors.New("unable to confirm transaction")
ErrInvalidURI = errors.New("invalid uri")
)

const (
txCheckInterval = 100 * time.Millisecond
)

type Network struct {
uris []string
}

func (n *Network) ConfirmTxs(ctx context.Context, uri string, txs []*chain.Transaction) error {
// this is the wrong way. for integration, we wante to test the block content directly.
instance, err := n.getInstance(uri)
if err != nil {
return err
}
expectBlk(instance)(false)

indexerCli := indexer.NewClient(uri)
for _, tx := range txs {
success, _, err := indexerCli.WaitForTransaction(ctx, txCheckInterval, tx.ID())
if err != nil {
return err
}
if !success {
return ErrUnableToConfirmTx
}
}
return nil
}

func (n *Network) SubmitTxs(ctx context.Context, uri string, txs []*chain.Transaction) error {
instance, err := n.getInstance(uri)
if err != nil {
return err
}
for _, tx := range txs {
_, err := instance.cli.SubmitTx(ctx, tx.Bytes())
if err != nil {
return err
}
}
return nil
}

func (n *Network) URIs() []string {
return n.uris
}

func (*Network) WorkloadFactory() workload.TxWorkloadFactory {
return txWorkloadFactory
}

func (*Network) getInstance(uri string) (instance, error) {
for _, instance := range instances {
if instance.routerServer.URL == uri {
return instance, nil
}
}
return instance{}, ErrInvalidURI
}
Loading
Loading