Skip to content
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

[testing] Add av command to simplify cross-repo tool maintenance #3619

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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
8 changes: 8 additions & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# TODO(marun) Document usage of direnv

# contains manually-installed tooling
PATH_add bin
# contains avalanchego and xsvm binaries
PATH_add build
# contains tool wrappers
PATH_add tools
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,5 @@ tests/upgrade/upgrade.test
vendor

**/testdata

.tool-downloads
12 changes: 3 additions & 9 deletions scripts/tests.e2e.bootstrap_monitor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ function ensure_command {
fi
}

# Ensure the kubectl command is available
KUBECTL_VERSION=v1.30.2
ensure_command kubectl "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/${OS}/${ARCH}/kubectl"

# Ensure the kind command is available
KIND_VERSION=v0.23.0
ensure_command kind "https://kind.sigs.k8s.io/dl/${KIND_VERSION}/kind-${OS}-${ARCH}"
Expand All @@ -61,9 +57,7 @@ ensure_command "kind-with-registry.sh" "https://raw.githubusercontent.com/kubern
# Deploy a kind cluster with a local registry. Include the local bin in the path to
# ensure locally installed kind and kubectl are available since the script expects to
# call them without a qualifying path.
PATH="${PWD}/bin:$PATH" bash -x "${PWD}/bin/kind-with-registry.sh"

# TODO(marun) Factor out ginkgo installation to avoid duplicating it across test scripts
go install -v github.com/onsi/ginkgo/v2/[email protected]
PATH="${PWD}/tools:${PWD}/bin:$PATH" bash -x "${PWD}/bin/kind-with-registry.sh"

