feat: starship e2e tests and devnet integration (#17077)

This commit is contained in:
Anmol 2023-08-10 19:29:36 +05:30 committed by GitHub
parent 48d79ff9d5
commit c3c82e27d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 2830 additions and 1 deletions

92
.github/workflows/starship-tests.yml vendored Normal file
View File

@ -0,0 +1,92 @@
name: Starship E2E Tests
# E2E tests using Starship, run on a schedule
on:
schedule:
- cron: "0 */6 * * *" # every 6 hours
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}-starship-tests
cancel-in-progress: true
jobs:
e2e-test:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: "1.20"
check-latest: true
# Starship Infra setup
# - Connects to k8s cluster with kubeconfig (digital ocean)
# - Creates a new namespace based on the name (deleted in next step)
# - Spins up the infra with the given config file
# - Waits till all nodes are running (timeout 30m)
# - Port forward all ports to localhost for next steps to connect
- name: Setup Test infra
id: starship-action
uses: cosmology-tech/starship-action@0.2.13
with:
values: tests/starship/configs/ci.yaml
port-forward: true
version: 0.1.42
- name: Run Tests
run: |
cd tests/starship/
make test
# Starship resource cleanup on cluster
- name: Cleanup cluster
if: always()
run: |
helm delete $DEVNET_NAME --debug --namespace $DEVNET_NAMESPACE --wait || true
kubectl delete namespace $DEVNET_NAMESPACE --wait=true || true
env:
DEVNET_NAME: ${{ steps.starship-action.outputs.name }}
DEVNET_NAMESPACE: ${{ steps.starship-action.outputs.namespace }}
sims-notify-success:
needs: [ e2e-test ]
runs-on: ubuntu-latest
if: ${{ success() }}
steps:
- name: Check out repository
uses: actions/checkout@v3
- name: Get previous workflow status
uses: ./.github/actions/last-workflow-status
id: last_status
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Notify Slack on success
if: ${{ steps.last_status.outputs.last_status == 'failure' }}
uses: rtCamp/action-slack-notify@v2.2.0
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: sdk-sims
SLACK_USERNAME: Sim Tests
SLACK_ICON_EMOJI: ":white_check_mark:"
SLACK_COLOR: good
SLACK_MESSAGE: Starship tests are passing
SLACK_FOOTER: ""
sims-notify-failure:
permissions:
contents: none
needs: [ e2e-test ]
runs-on: ubuntu-latest
if: ${{ failure() }}
steps:
- name: Notify Slack on failure
uses: rtCamp/action-slack-notify@v2.2.0
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: sdk-sims
SLACK_USERNAME: Sim Tests
SLACK_ICON_EMOJI: ":skull:"
SLACK_COLOR: danger
SLACK_MESSAGE: Starship tests are failing
SLACK_FOOTER: ""

View File

@ -9,7 +9,7 @@ CWD=$(pwd)
find . -type f -name 'go.mod' -print0 | while IFS= read -r -d '' file
do
d=$(dirname "$file")
if [[ "$d" =~ \./simapp$|\./tests$ ]]; then
if [[ "$d" =~ \./simapp$|\./tests* ]]; then
continue
fi

78
tests/starship/Makefile Normal file
View File

@ -0,0 +1,78 @@
NAME = cosmos-simapp-multi
FILE = configs/local.yaml
HELM_REPO = starship
HELM_CHART = devnet
HELM_VERSION = v0.1.42
###############################################################################
### All commands ###
###############################################################################
.PHONY: setup
setup: setup-deps setup-helm
.PHONY: stop
stop: stop-forward delete
.PHONY: clean
clean: stop clean-kind
###############################################################################
### Tests ###
###############################################################################
.PHONY: test
test:
cd tests/ && go test -count=1 -v -race ./...
###############################################################################
### Dependency check ###
###############################################################################
.PHONY: check
setup-deps:
bash $(CURDIR)/scripts/dev-setup.sh
###############################################################################
### Helm Charts ###
###############################################################################
setup-helm:
helm repo add $(HELM_REPO) https://cosmology-tech.github.io/starship/
helm repo update
helm search repo $(HELM_REPO)/$(HELM_CHART) --version $(HELM_VERSION)
install:
helm install -f $(FILE) $(NAME) $(HELM_REPO)/$(HELM_CHART) --version $(HELM_VERSION)
install-devnet:
helm install -f configs/devnet.yaml $(NAME) $(HELM_REPO)/$(HELM_CHART) --version $(HELM_VERSION)
delete:
-helm delete $(NAME)
###############################################################################
### Port forward ###
###############################################################################
.PHONY: port-forward
port-forward:
bash $(CURDIR)/scripts/port-forward.sh --config=$(FILE)
.PHONY: stop-forward
stop-forward:
-pkill -f "port-forward"
###############################################################################
### Local Kind Setup ###
###############################################################################
KIND_CLUSTER=starship
.PHONY: setup-kind
setup-kind:
kind create cluster --name $(KIND_CLUSTER)
.PHONY: clean-kind
clean-kind:
kind delete cluster --name $(KIND_CLUSTER)

