Skip to content

Commit

Permalink
fix: e2e tests (#3487)
Browse files Browse the repository at this point in the history
## Overview

Fixes #3453 

I encountered a lot of flakiness while running knuu tests in ci(view
logs in issue description) to resolve them i added a few workarounds
with @smuu which broke other things in our existing suite. those changes
are now reverted since the tests started passing on main again after
scaling some of the clusters that were stuck. DevOps is working on
addressing flakiness on knuu.

E2E tests are green:
https://github.com/celestiaorg/celestia-app/actions/runs/9179315870/job/25241185362?pr=3487

My changes:
-  Fix git tag fetching issue
-  Extract e2e tests into its own yaml file
-  Separate MinorVersionCompatibility and MajorupgradeToV2
  • Loading branch information
ninabarbakadze authored May 28, 2024
1 parent 321eff5 commit e42338d
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 141 deletions.
18 changes: 2 additions & 16 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,8 @@ on:

jobs:
test-e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'

- name: Setup kubeconfig
env:
KUBECONFIG_FILE: ${{ secrets.KNUU_KUBECONFIG_FILE }}
run: |
mkdir -p $HOME/.kube
echo "${KUBECONFIG_FILE}" > $HOME/.kube/config
- name: Run e2e tests
run: make test-e2e
uses: ./.github/workflows/test-e2e.yml
secrets: inherit

test:
uses: ./.github/workflows/test.yml
27 changes: 27 additions & 0 deletions .github/workflows/test-e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: test-e2e

on:
workflow_call:
secrets:
KNUU_KUBECONFIG_FILE:
required: true

jobs:
test-e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
ref: main
- uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
- name: Setup kubeconfig
env:
KUBECONFIG_FILE: ${{ secrets.KNUU_KUBECONFIG_FILE }}
run: |
mkdir -p $HOME/.kube
echo "${KUBECONFIG_FILE}" > $HOME/.kube/config
- name: Run e2e tests
run: make test-e2e
2 changes: 1 addition & 1 deletion test/e2e/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func main() {

if !specificTestFound {
logger.Println("No particular test specified. Running all tests.")
logger.Println("go run ./test/e2e <test_name> to run a specific test")
logger.Println("make test-e2e <test_name> to run a specific test")
logger.Printf("Valid tests are: %s\n\n", getTestNames(tests))
// if no specific test is passed, run all tests
for _, test := range tests {
Expand Down
140 changes: 140 additions & 0 deletions test/e2e/major_upgrade_v2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package main

import (
"context"
"errors"
"fmt"
"log"
"strings"
"time"

"github.com/celestiaorg/celestia-app/v2/app"
"github.com/celestiaorg/celestia-app/v2/app/encoding"
v1 "github.com/celestiaorg/celestia-app/v2/pkg/appconsts/v1"
v2 "github.com/celestiaorg/celestia-app/v2/pkg/appconsts/v2"
"github.com/celestiaorg/celestia-app/v2/test/e2e/testnet"
"github.com/celestiaorg/celestia-app/v2/test/txsim"
"github.com/celestiaorg/knuu/pkg/knuu"
"github.com/tendermint/tendermint/rpc/client/http"
)

func MajorUpgradeToV2(logger *log.Logger) error {
latestVersion, err := testnet.GetLatestVersion()
testnet.NoError("failed to get latest version", err)

logger.Println("Running major upgrade to v2 test", "version", latestVersion)

numNodes := 4
upgradeHeight := int64(12)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

logger.Println("Creating testnet")
testNet, err := testnet.New("runMajorUpgradeToV2", seed, nil, "test")
testnet.NoError("failed to create testnet", err)

defer testNet.Cleanup()

testNet.SetConsensusParams(app.DefaultInitialConsensusParams())

preloader, err := knuu.NewPreloader()
testnet.NoError("failed to create preloader", err)

defer func() { _ = preloader.EmptyImages() }()
testnet.NoError("failed to add image", preloader.AddImage(testnet.DockerImageName(latestVersion)))

logger.Println("Creating genesis nodes")
for i := 0; i < numNodes; i++ {
err := testNet.CreateGenesisNode(latestVersion, 10000000, upgradeHeight, testnet.DefaultResources)
testnet.NoError("failed to create genesis node", err)
}

kr, err := testNet.CreateAccount("alice", 1e12, "")
testnet.NoError("failed to create account", err)

logger.Println("Setting up testnet")
testnet.NoError("Failed to setup testnet", testNet.Setup())
logger.Println("Starting testnet")
testnet.NoError("Failed to start testnet", testNet.Start())

errCh := make(chan error)
encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...)
opts := txsim.DefaultOptions().WithSeed(seed).SuppressLogs()
sequences := txsim.NewBlobSequence(txsim.NewRange(200, 4000), txsim.NewRange(1, 3)).Clone(5)
sequences = append(sequences, txsim.NewSendSequence(4, 1000, 100).Clone(5)...)
go func() {
errCh <- txsim.Run(ctx, testNet.GRPCEndpoints()[0], kr, encCfg, opts, sequences...)
}()

heightBefore := upgradeHeight - 1
for i := 0; i < numNodes; i++ {
client, err := testNet.Node(i).Client()
testnet.NoError("failed to get client", err)

testnet.NoError("failed to wait for height", waitForHeight(testNet, testNet.Node(i), upgradeHeight, time.Minute))

resp, err := client.Header(ctx, &heightBefore)
testnet.NoError("failed to get header", err)
logger.Println("Node", i, "is running on version", resp.Header.Version.App)
if resp.Header.Version.App != v1.Version {
return fmt.Errorf("version mismatch before upgrade: expected %d, got %d", v1.Version, resp.Header.Version.App)
}

resp, err = client.Header(ctx, &upgradeHeight)
testnet.NoError("failed to get header", err)
if resp.Header.Version.App != v2.Version {
return fmt.Errorf("version mismatch after upgrade: expected %d, got %d", v2.Version, resp.Header.Version.App)
}
}

// end txsim
cancel()

err = <-errCh
if !strings.Contains(err.Error(), context.Canceled.Error()) {
return fmt.Errorf("expected context.Canceled error, got: %w", err)
}
return nil
}

func getHeight(ctx context.Context, client *http.HTTP, period time.Duration) (int64, error) {
timer := time.NewTimer(period)
ticker := time.NewTicker(100 * time.Millisecond)
for {
select {
case <-timer.C:
return 0, fmt.Errorf("failed to get height after %.2f seconds", period.Seconds())
case <-ticker.C:
status, err := client.Status(ctx)
if err == nil {
return status.SyncInfo.LatestBlockHeight, nil
}
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
return 0, err
}
}
}
}

func waitForHeight(testnet *testnet.Testnet, node *testnet.Node, height int64, period time.Duration) error {
timer := time.NewTimer(period)
ticker := time.NewTicker(100 * time.Millisecond)
for {
select {
case <-timer.C:
return fmt.Errorf("failed to reach height %d in %.2f seconds", height, period.Seconds())
case <-ticker.C:
executor, err := testnet.GetExecutor()
if err != nil {
return fmt.Errorf("failed to get executor: %w", err)
}
currentHeight, err := node.GetHeight(executor)
if err != nil {
return err
}
if currentHeight >= height {
return nil
}
}
}
}
124 changes: 0 additions & 124 deletions test/e2e/check_upgrades.go → test/e2e/minor_version_compatibility.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"github.com/celestiaorg/celestia-app/v2/test/e2e/testnet"
"github.com/celestiaorg/celestia-app/v2/test/txsim"
"github.com/celestiaorg/knuu/pkg/knuu"
"github.com/tendermint/tendermint/rpc/client/http"
)

func MinorVersionCompatibility(logger *log.Logger) error {
Expand Down Expand Up @@ -130,129 +129,6 @@ func MinorVersionCompatibility(logger *log.Logger) error {
return nil
}

func MajorUpgradeToV2(logger *log.Logger) error {
latestVersion, err := testnet.GetLatestVersion()
testnet.NoError("failed to get latest version", err)

logger.Println("Running major upgrade to v2 test", "version", latestVersion)

numNodes := 4
upgradeHeight := int64(12)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

logger.Println("Creating testnet")
testNet, err := testnet.New("runMajorUpgradeToV2", seed, nil, "test")
testnet.NoError("failed to create testnet", err)

defer testNet.Cleanup()

testNet.SetConsensusParams(app.DefaultInitialConsensusParams())

preloader, err := knuu.NewPreloader()
testnet.NoError("failed to create preloader", err)

defer func() { _ = preloader.EmptyImages() }()
testnet.NoError("failed to add image", preloader.AddImage(testnet.DockerImageName(latestVersion)))

logger.Println("Creating genesis nodes")
for i := 0; i < numNodes; i++ {
err := testNet.CreateGenesisNode(latestVersion, 10000000, upgradeHeight, testnet.DefaultResources)
testnet.NoError("failed to create genesis node", err)
}

kr, err := testNet.CreateAccount("alice", 1e12, "")
testnet.NoError("failed to create account", err)
// start the testnet

logger.Println("Setting up testnet")
testnet.NoError("Failed to setup testnet", testNet.Setup())
logger.Println("Starting testnet")
testnet.NoError("Failed to start testnet", testNet.Start())

errCh := make(chan error)
encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...)
opts := txsim.DefaultOptions().WithSeed(seed).SuppressLogs()
sequences := txsim.NewBlobSequence(txsim.NewRange(200, 4000), txsim.NewRange(1, 3)).Clone(5)
sequences = append(sequences, txsim.NewSendSequence(4, 1000, 100).Clone(5)...)
go func() {
errCh <- txsim.Run(ctx, testNet.GRPCEndpoints()[0], kr, encCfg, opts, sequences...)
}()

// assert that the network is initially running on v1
heightBefore := upgradeHeight - 1
for i := 0; i < numNodes; i++ {
client, err := testNet.Node(i).Client()
testnet.NoError("failed to get client", err)

testnet.NoError("failed to wait for height", waitForHeight(testNet, testNet.Node(i), upgradeHeight, time.Minute))

resp, err := client.Header(ctx, &heightBefore)
testnet.NoError("failed to get header", err)
logger.Println("Node", i, "is running on version", resp.Header.Version.App)
if resp.Header.Version.App != v1.Version {
return fmt.Errorf("version mismatch before upgrade: expected %d, got %d", v1.Version, resp.Header.Version.App)
}

resp, err = client.Header(ctx, &upgradeHeight)
testnet.NoError("failed to get header", err)
if resp.Header.Version.App != v2.Version {
return fmt.Errorf("version mismatch before upgrade: expected %d, got %d", v2.Version, resp.Header.Version.App)
}
}

// end txsim
cancel()

err = <-errCh
if !strings.Contains(err.Error(), context.Canceled.Error()) {
return fmt.Errorf("expected context.Canceled error, got: %w", err)
}
return nil
}

func getHeight(ctx context.Context, client *http.HTTP, period time.Duration) (int64, error) {
timer := time.NewTimer(period)
ticker := time.NewTicker(100 * time.Millisecond)
for {
select {
case <-timer.C:
return 0, fmt.Errorf("failed to get height after %.2f seconds", period.Seconds())
case <-ticker.C:
status, err := client.Status(ctx)
if err == nil {
return status.SyncInfo.LatestBlockHeight, nil
}
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
return 0, err
}
}
}
}

func waitForHeight(testnet *testnet.Testnet, node *testnet.Node, height int64, period time.Duration) error {
timer := time.NewTimer(period)
ticker := time.NewTicker(100 * time.Millisecond)
for {
select {
case <-timer.C:
return fmt.Errorf("failed to reach height %d in %.2f seconds", height, period.Seconds())
case <-ticker.C:
executor, err := testnet.GetExecutor()
if err != nil {
return fmt.Errorf("failed to get executor: %w", err)
}
currentHeight, err := node.GetHeight(executor)
if err != nil {
return err
}
if currentHeight >= height {
return nil
}
}
}
}

func getAllVersions() (string, error) {
cmd := exec.Command("git", "tag", "-l")
output, err := cmd.Output()
Expand Down
1 change: 1 addition & 0 deletions test/e2e/testnet/testnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ func (t *Testnet) CreateTxClient(name,
Msg("error adding keyring dir to txsim")
return err
}

err = txsim.Instance.Commit()
if err != nil {
log.Err(err).
Expand Down

0 comments on commit e42338d

Please sign in to comment.