-
Notifications
You must be signed in to change notification settings - Fork 117
Deploy flags e2e #2755
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
Deploy flags e2e #2755
Changes from 4 commits
afbba82
6a6fb04
7a7ec4f
f22428f
e491435
0c7e5df
f8f9225
b2f2222
a741643
47f4a46
12c704f
438fe47
abdc06a
23bb74c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| package blockchain | ||
|
|
||
| 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"` | ||
| ExpectedError string `json:"expectedError,omitempty"` | ||
| } | ||
|
|
||
| // TestJSONConfig represents the json configuration that contains cli command flag inputs | ||
| type TestJSONConfig struct { | ||
| GlobalFlags map[string]interface{} `json:"globalFlags"` | ||
| HappyPath []TestCase `json:"happyPath"` | ||
| NotHappyPath []TestCase `json:"notHappyPath"` | ||
| } | ||
|
|
||
| var avalancheBinaryPath = "./bin/avalanche" | ||
|
|
||
| // SetAvalancheBinaryPath sets the path to the avalanche binary | ||
| func SetAvalancheBinaryPath(path string) { | ||
| avalancheBinaryPath = path | ||
| } | ||
|
|
||
| // TestCommandWithJSONConfig tests a CLI command with flag inputs from a JSON file | ||
| func TestCommandWithJSONConfig(command string, configPath string, testCase *TestCase) (string, error) { | ||
|
||
| blockchainCmd := "blockchain" | ||
|
|
||
| // 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) | ||
| } | ||
|
|
||
| // Build command arguments | ||
| cmdArgs := []string{blockchainCmd, command} | ||
|
|
||
| // Add blockchain name from global flags | ||
| if blockchainName, ok := config.GlobalFlags["blockchainName"].(string); ok { | ||
| cmdArgs = append(cmdArgs, blockchainName) | ||
| } | ||
|
|
||
| // Create a map to store all flags, starting with global flags | ||
| allFlags := make(map[string]interface{}) | ||
| for flag, value := range config.GlobalFlags { | ||
| if flag != "blockchainName" { | ||
| 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 | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,7 +18,7 @@ import ( | |
|
|
||
| const ( | ||
| subnetEVMMainnetChainID = 11 | ||
| poaValidatorManagerOwner = "0x2e6FcBb9d4E17eC4cF67eddfa7D32eabC4cdCFc6" | ||
| PoaValidatorManagerOwner = "0x2e6FcBb9d4E17eC4cF67eddfa7D32eabC4cdCFc6" | ||
| bootstrapFilepathFlag = "--bootstrap-filepath" | ||
| avalancheGoPath = "--avalanchego-path" | ||
| localNodeClusterName = "testLocalNode" | ||
|
|
@@ -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 CreateSubnetEvmConfigSOV(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]) | ||
| CreateSubnetEvmConfigWithVersionSOV(subnetName, genesisPath, mapping[utils.LatestEVM2AvagoKey], validatorManagerOwner) | ||
| return mapping[utils.LatestEVM2AvagoKey], mapping[utils.LatestAvago2EVMKey] | ||
| } | ||
|
|
||
|
|
@@ -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 CreateSubnetEvmConfigWithVersionSOV(subnetName string, genesisPath string, version string, validatorManagerOwner string) { | ||
| // Check config does not already exist | ||
| exists, err := utils.SubnetConfigExists(subnetName) | ||
| gomega.Expect(err).Should(gomega.BeNil()) | ||
|
|
@@ -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", | ||
|
|
@@ -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()) | ||
|
|
@@ -236,9 +236,9 @@ func CreateCustomVMConfigSOV(subnetName string, genesisPath string, vmPath strin | |
| genesisPath, | ||
| "--proof-of-authority", | ||
| "--validator-manager-owner", | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| package blockchain | ||
|
|
||
| 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"` | ||
| ExpectedError string `json:"expectedError,omitempty"` | ||
| } | ||
|
|
||
| // TestJSONConfig represents the json configuration that contains cli command flag inputs | ||
| type TestJSONConfig struct { | ||
| GlobalFlags map[string]interface{} `json:"globalFlags"` | ||
| HappyPath []TestCase `json:"happyPath"` | ||
| NotHappyPath []TestCase `json:"notHappyPath"` | ||
| } | ||
|
|
||
| var avalancheBinaryPath = "./bin/avalanche" | ||
|
|
||
| // SetAvalancheBinaryPath sets the path to the avalanche binary | ||
| func SetAvalancheBinaryPath(path string) { | ||
| avalancheBinaryPath = path | ||
| } | ||
|
|
||
| // TestCommandWithJSONConfig tests a CLI command with flag inputs from a JSON file | ||
| func TestCommandWithJSONConfig(command string, configPath string, testCase *TestCase) (string, error) { | ||
| blockchainCmd := "blockchain" | ||
|
|
||
| // 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) | ||
| } | ||
|
|
||
| // Build command arguments | ||
| cmdArgs := []string{blockchainCmd, command} | ||
|
|
||
| // Add blockchain name from global flags | ||
| if blockchainName, ok := config.GlobalFlags["blockchainName"].(string); ok { | ||
| cmdArgs = append(cmdArgs, blockchainName) | ||
| } | ||
|
|
||
| // Create a map to store all flags, starting with global flags | ||
| allFlags := make(map[string]interface{}) | ||
| for flag, value := range config.GlobalFlags { | ||
| if flag != "blockchainName" { | ||
| 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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| { | ||
| "globalFlags": { | ||
| "local": true, | ||
| "skip-icm-deploy": true, | ||
| "skip-update-check": true, | ||
| "blockchainName": "testSubnet" | ||
| }, | ||
| "happyPath": [ | ||
| { | ||
| "name": "local_deploy", | ||
| "flags": {} | ||
| } | ||
|
||
| ], | ||
| "notHappyPath": [ | ||
| { | ||
| "name": "invalid_version", | ||
| "flags": { | ||
| "avalanchego-version": "invalid_version" | ||
| }, | ||
| "expectedError": "invalid version string" | ||
| } | ||
| ] | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| // 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/commands" | ||
| "github.com/ava-labs/avalanche-cli/tests/e2e/commands_e2e/blockchain" | ||
| "github.com/ava-labs/avalanche-cli/tests/e2e/utils" | ||
| ginkgo "github.com/onsi/ginkgo/v2" | ||
| "github.com/onsi/gomega" | ||
| ) | ||
|
|
||
| const ( | ||
| deployTestJSONPath = "tests/e2e/commands_e2e/blockchain/deploy/deploy_tests.json" | ||
| subnetName = "testSubnet" | ||
| ) | ||
|
|
||
| var ( | ||
| config *blockchain.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, utils.SubnetEvmGenesisPath, ewoqEVMAddress) | ||
|
||
|
|
||
| // Read test configuration | ||
| config, err = blockchain.ReadTestConfig(deployTestJSONPath) | ||
| gomega.Expect(err).Should(gomega.BeNil()) | ||
| }) | ||
|
|
||
| ginkgo.AfterEach(func() { | ||
| commands.CleanNetwork() | ||
| // Cleanup test subnet config | ||
| commands.DeleteSubnetConfig(subnetName) | ||
| }) | ||
|
|
||
| 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 = blockchain.TestCommandWithJSONConfig( | ||
| "deploy", | ||
| deployTestJSONPath, | ||
| &testCase, | ||
| ) | ||
| gomega.Expect(err).Should(gomega.BeNil()) | ||
| } | ||
| }) | ||
|
|
||
| ginkgo.It("should handle invalid configurations", func() { | ||
| // Run each not happy path test case | ||
| for _, testCase := range config.NotHappyPath { | ||
| ginkgo.By(fmt.Sprintf("Running test case: %s", testCase.Name)) | ||
| _, err = blockchain.TestCommandWithJSONConfig( | ||
| "deploy", | ||
| deployTestJSONPath, | ||
| &testCase, | ||
| ) | ||
| gomega.Expect(err).Should(gomega.HaveOccurred()) | ||
| } | ||
| }) | ||
| }) | ||
There was a problem hiding this comment.
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