134
tests/starship/README.md Normal file
View File

@ -0,0 +1,134 @@
# Starship
Starship is a tool to help simulate real chains, relayers and the interchain infra in a k8s cluster, locally, in the CI and
on large k8s clusters.
Perfect for running internal devnets, and writing e2e tests. Starship helps take projects from development to production.
## Directory Structure
* `configs/` is a directory holding various kinds of configuration for running Starship
* `configs/local.yaml` is configured specially to run locally
* `configs/devnet.yaml` is a larger scale dev environment that will spin up nodes in k8s cluster and keep them running for a week (after a weeks time nodes might start to fail)
* `configs/ci.yaml` light way setup supposed to be run in the CI runner itself
* `scripts/`: handy scripts to interact with Starship live here. These are standalone scripts that can be run anywhere
* `tests/`: Directory holding the e2e tests to run against the system
* `Makefile`: Handy commands go here
## Getting Started
### Setup dependencies
Checkout the [docs](https://starship.cosmology.tech/get-started/step-1) or just run:
```bash
make setup-deps
```
### Connect to kubernetes cluster
Connect to a k8s cluster. Follow one of the 2 steps based on your operating system
* [2.1.1](https://starship.cosmology.tech/get-started/step-2#211-setup-with-kind-cluster): Spin up using kind cluster, for linux
* [2.1.2](https://starship.cosmology.tech/get-started/step-2#212-setup-with-docker-desktop): Using docker-desktop, for mac
Run following to check the connection
```bash
kubectl get nodes
```
### Startup
We use helm-charts for packaging all k8s based setup. This is controlled by the helm chart versions.
Run the following to fetch the helm chart from the `Makefile` variable `HELM_VERSION`.
```bash
make setup-helm
```
Now you can spin up the local cluster with:
```bash
make install
```
Check the pods are in running state with:
```bash
kubectl get pods
```
Once all the pods are in `Running` state run port-forward command to get all ports forwarded locally:
```bash
make port-forward
```
Enjoy!!!!!
### Teardown
Once you are done:
```bash
make stop
```
If you spun up the kubernetes cluster, then please stop it or if you used kind run `make clean-kind`
## Run tests
Tests are designed such that one can re-run the same tests against an already running infra.
This will save the cost of initialization of the infra.
Startup the cluster
```bash
make install
## check status of the pods
kubectl get pods
## Once the pods are up run:
make port-forward
## Run tests, can run this now multiple times as long as tests are running
make test
## Cleanup
make stop
```
## Troubleshooting local setup
Currently, there seems to be some issues when running starship on a local system. This section will help clear out some of them
### Not starting
If all or some of the pods are in `Pending` state, then it means that resources for docker containers are not enough.
There can be 2 ways around this:
1. Increase the resources for your local kubernetes cluster.
* Docker Desktop: Go to `Settings` > `Resources`, increase CPU and memory
2. Reduce the resources for each of the nodes in `configs/local.yaml` file. You can look at `configs/ci.yaml` to understand the `resource` directive in the chains
* `configs/ci.yaml` uses very little resources, so should be able to run locally
> NOTE: When resoureces are reduced or if the devnet has been running for a longer time, then the pods seem to die out or keep restarting. This is due to memory overflow. Will be fixed soon. For now
> one can just run
```bash
make delete
## wait for nodes to die out, check with
kubectl get pods
## restart
make install
```
### Long startup time
## Future Work
### Dev-UX
* We will get rid of the whole `scripts/` dir and replace it with a handy `starship` cli tool.
* Local infra spinup, specially on a Mac takes alot of time, this is something we will speedup much more
* We will have auto resource allocation, so manual troubleshooting is reduced
* Longer running pods or infra without issues.
### Testing/Infra
* Add more tests based on requirements, port all exsiting adhoc tests to Starship
* Add build system into starship (premetive exists) to be able to build the current simapp from the branch
* Start from non-empty genesis
* Add the concept of `jobs` into Starship config, where we can run predefined jobs against the infra

View File

@ -0,0 +1,35 @@
chains:
- name: simapp
type: simapp
image: ghcr.io/cosmos/simapp:latest
numValidators: 2
ports:
rest: 1317
rpc: 26657
grpc: 9091
faucet: 8001
resources:
cpu: "0.2"
memory: "400M"
faucet:
# use v0.31.0-alpha.2 cosmjs-faucet for compatibility with simapp v0.47+
# todo: faucet seems to throw error with sdk version 0.50, still seems to work
image: ghcr.io/cosmology-tech/starship/cosmjs-faucet:v0.31.0
concurrency: 2
resources:
cpu: "0.1"
memory: "200M"
registry:
enabled: true
ports:
rest: 8081
resources:
cpu: "0.1"
memory: "100M"
exposer:
image: ghcr.io/cosmology-tech/starship/exposer:20230808-2333929
resources:
cpu: "0.1"
memory: "100M"

View File

@ -0,0 +1,33 @@
chains:
- name: simapp
type: simapp
image: ghcr.io/cosmos/simapp:latest
numValidators: 30
ports:
rest: 1317
rpc: 26657
grpc: 9091
faucet: 8001
faucet:
# use v0.31.0-alpha.2 cosmjs-faucet for compatibility with simapp v0.47+
# todo: faucet seems to throw error with sdk version 0.50, still seems to work
image: ghcr.io/cosmology-tech/starship/cosmjs-faucet:v0.31.0
# provide more resources to faucet since the number of validators is higher
# only a single faucet is spun up with the genesis node, so resources wont multiply
# with the number of validators
resources:
cpu: "0.5"
memory: "1Gi"
registry:
enabled: true
ports:
rest: 8081
explorer:
enabled: true
ports:
rest: 8080
exposer:
image: ghcr.io/cosmology-tech/starship/exposer:20230808-2333929

View File

@ -0,0 +1,30 @@
chains:
- name: simapp
type: simapp
image: ghcr.io/cosmos/simapp:latest
numValidators: 4
ports:
rest: 1317
rpc: 26657
grpc: 9091
faucet: 8001
faucet:
# use v0.31.0-alpha.2 cosmjs-faucet for compatibility with simapp v0.47+
# todo: faucet seems to throw error with sdk version 0.50, still seems to work
image: ghcr.io/cosmology-tech/starship/cosmjs-faucet:v0.31.0
# concurrency defines number of addresses used for faucet
# higher number would result in longer startup time
concurrency: 4
registry:
enabled: true
ports:
rest: 8081
explorer:
enabled: true
ports:
rest: 8080
exposer:
image: ghcr.io/cosmology-tech/starship/exposer:20230808-2333929

View File

@ -0,0 +1,68 @@
#!/bin/bash
set -euo pipefail
function color() {
local color=$1
shift
local black=30 red=31 green=32 yellow=33 blue=34 magenta=35 cyan=36 white=37
local color_code=${!color:-$green}
printf "\033[%sm%s\033[0m\n" "$color_code" "$*"
}
# Define a function to install a binary on macOS
install_macos() {
case $1 in
docker) color red "Please install docker. Follow: https://docs.docker.com/desktop/install/mac-install/" ;;
kubectl) brew install kubectl ;;
helm) brew install helm ;;
yq) brew install yq ;;
kind) brew install kind ;;
esac
}
# Define a function to install a binary on Linux
install_linux() {
color green "Installing $1 at ~/.local/bin, please add it to PATH"
mkdir -p ~/.local/bin
case $1 in
docker) color red "Please install docker. Follow: https://docs.docker.com/engine/install/ubuntu/" ;;
kubectl) curl -Lks "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" > ~/.local/bin/kubectl && chmod +x ~/.local/bin/kubectl ;;
helm) curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash ;;
yq) curl -Lks "https://github.com/mikefarah/yq/releases/download/v4.33.3/yq_linux_amd64" > ~/.local/bin/yq && chmod +x ~/.local/bin/yq ;;
kind) curl -Lks https://kind.sigs.k8s.io/dl/v0.18.0/kind-linux-amd64 > ~/.local/bin/kind && chmod +x ~/.local/bin/kind ;;
esac
}
# Define a function to install a binary
install_binary() {
if [[ $(uname -s) == "Darwin" ]]; then
install_macos $1
else
install_linux $1
fi
}
# Define a function to check for the presence of a binary
check_binary() {
if ! command -v $1 &> /dev/null
then
echo "$1 is not installed"
install_binary $1
if ! command -v $1 &> /dev/null
then
color red "Installation of $1 failed, exiting..."
color red "Please install $1 manually, then run me again to verify the installation"
exit 1
fi
fi
}
# Check the binaries
check_binary kubectl
check_binary helm
check_binary yq
check_binary kind
check_binary docker
color green "All binaries are installed"

