Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 9 additions & 1 deletion .github/workflows/test.upgrade.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,12 @@ jobs:
run: ./scripts/build.sh
- name: Run upgrade tests
shell: bash
run: scripts/tests.upgrade.sh 1.10.1 ./build/avalanchego
# 1.10.7 is the first version compatible with the testnet fixture by
# virtue of writing a process context file on node start.
run: ./scripts/tests.upgrade.sh 1.10.7
- name: Upload testnet network dir
uses: actions/upload-artifact@v3
if: always()
with:
name: testnet-data
path: ~/.testnetctl/networks/1000
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ require (
github.com/DataDog/zstd v1.5.2
github.com/Microsoft/go-winio v0.5.2
github.com/NYTimes/gziphandler v1.1.1
github.com/ava-labs/avalanche-network-runner-sdk v0.3.0
github.com/ava-labs/coreth v0.12.5-rc.6
github.com/ava-labs/ledger-avalanche/go v0.0.0-20230105152938-00a24d05a8c7
github.com/btcsuite/btcd/btcutil v1.1.3
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/ava-labs/avalanche-network-runner-sdk v0.3.0 h1:TVi9JEdKNU/RevYZ9PyW4pULbEdS+KQDA9Ki2DUvuAs=
github.com/ava-labs/avalanche-network-runner-sdk v0.3.0/go.mod h1:SgKJvtqvgo/Bl/c8fxEHCLaSxEbzimYfBopcfrajxQk=
github.com/ava-labs/coreth v0.12.5-rc.6 h1:OajGUyKkO5Q82XSuMa8T5UD6QywtCHUiZ4Tv3RFmRBU=
github.com/ava-labs/coreth v0.12.5-rc.6/go.mod h1:s5wVyy+5UCCk2m0Tq3jVmy0UqOpKBDYqRE13gInCJVs=
github.com/ava-labs/ledger-avalanche/go v0.0.0-20230105152938-00a24d05a8c7 h1:EdxD90j5sClfL5Ngpz2TlnbnkNYdFPDXa0jDOjam65c=
Expand Down
34 changes: 0 additions & 34 deletions scripts/install_anr.sh

This file was deleted.

49 changes: 7 additions & 42 deletions scripts/tests.upgrade.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
set -euo pipefail

# e.g.,
# ./scripts/build.sh
# ./scripts/tests.upgrade.sh 1.7.16 ./build/avalanchego
# ./scripts/tests.upgrade.sh 1.7.16
# AVALANCHEGO_PATH=./path/to/avalanchego ./scripts/tests.upgrade.sh 1.7.16 # Customization of avalanchego path
if ! [[ "$0" =~ scripts/tests.upgrade.sh ]]; then
echo "must be run from repository root"
exit 255
Expand All @@ -13,16 +13,11 @@ fi
VERSION="${1:-}"
if [[ -z "${VERSION}" ]]; then
echo "Missing version argument!"
echo "Usage: ${0} [VERSION] [NEW-BINARY]" >>/dev/stderr
echo "Usage: ${0} [VERSION]" >>/dev/stderr
exit 255
fi

NEW_BINARY="${2:-}"
if [[ -z "${NEW_BINARY}" ]]; then
echo "Missing new binary path argument!"
echo "Usage: ${0} [VERSION] [NEW-BINARY]" >>/dev/stderr
exit 255
fi
AVALANCHEGO_PATH="$(realpath ${AVALANCHEGO_PATH:-./build/avalanchego})"

#################################
# download avalanchego
Expand Down Expand Up @@ -52,11 +47,6 @@ elif [[ ${GOOS} == "darwin" ]]; then
fi
find /tmp/avalanchego-v${VERSION}

#################################
echo "installing avalanche-network-runner"
ANR_WORKDIR="/tmp"
./scripts/install_anr.sh

# Sourcing constants.sh ensures that the necessary CGO flags are set to
# build the portable version of BLST. Without this, ginkgo may fail to
# build the test binary if run on a host (e.g. github worker) that lacks
Expand All @@ -70,35 +60,10 @@ go install -v github.com/onsi/ginkgo/v2/ginkgo@v2.1.4
ACK_GINKGO_RC=true ginkgo build ./tests/upgrade
./tests/upgrade/upgrade.test --help

#################################
# run "avalanche-network-runner" server
echo "launch avalanche-network-runner in the background"
$ANR_WORKDIR/avalanche-network-runner \
server \
--log-level debug \
--port=":12340" \
--disable-grpc-gateway &
PID=${!}

#################################
# By default, it runs all upgrade test cases!
echo "running upgrade tests against the local cluster with ${NEW_BINARY}"
echo "running upgrade tests against the local cluster with ${AVALANCHEGO_PATH}"
./tests/upgrade/upgrade.test \
--ginkgo.v \
--log-level debug \
--network-runner-grpc-endpoint="0.0.0.0:12340" \
--network-runner-avalanchego-path=/tmp/avalanchego-v${VERSION}/avalanchego \
--network-runner-avalanchego-path-to-upgrade=${NEW_BINARY} \
--network-runner-avalanchego-log-level="WARN" || EXIT_CODE=$?

# "e2e.test" already terminates the cluster
# just in case tests are aborted, manually terminate them again
pkill -P ${PID} || true
kill -2 ${PID}

if [[ "${EXIT_CODE:-}" -gt 0 ]]; then
echo "FAILURE with exit code ${EXIT_CODE}"
exit ${EXIT_CODE}
else
echo "ALL SUCCESS!"
fi
--avalanchego-path=/tmp/avalanchego-v${VERSION}/avalanchego \
--avalanchego-path-to-upgrade-to=${AVALANCHEGO_PATH}
4 changes: 1 addition & 3 deletions tests/e2e/e2e.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,7 @@ func AddEphemeralNode(network testnet.Network, flags testnet.FlagsMap) testnet.N

// Wait for the given node to report healthy.
func WaitForHealthy(node testnet.Node) {
ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
defer cancel()
require.NoError(ginkgo.GinkgoT(), testnet.WaitForHealthy(ctx, node))
require.NoError(ginkgo.GinkgoT(), testnet.WaitForHealthy(DefaultContext(), node))
}

// Sends an eth transaction, waits for the transaction receipt to be issued
Expand Down
31 changes: 20 additions & 11 deletions tests/fixture/testnet/local/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -658,20 +658,33 @@ func (ln *LocalNetwork) AddLocalNode(w io.Writer, node *LocalNode, isEphemeral b
return nil, err
}

// Collect staking addresses of running nodes for use in bootstraping the new node
if err := ln.ReadNodes(); err != nil {
return nil, fmt.Errorf("failed to read local network nodes: %w", err)
bootstrapIPs, bootstrapIDs, err := ln.GetBootstrapIPsAndIDs()
if err != nil {
return nil, err
}

var (
// Use dynamic port allocation.
httpPort uint16 = 0
stakingPort uint16 = 0
)
node.SetNetworkingConfigDefaults(httpPort, stakingPort, bootstrapIDs, bootstrapIPs)

if err := node.WriteConfig(); err != nil {
return nil, err
}
return node, node.Start(w, ln.ExecPath)
}

func (ln *LocalNetwork) GetBootstrapIPsAndIDs() ([]string, []string, error) {
// Collect staking addresses of running nodes for use in bootstrapping a node
if err := ln.ReadNodes(); err != nil {
return nil, nil, fmt.Errorf("failed to read local network nodes: %w", err)
}
var (
bootstrapIPs = make([]string, 0, len(ln.Nodes))
bootstrapIDs = make([]string, 0, len(ln.Nodes))
)

for _, node := range ln.Nodes {
if len(node.StakingAddress) == 0 {
// Node is not running
Expand All @@ -681,14 +694,10 @@ func (ln *LocalNetwork) AddLocalNode(w io.Writer, node *LocalNode, isEphemeral b
bootstrapIPs = append(bootstrapIPs, node.StakingAddress)
bootstrapIDs = append(bootstrapIDs, node.NodeID.String())
}

if len(bootstrapIDs) == 0 {
return nil, errMissingBootstrapNodes
return nil, nil, errMissingBootstrapNodes
}

node.SetNetworkingConfigDefaults(httpPort, stakingPort, bootstrapIDs, bootstrapIPs)

if err := node.WriteConfig(); err != nil {
return nil, err
}
return node, node.Start(w, ln.ExecPath)
return bootstrapIPs, bootstrapIDs, nil
}
147 changes: 42 additions & 105 deletions tests/upgrade/upgrade_test.go
Original file line number Diff line number Diff line change
@@ -1,143 +1,80 @@
// Copyright (C) 2019-2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

// Runs upgrade tests.
package upgrade_test
package upgrade

import (
"context"
"flag"
"fmt"
"os"
"strings"
"testing"
"time"

"github.com/onsi/ginkgo/v2"

"github.com/onsi/gomega"

runner_sdk "github.com/ava-labs/avalanche-network-runner-sdk"
"github.com/stretchr/testify/require"

"github.com/ava-labs/avalanchego/tests"
"github.com/ava-labs/avalanchego/config"
"github.com/ava-labs/avalanchego/tests/e2e"
)

const DefaultTimeout = 2 * time.Minute

func TestUpgrade(t *testing.T) {
gomega.RegisterFailHandler(ginkgo.Fail)
ginkgo.RunSpecs(t, "upgrade test suites")
}

var (
logLevel string
networkRunnerGRPCEp string
networkRunnerAvalancheGoExecPath string
networkRunnerAvalancheGoExecPathToUpgrade string
networkRunnerAvalancheGoLogLevel string
avalancheGoExecPath string
avalancheGoExecPathToUpgradeTo string
)

func init() {
flag.StringVar(
&logLevel,
"log-level",
"info",
"log level",
)
flag.StringVar(
&networkRunnerGRPCEp,
"network-runner-grpc-endpoint",
"",
"gRPC server endpoint for network-runner",
)
flag.StringVar(
&networkRunnerAvalancheGoExecPath,
"network-runner-avalanchego-path",
&avalancheGoExecPath,
"avalanchego-path",
"",
"avalanchego executable path",
)
flag.StringVar(
&networkRunnerAvalancheGoExecPathToUpgrade,
"network-runner-avalanchego-path-to-upgrade",
&avalancheGoExecPathToUpgradeTo,
"avalanchego-path-to-upgrade-to",
"",
"avalanchego executable path (to upgrade to, only required for upgrade tests with local network-runner)",
)
flag.StringVar(
&networkRunnerAvalancheGoLogLevel,
"network-runner-avalanchego-log-level",
"INFO",
"avalanchego log-level",
"avalanchego executable path to upgrade to",
)
}

var runnerCli runner_sdk.Client

var _ = ginkgo.BeforeSuite(func() {
_, err := os.Stat(networkRunnerAvalancheGoExecPath)
gomega.Expect(err).Should(gomega.BeNil())

_, err = os.Stat(networkRunnerAvalancheGoExecPathToUpgrade)
gomega.Expect(err).Should(gomega.BeNil())

runnerCli, err = runner_sdk.New(runner_sdk.Config{
LogLevel: logLevel,
Endpoint: networkRunnerGRPCEp,
DialTimeout: 10 * time.Second,
})
gomega.Expect(err).Should(gomega.BeNil())

ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
presp, err := runnerCli.Ping(ctx)
cancel()
gomega.Expect(err).Should(gomega.BeNil())
tests.Outf("{{green}}network-runner running in PID %d{{/}}\n", presp.Pid)

tests.Outf("{{magenta}}starting network-runner with %q{{/}}\n", networkRunnerAvalancheGoExecPath)
ctx, cancel = context.WithTimeout(context.Background(), DefaultTimeout)
resp, err := runnerCli.Start(ctx, networkRunnerAvalancheGoExecPath,
runner_sdk.WithNumNodes(5),
runner_sdk.WithGlobalNodeConfig(fmt.Sprintf(`{"log-level":"%s"}`, networkRunnerAvalancheGoLogLevel)),
)
cancel()
gomega.Expect(err).Should(gomega.BeNil())
tests.Outf("{{green}}successfully started network-runner: {{/}} %+v\n", resp.ClusterInfo.NodeNames)

ctx, cancel = context.WithTimeout(context.Background(), DefaultTimeout)
_, err = runnerCli.Health(ctx)
cancel()
gomega.Expect(err).Should(gomega.BeNil())
})

var _ = ginkgo.AfterSuite(func() {
tests.Outf("{{red}}shutting down network-runner cluster{{/}}\n")
ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
_, err := runnerCli.Stop(ctx)
cancel()
gomega.Expect(err).Should(gomega.BeNil())

tests.Outf("{{red}}shutting down network-runner client{{/}}\n")
err = runnerCli.Close()
gomega.Expect(err).Should(gomega.BeNil())
})

var _ = ginkgo.Describe("[Upgrade]", func() {
require := require.New(ginkgo.GinkgoT())

ginkgo.It("can upgrade versions", func() {
tests.Outf("{{magenta}}starting upgrade tests %q{{/}}\n", networkRunnerAvalancheGoExecPathToUpgrade)
ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
sresp, err := runnerCli.Status(ctx)
cancel()
gomega.Expect(err).Should(gomega.BeNil())

for _, name := range sresp.ClusterInfo.NodeNames {
tests.Outf("{{magenta}}restarting the node %q{{/}} with %q\n", name, networkRunnerAvalancheGoExecPathToUpgrade)
ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
resp, err := runnerCli.RestartNode(ctx, name, runner_sdk.WithExecPath(networkRunnerAvalancheGoExecPathToUpgrade))
cancel()
gomega.Expect(err).Should(gomega.BeNil())

ctx, cancel = context.WithTimeout(context.Background(), DefaultTimeout)
_, err = runnerCli.Health(ctx)
cancel()
gomega.Expect(err).Should(gomega.BeNil())
tests.Outf("{{green}}successfully upgraded %q to %q{{/}} (current info: %+v)\n", name, networkRunnerAvalancheGoExecPathToUpgrade, resp.ClusterInfo.NodeInfos)
// TODO(marun) How many nodes should the target network have to best validate upgrade?
network := e2e.StartLocalNetwork(avalancheGoExecPath, e2e.DefaultNetworkDir)

ginkgo.By(fmt.Sprintf("restarting all nodes with %q binary", avalancheGoExecPathToUpgradeTo))
for _, node := range network.Nodes {
ginkgo.By(fmt.Sprintf("restarting node %q with %q binary", node.GetID(), avalancheGoExecPathToUpgradeTo))
require.NoError(node.Stop())

// A node must start with sufficient bootstrap nodes to represent a quorum. Since the node's current
// bootstrap configuration may not satisfy this requirement (i.e. if on network start the node was one of
// the first validators), updating the node to bootstrap from all running validators maximizes the
// chances of a successful start.
//
// TODO(marun) Refactor node start to do this automatically
bootstrapIPs, bootstrapIDs, err := network.GetBootstrapIPsAndIDs()
require.NoError(err)
require.NotEmpty(bootstrapIDs)
node.Flags[config.BootstrapIDsKey] = strings.Join(bootstrapIDs, ",")
node.Flags[config.BootstrapIPsKey] = strings.Join(bootstrapIPs, ",")
require.NoError(node.WriteConfig())

require.NoError(node.Start(ginkgo.GinkgoWriter, avalancheGoExecPath))

ginkgo.By(fmt.Sprintf("waiting for node %q to report healthy after restart", node.GetID()))
e2e.WaitForHealthy(node)
}

e2e.CheckBootstrapIsPossible(network)
})
})