Skip to content

Commit b2ad4d3

Browse files
authored
support procedural test style for VM-defined workloads (#1667)
Signed-off-by: Tsachi Herman <24438559+tsachiherman@users.noreply.github.com>
1 parent dbcc6c9 commit b2ad4d3

File tree

12 files changed

+601
-77
lines changed

12 files changed

+601
-77
lines changed

examples/morpheusvm/tests/e2e/e2e_test.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
package e2e_test
55

66
import (
7-
"encoding/json"
87
"testing"
98
"time"
109

1110
"github.com/ava-labs/avalanchego/tests/fixture/e2e"
1211
"github.com/stretchr/testify/require"
1312

13+
_ "github.com/ava-labs/hypersdk/examples/morpheusvm/tests" // include the tests that are shared between the integration and e2e
14+
1415
"github.com/ava-labs/hypersdk/abi"
1516
"github.com/ava-labs/hypersdk/auth"
1617
"github.com/ava-labs/hypersdk/examples/morpheusvm/consts"
@@ -39,14 +40,10 @@ func init() {
3940
var _ = ginkgo.SynchronizedBeforeSuite(func() []byte {
4041
require := require.New(ginkgo.GinkgoT())
4142

42-
keys := workload.NewDefaultKeys()
43-
genesis := workload.NewGenesis(keys, 100*time.Millisecond)
44-
genesisBytes, err := json.Marshal(genesis)
45-
require.NoError(err)
46-
expectedABI, err := abi.NewABI(vm.ActionParser.GetRegisteredTypes(), vm.OutputParser.GetRegisteredTypes())
43+
testingNetworkConfig, err := workload.NewTestNetworkConfig(100 * time.Millisecond)
4744
require.NoError(err)
4845

49-
parser, err := vm.CreateParser(genesisBytes)
46+
expectedABI, err := abi.NewABI(vm.ActionParser.GetRegisteredTypes(), vm.OutputParser.GetRegisteredTypes())
5047
require.NoError(err)
5148

5249
// Import HyperSDK e2e test coverage and inject MorpheusVM name
@@ -55,15 +52,16 @@ var _ = ginkgo.SynchronizedBeforeSuite(func() []byte {
5552
KeyType: auth.ED25519Key,
5653
}
5754

58-
generator := workload.NewTxGenerator(keys[0])
55+
firstKey := testingNetworkConfig.Keys()[0]
56+
generator := workload.NewTxGenerator(firstKey)
5957
spamKey := &auth.PrivateKey{
60-
Address: auth.NewED25519Address(keys[0].PublicKey()),
61-
Bytes: keys[0][:],
58+
Address: auth.NewED25519Address(firstKey.PublicKey()),
59+
Bytes: firstKey[:],
6260
}
6361
tc := e2e.NewTestContext()
64-
he2e.SetWorkload(consts.Name, generator, expectedABI, parser, &spamHelper, spamKey)
62+
he2e.SetWorkload(testingNetworkConfig, generator, expectedABI, &spamHelper, spamKey)
6563

66-
return fixture.NewTestEnvironment(tc, flagVars, owner, consts.Name, consts.ID, genesisBytes).Marshal()
64+
return fixture.NewTestEnvironment(tc, flagVars, owner, testingNetworkConfig, consts.ID).Marshal()
6765
}, func(envBytes []byte) {
6866
// Run in every ginkgo process
6967

examples/morpheusvm/tests/integration/integration_test.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
package integration_test
55

66
import (
7-
"encoding/json"
87
"testing"
98

109
"github.com/stretchr/testify/require"
1110

11+
_ "github.com/ava-labs/hypersdk/examples/morpheusvm/tests" // include the tests that are shared between the integration and e2e
12+
1213
"github.com/ava-labs/hypersdk/auth"
1314
"github.com/ava-labs/hypersdk/crypto/ed25519"
1415
"github.com/ava-labs/hypersdk/examples/morpheusvm/tests/workload"
@@ -26,23 +27,20 @@ func TestIntegration(t *testing.T) {
2627
var _ = ginkgo.BeforeSuite(func() {
2728
require := require.New(ginkgo.GinkgoT())
2829

29-
keys := workload.NewDefaultKeys()
30-
genesis := workload.NewGenesis(keys, 0)
31-
genesisBytes, err := json.Marshal(genesis)
30+
testingNetworkConfig, err := workload.NewTestNetworkConfig(0)
3231
require.NoError(err)
3332

3433
randomEd25519Priv, err := ed25519.GeneratePrivateKey()
3534
require.NoError(err)
3635

3736
randomEd25519AuthFactory := auth.NewED25519Factory(randomEd25519Priv)
3837

39-
generator := workload.NewTxGenerator(keys[0])
38+
generator := workload.NewTxGenerator(testingNetworkConfig.Keys()[0])
4039
// Setup imports the integration test coverage
4140
integration.Setup(
4241
vm.New,
43-
genesisBytes,
42+
testingNetworkConfig,
4443
lconsts.ID,
45-
vm.CreateParser,
4644
generator,
4745
randomEd25519AuthFactory,
4846
)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package tests
5+
6+
import (
7+
"context"
8+
"time"
9+
10+
"github.com/stretchr/testify/require"
11+
12+
"github.com/ava-labs/hypersdk/auth"
13+
"github.com/ava-labs/hypersdk/chain"
14+
"github.com/ava-labs/hypersdk/crypto/ed25519"
15+
"github.com/ava-labs/hypersdk/examples/morpheusvm/actions"
16+
"github.com/ava-labs/hypersdk/examples/morpheusvm/tests/workload"
17+
"github.com/ava-labs/hypersdk/tests/registry"
18+
19+
tworkload "github.com/ava-labs/hypersdk/tests/workload"
20+
ginkgo "github.com/onsi/ginkgo/v2"
21+
)
22+
23+
// TestsRegistry initialized during init to ensure tests are identical during ginkgo
24+
// suite construction and test execution
25+
// ref https://onsi.github.io/ginkgo/#mental-model-how-ginkgo-traverses-the-spec-hierarchy
26+
var TestsRegistry = &registry.Registry{}
27+
28+
var _ = registry.Register(TestsRegistry, "Transfer Transaction", func(t ginkgo.FullGinkgoTInterface, tn tworkload.TestNetwork) {
29+
require := require.New(t)
30+
other, err := ed25519.GeneratePrivateKey()
31+
require.NoError(err)
32+
toAddress := auth.NewED25519Address(other.PublicKey())
33+
34+
networkConfig := tn.Configuration().(*workload.NetworkConfiguration)
35+
spendingKey := networkConfig.Keys()[0]
36+
37+
tx, err := tn.GenerateTx(context.Background(), []chain.Action{&actions.Transfer{
38+
To: toAddress,
39+
Value: 1,
40+
}},
41+
auth.NewED25519Factory(spendingKey),
42+
)
43+
require.NoError(err)
44+
45+
timeoutCtx, timeoutCtxFnc := context.WithDeadline(context.Background(), time.Now().Add(2*time.Second))
46+
defer timeoutCtxFnc()
47+
48+
require.NoError(tn.ConfirmTxs(timeoutCtx, []*chain.Transaction{tx}))
49+
})

examples/morpheusvm/tests/workload/genesis.go

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,36 @@
44
package workload
55

66
import (
7+
"encoding/json"
78
"math"
89
"time"
910

11+
"github.com/ava-labs/avalanchego/ids"
12+
1013
"github.com/ava-labs/hypersdk/auth"
1114
"github.com/ava-labs/hypersdk/codec"
1215
"github.com/ava-labs/hypersdk/crypto/ed25519"
16+
"github.com/ava-labs/hypersdk/examples/morpheusvm/consts"
17+
"github.com/ava-labs/hypersdk/examples/morpheusvm/vm"
1318
"github.com/ava-labs/hypersdk/fees"
1419
"github.com/ava-labs/hypersdk/genesis"
20+
"github.com/ava-labs/hypersdk/tests/workload"
1521
)
1622

1723
const (
1824
// default initial balance for each address
1925
InitialBalance uint64 = 10_000_000_000_000
2026
)
2127

28+
var _ workload.TestNetworkConfiguration = &NetworkConfiguration{}
29+
2230
// hardcoded initial set of ed25519 keys. Each will be initialized with InitialBalance
2331
var ed25519HexKeys = []string{
2432
"323b1d8f4eed5f0da9da93071b034f2dce9d2d22692c172f3cb252a64ddfafd01b057de320297c29ad0c1f589ea216869cf1938d88c9fbd70d6748323dbf2fa7", //nolint:lll
2533
"8a7be2e0c9a2d09ac2861c34326d6fe5a461d920ba9c2b345ae28e603d517df148735063f8d5d8ba79ea4668358943e5c80bc09e9b2b9a15b5b15db6c1862e88", //nolint:lll
2634
}
2735

28-
func NewGenesis(keys []ed25519.PrivateKey, minBlockGap time.Duration) *genesis.DefaultGenesis {
36+
func newGenesis(keys []ed25519.PrivateKey, minBlockGap time.Duration) *genesis.DefaultGenesis {
2937
// allocate the initial balance to the addresses
3038
customAllocs := make([]*genesis.CustomAllocation, 0, len(keys))
3139
for _, key := range keys {
@@ -45,10 +53,13 @@ func NewGenesis(keys []ed25519.PrivateKey, minBlockGap time.Duration) *genesis.D
4553
genesis.Rules.MaxBlockUnits = fees.Dimensions{1800000, math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64}
4654
genesis.Rules.MinBlockGap = minBlockGap.Milliseconds()
4755

56+
genesis.Rules.NetworkID = uint32(1)
57+
genesis.Rules.ChainID = ids.GenerateTestID()
58+
4859
return genesis
4960
}
5061

51-
func NewDefaultKeys() []ed25519.PrivateKey {
62+
func newDefaultKeys() []ed25519.PrivateKey {
5263
testKeys := make([]ed25519.PrivateKey, len(ed25519HexKeys))
5364
for i, keyHex := range ed25519HexKeys {
5465
bytes, err := codec.LoadHex(keyHex, ed25519.PrivateKeyLen)
@@ -60,3 +71,28 @@ func NewDefaultKeys() []ed25519.PrivateKey {
6071

6172
return testKeys
6273
}
74+
75+
type NetworkConfiguration struct {
76+
workload.DefaultTestNetworkConfiguration
77+
keys []ed25519.PrivateKey
78+
}
79+
80+
func (n *NetworkConfiguration) Keys() []ed25519.PrivateKey {
81+
return n.keys
82+
}
83+
84+
func NewTestNetworkConfig(minBlockGap time.Duration) (*NetworkConfiguration, error) {
85+
keys := newDefaultKeys()
86+
genesis := newGenesis(keys, minBlockGap)
87+
genesisBytes, err := json.Marshal(genesis)
88+
if err != nil {
89+
return nil, err
90+
}
91+
return &NetworkConfiguration{
92+
DefaultTestNetworkConfiguration: workload.NewDefaultTestNetworkConfiguration(
93+
genesisBytes,
94+
consts.Name,
95+
vm.NewParser(genesis)),
96+
keys: keys,
97+
}, nil
98+
}

tests/e2e/e2e.go

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
"github.com/ava-labs/hypersdk/api/jsonrpc"
2020
"github.com/ava-labs/hypersdk/api/state"
2121
"github.com/ava-labs/hypersdk/auth"
22-
"github.com/ava-labs/hypersdk/chain"
22+
"github.com/ava-labs/hypersdk/tests/registry"
2323
"github.com/ava-labs/hypersdk/tests/workload"
2424
"github.com/ava-labs/hypersdk/throughput"
2525
"github.com/ava-labs/hypersdk/utils"
@@ -28,20 +28,18 @@ import (
2828
)
2929

3030
var (
31-
vmName string
32-
txWorkload workload.TxWorkload
33-
parser chain.Parser
34-
expectedABI abi.ABI
35-
spamKey *auth.PrivateKey
36-
spamHelper throughput.SpamHelper
31+
networkConfig workload.TestNetworkConfiguration
32+
txWorkload workload.TxWorkload
33+
expectedABI abi.ABI
34+
spamKey *auth.PrivateKey
35+
spamHelper throughput.SpamHelper
3736
)
3837

39-
func SetWorkload(name string, generator workload.TxGenerator, abi abi.ABI, chainParser chain.Parser, sh throughput.SpamHelper, key *auth.PrivateKey) {
40-
vmName = name
38+
func SetWorkload(networkConfigImpl workload.TestNetworkConfiguration, generator workload.TxGenerator, abi abi.ABI, sh throughput.SpamHelper, key *auth.PrivateKey) {
39+
networkConfig = networkConfigImpl
4140
txWorkload = workload.TxWorkload{
4241
Generator: generator,
4342
}
44-
parser = chainParser
4543
expectedABI = abi
4644
spamHelper = sh
4745
spamKey = key
@@ -52,23 +50,23 @@ var _ = ginkgo.Describe("[HyperSDK APIs]", func() {
5250
require := require.New(tc)
5351

5452
ginkgo.It("Ping", func() {
55-
expectedBlockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(vmName).Chains[0].ChainID
53+
expectedBlockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(networkConfig.Name()).Chains[0].ChainID
5654
workload.Ping(tc.DefaultContext(), require, getE2EURIs(tc, expectedBlockchainID))
5755
})
5856

5957
ginkgo.It("StableNetworkIdentity", func() {
6058
hardcodedHostPort := "http://localhost:9650"
61-
fixedNodeURL := hardcodedHostPort + "/ext/bc/" + vmName
59+
fixedNodeURL := hardcodedHostPort + "/ext/bc/" + networkConfig.Name()
6260

6361
c := jsonrpc.NewJSONRPCClient(fixedNodeURL)
6462
_, _, chainIDFromRPC, err := c.Network(tc.DefaultContext())
6563
require.NoError(err)
66-
expectedBlockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(vmName).Chains[0].ChainID
64+
expectedBlockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(networkConfig.Name()).Chains[0].ChainID
6765
require.Equal(expectedBlockchainID, chainIDFromRPC)
6866
})
6967

7068
ginkgo.It("GetNetwork", func() {
71-
expectedBlockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(vmName).Chains[0].ChainID
69+
expectedBlockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(networkConfig.Name()).Chains[0].ChainID
7270
baseURIs := getE2EBaseURIs(tc)
7371
baseURI := baseURIs[0]
7472
client := info.NewClient(baseURI)
@@ -78,12 +76,12 @@ var _ = ginkgo.Describe("[HyperSDK APIs]", func() {
7876
})
7977

8078
ginkgo.It("GetABI", func() {
81-
expectedBlockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(vmName).Chains[0].ChainID
79+
expectedBlockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(networkConfig.Name()).Chains[0].ChainID
8280
workload.GetABI(tc.DefaultContext(), require, getE2EURIs(tc, expectedBlockchainID), expectedABI)
8381
})
8482

8583
ginkgo.It("ReadState", func() {
86-
blockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(vmName).Chains[0].ChainID
84+
blockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(networkConfig.Name()).Chains[0].ChainID
8785
ctx := tc.DefaultContext()
8886
for _, uri := range getE2EURIs(tc, blockchainID) {
8987
client := state.NewJSONRPCStateClient(uri)
@@ -97,31 +95,31 @@ var _ = ginkgo.Describe("[HyperSDK APIs]", func() {
9795
})
9896
})
9997

100-
var _ = ginkgo.Describe("[HyperSDK Tx Workloads]", func() {
98+
var _ = ginkgo.Describe("[HyperSDK Tx Workloads]", ginkgo.Serial, func() {
10199
ginkgo.It("Basic Tx Workload", func() {
102100
tc := e2e.NewTestContext()
103101
require := require.New(tc)
104-
blockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(vmName).Chains[0].ChainID
102+
blockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(networkConfig.Name()).Chains[0].ChainID
105103

106104
ginkgo.By("Tx workloads", func() {
107105
txWorkload.GenerateBlocks(tc.DefaultContext(), require, getE2EURIs(tc, blockchainID), 1)
108106
})
109107

110108
ginkgo.By("Confirm accepted blocks indexed", func() {
111-
workload.GetBlocks(tc.DefaultContext(), require, parser, getE2EURIs(tc, blockchainID))
109+
workload.GetBlocks(tc.DefaultContext(), require, networkConfig.Parser(), getE2EURIs(tc, blockchainID))
112110
})
113111
})
114112
})
115113

116-
var _ = ginkgo.Describe("[HyperSDK Spam Workloads]", func() {
114+
var _ = ginkgo.Describe("[HyperSDK Spam Workloads]", ginkgo.Serial, func() {
117115
ginkgo.It("Spam Workload", func() {
118116
if spamKey == nil || spamHelper == nil {
119117
return
120118
}
121119

122120
tc := e2e.NewTestContext()
123121
require := require.New(tc)
124-
blockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(vmName).Chains[0].ChainID
122+
blockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(networkConfig.Name()).Chains[0].ChainID
125123
uris := getE2EURIs(tc, blockchainID)
126124
key := spamKey
127125

@@ -137,11 +135,11 @@ var _ = ginkgo.Describe("[HyperSDK Spam Workloads]", func() {
137135
})
138136
})
139137

140-
var _ = ginkgo.Describe("[HyperSDK Syncing]", func() {
138+
var _ = ginkgo.Describe("[HyperSDK Syncing]", ginkgo.Serial, func() {
141139
ginkgo.It("[Sync]", func() {
142140
tc := e2e.NewTestContext()
143141
require := require.New(tc)
144-
blockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(vmName).Chains[0].ChainID
142+
blockchainID := e2e.GetEnv(tc).GetNetwork().GetSubnet(networkConfig.Name()).Chains[0].ChainID
145143

146144
uris := getE2EURIs(tc, blockchainID)
147145
ginkgo.By("Generate 128 blocks", func() {
@@ -244,6 +242,19 @@ var _ = ginkgo.Describe("[HyperSDK Syncing]", func() {
244242
})
245243
})
246244

245+
var _ = ginkgo.Describe("[Custom VM Tests]", ginkgo.Serial, func() {
246+
tc := e2e.NewTestContext()
247+
248+
for testRegistry := range registry.GetTestsRegistries() {
249+
for _, test := range testRegistry.List() {
250+
ginkgo.It(test.Name, func() {
251+
testNetwork := NewNetwork(tc)
252+
test.Fnc(ginkgo.GinkgoT(), testNetwork)
253+
})
254+
}
255+
}
256+
})
257+
247258
func getE2EURIs(tc tests.TestContext, blockchainID ids.ID) []string {
248259
nodeURIs := e2e.GetEnv(tc).GetNetwork().GetNodeURIs()
249260
uris := make([]string, 0, len(nodeURIs))

0 commit comments

Comments
 (0)