View File

@ -0,0 +1,87 @@
#!/bin/bash
set -euo pipefail
function color() {
local color=$1
shift
local black=30 red=31 green=32 yellow=33 blue=34 magenta=35 cyan=36 white=37
local color_code=${!color:-$green}
printf "\033[%sm%s\033[0m\n" "$color_code" "$*"
}
function stop_port_forward() {
color green "Trying to stop all port-forward, if any...."
PIDS=$(ps -ef | grep -i -e 'kubectl port-forward' | grep -v 'grep' | cat | awk '{print $2}') || true
for p in $PIDS; do
kill -15 $p
done
sleep 2
}
# Default values
CHAIN_RPC_PORT=26657
CHAIN_GRPC_PORT=9090
CHAIN_LCD_PORT=1317
CHAIN_EXPOSER_PORT=8081
CHAIN_FAUCET_PORT=8000
EXPLORER_LCD_PORT=8080
REGISTRY_LCD_PORT=8080
REGISTRY_GRPC_PORT=9090
for i in "$@"; do
case $i in
-c=*|--config=*)
CONFIGFILE="${i#*=}"
shift # past argument=value
;;
-*|--*)
echo "Unknown option $i"
exit 1
;;
*)
;;
esac
done
stop_port_forward
echo "Port forwarding for config ${CONFIGFILE}"
echo "Port forwarding all chains"
num_chains=$(yq -r ".chains | length - 1" ${CONFIGFILE})
if [[ $num_chains -lt 0 ]]; then
echo "No chains to port-forward: num: $num_chains"
exit 1
fi
for i in $(seq 0 $num_chains); do
chain=$(yq -r ".chains[$i].name" ${CONFIGFILE} )
localrpc=$(yq -r ".chains[$i].ports.rpc" ${CONFIGFILE} )
localgrpc=$(yq -r ".chains[$i].ports.grpc" ${CONFIGFILE} )
locallcd=$(yq -r ".chains[$i].ports.rest" ${CONFIGFILE} )
localexp=$(yq -r ".chains[$i].ports.exposer" ${CONFIGFILE})
localfaucet=$(yq -r ".chains[$i].ports.faucet" ${CONFIGFILE})
color yellow "chains: forwarded $chain"
[[ "$localrpc" != "null" ]] && color yellow " rpc to http://localhost:$localrpc" && kubectl port-forward pods/$chain-genesis-0 $localrpc:$CHAIN_RPC_PORT > /dev/null 2>&1 &
[[ "$localgrpc" != "null" ]] && color yellow " grpc to http://localhost:$localgrpc" && kubectl port-forward pods/$chain-genesis-0 $localgrpc:$CHAIN_GRPC_PORT > /dev/null 2>&1 &
[[ "$locallcd" != "null" ]] && color yellow " lcd to http://localhost:$locallcd" && kubectl port-forward pods/$chain-genesis-0 $locallcd:$CHAIN_LCD_PORT > /dev/null 2>&1 &
[[ "$localexp" != "null" ]] && color yellow " exposer to http://localhost:$localexp" && kubectl port-forward pods/$chain-genesis-0 $localexp:$CHAIN_EXPOSER_PORT > /dev/null 2>&1 &
[[ "$localfaucet" != "null" ]] && color yellow " faucet to http://localhost:$localfaucet" && kubectl port-forward pods/$chain-genesis-0 $localfaucet:$CHAIN_FAUCET_PORT > /dev/null 2>&1 &
sleep 1
done
echo "Port forward services"
if [[ $(yq -r ".registry.enabled" $CONFIGFILE) == "true" ]];
then
kubectl port-forward service/registry 8081:$REGISTRY_LCD_PORT > /dev/null 2>&1 &
kubectl port-forward service/registry 9091:$REGISTRY_GRPC_PORT > /dev/null 2>&1 &
sleep 1
color yellow "registry: forwarded registry lcd to grpc http://localhost:8081, to http://localhost:9091"
fi
if [[ $(yq -r ".explorer.enabled" $CONFIGFILE) == "true" ]];
then
kubectl port-forward service/explorer 8080:$EXPLORER_LCD_PORT > /dev/null 2>&1 &
sleep 1
color green "Open the explorer to get started.... http://localhost:8080"
fi