KUBECONFIG="$HOME/.kube/config" PATH="${PWD}/bin:$PATH" ginkgo -v ./tests/fixture/bootstrapmonitor/e2e
KUBECONFIG="$HOME/.kube/config" PATH="${PWD}/bin:$PATH" \
./tools/ginkgo -v ./tests/fixture/bootstrapmonitor/e2e
2 changes: 1 addition & 1 deletion scripts/tests.e2e.existing.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function print_separator {
function cleanup {
print_separator
echo "cleaning up reusable network"
ginkgo -v ./tests/e2e/e2e.test -- --stop-network
./tools/ginkgo -v ./tests/e2e -- --stop-network
}
trap cleanup EXIT

Expand Down
17 changes: 5 additions & 12 deletions scripts/tests.e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,6 @@ fi
# the instructions to build non-portable BLST.
source ./scripts/constants.sh

#################################
echo "building e2e.test"
# to install the ginkgo binary (required for test build and run)
go install -v github.com/onsi/ginkgo/v2/[email protected]
ACK_GINKGO_RC=true ginkgo build ./tests/e2e
./tests/e2e/e2e.test --help

# Enable subnet testing by building xsvm
./scripts/build_xsvm.sh
echo ""
Expand All @@ -38,7 +31,7 @@ E2E_ARGS="--avalanchego-path=${AVALANCHEGO_PATH}"

#################################
# Determine ginkgo args
GINKGO_ARGS=""
GINKGO_ARGS="--ginkgo.v"
if [[ -n "${E2E_SERIAL:-}" ]]; then
# Specs will be executed serially. This supports running e2e tests in CI
# where parallel execution of tests that start new nodes beyond the
Expand All @@ -53,17 +46,17 @@ else
# since the test binary isn't capable of executing specs in
# parallel.
echo "tests will be executed in parallel"
GINKGO_ARGS="-p"
GINKGO_ARGS=+" --ginkgo.p"
fi
# Reference: https://onsi.github.io/ginkgo/#spec-randomization
if [[ -n "${E2E_RANDOM_SEED:-}" ]]; then
# Supply a specific seed to simplify reproduction of test failures
GINKGO_ARGS+=" --seed=${E2E_RANDOM_SEED}"
GINKGO_ARGS+=" --ginkgo.seed=${E2E_RANDOM_SEED}"
else
# Execute in random order to identify unwanted dependency
GINKGO_ARGS+=" --randomize-all"
GINKGO_ARGS+=" --ginkgo.randomize-all"
fi

#################################
# shellcheck disable=SC2086
ginkgo ${GINKGO_ARGS} -v ./tests/e2e/e2e.test -- "${E2E_ARGS[@]}" "${@}"
./tools/ginkgo ./tests/e2e -- ${GINKGO_ARGS} "${E2E_ARGS[@]}" "${@}"
10 changes: 1 addition & 9 deletions scripts/tests.upgrade.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,9 @@ find "/tmp/avalanchego-v${VERSION}"
# the instructions to build non-portable BLST.
source ./scripts/constants.sh

#################################
echo "building upgrade.test"
# to install the ginkgo binary (required for test build and run)
go install -v github.com/onsi/ginkgo/v2/[email protected]
ACK_GINKGO_RC=true ginkgo build ./tests/upgrade
./tests/upgrade/upgrade.test --help

#################################
# By default, it runs all upgrade test cases!
echo "running upgrade tests against the local cluster with ${AVALANCHEGO_PATH}"
./tests/upgrade/upgrade.test \
--ginkgo.v \
./tools/ginkgo -v ./tests/upgrade -- \
--avalanchego-path="/tmp/avalanchego-v${VERSION}/avalanchego" \
--avalanchego-path-to-upgrade-to="${AVALANCHEGO_PATH}"
172 changes: 172 additions & 0 deletions tests/av/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package main

import (
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"

"github.com/spf13/cobra"
"go.uber.org/zap"

"github.com/ava-labs/avalanchego/tests"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/perms"
)

const (
cmdName = "av"
kubectlVersion = "v1.30.2"
)

func main() {
var rawLogFormat string
rootCmd := &cobra.Command{
Use: cmdName,
Short: cmdName + " commands",
}
rootCmd.PersistentFlags().StringVar(&rawLogFormat, "log-format", logging.AutoString, logging.FormatDescription)

toolCmd := &cobra.Command{
Use: "tool",
Short: "configured cli tools",
RunE: func(*cobra.Command, []string) error {
return fmt.Errorf("please specify a valid tool name")

Check failure on line 38 in tests/av/cmd/main.go

View workflow job for this annotation

GitHub Actions / Lint

string-format: no format directive, use errors.New instead (revive)

Check failure on line 38 in tests/av/cmd/main.go

View workflow job for this annotation

GitHub Actions / Lint

fmt.Errorf can be replaced with errors.New (perfsprint)
},
}
rootCmd.AddCommand(toolCmd)

ginkgoCmd := &cobra.Command{
Use: "ginkgo",
Short: "cli for building and running e2e tests",
RunE: func(c *cobra.Command, args []string) error {
cmdArgs := []string{
"run",
"github.com/onsi/ginkgo/v2/ginkgo",
}
cmdArgs = append(cmdArgs, args...)
cmd := exec.Command("go", cmdArgs...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
c.SilenceUsage = true
c.SilenceErrors = true
// TODO(marun) Suppress the duplicated 'exit status X'
// caused by passing through the exit code from the
// `go run` subcommand
return cmd.Run()
},
}
toolCmd.AddCommand(ginkgoCmd)

tmpnetctlCmd := &cobra.Command{
Use: "tmpnetctl",
Short: "cli for managing temporary networks",
RunE: func(c *cobra.Command, args []string) error {
cmdArgs := []string{
"run",
"github.com/ava-labs/avalanchego/tests/fixture/tmpnet/cmd",
}
cmdArgs = append(cmdArgs, args...)
cmd := exec.Command("go", cmdArgs...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
c.SilenceUsage = true
c.SilenceErrors = true
// TODO(marun) Suppress the duplicated 'exit status X'
// caused by passing through the exit code from the
// `go run` subcommand
return cmd.Run()
},
}
toolCmd.AddCommand(tmpnetctlCmd)

kubectlCmd := &cobra.Command{
Use: "kubectl",
Short: "cli for interacting with a kubernetes cluster",
RunE: func(c *cobra.Command, args []string) error {
log, err := tests.LoggerForFormat("", rawLogFormat)
if err != nil {
return err
}

downloadDir, err := filepath.Abs(".tool-downloads")
if err != nil {
return err
}

// Ensure the download directory exists
if info, err := os.Stat(downloadDir); errors.Is(err, os.ErrNotExist) {
log.Info("creating tool download directory",
zap.String("dir", downloadDir),
)
if err := os.MkdirAll(downloadDir, perms.ReadWriteExecute); err != nil {
return err
}
} else if err != nil {
return err
} else if !info.IsDir() {
return fmt.Errorf("download path is not a directory: %s", downloadDir)
}

var (
kubectlPath = downloadDir + "/kubectl-" + kubectlVersion
// TODO(marun) Make these dynamic
kubeOS = "linux"
kubeArch = "arm64"
)

if _, err := os.Stat(downloadDir); errors.Is(err, os.ErrNotExist) {
// TODO(marun) Maybe use a library to download the binary?
curlArgs := []string{
"curl -L -o " + kubectlPath + " https://dl.k8s.io/release/" + kubectlVersion + "/bin/" + kubeOS + "/" + kubeArch + "/kubectl",
}
log.Info("downloading kubectl with curl",
zap.Strings("curlArgs", curlArgs),
)
// Run in a subshell to ensure -L redirects work
curl := exec.Command("bash", append([]string{"-x", "-c"}, curlArgs...)...)

Check failure on line 133 in tests/av/cmd/main.go

View workflow job for this annotation

GitHub Actions / Lint

G204: Subprocess launched with a potential tainted input or cmd arguments (gosec)
curl.Stdin = os.Stdin
curl.Stdout = os.Stdout
curl.Stderr = os.Stderr
c.SilenceUsage = true
c.SilenceErrors = true
err = curl.Run()
if err != nil {
return err
}

if err := os.Chmod(kubectlPath, perms.ReadWriteExecute); err != nil {
return err
}

log.Info("running kubectl for the first time",
zap.String("path", kubectlPath),
)
}

kubectl := exec.Command(kubectlPath, args...)
kubectl.Stdin = os.Stdin
kubectl.Stdout = os.Stdout
kubectl.Stderr = os.Stderr
c.SilenceUsage = true
c.SilenceErrors = true
return kubectl.Run()
},
}
toolCmd.AddCommand(kubectlCmd)

if err := rootCmd.Execute(); err != nil {
var exitCode int = 1

Check failure on line 165 in tests/av/cmd/main.go

View workflow job for this annotation

GitHub Actions / Lint

ST1023: should omit type int from declaration; it will be inferred from the right-hand side (stylecheck)
if exitError, ok := err.(*exec.ExitError); ok {
exitCode = exitError.ExitCode()
}
os.Exit(exitCode)
}
os.Exit(0)
}
26 changes: 9 additions & 17 deletions tests/e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@
## Running tests

```bash
go install -v github.com/onsi/ginkgo/v2/[email protected]
ACK_GINKGO_RC=true ginkgo build ./tests/e2e
./tests/e2e/e2e.test --help

./tests/e2e/e2e.test \
--avalanchego-path=./build/avalanchego
./scripts/build.sh # Builds avalanchego for use in deploying a test network
./scripts/build_xsvm.sh # Builds xsvm for use in deploying a test network with a subnet
./tools/ginkgo ./tests/e2e -- --ginkgo.v --avalanchego-path=./build/avalanchego
```

See [`tests.e2e.sh`](../../scripts/tests.e2e.sh) for an example.
Expand All @@ -27,9 +24,7 @@ primarily target the X-Chain:


```bash
./tests/e2e/e2e.test \
--avalanchego-path=./build/avalanchego \
--ginkgo.label-filter=x
./tools/ginkgo ./tests/e2e -- --ginkgo.v --ginkgo.label-filter=x --avalanchego-path=./build/avalanchego
```

The ginkgo docs provide further detail on [how to compose label
Expand All @@ -45,17 +40,14 @@ Create a new package to implement feature-specific tests, or add tests to an exi
tests
└── e2e
├── README.md
├── e2e.go
├── e2e_test.go
└── x
└── transfer.go
└── virtuous.go
```

`e2e.go` defines common configuration for other test
packages. `x/transfer/virtuous.go` defines X-Chain transfer tests,
labeled with `x`, which can be selected by `./tests/e2e/e2e.test
--ginkgo.label-filter "x"`.
`x/transfer/virtuous.go` defines X-Chain transfer tests,
labeled with `x`, which can be selected by `--label-filter=x`.

## Reusing temporary networks

Expand All @@ -70,7 +62,7 @@ To enable network reuse across test runs, pass `--reuse-network` as an
argument to the test suite:

```bash
ginkgo -v ./tests/e2e -- --avalanchego-path=/path/to/avalanchego --reuse-network
./scripts/gingko.sh -v ./tests/e2e -- --avalanchego-path=/path/to/avalanchego --reuse-network
```

If a network is not already running the first time the suite runs with
Expand All @@ -93,7 +85,7 @@ To stop a network configured for reuse, invoke the test suite with the
immediately without executing any tests:

```bash
ginkgo -v ./tests/e2e -- --stop-network
./scripts/gingko.sh -v ./tests/e2e -- --stop-network
```

## Skipping bootstrap checks
Expand All @@ -105,5 +97,5 @@ these bootstrap checks during development, set the
`E2E_SKIP_BOOTSTRAP_CHECKS` env var to a non-empty value:

```bash
E2E_SKIP_BOOTSTRAP_CHECKS=1 ginkgo -v ./tests/e2e ...
E2E_SKIP_BOOTSTRAP_CHECKS=1 ./tools/ginkgo ./tests/e2e ...
```
17 changes: 17 additions & 0 deletions tools/av
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env bash

set -euo pipefail

AVALANCHE_PATH=$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd .. && pwd )
cd ${AVALANCHE_PATH}

# Set the CGO flags to use the portable version of BLST
#
# We use "export" here instead of just setting a bash variable because we need
# to pass this flag to all child processes spawned by the shell.
export CGO_CFLAGS="-O2 -D__BLST_PORTABLE__"
# While CGO_ENABLED doesn't need to be explicitly set, it produces a much more
# clear error due to the default value change in go1.20.
export CGO_ENABLED=1

go run ./tests/av/cmd "${@}"
6 changes: 6 additions & 0 deletions tools/ginkgo
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash

set -euo pipefail

TOOLS_DIR="$( dirname "${BASH_SOURCE[0]}" )"
${TOOLS_DIR}/av tool ginkgo "$@"
6 changes: 6 additions & 0 deletions tools/kubectl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash

set -euo pipefail

TOOLS_DIR="$( dirname "${BASH_SOURCE[0]}" )"
${TOOLS_DIR}/av tool kubectl "$@"
6 changes: 6 additions & 0 deletions tools/tmpnetctl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash

set -euo pipefail

TOOLS_DIR="$( dirname "${BASH_SOURCE[0]}" )"
${TOOLS_DIR}/av tool tmpnetctl "$@"
Loading