Skip to content

Commit

Permalink
Testing: Allow go e2e tests to easily test multiple consensus versions (
Browse files Browse the repository at this point in the history
  • Loading branch information
jannotti authored Apr 26, 2024
1 parent adf39d2 commit 5f81b7b
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 37 deletions.
6 changes: 5 additions & 1 deletion cmd/goal/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@ var networkCreateCmd = &cobra.Command{
consensus, _ = config.PreloadConfigurableConsensusProtocols(dataDir)
}

network, err := netdeploy.CreateNetworkFromTemplate(networkName, networkRootDir, templateReader, binDir, !noImportKeys, nil, consensus, devModeOverride)
var overrides []netdeploy.TemplateOverride
if devModeOverride {
overrides = append(overrides, netdeploy.OverrideDevMode)
}
network, err := netdeploy.CreateNetworkFromTemplate(networkName, networkRootDir, templateReader, binDir, !noImportKeys, nil, consensus, overrides...)
if err != nil {
if noClean {
reportInfof(" ** failed ** - Preserving network rootdir '%s'", networkRootDir)
Expand Down
36 changes: 25 additions & 11 deletions netdeploy/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/algorand/go-algorand/libgoal"
"github.com/algorand/go-algorand/netdeploy/remote"
"github.com/algorand/go-algorand/nodecontrol"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/util"
"golang.org/x/exp/maps"
)
Expand All @@ -58,9 +59,27 @@ type Network struct {
nodeExitCallback nodecontrol.AlgodExitErrorCallback
}

// TemplateOverride is a function that modifies the NetworkTemplate after it is read in.
type TemplateOverride func(*NetworkTemplate)

// OverrideDevMode turns on dev mode, regardless of whether the json says so.
func OverrideDevMode(template *NetworkTemplate) {
template.Genesis.DevMode = true
if len(template.Nodes) > 0 {
template.Nodes[0].IsRelay = false
}
}

// OverrideConsensusVersion changes the protocol version of a template.
func OverrideConsensusVersion(ver protocol.ConsensusVersion) TemplateOverride {
return func(template *NetworkTemplate) {
template.Genesis.ConsensusProtocol = ver
}
}

// CreateNetworkFromTemplate uses the specified template to deploy a new private network
// under the specified root directory.
func CreateNetworkFromTemplate(name, rootDir string, templateReader io.Reader, binDir string, importKeys bool, nodeExitCallback nodecontrol.AlgodExitErrorCallback, consensus config.ConsensusProtocols, overrideDevMode bool) (Network, error) {
func CreateNetworkFromTemplate(name, rootDir string, templateReader io.Reader, binDir string, importKeys bool, nodeExitCallback nodecontrol.AlgodExitErrorCallback, consensus config.ConsensusProtocols, overrides ...TemplateOverride) (Network, error) {
n := Network{
rootDir: rootDir,
nodeExitCallback: nodeExitCallback,
Expand All @@ -70,19 +89,14 @@ func CreateNetworkFromTemplate(name, rootDir string, templateReader io.Reader, b
var err error
template := defaultNetworkTemplate

err = LoadTemplateFromReader(templateReader, &template)

if err == nil {
if overrideDevMode {
template.Genesis.DevMode = true
if len(template.Nodes) > 0 {
template.Nodes[0].IsRelay = false
}
}
} else {
if err = LoadTemplateFromReader(templateReader, &template); err != nil {
return n, err
}

for _, overide := range overrides {
overide(&template)
}

if err = template.Validate(); err != nil {
return n, err
}
Expand Down
22 changes: 11 additions & 11 deletions test/e2e-go/features/devmode/devmode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,21 @@ import (

"github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/netdeploy"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/test/framework/fixtures"
"github.com/algorand/go-algorand/test/partitiontest"
)

func TestDevMode(t *testing.T) {
partitiontest.PartitionTest(t)
fixtures.MultiProtocolTest(t, testDevMode, protocol.ConsensusFuture, protocol.ConsensusCurrentVersion)
}

if testing.Short() {
t.Skip()
}

func testDevMode(t *testing.T, version protocol.ConsensusVersion) {
// Start devmode network, and make sure everything is primed by sending a transaction.
var fixture fixtures.RestClientFixture
fixture.SetupNoStart(t, filepath.Join("nettemplates", "DevModeNetwork.json"))
fixture.SetupNoStart(t, filepath.Join("nettemplates", "DevModeNetwork.json"), netdeploy.OverrideConsensusVersion(version))
fixture.Start()
defer fixture.Shutdown()
sender, err := fixture.GetRichestAccount()
Expand Down Expand Up @@ -76,17 +77,16 @@ func TestDevMode(t *testing.T) {
}
}

// Starts up a devmode network, sends a txn, and fetches the txn group delta for that txn
func TestTxnGroupDeltasDevMode(t *testing.T) {
partitiontest.PartitionTest(t)
fixtures.MultiProtocolTest(t, testTxnGroupDeltasDevMode, protocol.ConsensusFuture, protocol.ConsensusCurrentVersion)
}

if testing.Short() {
t.Skip()
}

// Starts up a devmode network, sends a txn, and fetches the txn group delta for that txn
func testTxnGroupDeltasDevMode(t *testing.T, version protocol.ConsensusVersion) {
// Start devmode network, and send a transaction.
var fixture fixtures.RestClientFixture
fixture.SetupNoStart(t, filepath.Join("nettemplates", "DevModeTxnTracerNetwork.json"))
fixture.SetupNoStart(t, filepath.Join("nettemplates", "DevModeTxnTracerNetwork.json"), netdeploy.OverrideConsensusVersion(version))
fixture.Start()
defer fixture.Shutdown()
sender, err := fixture.GetRichestAccount()
Expand Down
14 changes: 14 additions & 0 deletions test/framework/fixtures/fixture.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package fixtures
import (
"testing"

"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-deadlock"
)

Expand Down Expand Up @@ -206,3 +207,16 @@ func (st *synchTest) Skipped() bool {
defer st.Unlock()
return st.t.Skipped()
}

// MultiProtocolTest runs a test for multiple consensus versions. It only runs
// against the *first* version when doing Short tests.
func MultiProtocolTest(t *testing.T, test func(t *testing.T, version protocol.ConsensusVersion), versions ...protocol.ConsensusVersion) {
for _, version := range versions {
t.Run(string(version), func(t *testing.T) {
test(t, version)
})
if testing.Short() {
break // supply most important version first, probably future
}
}
}
16 changes: 8 additions & 8 deletions test/framework/fixtures/libgoalFixture.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,27 +90,27 @@ func (f *RestClientFixture) FasterConsensus(ver protocol.ConsensusVersion, timeo
}

// Setup is called to initialize the test fixture for the test(s)
func (f *LibGoalFixture) Setup(t TestingTB, templateFile string) {
f.setup(t, t.Name(), templateFile, true)
func (f *LibGoalFixture) Setup(t TestingTB, templateFile string, overrides ...netdeploy.TemplateOverride) {
f.setup(t, t.Name(), templateFile, true, overrides...)
}

// SetupNoStart is called to initialize the test fixture for the test(s)
// but does not start the network before returning. Call NC.Start() to start later.
func (f *LibGoalFixture) SetupNoStart(t TestingTB, templateFile string) {
f.setup(t, t.Name(), templateFile, false)
func (f *LibGoalFixture) SetupNoStart(t TestingTB, templateFile string, overrides ...netdeploy.TemplateOverride) {
f.setup(t, t.Name(), templateFile, false, overrides...)
}

// SetupShared is called to initialize the test fixture that will be used for multiple tests
func (f *LibGoalFixture) SetupShared(testName string, templateFile string) {
f.setup(nil, testName, templateFile, true)
func (f *LibGoalFixture) SetupShared(testName string, templateFile string, overrides ...netdeploy.TemplateOverride) {
f.setup(nil, testName, templateFile, true, overrides...)
}

// Genesis returns the genesis data for this fixture
func (f *LibGoalFixture) Genesis() gen.GenesisData {
return f.network.Genesis()
}

func (f *LibGoalFixture) setup(test TestingTB, testName string, templateFile string, startNetwork bool) {
func (f *LibGoalFixture) setup(test TestingTB, testName string, templateFile string, startNetwork bool, overrides ...netdeploy.TemplateOverride) {
// Call initialize for our base implementation
f.initialize(f)
f.t = SynchronizedTest(test)
Expand All @@ -122,7 +122,7 @@ func (f *LibGoalFixture) setup(test TestingTB, testName string, templateFile str
importKeys := false // Don't automatically import root keys when creating folders, we'll import on-demand
file, err := os.Open(templateFile)
f.failOnError(err, "Template file could not be opened: %v")
network, err := netdeploy.CreateNetworkFromTemplate("test", f.rootDir, file, f.binDir, importKeys, f.nodeExitWithError, f.consensus, false)
network, err := netdeploy.CreateNetworkFromTemplate("test", f.rootDir, file, f.binDir, importKeys, f.nodeExitWithError, f.consensus, overrides...)
f.failOnError(err, "CreateNetworkFromTemplate failed: %v")
f.network = network

Expand Down
13 changes: 7 additions & 6 deletions test/framework/fixtures/restClientFixture.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/netdeploy"
"github.com/algorand/go-algorand/protocol"

"github.com/algorand/go-algorand/daemon/algod/api/client"
Expand All @@ -44,20 +45,20 @@ type RestClientFixture struct {
}

// Setup is called to initialize the test fixture for the test(s)
func (f *RestClientFixture) Setup(t TestingTB, templateFile string) {
f.LibGoalFixture.Setup(t, templateFile)
func (f *RestClientFixture) Setup(t TestingTB, templateFile string, overrides ...netdeploy.TemplateOverride) {
f.LibGoalFixture.Setup(t, templateFile, overrides...)
f.AlgodClient = f.GetAlgodClientForController(f.NC)
}

// SetupNoStart is called to initialize the test fixture for the test(s)
// but does not start the network before returning. Call NC.Start() to start later.
func (f *RestClientFixture) SetupNoStart(t TestingTB, templateFile string) {
f.LibGoalFixture.SetupNoStart(t, templateFile)
func (f *RestClientFixture) SetupNoStart(t TestingTB, templateFile string, overrides ...netdeploy.TemplateOverride) {
f.LibGoalFixture.SetupNoStart(t, templateFile, overrides...)
}

// SetupShared is called to initialize the test fixture that will be used for multiple tests
func (f *RestClientFixture) SetupShared(testName string, templateFile string) {
f.LibGoalFixture.SetupShared(testName, templateFile)
func (f *RestClientFixture) SetupShared(testName string, templateFile string, overrides ...netdeploy.TemplateOverride) {
f.LibGoalFixture.SetupShared(testName, templateFile, overrides...)
f.AlgodClient = f.GetAlgodClientForController(f.NC)
}

Expand Down

0 comments on commit 5f81b7b

Please sign in to comment.