View File

@ -0,0 +1,115 @@
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"google.golang.org/grpc"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
auth "github.com/cosmos/cosmos-sdk/x/auth/types"
)
// CreditFromFaucet will request facuet of the chain for tokens to address
func CreditFromFaucet(config *Config, address string) error {
url := fmt.Sprintf("%s/credit", config.GetChain(chainID).GetFaucetAddr())
body := map[string]string{
"address": address,
"denom": denom,
}
jsonBody, err := json.Marshal(body)
if err != nil {
return err
}
_, err = http.Post(url, "application/json", bytes.NewBuffer(jsonBody)) //nolint // test url is dependent on the config file
if err != nil {
return err
}
// Check the response status code
// Note: ignore response error due to cosmjs error
// todo: add check for error
// if res.StatusCode != http.StatusOK {
// return fmt.Errorf("request failed with status code: %d", res.StatusCode)
//}
return nil
}
// CreateTestTx creates a test tx with the given txConfig and txBuilder
func CreateTestTx(txConfig client.TxConfig, txBuilder client.TxBuilder, privs []cryptotypes.PrivKey, accNums, accSeqs []uint64, chainID string) (xauthsigning.Tx, []byte, error) {
defaultSignMode, err := xauthsigning.APISignModeToInternal(txConfig.SignModeHandler().DefaultMode())
if err != nil {
return nil, nil, err
}
// First round: we gather all the signer infos. We use the "set empty
// signature" hack to do that.
var sigsV2 []signing.SignatureV2
for i, priv := range privs {
sigV2 := signing.SignatureV2{
PubKey: priv.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: defaultSignMode,
Signature: nil,
},
Sequence: accSeqs[i],
}
sigsV2 = append(sigsV2, sigV2)
}
err = txBuilder.SetSignatures(sigsV2...)
if err != nil {
return nil, nil, err
}
// Second round: all signer infos are set, so each signer can sign.
sigsV2 = []signing.SignatureV2{}
for i, priv := range privs {
signerData := xauthsigning.SignerData{
Address: sdk.AccAddress(priv.PubKey().Bytes()).String(),
ChainID: chainID,
AccountNumber: accNums[i],
Sequence: accSeqs[i],
PubKey: priv.PubKey(),
}
sigV2, err := tx.SignWithPrivKey(
context.TODO(), defaultSignMode, signerData,
txBuilder, priv, txConfig, accSeqs[i])
if err != nil {
return nil, nil, err
}
sigsV2 = append(sigsV2, sigV2)
}
err = txBuilder.SetSignatures(sigsV2...)
if err != nil {
return nil, nil, err
}
txBytes, err := txConfig.TxEncoder()(txBuilder.GetTx())
if err != nil {
return nil, nil, err
}
return txBuilder.GetTx(), txBytes, nil
}
// GetAccSeqNumber returns the account number and sequence number for the given address
func GetAccSeqNumber(grpcConn *grpc.ClientConn, address string) (uint64, uint64, error) {
info, err := auth.NewQueryClient(grpcConn).AccountInfo(context.Background(), &auth.QueryAccountInfoRequest{Address: address})
if err != nil {
return 0, 0, err
}
return info.Info.GetAccountNumber(), info.Info.GetSequence(), nil
}

