From 58fc315d1e92a67ada9091c83f435d1363c1a3a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nina=20/=20=E1=83=9C=E1=83=98=E1=83=9C=E1=83=90?= Date: Fri, 19 Apr 2024 10:29:01 +0200 Subject: [PATCH] refactor: switch e2e tests to a binary (#3301) Fixes #3255 Opens https://github.com/celestiaorg/celestia-app/issues/3321 --------- Co-authored-by: Callum Waters --- Makefile | 3 +- test/e2e/benchmark/throughput.go | 83 +++++++++ .../{upgrade_test.go => check_upgrades.go} | 176 ++++++++++-------- test/e2e/main.go | 72 +++++++ test/e2e/readme.md | 23 ++- test/e2e/simple.go | 76 ++++++++ test/e2e/simple_test.go | 84 --------- test/e2e/{ => testnets}/defaults.go | 4 +- test/e2e/{ => testnets}/node.go | 2 +- test/e2e/{ => testnets}/setup.go | 2 +- test/e2e/testnets/test_helpers.go | 11 ++ test/e2e/{ => testnets}/testnet.go | 2 +- test/e2e/{ => testnets}/txsimNode.go | 2 +- test/e2e/{ => testnets}/util.go | 2 +- test/e2e/{ => testnets}/versions.go | 29 ++- test/e2e/testnets/versions_test.go | 49 +++++ test/e2e/throughput_test.go | 85 --------- test/e2e/versions_test.go | 49 ----- 18 files changed, 443 insertions(+), 311 deletions(-) create mode 100644 test/e2e/benchmark/throughput.go rename test/e2e/{upgrade_test.go => check_upgrades.go} (50%) create mode 100644 test/e2e/main.go create mode 100644 test/e2e/simple.go delete mode 100644 test/e2e/simple_test.go rename test/e2e/{ => testnets}/defaults.go (66%) rename test/e2e/{ => testnets}/node.go (99%) rename test/e2e/{ => testnets}/setup.go (98%) create mode 100644 test/e2e/testnets/test_helpers.go rename test/e2e/{ => testnets}/testnet.go (99%) rename test/e2e/{ => testnets}/txsimNode.go (98%) rename test/e2e/{ => testnets}/util.go (98%) rename test/e2e/{ => testnets}/versions.go (76%) create mode 100644 test/e2e/testnets/versions_test.go delete mode 100644 test/e2e/throughput_test.go delete mode 100644 test/e2e/versions_test.go diff --git a/Makefile b/Makefile index a911c4725d..65ab14103d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,6 @@ VERSION := $(shell echo $(shell git describe --tags 2>/dev/null || git log -1 --format='%h') | sed 's/^v//') COMMIT := $(shell git rev-parse --short HEAD) DOCKER := $(shell which docker) -ALL_VERSIONS := $(shell git tag -l) DOCKER_BUF := $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace bufbuild/buf IMAGE := ghcr.io/tendermint/docker-build-proto:latest DOCKER_PROTO_BUILDER := docker run -v $(shell pwd):/workspace --workdir /workspace $(IMAGE) @@ -136,7 +135,7 @@ test-short: ## test-e2e: Run end to end tests via knuu. This command requires a kube/config file to configure kubernetes. test-e2e: @echo "--> Running end to end tests" - @KNUU_NAMESPACE=test KNUU_TIMEOUT=20m E2E_LATEST_VERSION=$(shell git rev-parse --short main) E2E_VERSIONS="$(ALL_VERSIONS)" go test ./test/e2e/... -timeout 20m -v + go run ./test/e2e $(filter-out $@,$(MAKECMDGOALS)) .PHONY: test-e2e ## test-race: Run tests in race mode. diff --git a/test/e2e/benchmark/throughput.go b/test/e2e/benchmark/throughput.go new file mode 100644 index 0000000000..fec9849c2f --- /dev/null +++ b/test/e2e/benchmark/throughput.go @@ -0,0 +1,83 @@ +package main + +import ( + "context" + "fmt" + "log" + "os" + "time" + + "github.com/celestiaorg/celestia-app/v2/pkg/appconsts" + "github.com/celestiaorg/celestia-app/v2/test/e2e/testnets" + "github.com/celestiaorg/celestia-app/v2/test/util/testnode" +) + +const seed = 42 + +func main() { + if err := E2EThroughput(); err != nil { + log.Fatalf("--- ERROR Throughput test: %v", err.Error()) + } +} + +func E2EThroughput() error { + os.Setenv("KNUU_NAMESPACE", "test") + + latestVersion, err := testnets.GetLatestVersion() + testnets.NoError("failed to get latest version", err) + + log.Println("=== RUN E2EThroughput", "version:", latestVersion) + + // create a new testnet + testnet, err := testnets.New("E2EThroughput", seed, testnets.GetGrafanaInfoFromEnvVar()) + testnets.NoError("failed to create testnet", err) + + log.Println("Cleaning up testnet") + defer testnet.Cleanup() + + // add 2 validators + testnets.NoError("failed to create genesis nodes", testnet.CreateGenesisNodes(2, latestVersion, 10000000, 0, testnets.DefaultResources)) + + // obtain the GRPC endpoints of the validators + gRPCEndpoints, err := testnet.RemoteGRPCEndpoints() + testnets.NoError("failed to get validators GRPC endpoints", err) + log.Println("validators GRPC endpoints", gRPCEndpoints) + + // create txsim nodes and point them to the validators + log.Println("Creating txsim nodes") + // version of the txsim docker image to be used + txsimVersion := "a92de72" + + err = testnet.CreateTxClients(txsimVersion, 1, "10000-10000", testnets.DefaultResources, gRPCEndpoints) + testnets.NoError("failed to create tx clients", err) + + // start the testnet + log.Println("Setting up testnet") + testnets.NoError("failed to setup testnet", testnet.Setup()) + log.Println("Starting testnet") + testnets.NoError("failed to start testnet", testnet.Start()) + + // once the testnet is up, start the txsim + log.Println("Starting txsim nodes") + testnets.NoError("failed to start tx clients", testnet.StartTxClients()) + + // wait some time for the txsim to submit transactions + time.Sleep(1 * time.Minute) + + log.Println("Reading blockchain") + blockchain, err := testnode.ReadBlockchain(context.Background(), testnet.Node(0).AddressRPC()) + testnets.NoError("failed to read blockchain", err) + + totalTxs := 0 + for _, block := range blockchain { + if appconsts.LatestVersion != block.Version.App { + return fmt.Errorf("expected app version %d, got %d", appconsts.LatestVersion, block.Version.App) + } + totalTxs += len(block.Data.Txs) + } + if totalTxs < 10 { + return fmt.Errorf("expected at least 10 transactions, got %d", totalTxs) + } + log.Println("--- PASS ✅: E2EThroughput") + return nil +} diff --git a/test/e2e/upgrade_test.go b/test/e2e/check_upgrades.go similarity index 50% rename from test/e2e/upgrade_test.go rename to test/e2e/check_upgrades.go index d23c935aed..f8f751c4c4 100644 --- a/test/e2e/upgrade_test.go +++ b/test/e2e/check_upgrades.go @@ -1,74 +1,71 @@ -package e2e +package main import ( "context" "errors" "fmt" + "log" "math/rand" "os" + "os/exec" "strings" - "testing" "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/testnets" "github.com/celestiaorg/celestia-app/v2/test/txsim" "github.com/celestiaorg/knuu/pkg/knuu" - "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/rpc/client/http" ) -// This will only run tests within the v1 major release cycle -const MajorVersion = v1.Version +func MinorVersionCompatibility(logger *log.Logger) error { + os.Setenv("KNUU_NAMESPACE", "test") -func TestMinorVersionCompatibility(t *testing.T) { - // FIXME: This test currently panics in InitGenesis - t.Skip("test not working") - if os.Getenv("KNUU_NAMESPACE") != "test" { - t.Skip("skipping e2e test") - } - - if os.Getenv("E2E_VERSIONS") == "" { - t.Skip("skipping e2e test: E2E_VERSIONS not set") - } + versionStr, err := getAllVersions() + testnets.NoError("failed to get versions", err) + versions := testnets.ParseVersions(versionStr).FilterMajor(MajorVersion).FilterOutReleaseCandidates() - versionStr := os.Getenv("E2E_VERSIONS") - versions := ParseVersions(versionStr).FilterMajor(MajorVersion).FilterOutReleaseCandidates() if len(versions) == 0 { - t.Skip("skipping e2e test: no versions to test") + logger.Fatal("no versions to test") } numNodes := 4 r := rand.New(rand.NewSource(seed)) - t.Log("Running minor version compatibility test", "versions", versions) + logger.Println("Running minor version compatibility test", "versions", versions) + + testnet, err := testnets.New("runMinorVersionCompatibility", seed, nil) + testnets.NoError("failed to create testnet", err) + + defer testnet.Cleanup() - testnet, err := New(t.Name(), seed, GetGrafanaInfoFromEnvVar()) - require.NoError(t, err) - t.Cleanup(testnet.Cleanup) testnet.SetConsensusParams(app.DefaultInitialConsensusParams()) // preload all docker images preloader, err := knuu.NewPreloader() - require.NoError(t, err) - t.Cleanup(func() { _ = preloader.EmptyImages() }) + testnets.NoError("failed to create preloader", err) + + defer func() { _ = preloader.EmptyImages() }() for _, v := range versions { - err := preloader.AddImage(DockerImageName(v.String())) - require.NoError(t, err) + testnets.NoError("failed to add image", preloader.AddImage(testnets.DockerImageName(v.String()))) } for i := 0; i < numNodes; i++ { // each node begins with a random version within the same major version set v := versions.Random(r).String() - t.Log("Starting node", "node", i, "version", v) - require.NoError(t, testnet.CreateGenesisNode(v, 10000000, 0, defaultResources)) + logger.Println("Starting node", "node", i, "version", v) + testnets.NoError("failed to create genesis node", testnet.CreateGenesisNode(v, 10000000, 0, testnets.DefaultResources)) } kr, err := testnet.CreateAccount("alice", 1e12, "") - require.NoError(t, err) + testnets.NoError("failed to create account", err) - require.NoError(t, testnet.Setup()) - require.NoError(t, testnet.Start()) + // start the testnet + logger.Println("Setting up testnet") + testnets.NoError("Failed to setup testnet", testnet.Setup()) + logger.Println("Starting testnet") + testnets.NoError("Failed to start testnet", testnet.Start()) // TODO: with upgrade tests we should simulate a far broader range of transactions sequences := txsim.NewBlobSequence(txsim.NewRange(200, 4000), txsim.NewRange(1, 3)).Clone(5) @@ -90,33 +87,33 @@ func TestMinorVersionCompatibility(t *testing.T) { continue } client, err := testnet.Node(i % numNodes).Client() - require.NoError(t, err) + testnets.NoError("failed to get client", err) + heightBefore, err := getHeight(ctx, client, time.Second) - require.NoError(t, err) + testnets.NoError("failed to get height", err) + newVersion := versions.Random(r).String() - t.Log("Upgrading node", "node", i%numNodes, "version", newVersion) - err = testnet.Node(i % numNodes).Upgrade(newVersion) - require.NoError(t, err) + logger.Println("Upgrading node", "node", i%numNodes+1, "version", newVersion) + testnets.NoError("failed to upgrade node", testnet.Node(i%numNodes+1).Upgrade(newVersion)) // wait for the node to reach two more heights - err = waitForHeight(ctx, client, heightBefore+2, 30*time.Second) - require.NoError(t, err) + testnets.NoError("failed to wait for height", waitForHeight(ctx, client, heightBefore+2, 30*time.Second)) } heights := make([]int64, 4) for i := 0; i < numNodes; i++ { client, err := testnet.Node(i).Client() - require.NoError(t, err) + testnets.NoError("failed to get client", err) heights[i], err = getHeight(ctx, client, time.Second) - require.NoError(t, err) + testnets.NoError("failed to get height", err) } - t.Log("checking that all nodes are at the same height") + logger.Println("checking that all nodes are at the same height") const maxPermissableDiff = 2 for i := 0; i < len(heights); i++ { for j := i + 1; j < len(heights); j++ { diff := heights[i] - heights[j] if diff > maxPermissableDiff { - t.Fatalf("node %d is behind node %d by %d blocks", j, i, diff) + logger.Fatalf("node %d is behind node %d by %d blocks", j, i, diff) } } } @@ -125,54 +122,52 @@ func TestMinorVersionCompatibility(t *testing.T) { cancel() err = <-errCh - require.True(t, errors.Is(err, context.Canceled), err.Error()) -} -func TestMajorUpgradeToV2(t *testing.T) { - if os.Getenv("KNUU_NAMESPACE") != "test" { - t.Skip("skipping e2e test") + if !errors.Is(err, context.Canceled) { + return fmt.Errorf("expected context.Canceled error, got: %w", err) } + return nil +} - if os.Getenv("E2E_LATEST_VERSION") != "" { - latestVersion = os.Getenv("E2E_LATEST_VERSION") - _, isSemVer := ParseVersion(latestVersion) - switch { - case isSemVer: - case latestVersion == "latest": - case len(latestVersion) == 7: - case len(latestVersion) == 8: - // assume this is a git commit hash (we need to trim the last digit to match the docker image tag) - latestVersion = latestVersion[:7] - default: - t.Fatalf("unrecognised version: %s", latestVersion) - } - } +func MajorUpgradeToV2(logger *log.Logger) error { + os.Setenv("KNUU_NAMESPACE", "test") + + latestVersion, err := testnets.GetLatestVersion() + testnets.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() - testnet, err := New(t.Name(), seed, GetGrafanaInfoFromEnvVar()) - require.NoError(t, err) - t.Cleanup(testnet.Cleanup) + logger.Println("Creating testnet") + testnet, err := testnets.New("runMajorUpgradeToV2", seed, nil) + testnets.NoError("failed to create testnet", err) + + defer testnet.Cleanup() preloader, err := knuu.NewPreloader() - require.NoError(t, err) - t.Cleanup(func() { _ = preloader.EmptyImages() }) - err = preloader.AddImage(DockerImageName(latestVersion)) - require.NoError(t, err) + testnets.NoError("failed to create preloader", err) + + defer func() { _ = preloader.EmptyImages() }() + testnets.NoError("failed to add image", preloader.AddImage(testnets.DockerImageName(latestVersion))) + logger.Println("Creating genesis nodes") for i := 0; i < numNodes; i++ { - require.NoError(t, testnet.CreateGenesisNode(latestVersion, 10000000, - upgradeHeight, defaultResources)) + err := testnet.CreateGenesisNode(latestVersion, 10000000, upgradeHeight, testnets.DefaultResources) + testnets.NoError("failed to create genesis node", err) } kr, err := testnet.CreateAccount("alice", 1e12, "") - require.NoError(t, err) + testnets.NoError("failed to create account", err) + // start the testnet - require.NoError(t, testnet.Setup()) - require.NoError(t, testnet.Start()) + logger.Println("Setting up testnet") + testnets.NoError("Failed to setup testnet", testnet.Setup()) + logger.Println("Starting testnet") + testnets.NoError("Failed to start testnet", testnet.Start()) errCh := make(chan error) encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...) @@ -187,21 +182,32 @@ func TestMajorUpgradeToV2(t *testing.T) { heightBefore := upgradeHeight - 1 for i := 0; i < numNodes; i++ { client, err := testnet.Node(i).Client() - require.NoError(t, err) - require.NoError(t, waitForHeight(ctx, client, upgradeHeight, time.Minute)) + testnets.NoError("failed to get client", err) + + testnets.NoError("failed to wait for height", waitForHeight(ctx, client, upgradeHeight, time.Minute)) + resp, err := client.Header(ctx, &heightBefore) - require.NoError(t, err) - require.Equal(t, v1.Version, resp.Header.Version.App, "version mismatch before upgrade") + testnets.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) - require.NoError(t, err) - require.Equal(t, v2.Version, resp.Header.Version.App, "version mismatch after upgrade") + testnets.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 - require.True(t, strings.Contains(err.Error(), context.Canceled.Error()), err.Error()) + 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) { @@ -241,3 +247,13 @@ func waitForHeight(ctx context.Context, client *http.HTTP, height int64, period } } } + +func getAllVersions() (string, error) { + cmd := exec.Command("git", "tag", "-l") + output, err := cmd.Output() + if err != nil { + return "", fmt.Errorf("failed to get git tags: %v", err) + } + allVersions := strings.Split(strings.TrimSpace(string(output)), "\n") + return strings.Join(allVersions, " "), nil +} diff --git a/test/e2e/main.go b/test/e2e/main.go new file mode 100644 index 0000000000..d99c0a68c0 --- /dev/null +++ b/test/e2e/main.go @@ -0,0 +1,72 @@ +package main + +import ( + "log" + "os" + "strings" + + v1 "github.com/celestiaorg/celestia-app/v2/pkg/appconsts/v1" +) + +const ( + MajorVersion = v1.Version + seed = 42 +) + +type TestFunc func(*log.Logger) error + +type Test struct { + Name string + Func TestFunc +} + +func main() { + logger := log.New(os.Stdout, "test-e2e", log.LstdFlags) + + tests := []Test{ + // FIXME both tests are currently failing + // {"MinorVersionCompatibility", MinorVersionCompatibility}, + // {"MajorUpgradeToV2", MajorUpgradeToV2}, + {"E2ESimple", E2ESimple}, + } + + // check if a specific test is passed and run it + specificTestFound := false + for _, arg := range os.Args[1:] { + for _, test := range tests { + if test.Name == arg { + runTest(logger, test) + specificTestFound = true + break + } + } + } + + if !specificTestFound { + logger.Println("No particular test specified. Running all tests.") + logger.Println("go run test/e2e/*.go 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 { + runTest(logger, test) + } + } +} + +func runTest(logger *log.Logger, test Test) { + logger.SetPrefix(" ") + logger.Printf("=== RUN %s", test.Name) + err := test.Func(logger) + if err != nil { + logger.Fatalf("--- ERROR %s: %v", test.Name, err) + } + logger.Printf("--- ✅ PASS: %s \n\n", test.Name) +} + +func getTestNames(tests []Test) string { + testNames := make([]string, 0, len(tests)) + for _, test := range tests { + testNames = append(testNames, test.Name) + } + return strings.Join(testNames, ", ") +} diff --git a/test/e2e/readme.md b/test/e2e/readme.md index a20e942998..1f0b370d22 100644 --- a/test/e2e/readme.md +++ b/test/e2e/readme.md @@ -6,13 +6,30 @@ End to end tests pull docker images from ghcr.io/celestiaorg/celestia-app. These ## Usage -E2E tests can be simply run through go tests. They are distinguished from unit tests through an environment variable. To run all e2e tests run: +**Prerequisite: Requires a kubeconfig file.** + +You can run the End-to-End tests using either of the following commands: + +```shell +go run ./test/e2e``` ```shell -KNUU_NAMESPACE=test E2E_LATEST_VERSION="$(git rev-parse --short main)" E2E_VERSIONS="$(git tag -l)" go test ./test/e2e/... -timeout 30m -v +make test-e2e ``` -You can optionally set a global timeout using `KNUU_TIMEOUT` (default is 60m). +To run a specific test, you can pass the name of the test as a command-line argument. For example, to run the "E2ESimple" test, you would use either of the specified commands: + +```shell +go run ./test/e2e E2ESimple +``` + +```shell +make test-e2e E2ESimple +``` + +**Optional parameters**: + +- `KNUUU_TIMEOUT` can be used to override the default timeout of 60 minutes for the tests. ## Observation diff --git a/test/e2e/simple.go b/test/e2e/simple.go new file mode 100644 index 0000000000..c2d2911ccf --- /dev/null +++ b/test/e2e/simple.go @@ -0,0 +1,76 @@ +package main + +import ( + "context" + "errors" + "fmt" + "log" + "os" + "time" + + "github.com/celestiaorg/celestia-app/v2/app" + "github.com/celestiaorg/celestia-app/v2/app/encoding" + "github.com/celestiaorg/celestia-app/v2/pkg/appconsts" + "github.com/celestiaorg/celestia-app/v2/test/e2e/testnets" + "github.com/celestiaorg/celestia-app/v2/test/txsim" + "github.com/celestiaorg/celestia-app/v2/test/util/testnode" +) + +// This test runs a simple testnets with 4 validators. It submits both MsgPayForBlobs +// and MsgSends over 30 seconds and then asserts that at least 10 transactions were +// committed. +func E2ESimple(logger *log.Logger) error { + os.Setenv("KNUU_NAMESPACE", "test") + + latestVersion, err := testnets.GetLatestVersion() + testnets.NoError("failed to get latest version", err) + + logger.Println("Running simple e2e test", "version", latestVersion) + + testnet, err := testnets.New("E2ESimple", seed, nil) + testnets.NoError("failed to create testnets", err) + defer testnet.Cleanup() + + logger.Println("Creating testnets validators") + testnets.NoError("failed to create genesis nodes", testnet.CreateGenesisNodes(4, latestVersion, 10000000, 0, testnets.DefaultResources)) + + logger.Println("Creating account") + kr, err := testnet.CreateAccount("alice", 1e12, "") + testnets.NoError("failed to create account", err) + + logger.Println("Setting up testnets") + testnets.NoError("failed to setup testnets", testnet.Setup()) + + logger.Println("Starting testnets") + testnets.NoError("failed to start testnets", testnet.Start()) + + logger.Println("Running txsim") + sequences := txsim.NewBlobSequence(txsim.NewRange(200, 4000), txsim.NewRange(1, 3)).Clone(5) + sequences = append(sequences, txsim.NewSendSequence(4, 1000, 100).Clone(5)...) + + encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...) + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + opts := txsim.DefaultOptions().WithSeed(seed).SuppressLogs() + err = txsim.Run(ctx, testnet.GRPCEndpoints()[0], kr, encCfg, opts, sequences...) + + if !errors.Is(err, context.DeadlineExceeded) { + return fmt.Errorf("expected context.DeadlineExceeded, got %w", err) + } + + logger.Println("Reading blockchain") + blockchain, err := testnode.ReadBlockchain(context.Background(), testnet.Node(0).AddressRPC()) + testnets.NoError("failed to read blockchain", err) + + totalTxs := 0 + for _, block := range blockchain { + if appconsts.LatestVersion != block.Version.App { + return fmt.Errorf("expected app version %d, got %d in block %d", appconsts.LatestVersion, block.Version.App, block.Height) + } + totalTxs += len(block.Data.Txs) + } + if totalTxs < 10 { + return fmt.Errorf("expected at least 10 transactions, got %d", totalTxs) + } + return nil +} diff --git a/test/e2e/simple_test.go b/test/e2e/simple_test.go deleted file mode 100644 index b8a8c53be7..0000000000 --- a/test/e2e/simple_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package e2e - -import ( - "context" - "errors" - "os" - "testing" - "time" - - "github.com/celestiaorg/celestia-app/v2/app" - "github.com/celestiaorg/celestia-app/v2/app/encoding" - "github.com/celestiaorg/celestia-app/v2/pkg/appconsts" - "github.com/celestiaorg/celestia-app/v2/test/txsim" - "github.com/celestiaorg/celestia-app/v2/test/util/testnode" - "github.com/stretchr/testify/require" -) - -const seed = 42 - -var latestVersion = "latest" - -// This test runs a simple testnet with 4 validators. It submits both MsgPayForBlobs -// and MsgSends over 30 seconds and then asserts that at least 10 transactions were -// committed. -func TestE2ESimple(t *testing.T) { - if os.Getenv("KNUU_NAMESPACE") != "test" { - t.Skip("skipping e2e test") - } - - if os.Getenv("E2E_LATEST_VERSION") != "" { - latestVersion = os.Getenv("E2E_LATEST_VERSION") - _, isSemVer := ParseVersion(latestVersion) - switch { - case isSemVer: - case latestVersion == "latest": - case len(latestVersion) == 7: - case len(latestVersion) >= 8: - // assume this is a git commit hash (we need to trim the last digit to match the docker image tag) - latestVersion = latestVersion[:7] - default: - t.Fatalf("unrecognised version: %s", latestVersion) - } - } - t.Log("Running simple e2e test", "version", latestVersion) - - testnet, err := New(t.Name(), seed, GetGrafanaInfoFromEnvVar()) - require.NoError(t, err) - t.Cleanup(testnet.Cleanup) - - t.Log("Creating testnet validators") - require.NoError(t, testnet.CreateGenesisNodes(4, latestVersion, 10000000, - 0, defaultResources)) - - t.Log("Creating account") - kr, err := testnet.CreateAccount("alice", 1e12, "") - require.NoError(t, err) - - t.Log("Setting up testnet") - require.NoError(t, testnet.Setup()) - t.Log("Starting testnet") - require.NoError(t, testnet.Start()) - - t.Log("Running txsim") - sequences := txsim.NewBlobSequence(txsim.NewRange(200, 4000), txsim.NewRange(1, 3)).Clone(5) - sequences = append(sequences, txsim.NewSendSequence(4, 1000, 100).Clone(5)...) - - encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...) - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - opts := txsim.DefaultOptions().WithSeed(seed).SuppressLogs() - err = txsim.Run(ctx, testnet.GRPCEndpoints()[0], kr, encCfg, opts, sequences...) - require.True(t, errors.Is(err, context.DeadlineExceeded), err.Error()) - - t.Log("Reading blockchain") - blockchain, err := testnode.ReadBlockchain(context.Background(), testnet.Node(0).AddressRPC()) - require.NoError(t, err) - - totalTxs := 0 - for _, block := range blockchain { - require.Equal(t, appconsts.LatestVersion, block.Version.App) - totalTxs += len(block.Data.Txs) - } - require.Greater(t, totalTxs, 10) -} diff --git a/test/e2e/defaults.go b/test/e2e/testnets/defaults.go similarity index 66% rename from test/e2e/defaults.go rename to test/e2e/testnets/defaults.go index 41681f12ca..9641d164d2 100644 --- a/test/e2e/defaults.go +++ b/test/e2e/testnets/defaults.go @@ -1,6 +1,6 @@ -package e2e +package testnets -var defaultResources = Resources{ +var DefaultResources = Resources{ MemoryRequest: "200Mi", MemoryLimit: "200Mi", CPU: "300m", diff --git a/test/e2e/node.go b/test/e2e/testnets/node.go similarity index 99% rename from test/e2e/node.go rename to test/e2e/testnets/node.go index 61388ff167..b3d41ce58d 100644 --- a/test/e2e/node.go +++ b/test/e2e/testnets/node.go @@ -1,4 +1,4 @@ -package e2e +package testnets import ( "fmt" diff --git a/test/e2e/setup.go b/test/e2e/testnets/setup.go similarity index 98% rename from test/e2e/setup.go rename to test/e2e/testnets/setup.go index 810fd3dc71..266587e9f9 100644 --- a/test/e2e/setup.go +++ b/test/e2e/testnets/setup.go @@ -1,4 +1,4 @@ -package e2e +package testnets import ( "fmt" diff --git a/test/e2e/testnets/test_helpers.go b/test/e2e/testnets/test_helpers.go new file mode 100644 index 0000000000..7df9b783cd --- /dev/null +++ b/test/e2e/testnets/test_helpers.go @@ -0,0 +1,11 @@ +package testnets + +import ( + "log" +) + +func NoError(message string, err error) { + if err != nil { + log.Fatalf("%s: %v", message, err) + } +} diff --git a/test/e2e/testnet.go b/test/e2e/testnets/testnet.go similarity index 99% rename from test/e2e/testnet.go rename to test/e2e/testnets/testnet.go index 25c3926082..c818e97e92 100644 --- a/test/e2e/testnet.go +++ b/test/e2e/testnets/testnet.go @@ -1,4 +1,4 @@ -package e2e +package testnets import ( "context" diff --git a/test/e2e/txsimNode.go b/test/e2e/testnets/txsimNode.go similarity index 98% rename from test/e2e/txsimNode.go rename to test/e2e/testnets/txsimNode.go index 971aafb67e..6c8709db32 100644 --- a/test/e2e/txsimNode.go +++ b/test/e2e/testnets/txsimNode.go @@ -1,4 +1,4 @@ -package e2e +package testnets import ( "fmt" diff --git a/test/e2e/util.go b/test/e2e/testnets/util.go similarity index 98% rename from test/e2e/util.go rename to test/e2e/testnets/util.go index 5bf3bbcb7f..87067fefad 100644 --- a/test/e2e/util.go +++ b/test/e2e/testnets/util.go @@ -1,4 +1,4 @@ -package e2e +package testnets import ( "io" diff --git a/test/e2e/versions.go b/test/e2e/testnets/versions.go similarity index 76% rename from test/e2e/versions.go rename to test/e2e/testnets/versions.go index 51e0f5c329..2d029f3134 100644 --- a/test/e2e/versions.go +++ b/test/e2e/testnets/versions.go @@ -1,8 +1,9 @@ -package e2e +package testnets import ( "fmt" "math/rand" + "os/exec" "sort" "strings" ) @@ -76,6 +77,32 @@ func ParseVersion(version string) (Version, bool) { return Version{major, minor, patch, isRC, rc}, true } +// GetLatestVersion retrieves the latest git commit hash +// or semantic version of the main branch. +func GetLatestVersion() (string, error) { + cmd := exec.Command("git", "rev-parse", "--short", "main") + output, err := cmd.Output() + if err != nil { + return "", fmt.Errorf("failed to get git commit hash: %v", err) + } + latestVersion := string(output) + + _, isSemVer := ParseVersion(latestVersion) + switch { + case isSemVer: + return latestVersion, nil + case latestVersion == "latest": + return latestVersion, nil + case len(latestVersion) == 7: + return latestVersion, nil + case len(latestVersion) >= 8: + // assume this is a git commit hash (we need to trim the last digit to match the docker image tag) + return latestVersion[:7], nil + default: + return "", fmt.Errorf("unrecognised version %s", latestVersion) + } +} + func (v VersionSet) FilterMajor(majorVersion uint64) VersionSet { output := make(VersionSet, 0, len(v)) for _, version := range v { diff --git a/test/e2e/testnets/versions_test.go b/test/e2e/testnets/versions_test.go new file mode 100644 index 0000000000..f15bf69021 --- /dev/null +++ b/test/e2e/testnets/versions_test.go @@ -0,0 +1,49 @@ +package testnets_test + +import ( + "testing" + + "github.com/celestiaorg/celestia-app/v2/test/e2e/testnets" + "github.com/stretchr/testify/require" +) + +func TestVersionParsing(t *testing.T) { + versionStr := "v1.3.0 v1.1.0 v1.2.0-rc0" + versions := testnets.ParseVersions(versionStr) + require.Len(t, versions, 3) + require.Len(t, versions.FilterOutReleaseCandidates(), 2) + require.Equal(t, versions.GetLatest(), testnets.Version{1, 3, 0, false, 0}) +} + +// Test case with multiple major versions and filtering out a single major version +func TestFilterMajorVersions(t *testing.T) { + versionStr := "v2.0.0 v1.1.0 v2.1.0-rc0 v1.2.0 v2.2.0 v1.3.0" + versions := testnets.ParseVersions(versionStr) + require.Len(t, versions, 6) + require.Len(t, versions.FilterMajor(1), 3) +} + +// Test case to check the Order function +func TestOrder(t *testing.T) { + versionStr := "v1.3.0 v1.1.0 v1.2.0-rc0 v1.4.0 v1.2.1 v2.0.0" + versions := testnets.ParseVersions(versionStr) + versions.Order() + require.Equal(t, versions[0], testnets.Version{1, 1, 0, false, 0}) + require.Equal(t, versions[1], testnets.Version{1, 2, 0, true, 0}) + require.Equal(t, versions[2], testnets.Version{1, 2, 1, false, 0}) + require.Equal(t, versions[3], testnets.Version{1, 3, 0, false, 0}) + require.Equal(t, versions[4], testnets.Version{1, 4, 0, false, 0}) + require.Equal(t, versions[5], testnets.Version{2, 0, 0, false, 0}) + for i := len(versions) - 1; i > 0; i-- { + require.True(t, versions[i].IsGreater(versions[i-1])) + } +} + +func TestOrderOfReleaseCandidates(t *testing.T) { + versionsStr := "v1.0.0 v1.0.0-rc0 v1.0.0-rc1" + versions := testnets.ParseVersions(versionsStr) + versions.Order() + require.Equal(t, versions[0], testnets.Version{1, 0, 0, true, 0}) + require.Equal(t, versions[1], testnets.Version{1, 0, 0, true, 1}) + require.Equal(t, versions[2], testnets.Version{1, 0, 0, false, 0}) +} diff --git a/test/e2e/throughput_test.go b/test/e2e/throughput_test.go deleted file mode 100644 index 16848d1042..0000000000 --- a/test/e2e/throughput_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package e2e - -import ( - "context" - "os" - "testing" - "time" - - "github.com/celestiaorg/celestia-app/v2/pkg/appconsts" - "github.com/celestiaorg/celestia-app/v2/test/util/testnode" - "github.com/stretchr/testify/require" -) - -func TestE2EThroughput(t *testing.T) { - if os.Getenv("KNUU_NAMESPACE") != "test" { - t.Skip("skipping e2e throughput test") - } - - if os.Getenv("E2E_LATEST_VERSION") != "" { - latestVersion = os.Getenv("E2E_LATEST_VERSION") - _, isSemVer := ParseVersion(latestVersion) - switch { - case isSemVer: - case latestVersion == "latest": - case len(latestVersion) == 7: - case len(latestVersion) >= 8: - // assume this is a git commit hash (we need to trim the last digit to match the docker image tag) - latestVersion = latestVersion[:7] - default: - t.Fatalf("unrecognised version: %s", latestVersion) - } - } - - t.Log("Running throughput test", "version", latestVersion) - - // create a new testnet - testnet, err := New(t.Name(), seed, GetGrafanaInfoFromEnvVar()) - require.NoError(t, err) - t.Cleanup(func() { - t.Log("Cleaning up testnet") - testnet.Cleanup() - }) - - // add 2 validators - require.NoError(t, testnet.CreateGenesisNodes(2, latestVersion, 10000000, - 0, defaultResources)) - - // obtain the GRPC endpoints of the validators - gRPCEndpoints, err := testnet.RemoteGRPCEndpoints() - require.NoError(t, err) - t.Log("validators GRPC endpoints", gRPCEndpoints) - - // create txsim nodes and point them to the validators - t.Log("Creating txsim nodes") - // version of the txsim docker image to be used - txsimVersion := "a92de72" - - err = testnet.CreateTxClients(txsimVersion, 1, "10000-10000", defaultResources, gRPCEndpoints) - require.NoError(t, err) - - // start the testnet - t.Log("Setting up testnet") - require.NoError(t, testnet.Setup()) // configs, genesis files, etc. - t.Log("Starting testnet") - require.NoError(t, testnet.Start()) - - // once the testnet is up, start the txsim - t.Log("Starting txsim nodes") - err = testnet.StartTxClients() - require.NoError(t, err) - - // wait some time for the txsim to submit transactions - time.Sleep(1 * time.Minute) - - t.Log("Reading blockchain") - blockchain, err := testnode.ReadBlockchain(context.Background(), testnet.Node(0).AddressRPC()) - require.NoError(t, err) - - totalTxs := 0 - for _, block := range blockchain { - require.Equal(t, appconsts.LatestVersion, block.Version.App) - totalTxs += len(block.Data.Txs) - } - require.Greater(t, totalTxs, 10) -} diff --git a/test/e2e/versions_test.go b/test/e2e/versions_test.go deleted file mode 100644 index 605c5c5623..0000000000 --- a/test/e2e/versions_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package e2e_test - -import ( - "testing" - - "github.com/celestiaorg/celestia-app/v2/test/e2e" - "github.com/stretchr/testify/require" -) - -func TestVersionParsing(t *testing.T) { - versionStr := "v1.3.0 v1.1.0 v1.2.0-rc0" - versions := e2e.ParseVersions(versionStr) - require.Len(t, versions, 3) - require.Len(t, versions.FilterOutReleaseCandidates(), 2) - require.Equal(t, versions.GetLatest(), e2e.Version{1, 3, 0, false, 0}) -} - -// Test case with multiple major versions and filtering out a single major version -func TestFilterMajorVersions(t *testing.T) { - versionStr := "v2.0.0 v1.1.0 v2.1.0-rc0 v1.2.0 v2.2.0 v1.3.0" - versions := e2e.ParseVersions(versionStr) - require.Len(t, versions, 6) - require.Len(t, versions.FilterMajor(1), 3) -} - -// Test case to check the Order function -func TestOrder(t *testing.T) { - versionStr := "v1.3.0 v1.1.0 v1.2.0-rc0 v1.4.0 v1.2.1 v2.0.0" - versions := e2e.ParseVersions(versionStr) - versions.Order() - require.Equal(t, versions[0], e2e.Version{1, 1, 0, false, 0}) - require.Equal(t, versions[1], e2e.Version{1, 2, 0, true, 0}) - require.Equal(t, versions[2], e2e.Version{1, 2, 1, false, 0}) - require.Equal(t, versions[3], e2e.Version{1, 3, 0, false, 0}) - require.Equal(t, versions[4], e2e.Version{1, 4, 0, false, 0}) - require.Equal(t, versions[5], e2e.Version{2, 0, 0, false, 0}) - for i := len(versions) - 1; i > 0; i-- { - require.True(t, versions[i].IsGreater(versions[i-1])) - } -} - -func TestOrderOfReleaseCandidates(t *testing.T) { - versionsStr := "v1.0.0 v1.0.0-rc0 v1.0.0-rc1" - versions := e2e.ParseVersions(versionsStr) - versions.Order() - require.Equal(t, versions[0], e2e.Version{1, 0, 0, true, 0}) - require.Equal(t, versions[1], e2e.Version{1, 0, 0, true, 1}) - require.Equal(t, versions[2], e2e.Version{1, 0, 0, false, 0}) -}