Skip to content
Closed
Show file tree
Hide file tree
Changes from 11 commits
Commits
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
1 change: 1 addition & 0 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ jobs:
"\\[Node create\\]",
"\\[Node devnet\\]",
"\\[Docker\\]",
"\\[Blockchain Deploy Flags\\]",
Copy link
Collaborator

Choose a reason for hiding this comment

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

not sure we want to start modifying CI at this stage

]
os: [ubuntu-24.04, macos-14]
exclude:
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/commands/etna.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const (
PoAString = "proof-of-authority"
)

func CreateEtnaSubnetEvmConfig(
func CreateSubnetEvmConfigSOV(
subnetName string,
ewoqEVMAddress string,
subnetManagementType SubnetManagementType,
Expand Down
18 changes: 9 additions & 9 deletions tests/e2e/commands/subnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (

const (
subnetEVMMainnetChainID = 11
poaValidatorManagerOwner = "0x2e6FcBb9d4E17eC4cF67eddfa7D32eabC4cdCFc6"
PoaValidatorManagerOwner = "0x2e6FcBb9d4E17eC4cF67eddfa7D32eabC4cdCFc6"
bootstrapFilepathFlag = "--bootstrap-filepath"
avalancheGoPath = "--avalanchego-path"
localNodeClusterName = "testLocalNode"
Expand All @@ -35,12 +35,12 @@ func CreateSubnetEvmConfigNonSOV(subnetName string, genesisPath string) (string,
return mapping[utils.LatestEVM2AvagoKey], mapping[utils.LatestAvago2EVMKey]
}

func CreateSubnetEvmConfigSOV(subnetName string, genesisPath string) (string, string) {
func CreateSubnetEvmConfigSOVWithGenesisPath(subnetName string, genesisPath string, validatorManagerOwner string) (string, string) {
mapper := utils.NewVersionMapper()
mapping, err := utils.GetVersionMapping(mapper)
gomega.Expect(err).Should(gomega.BeNil())
// let's use a SubnetEVM version which has a guaranteed compatible avago
CreateSubnetEvmConfigWithVersionSOV(subnetName, genesisPath, mapping[utils.LatestEVM2AvagoKey])
CreateSubnetEvmConfigGenesisPathWithVersionSOV(subnetName, genesisPath, mapping[utils.LatestEVM2AvagoKey], validatorManagerOwner)
return mapping[utils.LatestEVM2AvagoKey], mapping[utils.LatestAvago2EVMKey]
}

Expand Down Expand Up @@ -85,7 +85,7 @@ func CreateSubnetEvmConfigWithVersionNonSOV(subnetName string, genesisPath strin
gomega.Expect(exists).Should(gomega.BeTrue())
}

func CreateSubnetEvmConfigWithVersionSOV(subnetName string, genesisPath string, version string) {
func CreateSubnetEvmConfigGenesisPathWithVersionSOV(subnetName string, genesisPath string, version string, validatorManagerOwner string) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

we need a generic function that just take the command name, the non flag args, and a map for flags, and
stopping doing this

// Check config does not already exist
exists, err := utils.SubnetConfigExists(subnetName)
gomega.Expect(err).Should(gomega.BeNil())
Expand All @@ -101,9 +101,9 @@ func CreateSubnetEvmConfigWithVersionSOV(subnetName string, genesisPath string,
subnetName,
"--proof-of-authority",
"--validator-manager-owner",
poaValidatorManagerOwner,
validatorManagerOwner,
"--proxy-contract-owner",
poaValidatorManagerOwner,
validatorManagerOwner,
"--" + constants.SkipUpdateFlag,
"--icm=false",
"--evm-token",
Expand Down Expand Up @@ -217,7 +217,7 @@ func CreateCustomVMConfigNonSOV(subnetName string, genesisPath string, vmPath st
gomega.Expect(exists).Should(gomega.BeTrue())
}

func CreateCustomVMConfigSOV(subnetName string, genesisPath string, vmPath string) {
func CreateCustomVMConfigSOV(subnetName string, genesisPath string, vmPath string, validatorManagerOwner string) {
// Check config does not already exist
exists, err := utils.SubnetConfigExists(subnetName)
gomega.Expect(err).Should(gomega.BeNil())
Expand All @@ -236,9 +236,9 @@ func CreateCustomVMConfigSOV(subnetName string, genesisPath string, vmPath strin
genesisPath,
"--proof-of-authority",
"--validator-manager-owner",
Copy link
Collaborator

Choose a reason for hiding this comment

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

we also need to stop using flag constants here, and take those from cmd/flags

poaValidatorManagerOwner,
validatorManagerOwner,
"--proxy-contract-owner",
poaValidatorManagerOwner,
validatorManagerOwner,
"--custom",
subnetName,
"--custom-vm-path",
Expand Down
22 changes: 22 additions & 0 deletions tests/e2e/commandse2e/blockchain/deploy/deploy_tests.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
Copy link
Collaborator

Choose a reason for hiding this comment

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

I like this cmd tree. probably this can have a default name, like test_table.json

"globalFlags": {
"local": true,
"skip-icm-deploy": true,
"skip-update-check": true
},
"happyPath": [
{
"name": "local_deploy",
"flags": {}
}
],
"notHappyPath": [
{
"name": "invalid_version",
"flags": {
"avalanchego-version": "invalid_version"
},
"expectedError": "invalid version string"
}
]
}
73 changes: 73 additions & 0 deletions tests/e2e/commandse2e/blockchain/deploy/suite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package deploy

import (
"fmt"

"github.com/ava-labs/avalanche-cli/tests/e2e/commandse2e"

"github.com/ava-labs/avalanche-cli/tests/e2e/commands"
ginkgo "github.com/onsi/ginkgo/v2"
"github.com/onsi/gomega"
)

const (
deployTestJSONPath = "tests/e2e/commandse2e/blockchain/deploy/deploy_tests.json"
subnetName = "testSubnet"
)

var (
config *commandse2e.TestJSONConfig
err error
)

const ewoqEVMAddress = "0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC"

var _ = ginkgo.Describe("[Blockchain Deploy Flags]", ginkgo.Ordered, func() {
_ = ginkgo.BeforeEach(func() {
// Create test subnet config
commands.CreateSubnetEvmConfigSOV(subnetName, ewoqEVMAddress, commands.PoA)
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe this should be added to the json spec (how to setup required env)


// Read test configuration
config, err = commandse2e.ReadTestConfig(deployTestJSONPath)
gomega.Expect(err).Should(gomega.BeNil())
})

ginkgo.AfterEach(func() {
commands.CleanNetwork()
// Cleanup test subnet config
commands.DeleteSubnetConfig(subnetName)
})
blockchainCmdArgs := []string{subnetName}
Copy link
Collaborator

Choose a reason for hiding this comment

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

this should belong to the json test case IMO

ginkgo.It("should successfully deploy a blockchain", func() {
// Run each happy path test case
for _, testCase := range config.HappyPath {
ginkgo.By(fmt.Sprintf("Running test case: %s", testCase.Name))
_, err = commandse2e.TestCommandWithJSONConfig(
commandse2e.BlockchainCmd,
"deploy",
Copy link
Collaborator

Choose a reason for hiding this comment

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

this should be a constant on cmd/blockchaincmd/

blockchainCmdArgs,
deployTestJSONPath,
&testCase,
)
gomega.Expect(err).Should(gomega.BeNil())
}
})

ginkgo.It("should handle error cases", func() {
// Run each not happy path test case
for _, testCase := range config.NotHappyPath {
ginkgo.By(fmt.Sprintf("Running test case: %s", testCase.Name))
_, err = commandse2e.TestCommandWithJSONConfig(
commandse2e.BlockchainCmd,
"deploy",
blockchainCmdArgs,
deployTestJSONPath,
&testCase,
)
gomega.Expect(err).Should(gomega.HaveOccurred())
}
})
})
111 changes: 111 additions & 0 deletions tests/e2e/commandse2e/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright (C) 2022, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package commandse2e

import (
"encoding/json"
"errors"
"fmt"
"os"
"os/exec"

"github.com/ava-labs/avalanche-cli/tests/e2e/utils"
)

// TestCase represents a single test case configuration
type TestCase struct {
Name string `json:"name"`
Flags map[string]string `json:"flags"`
Copy link
Collaborator

Choose a reason for hiding this comment

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

You also need non flag args here

ExpectedError string `json:"expectedError,omitempty"`
Copy link
Collaborator

Choose a reason for hiding this comment

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

Probably we can have an ExpectedOutput to use at not error cases

Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe a regex

}

// TestJSONConfig represents the json configuration that contains cli command flag inputs
type TestJSONConfig struct {
GlobalFlags map[string]interface{} `json:"globalFlags"`
Copy link
Collaborator

Choose a reason for hiding this comment

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

CommonFlags?

HappyPath []TestCase `json:"happyPath"`
NotHappyPath []TestCase `json:"notHappyPath"`
}

// CommandGroup represents the different command groups available in the CLI
type CommandGroup string

const (
BlockchainCmd CommandGroup = "blockchain"
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would rather add this constant on cmd/blockchaincmd/ and import that here

)

var avalancheBinaryPath = "./bin/avalanche"

// TestCommandWithJSONConfig tests a CLI command with flag inputs from a JSON file
func TestCommandWithJSONConfig(commandGroup CommandGroup, command string, args []string, configPath string, testCase *TestCase) (string, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice this is generic

Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe this should not take configPath as string and testCase as TestCase, it should either receive
one object with the full test spec, or be smart enough to gather all info from a json file

// Build command arguments
cmdArgs := []string{string(commandGroup), command}

// Read and parse the JSON config file
configData, err := os.ReadFile(configPath)
if err != nil {
return "", fmt.Errorf("failed to read config file: %w", err)
}

var config TestJSONConfig
if err := json.Unmarshal(configData, &config); err != nil {
return "", fmt.Errorf("failed to parse config file: %w", err)
}

// Append any additional arguments
if len(args) > 0 {
Copy link
Collaborator

Choose a reason for hiding this comment

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

this should belong to the test case

cmdArgs = append(cmdArgs, args...)
}

// Create a map to store all flags, starting with global flags
allFlags := make(map[string]interface{})
for flag, value := range config.GlobalFlags {
allFlags[flag] = value
}

// Override with test case specific flags if provided
if testCase != nil {
for flag, value := range testCase.Flags {
allFlags[flag] = value
}
}

// Add all flags to command arguments
for flag, value := range allFlags {
cmdArgs = append(cmdArgs, "--"+flag+"="+fmt.Sprintf("%v", value))
}

// Execute the command
cmd := exec.Command(avalancheBinaryPath, cmdArgs...)
fmt.Println(cmd)
output, err := cmd.CombinedOutput()
if err != nil {
var (
exitErr *exec.ExitError
stderr string
)
if errors.As(err, &exitErr) {
stderr = string(exitErr.Stderr)
}
fmt.Println(string(output))
utils.PrintStdErr(err)
fmt.Println(stderr)
return "", err
}

return string(output), nil
}

// ReadTestConfig reads and parses the test configuration from a JSON file
func ReadTestConfig(configPath string) (*TestJSONConfig, error) {
configData, err := os.ReadFile(configPath)
if err != nil {
return nil, fmt.Errorf("failed to read config file: %w", err)
}

var config TestJSONConfig
if err := json.Unmarshal(configData, &config); err != nil {
return nil, fmt.Errorf("failed to parse config file: %w", err)
}

return &config, nil
}
1 change: 1 addition & 0 deletions tests/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"testing"

"github.com/ava-labs/avalanche-cli/pkg/utils"
_ "github.com/ava-labs/avalanche-cli/tests/e2e/commandse2e/blockchain/deploy"
_ "github.com/ava-labs/avalanche-cli/tests/e2e/testcases/apm"
_ "github.com/ava-labs/avalanche-cli/tests/e2e/testcases/errhandling"
_ "github.com/ava-labs/avalanche-cli/tests/e2e/testcases/key"
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/testcases/errhandling/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ var _ = ginkgo.Describe("[Error handling]", func() {
ginkgo.Skip("run this manually only, times out")
// this will boot the subnet with a bad genesis:
// the root gas limit is smaller than the fee config gas limit, should fail
commands.CreateSubnetEvmConfigSOV(subnetName, utils.SubnetEvmGenesisBadPath)
commands.CreateSubnetEvmConfigSOVWithGenesisPath(subnetName, utils.SubnetEvmGenesisBadPath, commands.PoaValidatorManagerOwner)
out, err := commands.DeploySubnetLocallyWithArgsAndOutputSOV(subnetName, "", "")
gomega.Expect(err).Should(gomega.HaveOccurred())
gomega.Expect(out).Should(gomega.ContainSubstring("does not match gas limit"))
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/testcases/network/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ var _ = ginkgo.Describe("[Network]", ginkgo.Ordered, func() {
})

ginkgo.It("can stop and restart a deployed subnet SOV", func() {
commands.CreateSubnetEvmConfigSOV(subnetName, utils.SubnetEvmGenesisPoaPath)
commands.CreateSubnetEvmConfigSOVWithGenesisPath(subnetName, utils.SubnetEvmGenesisPoaPath, commands.PoaValidatorManagerOwner)
deployOutput := commands.DeploySubnetLocallySOV(subnetName)
rpcs, err := utils.ParseRPCsFromOutput(deployOutput)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/testcases/packageman/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ var _ = ginkgo.Describe("[Package Management]", ginkgo.Ordered, func() {
gomega.Expect(utils.CheckSubnetEVMExists(evmVersion)).Should(gomega.BeFalse())
gomega.Expect(utils.CheckAvalancheGoExists(avagoVersion)).Should(gomega.BeFalse())

commands.CreateSubnetEvmConfigWithVersionSOV(subnetName, utils.SubnetEvmGenesisPoaPath, evmVersion)
commands.CreateSubnetEvmConfigGenesisPathWithVersionSOV(subnetName, utils.SubnetEvmGenesisPoaPath, evmVersion, commands.PoaValidatorManagerOwner)
deployOutput := commands.DeploySubnetLocallyWithVersionSOV(subnetName, avagoVersion)
rpcs, err := utils.ParseRPCsFromOutput(deployOutput)
if err != nil {
Expand Down Expand Up @@ -214,7 +214,7 @@ var _ = ginkgo.Describe("[Package Management]", ginkgo.Ordered, func() {
gomega.Expect(utils.CheckAvalancheGoExists(avagoVersion1)).Should(gomega.BeFalse())
gomega.Expect(utils.CheckAvalancheGoExists(avagoVersion2)).Should(gomega.BeFalse())

commands.CreateSubnetEvmConfigWithVersionSOV(subnetName, utils.SubnetEvmGenesisPoaPath, evmVersion)
commands.CreateSubnetEvmConfigGenesisPathWithVersionSOV(subnetName, utils.SubnetEvmGenesisPoaPath, evmVersion, commands.PoaValidatorManagerOwner)
deployOutput := commands.DeploySubnetLocallyWithVersionSOV(subnetName, avagoVersion1)
rpcs, err := utils.ParseRPCsFromOutput(deployOutput)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ var (

var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoA]", func() {
ginkgo.It("Create Etna Subnet Config", func() {
_, avagoVersion = commands.CreateEtnaSubnetEvmConfig(
_, avagoVersion = commands.CreateSubnetEvmConfigSOV(
utils.SubnetName,
ewoqEVMAddress,
commands.PoA,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ var (

var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() {
ginkgo.It("Create Etna Subnet Config", func() {
_, avagoVersion = commands.CreateEtnaSubnetEvmConfig(
_, avagoVersion = commands.CreateSubnetEvmConfigSOV(
utils.SubnetName,
ewoqEVMAddress,
commands.PoS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var avagoVersion string

var _ = ginkgo.Describe("[Etna Add Validator SOV Local]", func() {
ginkgo.It("Create Etna Subnet Config", func() {
_, avagoVersion = commands.CreateEtnaSubnetEvmConfig(
_, avagoVersion = commands.CreateSubnetEvmConfigSOV(
utils.SubnetName,
ewoqEVMAddress,
commands.PoS,
Expand Down
Loading
Loading