View File

@ -0,0 +1,100 @@
package main
import (
"fmt"
)
type Chain struct {
Name string `name:"name" json:"name" yaml:"name"`
Type string `name:"type" json:"type" yaml:"type"`
NumValidators int `name:"num-validators" json:"num_validators" yaml:"numValidators"`
Ports Port `name:"ports" json:"ports" yaml:"ports"`
Upgrade Upgrade `name:"upgrade" json:"upgrade" yaml:"upgrade"`
}
func (c *Chain) GetRPCAddr() string {
return fmt.Sprintf("http://localhost:%d", c.Ports.Rpc)
}
func (c *Chain) GetRESTAddr() string {
return fmt.Sprintf("http://localhost:%d", c.Ports.Rest)
}
func (c *Chain) GetGRPCAddr() string {
return fmt.Sprintf("http://localhost:%d", c.Ports.Grpc)
}
func (c *Chain) GetFaucetAddr() interface{} {
return fmt.Sprintf("http://localhost:%d", c.Ports.Faucet)
}
type Upgrade struct {
Enabled bool `name:"eanbled" json:"enabled" yaml:"enabled"`
Type string `name:"type" json:"type" yaml:"type"`
Genesis string `name:"genesis" json:"genesis" yaml:"genesis"`
Upgrades []struct {
Name string `name:"name" json:"name" yaml:"name"`
Version string `name:"version" json:"version" yaml:"version"`
} `name:"upgrades" json:"upgrades" yaml:"upgrades"`
}
type Port struct {
Rest int `name:"rest" json:"rest" yaml:"rest"`
Rpc int `name:"rpc" json:"rpc" yaml:"rpc"`
Grpc int `name:"grpc" json:"grpc" yaml:"grpc"`
Exposer int `name:"exposer" json:"exposer" yaml:"exposer"`
Faucet int `name:"faucet" json:"faucet" yaml:"faucet"`
}
type Relayer struct {
Name string `name:"name" json:"name" yaml:"name"`
Type string `name:"type" json:"type" yaml:"type"`
Replicas int `name:"replicas" json:"replicas" yaml:"replicas"`
Chains []string `name:"chains" json:"chains" yaml:"chains"`
}
type Feature struct {
Enabled bool `name:"enabled" json:"enabled" yaml:"enabled"`
Image string `name:"image" json:"image" yaml:"image"`
Ports Port `name:"ports" json:"ports" yaml:"ports"`
}
func (f *Feature) GetRPCAddr() string {
return fmt.Sprintf("http://localhost:%d", f.Ports.Rpc)
}
func (f *Feature) GetRESTAddr() string {
return fmt.Sprintf("http://localhost:%d", f.Ports.Rest)
}
// Config is the struct for the config.yaml setup file
// todo: move this to a more common place, outside just tests
// todo: can be moved to proto definition
type Config struct {
Chains []*Chain `name:"chains" json:"chains" yaml:"chains"`
Relayers []*Relayer `name:"relayers" json:"relayers" yaml:"relayers"`
Explorer *Feature `name:"explorer" json:"explorer" yaml:"explorer"`
Registry *Feature `name:"registry" json:"registry" yaml:"registry"`
}
// HasChainId returns true if chain id found in list of chains
func (c *Config) HasChainId(chainId string) bool {
for _, chain := range c.Chains {
if chain.Name == chainId {
return true
}
}
return false
}
// GetChain returns the Chain object pointer for the given chain id
func (c *Config) GetChain(chainId string) *Chain {
for _, chain := range c.Chains {
if chain.Name == chainId {
return chain
}
}
return nil
}

220
tests/starship/tests/go.mod Normal file
View File

@ -0,0 +1,220 @@
module github.com/cosmos-sdk/tests/starship/tests
go 1.20
replace (
github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0
// Update to rosetta-sdk-go temporarly to have `check:spec` passing. See https://github.com/coinbase/rosetta-sdk-go/issues/449
github.com/coinbase/rosetta-sdk-go => github.com/coinbase/rosetta-sdk-go v0.8.2-0.20221007214527-e03849ba430a
// We always want to test against the latest version of the SDK.
github.com/cosmos/cosmos-sdk => ../../../.
)
// SimApp on main always tests the latest extracted SDK modules importing the sdk
replace (
cosmossdk.io/api => ../../../api
cosmossdk.io/client/v2 => ../../../client/v2
cosmossdk.io/collections => ../../../collections
cosmossdk.io/core => ../../../core
cosmossdk.io/depinject => ../../../depinject
cosmossdk.io/errors => ../../../errors
cosmossdk.io/log => ../../../log
cosmossdk.io/math => ../../../math
cosmossdk.io/simapp => ../../../simapp
cosmossdk.io/store => ../../../store
cosmossdk.io/x/circuit => ../../../x/circuit
cosmossdk.io/x/evidence => ../../../x/evidence
cosmossdk.io/x/feegrant => ../../../x/feegrant
cosmossdk.io/x/nft => ../../../x/nft
cosmossdk.io/x/tx => ../../../x/tx
cosmossdk.io/x/upgrade => ../../../x/upgrade
)
require (
cosmossdk.io/log v1.2.0
cosmossdk.io/math v1.0.1
cosmossdk.io/simapp v0.0.0-00010101000000-000000000000
github.com/cosmos/cosmos-db v1.0.0
github.com/cosmos/cosmos-sdk v0.51.0
github.com/stretchr/testify v1.8.4
google.golang.org/grpc v1.57.0
gopkg.in/yaml.v3 v3.0.1
)
require (
cloud.google.com/go v0.110.6 // indirect
cloud.google.com/go/compute v1.23.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.1 // indirect
cloud.google.com/go/storage v1.31.0 // indirect
cosmossdk.io/api v0.7.0 // indirect
cosmossdk.io/client/v2 v2.0.0-20230630094428-02b760776860 // indirect
cosmossdk.io/collections v0.3.1-0.20230808102719-f04fefdc7a68 // indirect
cosmossdk.io/core v0.9.0 // indirect
cosmossdk.io/depinject v1.0.0-alpha.4 // indirect
cosmossdk.io/errors v1.0.0 // indirect
cosmossdk.io/store v1.0.0-alpha.1.0.20230728080422-54ed7dab3982 // indirect
cosmossdk.io/x/circuit v0.0.0-20230613133644-0a778132a60f // indirect
cosmossdk.io/x/evidence v0.0.0-20230613133644-0a778132a60f // indirect
cosmossdk.io/x/feegrant v0.0.0-20230613133644-0a778132a60f // indirect
cosmossdk.io/x/nft v0.0.0-20230613133644-0a778132a60f // indirect
cosmossdk.io/x/tx v0.9.1 // indirect
cosmossdk.io/x/upgrade v0.0.0-20230613133644-0a778132a60f // indirect
filippo.io/edwards25519 v1.0.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.1 // indirect
github.com/DataDog/zstd v1.5.5 // indirect
github.com/aws/aws-sdk-go v1.44.312 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect
github.com/bits-and-blooms/bitset v1.8.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/cockroachdb/apd/v2 v2.0.2 // indirect
github.com/cockroachdb/errors v1.10.0 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/pebble v0.0.0-20230710174534-a9a079d4fb6b // indirect
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20230613231145-182959a1fad6 // indirect
github.com/cometbft/cometbft v0.38.0-rc3 // indirect
github.com/cometbft/cometbft-db v0.7.0 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/cosmos-proto v1.0.0-beta.3 // indirect
github.com/cosmos/go-bip39 v1.0.0 // indirect
github.com/cosmos/gogogateway v1.2.0 // indirect
github.com/cosmos/gogoproto v1.4.10 // indirect
github.com/cosmos/iavl v1.0.0-beta.2 // indirect
github.com/cosmos/ics23/go v0.10.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.13.0 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
github.com/emicklei/dot v1.5.0 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/getsentry/sentry-go v0.23.0 // indirect
github.com/go-kit/kit v0.12.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.1.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/google/s2a-go v0.1.4 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-getter v1.7.2 // indirect
github.com/hashicorp/go-hclog v1.5.0 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-metrics v0.5.1 // indirect
github.com/hashicorp/go-plugin v1.4.10 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/hdevalence/ed25519consensus v0.1.0 // indirect
github.com/huandu/skiplist v1.2.0 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/improbable-eng/grpc-web v0.15.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/klauspost/compress v1.16.7 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lib/pq v1.10.7 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/linxGnu/grocksdb v1.8.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/manifoldco/promptui v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/minio/highwayhash v1.0.2 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/oasisprotocol/curve25519-voi v0.0.0-20230110094441-db37f07504ce // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/onsi/gomega v1.27.4 // indirect
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect
github.com/opencontainers/runc v1.1.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
github.com/petermattis/goid v0.0.0-20230518223814-80aa455d8761 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.11.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/rs/cors v1.8.3 // indirect
github.com/rs/zerolog v1.30.0 // indirect
github.com/sasha-s/go-deadlock v0.3.1 // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/cobra v1.7.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.16.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/tidwall/btree v1.6.0 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/zondax/hid v0.9.1 // indirect
github.com/zondax/ledger-go v0.14.1 // indirect
go.etcd.io/bbolt v1.3.7 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/term v0.11.0 // indirect
golang.org/x/text v0.12.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.134.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gotest.tools/v3 v3.5.0 // indirect
nhooyr.io/websocket v1.8.6 // indirect
pgregory.net/rapid v1.1.0 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

1664
tests/starship/tests/go.sum Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
package main
import (
"context"
"fmt"
"os"
"time"
dbm "github.com/cosmos/cosmos-db"
"github.com/stretchr/testify/suite"
"google.golang.org/grpc"
"gopkg.in/yaml.v3"
"cosmossdk.io/log"
"cosmossdk.io/simapp"
"cosmossdk.io/simapp/params"
"github.com/cosmos/cosmos-sdk/codec"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
)
var (
configFile = "../configs/devnet.yaml"
chainID = "simapp"
denom = "stake"
)
type TestSuite struct {
suite.Suite
config *Config
cdc params.EncodingConfig
grpcConn *grpc.ClientConn
}
func (s *TestSuite) SetupTest() {
s.T().Log("setting up e2e integration test suite...")
// read config file from yaml
yamlFile, err := os.ReadFile(configFile)
s.Require().NoError(err)
config := &Config{}
err = yaml.Unmarshal(yamlFile, config)
s.Require().NoError(err)
s.config = config
tempApp := simapp.NewSimApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(s.T().TempDir()))
encodingConfig := params.EncodingConfig{
InterfaceRegistry: tempApp.InterfaceRegistry(),
Codec: tempApp.AppCodec(),
TxConfig: tempApp.TxConfig(),
Amino: tempApp.LegacyAmino(),
}
s.cdc = encodingConfig
grpcConn, err := grpc.Dial(
fmt.Sprintf("0.0.0.0:%d", config.GetChain(chainID).Ports.Grpc),
grpc.WithInsecure(), //nolint:staticcheck // ignore SA1019, we don't need to use a secure connection for tests
grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(s.cdc.InterfaceRegistry).GRPCCodec())))
s.Require().NoError(err)
s.grpcConn = grpcConn
}
func (s *TestSuite) TearDownTest() {
s.T().Log("tearing down e2e integration test suite...")
err := s.grpcConn.Close()
s.Require().NoError(err)
}
// WaitForTx will wait for the tx to complete, fail if not able to find tx
func (s *TestSuite) WaitForTx(txHex string) {
var resTx *txtypes.GetTxResponse
var err error
txClient := txtypes.NewServiceClient(s.grpcConn)
s.Require().Eventuallyf(
func() bool {
resTx, err = txClient.GetTx(context.Background(), &txtypes.GetTxRequest{Hash: txHex})
if err != nil {
return false
}
if resTx.TxResponse.Height > 1 {
return true
}
return false
},
5*time.Second,
time.Second,
"waited for too long, still txn not successful",
)
s.Require().NotNil(resTx.TxResponse)
}

View File

@ -0,0 +1,78 @@
package main
import (
"context"
"testing"
"github.com/stretchr/testify/suite"
"cosmossdk.io/math"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
func TestE2ETestSuite(t *testing.T) {
suite.Run(t, new(TestSuite))
}
func (s *TestSuite) TestChainTokenTransfer() {
txConfig := s.cdc.TxConfig
txBuilder := txConfig.NewTxBuilder()
// create a new address, and send it some tokens from faucet
priv1, _, addr1 := testdata.KeyTestPubAddr()
_, _, addr2 := testdata.KeyTestPubAddr()
err := CreditFromFaucet(s.config, addr1.String())
s.Require().NoError(err)
s.T().Run("query balance for addr1", func(t *testing.T) {
balance, err := banktypes.NewQueryClient(s.grpcConn).Balance(context.Background(), &banktypes.QueryBalanceRequest{
Address: addr1.String(),
Denom: denom,
})
s.Require().NoError(err)
s.Require().Equal(int64(10000000000), balance.Balance.Amount.Int64())
})
s.T().Run("send tokens from addr1 to addr2", func(t *testing.T) {
// get account number and sequence
accNum, seq, err := GetAccSeqNumber(s.grpcConn, addr1.String())
s.Require().NoError(err)
// build tx into the txBuilder
msg := banktypes.NewMsgSend(addr1, addr2, sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(1230000))))
s.Require().NoError(err)
err = txBuilder.SetMsgs(msg)
s.Require().NoError(err)
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(200000))))
txBuilder.SetGasLimit(200000)
txBuilder.SetTimeoutHeight(100000)
// sign txn
_, txBytes, err := CreateTestTx(txConfig, txBuilder, []cryptotypes.PrivKey{priv1}, []uint64{accNum}, []uint64{seq}, chainID)
s.Require().NoError(err)
// broadcast tx
txClient := txtypes.NewServiceClient(s.grpcConn)
res, err := txClient.BroadcastTx(context.Background(), &txtypes.BroadcastTxRequest{
Mode: txtypes.BroadcastMode_BROADCAST_MODE_SYNC,
TxBytes: txBytes,
})
s.Require().NoError(err)
s.Require().Equal(uint32(0), res.TxResponse.Code)
s.WaitForTx(res.TxResponse.TxHash)
})
s.T().Run("query balance for addr2", func(t *testing.T) {
balance, err := banktypes.NewQueryClient(s.grpcConn).Balance(context.Background(), &banktypes.QueryBalanceRequest{
Address: addr2.String(),
Denom: denom,
})
s.Require().NoError(err)
s.Require().Equal(int64(1230000), balance.Balance.Amount.Int64())
})
}