From e74cc906769916af2626fbac2fdb65fd7dcd4fa7 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Fri, 28 Jul 2023 16:53:00 -0700 Subject: [PATCH 01/15] E2E State Sync Test --- .gitignore | 6 +- .tiltignore | 3 - Makefile | 34 ++-- app/client/cli/debug.go | 137 ++++++++++++--- build/config/README.md | 2 +- build/docs/CHANGELOG.md | 2 +- build/localnet/Tiltfile | 215 ++++++++++++++---------- build/scripts/watch.sh | 9 +- build/scripts/watch_build.sh | 8 - consensus/module_consensus_debugging.go | 6 +- docs/demos/iteration_3_end_to_end_tx.md | 4 +- docs/development/FAQ.md | 4 +- docs/development/README.md | 7 +- e2e/README.md | 27 ++- e2e/docs/E2E_ADR.md | 8 +- e2e/tests/debug.feature | 16 ++ e2e/tests/node.feature | 27 +++ e2e/tests/node.go | 76 +++++++++ e2e/tests/state_sync.feature | 20 +++ e2e/tests/steps_init_test.go | 201 +++++++++++++++++++--- e2e/tests/tilt_helpers.go | 36 ++++ e2e/tests/valdator.feature | 28 --- e2e/tests/validator.go | 67 -------- go.mod | 2 +- persistence/docs/CHANGELOG.md | 2 +- persistence/docs/README.md | 2 +- shared/modules/doc/CHANGELOG.md | 4 +- telemetry/README.md | 2 +- 28 files changed, 663 insertions(+), 292 deletions(-) delete mode 100755 build/scripts/watch_build.sh create mode 100644 e2e/tests/debug.feature create mode 100644 e2e/tests/node.feature create mode 100644 e2e/tests/node.go create mode 100644 e2e/tests/state_sync.feature create mode 100644 e2e/tests/tilt_helpers.go delete mode 100644 e2e/tests/valdator.feature delete mode 100644 e2e/tests/validator.go diff --git a/.gitignore b/.gitignore index d049b2729..4996b6c24 100644 --- a/.gitignore +++ b/.gitignore @@ -55,9 +55,6 @@ temp_test.go test_results.json coverage.out -# Output of `make build_and_watch` -main - # generated RPC server and client from openapi.yaml rpc/server.gen.go rpc/client.gen.go @@ -90,3 +87,6 @@ tools/wiki # ggshield .cache_ggshield + +# mock temporary files +**/gomock_reflect_*/ diff --git a/.tiltignore b/.tiltignore index 63afc9698..9a59a3fde 100644 --- a/.tiltignore +++ b/.tiltignore @@ -41,9 +41,6 @@ temp_test.go test_results.json coverage.out -# Output of `make build_and_watch` -main - # generated RPC server and client from openapi.yaml rpc/server.gen.go rpc/client.gen.go diff --git a/Makefile b/Makefile index 9ec1c636a..e3c289138 100644 --- a/Makefile +++ b/Makefile @@ -163,33 +163,27 @@ develop_test: docker_check ## Run all of the make commands necessary to develop make develop_start && \ make test_all -.PHONY: client_start -client_start: docker_check ## Run a client daemon which is only used for debugging purposes +.PHONY: lightweight_localnet_client +lightweight_localnet_client: docker_check ## Run a client daemon which is only used for debugging purposes +# Add `--build` to rebuild the client ${docker-compose} up -d client -.PHONY: rebuild_client_start -rebuild_client_start: docker_check ## Rebuild and run a client daemon which is only used for debugging purposes - ${docker-compose} up -d --build client - -.PHONY: client_connect -client_connect: docker_check ## Connect to the running client debugging daemon +.PHONY: lightweight_localnet_client_debug +lightweight_localnet_client_debug: docker_check ## Connect to the running client debugging daemon docker exec -it client /bin/bash -c "go run -tags=debug app/client/*.go DebugUI" -.PHONY: build_and_watch -build_and_watch: ## Continous build Pocket's main entrypoint as files change - /bin/sh ${PWD}/build/scripts/watch_build.sh +# IMPROVE: Avoid building the binary on every shell execution and sync it from local instead +.PHONY: lightweight_localnet_shell +lightweight_localnet_shell: docker_check ## Connect to the running client debugging daemon + docker exec -it client /bin/bash -c "go build -tags=debug -o p1 ./app/client/*.go && chmod +x p1 && mv p1 /usr/bin && echo \"Finished building a new p1 binary\" && /bin/bash" -# TODO(olshansky): Need to think of a Pocket related name for `compose_and_watch`, maybe just `pocket_watch`? -.PHONY: compose_and_watch -compose_and_watch: docker_check db_start monitoring_start ## Run a localnet composed of 4 consensus validators w/ hot reload & debugging +.PHONY: lightweight_localnet +lightweight_localnet: docker_check db_start monitoring_start ## Run a lightweight localnet composed of 4 validators w/ hot reload & debugging +# Add `--build` to rebuild the client ${docker-compose} up --force-recreate validator1 validator2 validator3 validator4 servicer1 fisherman1 -.PHONY: rebuild_and_compose_and_watch -rebuild_and_compose_and_watch: docker_check db_start monitoring_start ## Rebuilds the container from scratch and launches compose_and_watch - ${docker-compose} up --build --force-recreate validator1 validator2 validator3 validator4 servicer1 fisherman1 - .PHONY: db_start -db_start: docker_check ## Start a detached local postgres and admin instance; compose_and_watch is responsible for instantiating the actual schemas +db_start: docker_check ## Start a detached local postgres and admin instance; lightweight_localnet is responsible for instantiating the actual schemas ${docker-compose} up --no-recreate -d db pgadmin .PHONY: db_cli @@ -245,7 +239,7 @@ docker_wipe_nodes: docker_check prompt_user db_drop ## [WARNING] Remove all the docker ps -a -q --filter="name=node*" | xargs -r -I {} docker rm {} .PHONY: monitoring_start -monitoring_start: docker_check ## Start grafana, metrics and logging system (this is auto-triggered by compose_and_watch) +monitoring_start: docker_check ## Start grafana, metrics and logging system (this is auto-triggered by lightweight_localnet) ${docker-compose} up --no-recreate -d grafana loki vm .PHONY: docker_loki_install diff --git a/app/client/cli/debug.go b/app/client/cli/debug.go index 99d5b83de..ca5a1b764 100644 --- a/app/client/cli/debug.go +++ b/app/client/cli/debug.go @@ -1,10 +1,15 @@ package cli import ( + "fmt" + "log" "os" + "os/exec" + "time" "github.com/manifoldco/promptui" "github.com/spf13/cobra" + "golang.org/x/exp/slices" "google.golang.org/protobuf/types/known/anypb" "github.com/pokt-network/pocket/app/client/cli/helpers" @@ -34,43 +39,123 @@ var items = []string{ } func init() { + dbg := newDebugCommand() + dbg.AddCommand(newDebugSubCommands()...) + rootCmd.AddCommand(dbg) + dbgUI := newDebugUICommand() - dbgUI.AddCommand(newDebugUISubCommands()...) rootCmd.AddCommand(dbgUI) } -// newDebugUISubCommands builds out the list of debug subcommands by matching the -// handleSelect dispatch to the appropriate command. -// * To add a debug subcommand, you must add it to the `items` array and then -// write a function handler to match for it in `handleSelect`. -func newDebugUISubCommands() []*cobra.Command { - commands := make([]*cobra.Command, len(items)) - for idx, promptItem := range items { - commands[idx] = &cobra.Command{ - Use: promptItem, +// newDebugCommand returns the cobra CLI for the Debug command. +func newDebugCommand() *cobra.Command { + return &cobra.Command{ + Use: "Debug", + Aliases: []string{"d"}, + Short: "Debug utility for rapid development", + Long: "Debug utility to send fire-and-forget messages to the network for development purposes", + Args: cobra.MaximumNArgs(1), + } +} + +// newDebugSubCommands is a list of commands that can be "fired & forgotten" (no selection necessary) +func newDebugSubCommands() []*cobra.Command { + cmds := []*cobra.Command{ + { + Use: "PrintNodeState", + Aliases: []string{"print", "state"}, + Short: "Prints the node state", + Long: "Sends a message to all visible nodes to log the current state of their consensus", + Args: cobra.ExactArgs(0), PersistentPreRunE: helpers.P2PDependenciesPreRunE, - Run: func(cmd *cobra.Command, _ []string) { - handleSelect(cmd, cmd.Use) + Run: func(cmd *cobra.Command, args []string) { + runWithSleep(func() { + handleSelect(cmd, PromptPrintNodeState) + }) }, - ValidArgs: items, - } + }, + { + Use: "ResetToGenesis", + Aliases: []string{"reset", "genesis"}, + Short: "Reset to genesis", + Long: "Broadcast a message to all visible nodes to reset the state to genesis", + Args: cobra.ExactArgs(0), + PersistentPreRunE: helpers.P2PDependenciesPreRunE, + Run: func(cmd *cobra.Command, args []string) { + runWithSleep(func() { + handleSelect(cmd, PromptResetToGenesis) + }) + }, + }, + { + Use: "TriggerView", + Aliases: []string{"next", "trigger", "view"}, + Short: "Trigger the next view in consensus", + Long: "Sends a message to all visible nodes on the network to start the next view (height/step/round) in consensus", + Args: cobra.ExactArgs(0), + PersistentPreRunE: helpers.P2PDependenciesPreRunE, + Run: func(cmd *cobra.Command, args []string) { + runWithSleep(func() { + handleSelect(cmd, PromptTriggerNextView) + }) + }, + }, + { + Use: "TogglePacemakerMode", + Aliases: []string{"toggle", "pcm"}, + Short: "Toggle the pacemaker", + Long: "Toggle the consensus pacemaker either on or off so the chain progresses on its own or loses liveness", + Args: cobra.ExactArgs(0), + PersistentPreRunE: helpers.P2PDependenciesPreRunE, + Run: func(cmd *cobra.Command, args []string) { + runWithSleep(func() { + handleSelect(cmd, PromptTogglePacemakerMode) + }) + }, + }, + { + Use: "ScaleActor", + Aliases: []string{"scale"}, + Short: "Scales the number of actors up or down", + Long: "Scales the type of actor specified to the number provided", + Args: cobra.ExactArgs(2), + PersistentPreRunE: helpers.P2PDependenciesPreRunE, + Run: func(cmd *cobra.Command, args []string) { + actor := args[0] + numActors := args[1] + validActors := []string{"fishermen", "full_nodes", "servicers", "validators"} + if !slices.Contains(validActors, actor) { + logger.Global.Fatal().Msg("Invalid actor type provided") + } + sedCmd := exec.Command("sed", "-i", fmt.Sprintf("/%s:/,/count:/ s/count: [0-9]*/count: %s/", actor, numActors), "/usr/local/localnet_config.yaml") + err := sedCmd.Run() + if err != nil { + log.Fatal(err) + } + }, + }, } - return commands + return cmds } // newDebugUICommand returns the cobra CLI for the Debug UI interface. func newDebugUICommand() *cobra.Command { return &cobra.Command{ - Aliases: []string{"dui"}, Use: "DebugUI", - Short: "Debug selection ui for rapid development", + Aliases: []string{"dui"}, + Short: "Debug utility with an interactive UI for development purposes", + Long: "Opens a shell-driven selection UI to view and select from a list of debug actions for development purposes", Args: cobra.MaximumNArgs(0), PersistentPreRunE: helpers.P2PDependenciesPreRunE, - RunE: runDebug, + RunE: selectDebugCommand, } } -func runDebug(cmd *cobra.Command, _ []string) (err error) { +// selectDebugCommand builds out the list of debug subcommands by matching the +// handleSelect dispatch to the appropriate command. +// - To add a debug subcommand, you must add it to the `items` array and then +// write a function handler to match for it in `handleSelect`. +func selectDebugCommand(cmd *cobra.Command, _ []string) error { for { if selection, err := promptGetInput(); err == nil { handleSelect(cmd, selection) @@ -158,7 +243,17 @@ func handleSelect(cmd *cobra.Command, selection string) { } } -// Broadcast to the entire network. +// HACK: Because of how the p2p module works, we need to surround it with sleep both BEFORE and AFTER the task. +// - Starting the task too early after the debug client initializes results in a lack of visibility of the nodes in the network +// - Ending the task too early before the debug client completes its task results in a lack of propagation of the message or retrieval of the result +// TECHDEBT: There is likely an event based solution to this but it would require a lot more refactoring of the p2p module. +func runWithSleep(task func()) { + time.Sleep(1000 * time.Millisecond) + task() + time.Sleep(1000 * time.Millisecond) +} + +// broadcastDebugMessage broadcasts the debug message to the entire visible network. func broadcastDebugMessage(cmd *cobra.Command, debugMsg *messaging.DebugMessage) { anyProto, err := anypb.New(debugMsg) if err != nil { @@ -174,7 +269,7 @@ func broadcastDebugMessage(cmd *cobra.Command, debugMsg *messaging.DebugMessage) } } -// Send to just a single (i.e. first) validator in the set +// sendDebugMessage sends the debug message to just a single (i.e. first) node visible func sendDebugMessage(cmd *cobra.Command, debugMsg *messaging.DebugMessage) { anyProto, err := anypb.New(debugMsg) if err != nil { diff --git a/build/config/README.md b/build/config/README.md index 24d8d110c..fffb1883b 100644 --- a/build/config/README.md +++ b/build/config/README.md @@ -12,7 +12,7 @@ It is not recommended at this time to build infrastructure components that rely ## Origin Document -Currently, the Genesis and Configuration generator is necessary to create development `localnet` environments for iterating on V1. A current example (as of 09/2022) of this is the `make compose_and_watch` debug utility that generates a `localnet` using `docker-compose` by injecting the appropriate `config.json` and `genesis.json` files. +Currently, the Genesis and Configuration generator is necessary to create development `localnet` environments for iterating on V1. A current example (as of 09/2022) of this is the `make lightweight_localnet` debug utility that generates a `localnet` using `docker-compose` by injecting the appropriate `config.json` and `genesis.json` files. ## Usage diff --git a/build/docs/CHANGELOG.md b/build/docs/CHANGELOG.md index a23ab1698..aec7e163e 100644 --- a/build/docs/CHANGELOG.md +++ b/build/docs/CHANGELOG.md @@ -233,7 +233,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.0.0.1] - 2022-12-29 - Updated all `config*.json` files with the missing `max_mempool_count` value -- Added `is_client_only` to `config1.json` so Viper knows it can be overridden. The config override is done in the Makefile's `client_connect` target. Setting this can be avoided if we merge the changes in https://github.com/pokt-network/pocket/compare/main...issue/cli-viper-environment-vars-fix +- Added `is_client_only` to `config1.json` so Viper knows it can be overridden. The config override is done in the Makefile's `lightweight_localnet_client_debug` target. Setting this can be avoided if we merge the changes in https://github.com/pokt-network/pocket/compare/main...issue/cli-viper-environment-vars-fix ## [0.0.0.0] - 2022-12-22 diff --git a/build/localnet/Tiltfile b/build/localnet/Tiltfile index 9f5a36b4c..9fc086763 100644 --- a/build/localnet/Tiltfile +++ b/build/localnet/Tiltfile @@ -2,7 +2,8 @@ load("ext://helm_resource", "helm_resource", "helm_repo") load("ext://namespace", "namespace_create") load("ext://restart_process", "docker_build_with_restart") -load('ext://tests/golang', 'test_go') +load("ext://tests/golang", "test_go") +load("ext://syncback", "syncback") tiltfile_dir = os.path.dirname(config.main_dir) root_dir = os.path.dirname(tiltfile_dir + "/../..") @@ -13,7 +14,7 @@ localnet_config_defaults = { "validators": {"count": 4}, "servicers": {"count": 1}, "fishermen": {"count": 1}, - "full_nodes": {"count": 1} + "full_nodes": {"count": 1}, } localnet_config_file = read_yaml(localnet_config_path, default=localnet_config_defaults) @@ -22,6 +23,7 @@ localnet_config = {} localnet_config.update(localnet_config_defaults) localnet_config.update(localnet_config_file) + # Create a default config file if it does not exist if (localnet_config_file != localnet_config) or ( not os.path.exists(localnet_config_path) @@ -29,6 +31,15 @@ if (localnet_config_file != localnet_config) or ( print("Updating " + localnet_config_path + " with defaults") local("cat - > " + localnet_config_path, stdin=encode_yaml(localnet_config)) +syncback( + name="syncback_localnet_config", + k8s_object="deploy/dev-cli-client", + src_dir="/usr/local/", + paths=["localnet_config.yaml"], + target_dir=root_dir, + labels=["watchers"], +) + # List of directories Tilt watches to trigger a hot-reload on changes. # CONSIDERATION: This can potentially can be replaced with a list of excluded directories. deps = [ @@ -49,6 +60,7 @@ deps = [ deps_full_path = [root_dir + "/" + depdir for depdir in deps] + # Avoid downloading dependencies if no missing/outdated charts are found def check_helm_dependencies_for_chart(path): check_helm_dependencies = local( @@ -58,6 +70,7 @@ def check_helm_dependencies_for_chart(path): if helm_dependencies_not_ok_count > 1: local("helm dependency update " + path) + check_helm_dependencies_for_chart("dependencies") k8s_yaml(helm("dependencies", name="dependencies")) @@ -78,7 +91,7 @@ local_resource( root_dir=root_dir ), deps=deps_full_path, - labels=['watchers'] + labels=["watchers"], ) local_resource( "debug client: Watch & Compile", @@ -86,16 +99,16 @@ local_resource( root_dir=root_dir ), deps=deps_full_path, - labels=['watchers'] + labels=["watchers"], ) # Builds the cluster manager binary local_resource( - 'cluster manager: Watch & Compile', - 'GOOS=linux go build -o {root_dir}/bin/cluster-manager {root_dir}/build/localnet/cluster-manager/*.go'.format( + "cluster manager: Watch & Compile", + "GOOS=linux go build -o {root_dir}/bin/cluster-manager {root_dir}/build/localnet/cluster-manager/*.go".format( root_dir=root_dir ), deps=deps_full_path, - labels=['watchers'] + labels=["watchers"], ) # Builds and maintains the pocket container image after the binary is built on local machine, restarts a process on code change @@ -126,10 +139,14 @@ RUN echo "source /etc/bash_completion" >> ~/.bashrc RUN echo "source <(p1 completion bash | tail -n +2)" >> ~/.bashrc WORKDIR /root COPY bin/p1-linux /usr/local/bin/p1 +COPY localnet_config.yaml /usr/local/localnet_config.yaml """, - only=["bin/p1-linux"], + only=["bin/p1-linux", localnet_config_path], entrypoint=["sleep", "infinity"], - live_update=[sync("bin/p1-linux", "/usr/local/bin/p1")], + live_update=[ + sync("bin/p1-linux", "/usr/local/bin/p1"), + sync(localnet_config_path, "/usr/local/localnet_config.yaml"), + ], ) # Builds and maintains the cluster-manager container image after the binary is built on local machine @@ -141,12 +158,12 @@ WORKDIR / COPY bin/cluster-manager /usr/local/bin/cluster-manager COPY bin/p1-linux /usr/local/bin/p1 """, - only=['bin/cluster-manager', 'bin/p1-linux'], + only=["bin/cluster-manager", "bin/p1-linux"], entrypoint=["/usr/local/bin/cluster-manager"], live_update=[ sync("bin/cluster-manager", "/usr/local/bin/cluster-manager"), sync("bin/p1-linux", "/usr/local/bin/p1"), - ] + ], ) # Pushes localnet manifests to the cluster. @@ -162,9 +179,9 @@ k8s_yaml( ) k8s_yaml(["manifests/cli-client.yaml"]) -k8s_resource('dev-cli-client', labels=['client']) -k8s_yaml(['manifests/cluster-manager.yaml']) -k8s_resource('pocket-v1-cluster-manager', labels=['cluster-manager']) +k8s_resource("dev-cli-client", labels=["client"]) +k8s_yaml(["manifests/cluster-manager.yaml"]) +k8s_resource("pocket-v1-cluster-manager", labels=["cluster-manager"]) chart_dir = root_dir + "/charts/pocket" check_helm_dependencies_for_chart(chart_dir) @@ -173,28 +190,35 @@ check_helm_dependencies_for_chart(chart_dir) def formatted_actor_number(n): return local('printf "%03d" ' + str(n)) + # Provisions validators actor_number = 0 for x in range(localnet_config["validators"]["count"]): actor_number = actor_number + 1 formatted_number = formatted_actor_number(actor_number) - k8s_yaml(helm(chart_dir, - name="validator-%s-pocket" % formatted_number, - set=[ - "global.postgresql.auth.postgresPassword=LocalNetPassword", - "image.repository=pocket-image", - "privateKeySecretKeyRef.name=validators-private-keys", - "privateKeySecretKeyRef.key=%s" % formatted_number, - "genesis.preProvisionedGenesis.enabled=false", - "genesis.externalConfigMap.name=v1-localnet-genesis", - "genesis.externalConfigMap.key=genesis.json", - "postgresql.primary.persistence.enabled=false", - "nodeType=validator", - ], - values=[chart_dir + "/pocket-validator-overrides.yaml"] if os.path.exists(chart_dir + "/pocket-validator-overrides.yaml") else [],)) - - k8s_resource("validator-%s-pocket" % formatted_number, labels=['pocket-validators']) + k8s_yaml( + helm( + chart_dir, + name="validator-%s-pocket" % formatted_number, + set=[ + "global.postgresql.auth.postgresPassword=LocalNetPassword", + "image.repository=pocket-image", + "privateKeySecretKeyRef.name=validators-private-keys", + "privateKeySecretKeyRef.key=%s" % formatted_number, + "genesis.preProvisionedGenesis.enabled=false", + "genesis.externalConfigMap.name=v1-localnet-genesis", + "genesis.externalConfigMap.key=genesis.json", + "postgresql.primary.persistence.enabled=false", + "nodeType=validator", + ], + values=[chart_dir + "/pocket-validator-overrides.yaml"] + if os.path.exists(chart_dir + "/pocket-validator-overrides.yaml") + else [], + ) + ) + + k8s_resource("validator-%s-pocket" % formatted_number, labels=["pocket-validators"]) # Provisions servicer nodes actor_number = 0 @@ -202,23 +226,29 @@ for x in range(localnet_config["servicers"]["count"]): actor_number = actor_number + 1 formatted_number = formatted_actor_number(actor_number) - k8s_yaml(helm(chart_dir, - name="servicer-%s-pocket" % formatted_number, - set=[ - "global.postgresql.auth.postgresPassword=LocalNetPassword", - "image.repository=pocket-image", - "privateKeySecretKeyRef.name=servicers-private-keys", - "privateKeySecretKeyRef.key=%s" % formatted_number, - "genesis.preProvisionedGenesis.enabled=false", - "genesis.externalConfigMap.name=v1-localnet-genesis", - "genesis.externalConfigMap.key=genesis.json", - "postgresql.primary.persistence.enabled=false", - "config.servicer.enabled=true", - "nodeType=servicer", - ], - values=[chart_dir + "/pocket-servicer-overrides.yaml"] if os.path.exists(chart_dir + "/pocket-servicer-overrides.yaml") else [],)) - - k8s_resource("servicer-%s-pocket" % formatted_number, labels=['pocket-servicers']) + k8s_yaml( + helm( + chart_dir, + name="servicer-%s-pocket" % formatted_number, + set=[ + "global.postgresql.auth.postgresPassword=LocalNetPassword", + "image.repository=pocket-image", + "privateKeySecretKeyRef.name=servicers-private-keys", + "privateKeySecretKeyRef.key=%s" % formatted_number, + "genesis.preProvisionedGenesis.enabled=false", + "genesis.externalConfigMap.name=v1-localnet-genesis", + "genesis.externalConfigMap.key=genesis.json", + "postgresql.primary.persistence.enabled=false", + "config.servicer.enabled=true", + "nodeType=servicer", + ], + values=[chart_dir + "/pocket-servicer-overrides.yaml"] + if os.path.exists(chart_dir + "/pocket-servicer-overrides.yaml") + else [], + ) + ) + + k8s_resource("servicer-%s-pocket" % formatted_number, labels=["pocket-servicers"]) # Provisions fishermen nodes actor_number = 0 @@ -226,23 +256,29 @@ for x in range(localnet_config["fishermen"]["count"]): actor_number = actor_number + 1 formatted_number = formatted_actor_number(actor_number) - k8s_yaml(helm(chart_dir, - name="fisherman-%s-pocket" % formatted_number, - set=[ - "global.postgresql.auth.postgresPassword=LocalNetPassword", - "image.repository=pocket-image", - "privateKeySecretKeyRef.name=fishermen-private-keys", - "privateKeySecretKeyRef.key=%s" % formatted_number, - "genesis.preProvisionedGenesis.enabled=false", - "genesis.externalConfigMap.name=v1-localnet-genesis", - "genesis.externalConfigMap.key=genesis.json", - "postgresql.primary.persistence.enabled=false", - "config.fisherman.enabled=true", - "nodeType=fisherman", - ], - values=[chart_dir + "/pocket-fisherman-overrides.yaml"] if os.path.exists(chart_dir + "/pocket-fisherman-overrides.yaml") else [],)) - - k8s_resource("fisherman-%s-pocket" % formatted_number, labels=['pocket-fishermen']) + k8s_yaml( + helm( + chart_dir, + name="fisherman-%s-pocket" % formatted_number, + set=[ + "global.postgresql.auth.postgresPassword=LocalNetPassword", + "image.repository=pocket-image", + "privateKeySecretKeyRef.name=fishermen-private-keys", + "privateKeySecretKeyRef.key=%s" % formatted_number, + "genesis.preProvisionedGenesis.enabled=false", + "genesis.externalConfigMap.name=v1-localnet-genesis", + "genesis.externalConfigMap.key=genesis.json", + "postgresql.primary.persistence.enabled=false", + "config.fisherman.enabled=true", + "nodeType=fisherman", + ], + values=[chart_dir + "/pocket-fisherman-overrides.yaml"] + if os.path.exists(chart_dir + "/pocket-fisherman-overrides.yaml") + else [], + ) + ) + + k8s_resource("fisherman-%s-pocket" % formatted_number, labels=["pocket-fishermen"]) # Provisions full nodes actor_number = 0 @@ -250,22 +286,28 @@ for x in range(localnet_config["full_nodes"]["count"]): actor_number = actor_number + 1 formatted_number = formatted_actor_number(actor_number) - k8s_yaml(helm(root_dir + "/charts/pocket", - name="full-node-%s-pocket" % formatted_number, - set=[ - "global.postgresql.auth.postgresPassword=LocalNetPassword", - "image.repository=pocket-image", - "privateKeySecretKeyRef.name=misc-private-keys", - "privateKeySecretKeyRef.key=%s" % formatted_number, - "genesis.preProvisionedGenesis.enabled=false", - "genesis.externalConfigMap.name=v1-localnet-genesis", - "genesis.externalConfigMap.key=genesis.json", - "postgresql.primary.persistence.enabled=false", - "nodeType=full", - ], - values=[chart_dir + "/pocket-full-node-overrides.yaml"] if os.path.exists(chart_dir + "/pocket-full-node-overrides.yaml") else [],)) - - k8s_resource("full-node-%s-pocket" % formatted_number, labels=['pocket-full-nodes']) + k8s_yaml( + helm( + root_dir + "/charts/pocket", + name="full-node-%s-pocket" % formatted_number, + set=[ + "global.postgresql.auth.postgresPassword=LocalNetPassword", + "image.repository=pocket-image", + "privateKeySecretKeyRef.name=misc-private-keys", + "privateKeySecretKeyRef.key=%s" % formatted_number, + "genesis.preProvisionedGenesis.enabled=false", + "genesis.externalConfigMap.name=v1-localnet-genesis", + "genesis.externalConfigMap.key=genesis.json", + "postgresql.primary.persistence.enabled=false", + "nodeType=full", + ], + values=[chart_dir + "/pocket-full-node-overrides.yaml"] + if os.path.exists(chart_dir + "/pocket-full-node-overrides.yaml") + else [], + ) + ) + + k8s_resource("full-node-%s-pocket" % formatted_number, labels=["pocket-full-nodes"]) # Exposes grafana k8s_resource( @@ -273,12 +315,15 @@ k8s_resource( workload="dependencies-grafana", extra_pod_selectors=[{"app.kubernetes.io/name": "grafana"}], port_forwards=["42000:3000"], - labels=["monitoring"] + labels=["monitoring"], ) # E2E test button -test_go('e2e-tests', '{root_dir}/e2e/tests'.format(root_dir=root_dir), '.', - extra_args=["-v", "-count=1", "-tags=e2e"], - labels=['e2e-tests'], - trigger_mode=TRIGGER_MODE_MANUAL, +test_go( + "e2e-tests", + "{root_dir}/e2e/tests".format(root_dir=root_dir), + ".", + extra_args=["-v", "-count=1", "-tags=e2e"], + labels=["e2e-tests"], + trigger_mode=TRIGGER_MODE_MANUAL, ) diff --git a/build/scripts/watch.sh b/build/scripts/watch.sh index 01d55d544..b2fbdd892 100755 --- a/build/scripts/watch.sh +++ b/build/scripts/watch.sh @@ -19,7 +19,8 @@ else fi reflex \ - --start-service \ - -r '\.go' \ - --decoration="none" \ - -s -- sh -c "$command"; + --start-service \ + -R '^app/client' \ + -r '\.go' \ + --decoration="none" \ + -s -- sh -c "$command" diff --git a/build/scripts/watch_build.sh b/build/scripts/watch_build.sh deleted file mode 100755 index 5f5e5b920..000000000 --- a/build/scripts/watch_build.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -if command -v reflex >/dev/null -then - reflex -r '\.go$' -s --decoration="none" -- sh -c "go build -v app/pocket/main.go" -else - echo "reflex not found. Install with `go install github.com/cespare/reflex@latest`" -fi diff --git a/consensus/module_consensus_debugging.go b/consensus/module_consensus_debugging.go index a302f1444..137643df6 100644 --- a/consensus/module_consensus_debugging.go +++ b/consensus/module_consensus_debugging.go @@ -13,11 +13,11 @@ func (m *consensusModule) HandleDebugMessage(debugMessage *messaging.DebugMessag m.m.Lock() defer m.m.Unlock() + m.logger.Debug().Msgf("Consensus module handling debug message: %s", debugMessage.Action) + switch debugMessage.Action { case messaging.DebugMessageAction_DEBUG_CONSENSUS_RESET_TO_GENESIS: - if err := m.resetToGenesis(debugMessage); err != nil { - return err - } + return m.resetToGenesis(debugMessage) case messaging.DebugMessageAction_DEBUG_CONSENSUS_PRINT_NODE_STATE: m.printNodeState(debugMessage) case messaging.DebugMessageAction_DEBUG_CONSENSUS_TRIGGER_NEXT_VIEW: diff --git a/docs/demos/iteration_3_end_to_end_tx.md b/docs/demos/iteration_3_end_to_end_tx.md index 1ace95335..86d2dab19 100644 --- a/docs/demos/iteration_3_end_to_end_tx.md +++ b/docs/demos/iteration_3_end_to_end_tx.md @@ -43,13 +43,13 @@ make protogen_local # generate the protobuf files make generate_rpc_openapi # generate the OpenAPI spec make docker_wipe_nodes # clear all the 4 validator nodes make db_drop # clear the existing database -make compose_and_watch # Start 4 validator node LocalNet +make lightweight_localnet # Start 4 validator node LocalNet ``` ## Shell #2: Setup Consensus debugger ```bash -make client_start && make client_connect # start the consensus debugger +make lightweight_localnet_client && make lightweight_localnet_client_debug # start the consensus debugger ``` Use `TriggerNextView` and `PrintNodeState` to increment and inspect each node's `height/round/step`. diff --git a/docs/development/FAQ.md b/docs/development/FAQ.md index 4d4eaf1ff..8b7de79a7 100644 --- a/docs/development/FAQ.md +++ b/docs/development/FAQ.md @@ -11,9 +11,9 @@ _NOTE: Consider turning off the `gofmt` in your IDE to prevent unexpected format ## Unable to start LocalNet - permission denied -- **Issue**: when trying to run `make compose_and_watch` on an operating system with SELinux, the command gives the error: +- **Issue**: when trying to run `make lightweight_localnet` on an operating system with SELinux, the command gives the error: -``` +```bash Recreating validator2 ... done Recreating validator4 ... done Recreating validator1 ... done diff --git a/docs/development/README.md b/docs/development/README.md index 3f62d8a6b..84dfad020 100644 --- a/docs/development/README.md +++ b/docs/development/README.md @@ -86,6 +86,7 @@ Optionally activate changelog pre-commit hook cp .githooks/pre-commit .git/hooks/pre-commit chmod +x .git/hooks/pre-commit ``` + _**NOTE**: The pre-commit changelog verification has been disabled during the developement of V1 as of 2023-05-16 to unblock development velocity; see more details [here](https://github.com/pokt-network/pocket/assets/1892194/394fdb09-e388-44aa-820d-e9d5a23578cf). This check is no longer done in the CI and is not recommended for local development either currently._ ### Pocket Network CLI @@ -167,7 +168,7 @@ Note that there are a few tests in the library that are prone to race conditions ### Running LocalNet -At the time of writing, we have two basic approaches to running a LocalNet. We suggest getting started with the `Docker Compose` approach outlined below before moving to the advanced Kubernetes configuration. +At the time of writing, we have two basic approaches to running a LocalNet. We suggest getting started with the `Docker Compose` (aka `lightweight LocalNet`) approach outlined below before moving to the advanced Kubernetes (aka LocalNet) configuration. #### [Advanced] Kubernetes @@ -186,13 +187,13 @@ make docker_wipe 2. In one shell, run the 4 nodes setup: ```bash -make compose_and_watch +make lightweight_localnet ``` 4. In another shell, run the development client: ```bash -make client_start && make client_connect +make lightweight_localnet_client && make lightweight_localnet_client_debug ``` 4. Check the state of each node: diff --git a/e2e/README.md b/e2e/README.md index a87c4fcf2..5e3ee41c9 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -7,6 +7,7 @@ - [Build Tags](#build-tags) - [Issue templates](#issue-templates) - [Implementation](#implementation) +- [Keywords](#keywords) > tl; dr - `make localnet_up` and then `make test_e2e` @@ -35,8 +36,8 @@ Issues can formally define features by attaching an erroring `feature` file to b ```gherkin Feature: Example Namespace - Scenario: User Needs Example - Given the user has a validator + Scenario: User Needs Example + Given the user has a node When the user runs the command "example" Then the user should be able to see standard output containing "Example Output" And the pocket client should have exited without error @@ -46,7 +47,7 @@ Feature: Example Namespace The test suite is located in `e2e/tests` and it contains a set of Cucumber feature files and the associated Go tests to run them. `make test_e2e` sees any files named with the pattern `*.feature` in `e2e/tests` and runs them with [godog](https://github.com/cucumber/godog), the Go test runner for Cucumber tests. The LocalNet must be up and running for the E2E test suite to run. -The Validator issues RPC commands on the container by calling `kubectl exec` and targeting the pod in the cluster by name. It records the results of the command including stdout and stderr, allowing for assertions about the results of the command. +The Node issues RPC commands on the container by calling `kubectl exec` and targeting the pod in the cluster by name. It records the results of the command including stdout and stderr, allowing for assertions about the results of the command. ```mermaid --- @@ -60,10 +61,26 @@ flowchart TD Kubeconfig --> Kubectl Kubeconfig --> DevNet subgraph E2E [E2E scenarios] - Kubectl -- commandResult --> Validator - Validator -- args --> Kubectl + Kubectl -- commandResult --> Node + Node -- args --> Kubectl end subgraph DevNet [DevNet] Runner[E2E Test Runner] end ``` + +## Keywords + +The keywords below are a summary of the source documentation available [here](https://cucumber.io/docs/gherkin/reference/#keywords). + +- **Feature**: This keyword, followed by the name and optional description, is used to describe a feature of the system that you're testing. It should provide a high-level description of a software feature, and to group related scenarios. +- **Scenario**: This keyword, followed by the name and optional description, is used to describe a particular behavior of the system that you're testing. A feature can have multiple scenarios, and each scenario should follow the 'Given-When-Then' structure. +- **Given**: This keyword is used to set up a situation or a context. It puts the system in a known state before the user interacts with the system. +- **When**: This keyword is used to describe an action or event. This is something the user does or the system does. +- **Then**: This keyword is used to describe an expected outcome or result. +- **And**, But: These keywords are used when you have more than one Given, When, or Then step. They help to make the specifications more readable. +- **Background**: This keyword provides the context for the following scenarios. It allows you to add some context to the scenarios in a single place. +- **Scenario Outline**: This keyword can be used when the same test is performed multiple times with a different combination of values. +- **Examples**: This keyword is used in conjunction with **Scenario Outline** to provide the values for the test. +- **Rule**: This keyword is used to represent one business rule that should be implemented. It provides additional information for a feature. +- **Tags**: This is not a Gherkin keyword but an integral part of organizing your Cucumber features. They are preceded by '@' symbol and can be used before Feature, Scenario, Scenario Outline, or Examples. diff --git a/e2e/docs/E2E_ADR.md b/e2e/docs/E2E_ADR.md index d3e7dee53..59a7546dd 100644 --- a/e2e/docs/E2E_ADR.md +++ b/e2e/docs/E2E_ADR.md @@ -124,16 +124,16 @@ type PocketClient interface { ``` - The `PocketClient` interface is included in the test suite and defines a single function interface with the `RunCommand` method. -- The `validatorPod` adapter fulfills the `PocketClient` interface and lets us call commands through Kubernetes. This is the main way that tests assemble the environment for later assertions. +- The `nodePod` adapter fulfills the `PocketClient` interface and lets us call commands through Kubernetes. This is the main way that tests assemble the environment for later assertions. ```go -// validatorPod holds the connection information to pod validator-001 for testing -type validatorPod struct { +// nodePod holds the connection information to pod validator-001 for testing +type nodePod struct { result *commandResult // stores the result of the last command that was run } // RunCommand runs a command on the pocket binary -func (v *validatorPod) RunCommand(args ...string) (*commandResult, error) { +func (v *nodePod) RunCommand(args ...string) (*commandResult, error) { base := []string{ "exec", "-i", "deploy/pocket-v1-cli-client", "--container", "pocket", diff --git a/e2e/tests/debug.feature b/e2e/tests/debug.feature new file mode 100644 index 000000000..e33bf33a7 --- /dev/null +++ b/e2e/tests/debug.feature @@ -0,0 +1,16 @@ +Feature: Debug Namespace + + # Since the configuration for consensus is optimistically responsive, we need to be in manual + # Pacemaker mode and call TriggerView to further the blockchain. + # 1 second was chosen arbitrarily for the time for block propagation. + Scenario: 4 Validator blockchain from genesis reaches block 2 when TriggerView is executed twice + Given the network is at genesis + And the network has "4" actors of type "Validator" + When the developer runs the command "TriggerView" + And the developer waits for "1000" milliseconds + Then "validator-001" should be at height "1" + And "validator-004" should be at height "1" + When the developer runs the command "TriggerView" + And the developer waits for "1000" milliseconds + Then "validator-001" should be at height "2" + And "validator-004" should be at height "2" \ No newline at end of file diff --git a/e2e/tests/node.feature b/e2e/tests/node.feature new file mode 100644 index 000000000..69e1cc26f --- /dev/null +++ b/e2e/tests/node.feature @@ -0,0 +1,27 @@ +Feature: Node Namespace + + Scenario: User Wants Help Using The Node Command + Given the user has a node + When the user runs the command "Node help" + Then the user should be able to see standard output containing "Available Commands" + And the node should have exited without error + + Scenario: User Can Stake An Address + Given the user has a node + When the user stakes their node with amount 150000000001 uPOKT + Then the user should be able to see standard output containing "" + And the node should have exited without error + + Scenario: User Can Unstake An Address + Given the user has a node + When the user stakes their node with amount 150000000001 uPOKT + Then the user should be able to see standard output containing "" + Then the user should be able to unstake their node + Then the user should be able to see standard output containing "" + And the node should have exited without error + + Scenario: User Can Send To An Address + Given the user has a node + When the user sends 150000000 uPOKT to another address + Then the user should be able to see standard output containing "" + And the node should have exited without error diff --git a/e2e/tests/node.go b/e2e/tests/node.go new file mode 100644 index 000000000..0d626756a --- /dev/null +++ b/e2e/tests/node.go @@ -0,0 +1,76 @@ +// //go:build e2e + +package e2e + +import ( + "fmt" + "os/exec" + + "github.com/pokt-network/pocket/runtime" + "github.com/pokt-network/pocket/runtime/defaults" +) + +// cliPath is the path of the binary installed and is set by the Tiltfile +const cliPath = "/usr/local/bin/p1" + +var ( + // defaultRPCURL used by targetPod to build commands + defaultRPCURL string + // targetDevClientPod is the kube pod that executes calls to the pocket binary under test + targetDevClientPod = "deploy/dev-cli-client" +) + +func init() { + defaultRPCHost := runtime.GetEnv("RPC_HOST", defaults.RandomValidatorEndpointK8SHostname) + defaultRPCURL = fmt.Sprintf("http://%s:%s", defaultRPCHost, defaults.DefaultRPCPort) +} + +// commandResult combines the stdout, stderr, and err of an operation +type commandResult struct { + Stdout string + Stderr string + Err error +} + +// PocketClient is a single function interface for interacting with a node +type PocketClient interface { + RunCommand(...string) (*commandResult, error) + RunCommandOnHost(string, ...string) (*commandResult, error) +} + +// Ensure that Validator fulfills PocketClient +var _ PocketClient = &nodePod{} + +// nodePod holds the connection information to a specific pod in between different instructions during testing +type nodePod struct { + targetPodName string + result *commandResult // stores the result of the last command that was run +} + +// RunCommand runs a command on a pre-configured kube pod with the given args +func (n *nodePod) RunCommand(args ...string) (*commandResult, error) { + return n.RunCommandOnHost(defaultRPCURL, args...) +} + +// RunCommandOnHost runs a command on specified kube pod with the given args +func (n *nodePod) RunCommandOnHost(rpcUrl string, args ...string) (*commandResult, error) { + base := []string{ + "exec", "-i", targetDevClientPod, + "--container", "pocket", + "--", cliPath, + "--non_interactive=true", + "--remote_cli_url=" + rpcUrl, + } + args = append(base, args...) + cmd := exec.Command("kubectl", args...) + r := &commandResult{} + out, err := cmd.Output() + r.Stdout = string(out) + n.result = r + // IMPROVE: make targetPodName configurable + n.targetPodName = targetDevClientPod + if err != nil { + return r, err + } + return r, nil +} diff --git a/e2e/tests/state_sync.feature b/e2e/tests/state_sync.feature new file mode 100644 index 000000000..837159722 --- /dev/null +++ b/e2e/tests/state_sync.feature @@ -0,0 +1,20 @@ +Feature: State Sync Namespace + + Scenario: New FullNode does not sync to Blockchain at height 2 + Given the network is at genesis + And the network has "4" actors of type "Validator" + When the developer runs the command "ScaleActor full_nodes 1" + And the developer waits for "3000" milliseconds + Then "full-node-002" should be unreachable + When the developer runs the command "TriggerView" + And the developer waits for "1000" milliseconds + And the developer runs the command "TriggerView" + And the developer waits for "1000" milliseconds + Then "validator-001" should be at height "2" + And "validator-004" should be at height "2" + # full_nodes is the key used in `localnet_config.yaml` + When the developer runs the command "ScaleActor full_nodes 2" + # IMPROVE: Figure out if there's something better to do then waiting for a node to spin up + And the developer waits for "20000" milliseconds + # TODO(#812): The full node should be at height "2" after state sync is implemented + Then "full-node-002" should be at height "1" \ No newline at end of file diff --git a/e2e/tests/steps_init_test.go b/e2e/tests/steps_init_test.go index ee680cd82..1bd8dea7d 100644 --- a/e2e/tests/steps_init_test.go +++ b/e2e/tests/steps_init_test.go @@ -1,13 +1,15 @@ -//go:build e2e +// // go:build e2e package e2e import ( + "encoding/json" "fmt" "os" "path/filepath" "strings" "testing" + "time" pocketLogger "github.com/pokt-network/pocket/logger" "github.com/pokt-network/pocket/runtime/defaults" @@ -15,6 +17,8 @@ import ( pocketk8s "github.com/pokt-network/pocket/shared/k8s" "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" + "golang.org/x/text/cases" + "golang.org/x/text/language" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -25,13 +29,12 @@ var e2eLogger = pocketLogger.Global.CreateLoggerForModule("e2e") const ( // Each actor is represented e.g. validator-001-pocket:42069 thru validator-999-pocket:42069. // Defines the host & port scheme that LocalNet uses for naming actors. - validatorServiceURLTmpl = "validator-%s-pocket:%d" - // validatorA maps to suffix ID 001 and is also used by the cluster-manager - // though it has no special permissions. + validatorServiceURLTemplate = "validator-%s-pocket:%d" + // Mapping from validators to suffix IDs as convienece for some of the tests validatorA = "001" - // validatorB maps to suffix ID 002 and receives in the Send test. validatorB = "002" - chainId = "0001" + // Placeholder chainID + chainId = "0001" ) type rootSuite struct { @@ -42,24 +45,22 @@ type rootSuite struct { validatorKeys map[string]string // clientset is the kubernetes API we acquire from the user's $HOME/.kube/config clientset *kubernetes.Clientset - // validator holds command results between runs and reports errors to the test suite - // TECHDEBT: Rename `validator` to something more appropriate - validator *validatorPod - // validatorA maps to suffix ID 001 of the kube pod that we use as our control agent + // node holds command results between runs and reports errors to the test suite + node *nodePod } func (s *rootSuite) Before() { clientSet, err := getClientset(s) require.NoErrorf(s, err, "failed to get clientset") - vkmap, err := pocketk8s.FetchValidatorPrivateKeys(clientSet) + validatorKeyMap, err := pocketk8s.FetchValidatorPrivateKeys(clientSet) if err != nil { e2eLogger.Fatal().Err(err).Msg("failed to get validator key map") } - s.validator = new(validatorPod) + s.node = new(nodePod) s.clientset = clientSet - s.validatorKeys = vkmap + s.validatorKeys = validatorKeyMap } // TestFeatures runs the e2e tests specified in any .features files in this directory @@ -71,24 +72,136 @@ func TestFeatures(t *testing.T) { // InitializeScenario registers step regexes to function handlers func (s *rootSuite) TheUserHasAValidator() { - res, err := s.validator.RunCommand("help") + res, err := s.node.RunCommand("help") require.NoErrorf(s, err, res.Stderr) - s.validator.result = res + s.node.result = res } func (s *rootSuite) TheValidatorShouldHaveExitedWithoutError() { - require.NoError(s, s.validator.result.Err) + require.NoError(s, s.node.result.Err) } func (s *rootSuite) TheUserRunsTheCommand(cmd string) { cmds := strings.Split(cmd, " ") - res, err := s.validator.RunCommand(cmds...) + res, err := s.node.RunCommand(cmds...) require.NoError(s, err) - s.validator.result = res + s.node.result = res +} + +// TheDeveloperRunsTheCommand is similar to TheUserRunsTheCommand but exclusive to `Debug` commands +func (s *rootSuite) TheDeveloperRunsTheCommand(cmd string) { + cmds := strings.Split(cmd, " ") + cmds = append([]string{"Debug"}, cmds...) + res, err := s.node.RunCommand(cmds...) + require.NoError(s, err, fmt.Sprintf("failed to run command: '%s' due to error: %s", cmd, err)) + s.node.result = res + e2eLogger.Debug().Msgf("TheDeveloperRunsTheCommand: '%s' with result: %s", cmd, res.Stdout) + + // Special case for managing LocalNet config when scaling actors + if cmds[1] == "ScaleActor" { + s.syncLocalNetConfigFromHostToLocalFS() + } +} + +func (s *rootSuite) TheNetworkIsAtGenesis() { + s.TheDeveloperRunsTheCommand("ResetToGenesis") +} + +func (s *rootSuite) TheDeveloperWaitsForMilliseconds(millis int64) { + time.Sleep(time.Duration(millis) * time.Millisecond) +} + +func (s *rootSuite) TheNetworkHasActorsOfType(num int64, actor string) { + // normalize actor to Title case and plural + caser := cases.Title(language.AmericanEnglish) + actor = caser.String(strings.ToLower(actor)) + if len(actor) > 0 && actor[len(actor)-1] != 's' { + actor += "s" + } + args := []string{ + "Query", + actor, + } + + // Depending ont he type of `actor` we're querying, we'll have a different expected responses + // so not all of these fields will be populated, but at least one will be. + type expectedResponse struct { + NumValidators *int64 `json:"total_validators"` + NumApps *int64 `json:"total_apps"` + NumFishermen *int64 `json:"total_fishermen"` + NumServicers *int64 `json:"total_servicers"` + NumAccounts *int64 `json:"total_accounts"` + } + validate := func(res *expectedResponse) bool { + return res != nil && ((res.NumValidators != nil && *res.NumValidators > 0) || + (res.NumApps != nil && *res.NumApps > 0) || + (res.NumFishermen != nil && *res.NumFishermen > 0) || + (res.NumServicers != nil && *res.NumServicers > 0) || + (res.NumAccounts != nil && *res.NumAccounts > 0)) + } + + resRaw, err := s.node.RunCommand(args...) + require.NoError(s, err) + + res := getResponseFromStdout[expectedResponse](s, resRaw.Stdout, validate) + require.NotNil(s, res) + + // Validate that at least one of the fields that is populated has the right number of actors + if res.NumValidators != nil { + require.Equal(s, num, *res.NumValidators) + } else if res.NumApps != nil { + require.Equal(s, num, *res.NumApps) + } else if res.NumFishermen != nil { + require.Equal(s, num, *res.NumFishermen) + } else if res.NumServicers != nil { + require.Equal(s, num, *res.NumServicers) + } else if res.NumAccounts != nil { + require.Equal(s, num, *res.NumAccounts) + } +} + +func (s *rootSuite) ShouldBeUnreachable(pod string) { + validate := func(res *string) bool { + return res != nil && strings.Contains(*res, "Unable to connect to the RPC") + } + args := []string{ + "Query", + "Height", + } + rpcURL := fmt.Sprintf("http://%s-pocket:%s", pod, defaults.DefaultRPCPort) + resRaw, err := s.node.RunCommandOnHost(rpcURL, args...) + require.NoError(s, err) + + res := getStrFromStdout(s, resRaw.Stdout, validate) + require.NotNil(s, res) + + require.Equal(s, fmt.Sprintf("❌ Unable to connect to the RPC @ \x1b[1mhttp://%s-pocket:%s\x1b[0m", pod, defaults.DefaultRPCPort), *res) +} + +func (s *rootSuite) ShouldBeAtHeight(pod string, height int64) { + args := []string{ + "Query", + "Height", + } + type expectedResponse struct { + Height *int64 `json:"Height"` + } + validate := func(res *expectedResponse) bool { + return res != nil && res.Height != nil + } + + rpcURL := fmt.Sprintf("http://%s-pocket:%s", pod, defaults.DefaultRPCPort) + resRaw, err := s.node.RunCommandOnHost(rpcURL, args...) + require.NoError(s, err) + + res := getResponseFromStdout[expectedResponse](s, resRaw.Stdout, validate) + require.NotNil(s, res) + + require.Equal(s, height, *res.Height) } func (s *rootSuite) TheUserShouldBeAbleToSeeStandardOutputContaining(arg1 string) { - require.Contains(s, s.validator.result.Stdout, arg1) + require.Contains(s, s.node.result.Stdout, arg1) } func (s *rootSuite) TheUserStakesTheirValidatorWithAmountUpokt(amount int64) { @@ -111,15 +224,15 @@ func (s *rootSuite) TheUserSendsUpoktToAnotherAddress(amount int64) { valB.Address().String(), fmt.Sprintf("%d", amount), } - res, err := s.validator.RunCommand(args...) + res, err := s.node.RunCommand(args...) require.NoError(s, err) - s.validator.result = res + s.node.result = res } // stakeValidator runs Validator stake command with the address, amount, chains..., and serviceURL provided func (s *rootSuite) stakeValidator(privKey cryptoPocket.PrivateKey, amount string) { - validatorServiceUrl := fmt.Sprintf(validatorServiceURLTmpl, validatorA, defaults.DefaultP2PPort) + validatorServiceUrl := fmt.Sprintf(validatorServiceURLTemplate, validatorA, defaults.DefaultP2PPort) args := []string{ "Validator", "Stake", @@ -128,10 +241,10 @@ func (s *rootSuite) stakeValidator(privKey cryptoPocket.PrivateKey, amount strin chainId, validatorServiceUrl, } - res, err := s.validator.RunCommand(args...) + res, err := s.node.RunCommand(args...) require.NoError(s, err) - s.validator.result = res + s.node.result = res } // unstakeValidator unstakes the Validator at the same address that stakeValidator uses @@ -142,10 +255,10 @@ func (s *rootSuite) unstakeValidator() { "Unstake", privKey.Address().String(), } - res, err := s.validator.RunCommand(args...) + res, err := s.node.RunCommand(args...) require.NoError(s, err) - s.validator.result = res + s.node.result = res } // getPrivateKey generates a new keypair from the private hex key that we get from the clientset @@ -190,3 +303,39 @@ func inClusterConfig(t gocuke.TestingT) *rest.Config { return config } + +// getResponseFromStdout returns the first output from stdout that passes the validate function provided. +// For example, when running `p1 Query Height`, the output is: +// +// {"level":"info","module":"e2e","time":"2023-07-11T15:46:07-07:00","message":"..."} +// {"height":3} +// +// And will return the following map so it can be used by the caller: +// +// map[height:3] +func getResponseFromStdout[T any](t gocuke.TestingT, stdout string, validate func(res *T) bool) *T { + t.Helper() + + for _, s := range strings.Split(stdout, "\n") { + var m T + if err := json.Unmarshal([]byte(s), &m); err != nil { + continue + } + if !validate(&m) { + continue + } + return &m + } + return nil +} + +func getStrFromStdout(t gocuke.TestingT, stdout string, validate func(res *string) bool) *string { + t.Helper() + for _, s := range strings.Split(stdout, "\n") { + if !validate(&s) { + continue + } + return &s + } + return nil +} diff --git a/e2e/tests/tilt_helpers.go b/e2e/tests/tilt_helpers.go new file mode 100644 index 000000000..635217fa2 --- /dev/null +++ b/e2e/tests/tilt_helpers.go @@ -0,0 +1,36 @@ +// // go:build e2e +package e2e + +import ( + "log" + "os/exec" +) + +// HACK: Dynamic scaling actors using `p1` and the `e2e test framework` is still a WIP so this is a +// functional interim solution until there's a need for a proper design. +func (s *rootSuite) syncLocalNetConfigFromHostToLocalFS() { + if !isPackageInstalled("tilt") { + e2eLogger.Debug().Msgf("syncLocalNetConfigFromHostToLocalFS: 'tilt' is not installed, skipping...") + return + } + sedCmd := exec.Command("tilt", "trigger", "syncback_localnet_config") + err := sedCmd.Run() + if err != nil { + e2eLogger.Err(err).Msgf("syncLocalNetConfigFromHostToLocalFS: failed to run command: '%s'", sedCmd.String()) + log.Fatal(err) + } +} + +func isPackageInstalled(pkg string) bool { + _, err := exec.LookPath(pkg) + // check error + if err != nil { + // the executable is not found, return false + if execErr, ok := err.(*exec.Error); ok && execErr.Err == exec.ErrNotFound { + return false + } + // another kind of error happened, let's log and exit + log.Fatal(err) + } + return true +} diff --git a/e2e/tests/valdator.feature b/e2e/tests/valdator.feature deleted file mode 100644 index ec8a2ca47..000000000 --- a/e2e/tests/valdator.feature +++ /dev/null @@ -1,28 +0,0 @@ -# TECHDEBT: Validator should eventually be changed to full node or just node. -Feature: Validator Namespace - - Scenario: User Wants Help Using The Validator Command - Given the user has a validator - When the user runs the command "Validator help" - Then the user should be able to see standard output containing "Available Commands" - And the validator should have exited without error - - Scenario: User Can Stake An Address - Given the user has a validator - When the user stakes their validator with amount 150000000001 uPOKT - Then the user should be able to see standard output containing "" - And the validator should have exited without error - - Scenario: User Can Unstake An Address - Given the user has a validator - When the user stakes their validator with amount 150000000001 uPOKT - Then the user should be able to see standard output containing "" - Then the user should be able to unstake their validator - Then the user should be able to see standard output containing "" - And the validator should have exited without error - - Scenario: User Can Send To An Address - Given the user has a validator - When the user sends 150000000 uPOKT to another address - Then the user should be able to see standard output containing "" - And the validator should have exited without error diff --git a/e2e/tests/validator.go b/e2e/tests/validator.go deleted file mode 100644 index 04b27bf7f..000000000 --- a/e2e/tests/validator.go +++ /dev/null @@ -1,67 +0,0 @@ -//go:build e2e - -package e2e - -import ( - "fmt" - "os/exec" - - "github.com/pokt-network/pocket/runtime" - "github.com/pokt-network/pocket/runtime/defaults" -) - -var ( - // rpcURL used by targetPod to build commands - rpcURL string - // targetPod is the kube pod that executes calls to the pocket binary under test - targetPod = "deploy/dev-cli-client" -) - -func init() { - rpcHost := runtime.GetEnv("RPC_HOST", defaults.RandomValidatorEndpointK8SHostname) - rpcURL = fmt.Sprintf("http://%s:%s", rpcHost, defaults.DefaultRPCPort) -} - -// cliPath is the path of the binary installed and is set by the Tiltfile -const cliPath = "/usr/local/bin/p1" - -// commandResult combines the stdout, stderr, and err of an operation -type commandResult struct { - Stdout string - Stderr string - Err error -} - -// PocketClient is a single function interface for interacting with a node -type PocketClient interface { - RunCommand(...string) (*commandResult, error) -} - -// Ensure that Validator fulfills PocketClient -var _ PocketClient = &validatorPod{} - -// validatorPod holds the connection information to pod validator-001 for testing -type validatorPod struct { - result *commandResult // stores the result of the last command that was run -} - -// RunCommand runs a command on a target kube pod -func (v *validatorPod) RunCommand(args ...string) (*commandResult, error) { - base := []string{ - "exec", "-i", targetPod, - "--container", "pocket", - "--", cliPath, - "--non_interactive=true", - "--remote_cli_url=" + rpcURL, - } - args = append(base, args...) - cmd := exec.Command("kubectl", args...) - r := &commandResult{} - out, err := cmd.Output() - r.Stdout = string(out) - v.result = r - if err != nil { - return r, err - } - return r, nil -} diff --git a/go.mod b/go.mod index e9772889b..1599c24de 100644 --- a/go.mod +++ b/go.mod @@ -251,7 +251,7 @@ require ( github.com/valyala/fasttemplate v1.2.2 // indirect golang.org/x/mod v0.7.0 // indirect golang.org/x/sys v0.6.0 // indirect - golang.org/x/text v0.7.0 // indirect + golang.org/x/text v0.7.0 golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect golang.org/x/tools v0.3.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/persistence/docs/CHANGELOG.md b/persistence/docs/CHANGELOG.md index 1bdae0d55..53c60d026 100644 --- a/persistence/docs/CHANGELOG.md +++ b/persistence/docs/CHANGELOG.md @@ -422,7 +422,7 @@ Deprecate PrePersistence - Added PopulateGenesisState function to persistence module - Fixed the stake status iota issue - Discovered and documented (with TODO) double setting parameters issue -- Attached to the Utility Module and using in `make compose_and_watch` +- Attached to the Utility Module and using in `make lightweight_localnet` ## [0.0.0.1] - 2022-07-05 diff --git a/persistence/docs/README.md b/persistence/docs/README.md index d29b5fab0..08d8398e1 100644 --- a/persistence/docs/README.md +++ b/persistence/docs/README.md @@ -99,7 +99,7 @@ A subset of these are explained below. Any targets or helpers to configure and launch the database instances do not populate the actual database. -A LocalNet (see `make compose_and_watch`) must have been executed in order to trigger creation of schemas and hydration of the relevant tables. +A LocalNet (see `make lightweight_localnet`) must have been executed in order to trigger creation of schemas and hydration of the relevant tables. #### CLI Access - db_cli_node diff --git a/shared/modules/doc/CHANGELOG.md b/shared/modules/doc/CHANGELOG.md index d6d965cce..207e7a92a 100644 --- a/shared/modules/doc/CHANGELOG.md +++ b/shared/modules/doc/CHANGELOG.md @@ -125,7 +125,7 @@ UtilityModule - Opened followup issue #163 - Added config and genesis generator to build package - Deprecated old build files -- Use new config and genesis files for make compose_and_watch -- Use new config and genesis files for make client_start && make client_connect +- Use new config and genesis files for make lightweight_localnet +- Use new config and genesis files for make lightweight_localnet_client && make lightweight_localnet_client_debug diff --git a/telemetry/README.md b/telemetry/README.md index eed3bb8b9..fd61c911a 100644 --- a/telemetry/README.md +++ b/telemetry/README.md @@ -158,7 +158,7 @@ make docker_loki_install 1. Spin up the stack ```bash -make compose_and_watch +make lightweight_localnet ``` 2. Wait a few seconds and **Voila!** From 9d840ed87c9585d7dbfbe191440ed079c82cecda Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Fri, 28 Jul 2023 17:04:34 -0700 Subject: [PATCH 02/15] Linting improvements --- app/client/cli/debug.go | 6 +++--- e2e/tests/node.go | 2 +- e2e/tests/state_sync.feature | 4 ++-- e2e/tests/steps_init_test.go | 10 +++++----- e2e/tests/tilt_helpers.go | 10 ++++------ 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/app/client/cli/debug.go b/app/client/cli/debug.go index ca5a1b764..1d3784445 100644 --- a/app/client/cli/debug.go +++ b/app/client/cli/debug.go @@ -127,9 +127,9 @@ func newDebugSubCommands() []*cobra.Command { if !slices.Contains(validActors, actor) { logger.Global.Fatal().Msg("Invalid actor type provided") } - sedCmd := exec.Command("sed", "-i", fmt.Sprintf("/%s:/,/count:/ s/count: [0-9]*/count: %s/", actor, numActors), "/usr/local/localnet_config.yaml") - err := sedCmd.Run() - if err != nil { + sedReplaceCmd := fmt.Sprintf("/%s:/,/count:/ s/count: [0-9]*/count: %s/", actor, numActors) + sedCmd := exec.Command("sed", "-i", sedReplaceCmd, "/usr/local/localnet_config.yaml") + if err := sedCmd.Run(); err != nil { log.Fatal(err) } }, diff --git a/e2e/tests/node.go b/e2e/tests/node.go index 0d626756a..7e484d92d 100644 --- a/e2e/tests/node.go +++ b/e2e/tests/node.go @@ -1,4 +1,4 @@ -// //go:build e2e +//go:build e2e package e2e diff --git a/e2e/tests/state_sync.feature b/e2e/tests/state_sync.feature index 837159722..f296f88b0 100644 --- a/e2e/tests/state_sync.feature +++ b/e2e/tests/state_sync.feature @@ -15,6 +15,6 @@ Feature: State Sync Namespace # full_nodes is the key used in `localnet_config.yaml` When the developer runs the command "ScaleActor full_nodes 2" # IMPROVE: Figure out if there's something better to do then waiting for a node to spin up - And the developer waits for "20000" milliseconds + And the developer waits for "40000" milliseconds # TODO(#812): The full node should be at height "2" after state sync is implemented - Then "full-node-002" should be at height "1" \ No newline at end of file + Then "full-node-002" should be at height "0" \ No newline at end of file diff --git a/e2e/tests/steps_init_test.go b/e2e/tests/steps_init_test.go index 1bd8dea7d..f60dd2ae2 100644 --- a/e2e/tests/steps_init_test.go +++ b/e2e/tests/steps_init_test.go @@ -1,4 +1,4 @@ -// // go:build e2e +//go:build e2e package e2e @@ -161,8 +161,8 @@ func (s *rootSuite) TheNetworkHasActorsOfType(num int64, actor string) { } func (s *rootSuite) ShouldBeUnreachable(pod string) { - validate := func(res *string) bool { - return res != nil && strings.Contains(*res, "Unable to connect to the RPC") + validate := func(res string) bool { + return strings.Contains(res, "Unable to connect to the RPC") } args := []string{ "Query", @@ -329,10 +329,10 @@ func getResponseFromStdout[T any](t gocuke.TestingT, stdout string, validate fun return nil } -func getStrFromStdout(t gocuke.TestingT, stdout string, validate func(res *string) bool) *string { +func getStrFromStdout(t gocuke.TestingT, stdout string, validate func(res string) bool) *string { t.Helper() for _, s := range strings.Split(stdout, "\n") { - if !validate(&s) { + if !validate(s) { continue } return &s diff --git a/e2e/tests/tilt_helpers.go b/e2e/tests/tilt_helpers.go index 635217fa2..7cc10cb36 100644 --- a/e2e/tests/tilt_helpers.go +++ b/e2e/tests/tilt_helpers.go @@ -1,4 +1,5 @@ -// // go:build e2e +//go:build e2e + package e2e import ( @@ -14,17 +15,14 @@ func (s *rootSuite) syncLocalNetConfigFromHostToLocalFS() { return } sedCmd := exec.Command("tilt", "trigger", "syncback_localnet_config") - err := sedCmd.Run() - if err != nil { + if err := sedCmd.Run(); err != nil { e2eLogger.Err(err).Msgf("syncLocalNetConfigFromHostToLocalFS: failed to run command: '%s'", sedCmd.String()) log.Fatal(err) } } func isPackageInstalled(pkg string) bool { - _, err := exec.LookPath(pkg) - // check error - if err != nil { + if _, err := exec.LookPath(pkg); err != nil { // the executable is not found, return false if execErr, ok := err.(*exec.Error); ok && execErr.Err == exec.ErrNotFound { return false From 2395a6177ecc31e7b4e5fa0059acb610053590a7 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 1 Aug 2023 15:28:29 -0700 Subject: [PATCH 03/15] Update e2e/tests/steps_init_test.go Co-authored-by: d7t --- e2e/tests/steps_init_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/tests/steps_init_test.go b/e2e/tests/steps_init_test.go index f60dd2ae2..aeaffaf53 100644 --- a/e2e/tests/steps_init_test.go +++ b/e2e/tests/steps_init_test.go @@ -123,7 +123,7 @@ func (s *rootSuite) TheNetworkHasActorsOfType(num int64, actor string) { actor, } - // Depending ont he type of `actor` we're querying, we'll have a different expected responses + // Depending on the type of `actor` we're querying, we'll have a different set of expected responses // so not all of these fields will be populated, but at least one will be. type expectedResponse struct { NumValidators *int64 `json:"total_validators"` From 489978f040cffab5b146014ecaf12222f5828e70 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 1 Aug 2023 15:41:52 -0700 Subject: [PATCH 04/15] Update documentation related to installing rsync --- Makefile | 16 +++++++++++++--- build/localnet/README.md | 10 +++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index e3c289138..0bf862535 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ help: docker_check: { \ if ( ! ( command -v docker >/dev/null && (docker compose version >/dev/null || command -v docker-compose >/dev/null) )); then \ - echo "Seems like you don't have Docker or docker-compose installed. Make sure you review docs/development/README.md before continuing"; \ + echo "Seems like you don't have Docker or docker-compose installed. Make sure you review build/localnet/README.md and docs/development/README.md before continuing"; \ exit 1; \ fi; \ } @@ -47,11 +47,21 @@ docker_check: kubectl_check: { \ if ( ! ( command -v kubectl >/dev/null )); then \ - echo "Seems like you don't have Kubectl installed. Make sure you review docs/development/README.md before continuing"; \ + echo "Seems like you don't have Kubectl installed. Make sure you review build/localnet/README.md and docs/development/README.md before continuing"; \ exit 1; \ fi; \ } +# Internal helper target - check if rsync is installed. +rsync_check: + { \ + if ( ! ( command -v kubectl >/dev/null )); then \ + echo "Seems like you don't have rsync installed. Make sure you review build/localnet/README.md and docs/development/README.md before continuing"; \ + exit 1; \ + fi; \ + } + + .PHONY: trigger_ci trigger_ci: ## Trigger the CI pipeline by submitting an empty commit; See https://github.com/pokt-network/pocket/issues/900 for details git commit --allow-empty -m "Empty commit" @@ -134,7 +144,7 @@ go_fmt: ## Format all the .go files in the project in place. gofmt -w -s . .PHONY: install_cli_deps -install_cli_deps: ## Installs `helm`, `tilt` and the underlying `ci_deps` +install_cli_deps: rsync_check kubectl_check docker_check ## Installs `helm`, `tilt` and the underlying `ci_deps` make install_ci_deps curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash diff --git a/build/localnet/README.md b/build/localnet/README.md index ae52c319a..02d9a1494 100644 --- a/build/localnet/README.md +++ b/build/localnet/README.md @@ -2,7 +2,7 @@ This guide shows how to deploy a LocalNet using [pocket-operator](https://github.com/pokt-network/pocket-operator). -- [TLDR](#tldr) +- [TL;DR](#tldr) - [Dependencies](#dependencies) - [Choosing Kubernetes Distribution](#choosing-kubernetes-distribution) - [How to create Kind Kubernetes cluster](#how-to-create-kind-kubernetes-cluster) @@ -16,6 +16,8 @@ This guide shows how to deploy a LocalNet using [pocket-operator](https://github - [Interacting w/ LocalNet](#interacting-w-localnet) - [Make Targets](#make-targets) - [Addresses and keys on LocalNet](#addresses-and-keys-on-localnet) + - [Applications staked on LocalNet](#applications-staked-on-localnet) + - [Servicers staked on LocalNet](#servicers-staked-on-localnet) - [How to change configuration files](#how-to-change-configuration-files) - [Overriding default values for localnet with Tilt](#overriding-default-values-for-localnet-with-tilt) - [How does it work?](#how-does-it-work) @@ -26,7 +28,7 @@ This guide shows how to deploy a LocalNet using [pocket-operator](https://github - [Full Cleanup](#full-cleanup) - [Code Structure](#code-structure) -## TLDR +## TL;DR If you feel adventurous, and you know what you're doing, here is a rapid guide to start LocalNet: @@ -46,6 +48,7 @@ All necessary dependencies, except Docker and Kubernetes cluster, are installed 3. `Kubernetes cluster`: refer to [Choosing Kubernetes Distribution](#choosing-kubernetes-distribution) section for more details. 4. `kubectl`: CLI is required and should be configured to access the cluster. This should happen automatically if using Docker Desktop, Rancher Desktop, k3s, k3d, minikube, etc. 5. [helm](https://helm.sh/docs/intro/install): required to template the YAML manifests for the dependencies (e.g., Postgres, Grafana). Installation instructions available. +6. [rsync](https://www.hostinger.com/tutorials/how-to-use-rsync): required to for some extensions used with `Tilt`; https://github.com/tilt-dev/tilt-extensions/tree/master/syncback#usage ### Choosing Kubernetes Distribution @@ -149,8 +152,8 @@ For example: - `0010297b55fc9278e4be4f1bcfe52bf9bd0443f8` is a servicer #001. - `314019dbb7faf8390c1f0cf4976ef1215c90b7e4` is an application #314. - #### Applications staked on LocalNet + Applications with the following addresses are staked on LocalNet, through the [applications field of the genesis.json in the LocalNet configuration](https://github.com/pokt-network/pocket/blob/main/build/localnet/manifests/configs.yaml#L4088) - `00001fff518b1cdddd74c197d76ba5b5dedc0301` @@ -159,6 +162,7 @@ Applications with the following addresses are staked on LocalNet, through the [a These addresses can be used for e.g. testing the CLI. #### Servicers staked on LocalNet + Servicers with the following addresses are staked on LocalNet, through the [servicers field of the genesis.json in the LocalNet configuration](https://github.com/pokt-network/pocket/blob/main/build/localnet/manifests/configs.yaml#L4120) - `00002b8cea1bcc3dadc72ebecf95564ceb9c2e2a` From 4cc8405cf51eb8a9e361c471d7e90ac8a03d6da2 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 1 Aug 2023 17:13:32 -0700 Subject: [PATCH 05/15] Added # IMPROVE(#959): Remove time-based waits from tests --- e2e/tests/debug.feature | 2 ++ e2e/tests/state_sync.feature | 2 ++ 2 files changed, 4 insertions(+) diff --git a/e2e/tests/debug.feature b/e2e/tests/debug.feature index e33bf33a7..38026897c 100644 --- a/e2e/tests/debug.feature +++ b/e2e/tests/debug.feature @@ -1,5 +1,7 @@ Feature: Debug Namespace + # IMPROVE(#959): Remove time-based waits from tests + # Since the configuration for consensus is optimistically responsive, we need to be in manual # Pacemaker mode and call TriggerView to further the blockchain. # 1 second was chosen arbitrarily for the time for block propagation. diff --git a/e2e/tests/state_sync.feature b/e2e/tests/state_sync.feature index f296f88b0..dc2d96beb 100644 --- a/e2e/tests/state_sync.feature +++ b/e2e/tests/state_sync.feature @@ -1,5 +1,7 @@ Feature: State Sync Namespace + # IMPROVE(#959): Remove time-based waits from tests + Scenario: New FullNode does not sync to Blockchain at height 2 Given the network is at genesis And the network has "4" actors of type "Validator" From 27922107e800ed90f3c2245d7c429c8270dd0768 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Wed, 2 Aug 2023 15:00:57 -0700 Subject: [PATCH 06/15] Follow up on minor comments --- build/localnet/Tiltfile | 71 +++++---------------------------------- e2e/tests/node.go | 6 ++-- e2e/tests/tilt_helpers.go | 6 ++-- 3 files changed, 14 insertions(+), 69 deletions(-) diff --git a/build/localnet/Tiltfile b/build/localnet/Tiltfile index 0225c1d79..d4534df35 100644 --- a/build/localnet/Tiltfile +++ b/build/localnet/Tiltfile @@ -197,7 +197,6 @@ for x in range(localnet_config["validators"]["count"]): actor_number = actor_number + 1 formatted_number = formatted_actor_number(actor_number) -<<<<<<< HEAD k8s_yaml( helm( chart_dir, @@ -211,6 +210,8 @@ for x in range(localnet_config["validators"]["count"]): "genesis.externalConfigMap.name=v1-localnet-genesis", "genesis.externalConfigMap.key=genesis.json", "postgresql.primary.persistence.enabled=false", + "podAnnotations.prometheus\\.io/scrape=true", + "podAnnotations.prometheus\\.io/port=9000", "nodeType=validator", ], values=[chart_dir + "/pocket-validator-overrides.yaml"] @@ -218,25 +219,6 @@ for x in range(localnet_config["validators"]["count"]): else [], ) ) -======= - k8s_yaml(helm(chart_dir, - name="validator-%s-pocket" % formatted_number, - set=[ - "global.postgresql.auth.postgresPassword=LocalNetPassword", - "image.repository=pocket-image", - "privateKeySecretKeyRef.name=validators-private-keys", - "privateKeySecretKeyRef.key=%s" % formatted_number, - "genesis.preProvisionedGenesis.enabled=false", - "genesis.externalConfigMap.name=v1-localnet-genesis", - "genesis.externalConfigMap.key=genesis.json", - "postgresql.primary.persistence.enabled=false", - "podAnnotations.prometheus\\.io/scrape=true", - "podAnnotations.prometheus\\.io/port=9000", - "nodeType=validator", - ], - values=[chart_dir + "/pocket-validator-overrides.yaml"] if os.path.exists(chart_dir + "/pocket-validator-overrides.yaml") else [],)) ->>>>>>> main - k8s_resource("validator-%s-pocket" % formatted_number, labels=["pocket-validators"]) # Provisions servicer nodes @@ -245,7 +227,6 @@ for x in range(localnet_config["servicers"]["count"]): actor_number = actor_number + 1 formatted_number = formatted_actor_number(actor_number) -<<<<<<< HEAD k8s_yaml( helm( chart_dir, @@ -259,6 +240,8 @@ for x in range(localnet_config["servicers"]["count"]): "genesis.externalConfigMap.name=v1-localnet-genesis", "genesis.externalConfigMap.key=genesis.json", "postgresql.primary.persistence.enabled=false", + "podAnnotations.prometheus\\.io/scrape=true", + "podAnnotations.prometheus\\.io/port=9000", "config.servicer.enabled=true", "nodeType=servicer", ], @@ -267,26 +250,6 @@ for x in range(localnet_config["servicers"]["count"]): else [], ) ) -======= - k8s_yaml(helm(chart_dir, - name="servicer-%s-pocket" % formatted_number, - set=[ - "global.postgresql.auth.postgresPassword=LocalNetPassword", - "image.repository=pocket-image", - "privateKeySecretKeyRef.name=servicers-private-keys", - "privateKeySecretKeyRef.key=%s" % formatted_number, - "genesis.preProvisionedGenesis.enabled=false", - "genesis.externalConfigMap.name=v1-localnet-genesis", - "genesis.externalConfigMap.key=genesis.json", - "postgresql.primary.persistence.enabled=false", - "podAnnotations.prometheus\\.io/scrape=true", - "podAnnotations.prometheus\\.io/port=9000", - "config.servicer.enabled=true", - "nodeType=servicer", - ], - values=[chart_dir + "/pocket-servicer-overrides.yaml"] if os.path.exists(chart_dir + "/pocket-servicer-overrides.yaml") else [],)) ->>>>>>> main - k8s_resource("servicer-%s-pocket" % formatted_number, labels=["pocket-servicers"]) # Provisions fishermen nodes @@ -295,7 +258,6 @@ for x in range(localnet_config["fishermen"]["count"]): actor_number = actor_number + 1 formatted_number = formatted_actor_number(actor_number) -<<<<<<< HEAD k8s_yaml( helm( chart_dir, @@ -309,6 +271,8 @@ for x in range(localnet_config["fishermen"]["count"]): "genesis.externalConfigMap.name=v1-localnet-genesis", "genesis.externalConfigMap.key=genesis.json", "postgresql.primary.persistence.enabled=false", + "podAnnotations.prometheus\\.io/scrape=true", + "podAnnotations.prometheus\\.io/port=9000", "config.fisherman.enabled=true", "nodeType=fisherman", ], @@ -317,25 +281,6 @@ for x in range(localnet_config["fishermen"]["count"]): else [], ) ) -======= - k8s_yaml(helm(chart_dir, - name="fisherman-%s-pocket" % formatted_number, - set=[ - "global.postgresql.auth.postgresPassword=LocalNetPassword", - "image.repository=pocket-image", - "privateKeySecretKeyRef.name=fishermen-private-keys", - "privateKeySecretKeyRef.key=%s" % formatted_number, - "genesis.preProvisionedGenesis.enabled=false", - "genesis.externalConfigMap.name=v1-localnet-genesis", - "genesis.externalConfigMap.key=genesis.json", - "postgresql.primary.persistence.enabled=false", - "podAnnotations.prometheus\\.io/scrape=true", - "podAnnotations.prometheus\\.io/port=9000", - "config.fisherman.enabled=true", - "nodeType=fisherman", - ], - values=[chart_dir + "/pocket-fisherman-overrides.yaml"] if os.path.exists(chart_dir + "/pocket-fisherman-overrides.yaml") else [],)) ->>>>>>> main k8s_resource("fisherman-%s-pocket" % formatted_number, labels=["pocket-fishermen"]) @@ -357,8 +302,8 @@ for x in range(localnet_config["full_nodes"]["count"]): "genesis.externalConfigMap.name=v1-localnet-genesis", "genesis.externalConfigMap.key=genesis.json", "postgresql.primary.persistence.enabled=false", - "podAnnotations.prometheus\\.io/scrape=true", - "podAnnotations.prometheus\\.io/port=9000", + "podAnnotations.prometheus\\.io/scrape=true", + "podAnnotations.prometheus\\.io/port=9000", "nodeType=full", ], values=[chart_dir + "/pocket-full-node-overrides.yaml"] diff --git a/e2e/tests/node.go b/e2e/tests/node.go index 7e484d92d..422e6e009 100644 --- a/e2e/tests/node.go +++ b/e2e/tests/node.go @@ -65,12 +65,12 @@ func (n *nodePod) RunCommandOnHost(rpcUrl string, args ...string) (*commandResul cmd := exec.Command("kubectl", args...) r := &commandResult{} out, err := cmd.Output() + if err != nil { + return nil, err + } r.Stdout = string(out) n.result = r // IMPROVE: make targetPodName configurable n.targetPodName = targetDevClientPod - if err != nil { - return r, err - } return r, nil } diff --git a/e2e/tests/tilt_helpers.go b/e2e/tests/tilt_helpers.go index 7cc10cb36..a605ee22e 100644 --- a/e2e/tests/tilt_helpers.go +++ b/e2e/tests/tilt_helpers.go @@ -14,9 +14,9 @@ func (s *rootSuite) syncLocalNetConfigFromHostToLocalFS() { e2eLogger.Debug().Msgf("syncLocalNetConfigFromHostToLocalFS: 'tilt' is not installed, skipping...") return } - sedCmd := exec.Command("tilt", "trigger", "syncback_localnet_config") - if err := sedCmd.Run(); err != nil { - e2eLogger.Err(err).Msgf("syncLocalNetConfigFromHostToLocalFS: failed to run command: '%s'", sedCmd.String()) + tiltLocalnetConfigSyncbackTrigger := exec.Command("tilt", "trigger", "syncback_localnet_config") + if err := tiltLocalnetConfigSyncbackTrigger.Run(); err != nil { + e2eLogger.Err(err).Msgf("syncLocalNetConfigFromHostToLocalFS: failed to run command: '%s'", tiltLocalnetConfigSyncbackTrigger.String()) log.Fatal(err) } } From 9ce788287f17518f3827dcd29003ffe609d8e38a Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Wed, 2 Aug 2023 15:25:35 -0700 Subject: [PATCH 07/15] s/validator/node in a few places --- e2e/docs/E2E_ADR.md | 2 +- e2e/tests/node.feature | 6 +++--- e2e/tests/query.feature | 10 +++++----- e2e/tests/root.feature | 4 ++-- e2e/tests/steps_init_test.go | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/e2e/docs/E2E_ADR.md b/e2e/docs/E2E_ADR.md index 59a7546dd..ecefeda62 100644 --- a/e2e/docs/E2E_ADR.md +++ b/e2e/docs/E2E_ADR.md @@ -79,7 +79,7 @@ Below is an example of testing the `help` command of the Pocket binary. Feature: Root Namespace Scenario: User Needs Help - Given the user has a validator + Given the user has a node When the user runs the command "help" Then the user should be able to see standard output containing "Available Commands" And the pocket client should have exited without error diff --git a/e2e/tests/node.feature b/e2e/tests/node.feature index 69e1cc26f..45c73ac41 100644 --- a/e2e/tests/node.feature +++ b/e2e/tests/node.feature @@ -8,15 +8,15 @@ Feature: Node Namespace Scenario: User Can Stake An Address Given the user has a node - When the user stakes their node with amount 150000000001 uPOKT + When the user stakes their validator with amount 150000000001 uPOKT Then the user should be able to see standard output containing "" And the node should have exited without error Scenario: User Can Unstake An Address Given the user has a node - When the user stakes their node with amount 150000000001 uPOKT + When the user stakes their validator with amount 150000000001 uPOKT Then the user should be able to see standard output containing "" - Then the user should be able to unstake their node + Then the user should be able to unstake their validator Then the user should be able to see standard output containing "" And the node should have exited without error diff --git a/e2e/tests/query.feature b/e2e/tests/query.feature index 91e3e4eb9..74cc60180 100644 --- a/e2e/tests/query.feature +++ b/e2e/tests/query.feature @@ -1,14 +1,14 @@ Feature: Query Namespace - Scenario: User Wants Help Using The Query Command - Given the user has a validator + Scenario: User Wants Help Using The Query Command + Given the user has a node When the user runs the command "Query help" Then the user should be able to see standard output containing "Available Commands" - And the validator should have exited without error + And the node should have exited without error Scenario: User Wants To See The Block At Current Height - Given the user has a validator + Given the user has a node When the user runs the command "Query Block" Then the user should be able to see standard output containing "state_hash" - And the validator should have exited without error \ No newline at end of file + And the node should have exited without error \ No newline at end of file diff --git a/e2e/tests/root.feature b/e2e/tests/root.feature index 754534f2e..b9d6225d4 100644 --- a/e2e/tests/root.feature +++ b/e2e/tests/root.feature @@ -1,7 +1,7 @@ Feature: Root Namespace Scenario: User Needs Help - Given the user has a validator + Given the user has a node When the user runs the command "help" Then the user should be able to see standard output containing "Available Commands" - And the validator should have exited without error \ No newline at end of file + And the node should have exited without error \ No newline at end of file diff --git a/e2e/tests/steps_init_test.go b/e2e/tests/steps_init_test.go index aeaffaf53..bf56d87dd 100644 --- a/e2e/tests/steps_init_test.go +++ b/e2e/tests/steps_init_test.go @@ -71,13 +71,13 @@ func TestFeatures(t *testing.T) { // InitializeScenario registers step regexes to function handlers -func (s *rootSuite) TheUserHasAValidator() { +func (s *rootSuite) TheUserHasANode() { res, err := s.node.RunCommand("help") require.NoErrorf(s, err, res.Stderr) s.node.result = res } -func (s *rootSuite) TheValidatorShouldHaveExitedWithoutError() { +func (s *rootSuite) TheNodeShouldHaveExitedWithoutError() { require.NoError(s, s.node.result.Err) } From 4df3e28621999a51767086ab8ff8e10daf0d40fd Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Wed, 2 Aug 2023 15:32:55 -0700 Subject: [PATCH 08/15] Add account.feature and validator.feature --- Makefile | 4 ++- e2e/tests/{node.feature => account.feature} | 6 ++--- e2e/tests/validator.feature | 27 +++++++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) rename e2e/tests/{node.feature => account.feature} (89%) create mode 100644 e2e/tests/validator.feature diff --git a/Makefile b/Makefile index 0bf862535..f3799e0bf 100644 --- a/Makefile +++ b/Makefile @@ -143,8 +143,10 @@ go_imports: ## Group imports using rinchsan/gosimports go_fmt: ## Format all the .go files in the project in place. gofmt -w -s . +# TODO(kdas): add `rsync_check` as a validation in `install_cli_deps`; https://github.com/pokt-network/pocket/assets/1892194/a7a24a11-f54d-46e2-a73e-9e8ea7d06726 + .PHONY: install_cli_deps -install_cli_deps: rsync_check kubectl_check docker_check ## Installs `helm`, `tilt` and the underlying `ci_deps` +install_cli_deps: kubectl_check docker_check ## Installs `helm`, `tilt` and the underlying `ci_deps` make install_ci_deps curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash diff --git a/e2e/tests/node.feature b/e2e/tests/account.feature similarity index 89% rename from e2e/tests/node.feature rename to e2e/tests/account.feature index 45c73ac41..8e793dcd9 100644 --- a/e2e/tests/node.feature +++ b/e2e/tests/account.feature @@ -2,17 +2,17 @@ Feature: Node Namespace Scenario: User Wants Help Using The Node Command Given the user has a node - When the user runs the command "Node help" + When the user runs the command "Validator help" Then the user should be able to see standard output containing "Available Commands" And the node should have exited without error - Scenario: User Can Stake An Address + Scenario: User Can Stake A Validator Given the user has a node When the user stakes their validator with amount 150000000001 uPOKT Then the user should be able to see standard output containing "" And the node should have exited without error - Scenario: User Can Unstake An Address + Scenario: User Can Unstake A Validator Given the user has a node When the user stakes their validator with amount 150000000001 uPOKT Then the user should be able to see standard output containing "" diff --git a/e2e/tests/validator.feature b/e2e/tests/validator.feature new file mode 100644 index 000000000..e1bd22c4f --- /dev/null +++ b/e2e/tests/validator.feature @@ -0,0 +1,27 @@ +Feature: Validator Namespace + + Scenario: User Wants Help Using The Validator Command + Given the user has a node + When the user runs the command "Validator help" + Then the user should be able to see standard output containing "Available Commands" + And the node should have exited without error + + Scenario: User Can Stake A Validator + Given the user has a node + When the user stakes their validator with amount 150000000001 uPOKT + Then the user should be able to see standard output containing "" + And the node should have exited without error + + Scenario: User Can Unstake A Validator + Given the user has a node + When the user stakes their validator with amount 150000000001 uPOKT + Then the user should be able to see standard output containing "" + Then the user should be able to unstake their validator + Then the user should be able to see standard output containing "" + And the node should have exited without error + + Scenario: User Can Send To An Address + Given the user has a node + When the user sends 150000000 uPOKT to another address + Then the user should be able to see standard output containing "" + And the node should have exited without error From 34f635a6857c1548579b06199fab48fcb7d7308e Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Wed, 2 Aug 2023 15:49:27 -0700 Subject: [PATCH 09/15] Remove kubectl_check from install_cli_deps --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index f3799e0bf..8e9b99a68 100644 --- a/Makefile +++ b/Makefile @@ -143,10 +143,10 @@ go_imports: ## Group imports using rinchsan/gosimports go_fmt: ## Format all the .go files in the project in place. gofmt -w -s . -# TODO(kdas): add `rsync_check` as a validation in `install_cli_deps`; https://github.com/pokt-network/pocket/assets/1892194/a7a24a11-f54d-46e2-a73e-9e8ea7d06726 +# TODO(kdas): add `rsync_check` and `kubectl_check` as a validation in `install_cli_deps`; https://github.com/pokt-network/pocket/assets/1892194/a7a24a11-f54d-46e2-a73e-9e8ea7d06726 .PHONY: install_cli_deps -install_cli_deps: kubectl_check docker_check ## Installs `helm`, `tilt` and the underlying `ci_deps` +install_cli_deps: docker_check ## Installs `helm`, `tilt` and the underlying `ci_deps` make install_ci_deps curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash From 12890634688fecee3675b15d7ba93f2150ef3fe6 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Wed, 2 Aug 2023 16:06:03 -0700 Subject: [PATCH 10/15] Remove kubectl_check from install_cli_deps --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 8e9b99a68..5330a0ff2 100644 --- a/Makefile +++ b/Makefile @@ -143,10 +143,10 @@ go_imports: ## Group imports using rinchsan/gosimports go_fmt: ## Format all the .go files in the project in place. gofmt -w -s . -# TODO(kdas): add `rsync_check` and `kubectl_check` as a validation in `install_cli_deps`; https://github.com/pokt-network/pocket/assets/1892194/a7a24a11-f54d-46e2-a73e-9e8ea7d06726 +# TODO(kdas): add `rsync_check`, `kubectl_check`, `docker_check` as a validation in `install_cli_deps`; https://github.com/pokt-network/pocket/assets/1892194/a7a24a11-f54d-46e2-a73e-9e8ea7d06726 .PHONY: install_cli_deps -install_cli_deps: docker_check ## Installs `helm`, `tilt` and the underlying `ci_deps` +install_cli_deps: ## Installs `helm`, `tilt` and the underlying `ci_deps` make install_ci_deps curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash From 031c10cd70b66101f6deb77f975fcda11844061f Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Wed, 2 Aug 2023 17:22:47 -0700 Subject: [PATCH 11/15] Skip E2E test --- .github/workflows/main.yml | 1 + e2e/tests/state_sync.feature | 2 ++ e2e/tests/steps_init_test.go | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 24d809706..486ab2ba7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -150,6 +150,7 @@ jobs: needs: build-images if: contains(github.event.pull_request.labels.*.name, 'e2e-devnet-test') env: + POCKET_E2E_TEST_TAGS: "~@skip_in_ci" ARGO_HTTP1: true ARGO_SECURE: true ARGO_SERVER: ${{ vars.ARGO_SERVER }} diff --git a/e2e/tests/state_sync.feature b/e2e/tests/state_sync.feature index dc2d96beb..a412f033a 100644 --- a/e2e/tests/state_sync.feature +++ b/e2e/tests/state_sync.feature @@ -2,6 +2,8 @@ Feature: State Sync Namespace # IMPROVE(#959): Remove time-based waits from tests + + @skip_in_ci Scenario: New FullNode does not sync to Blockchain at height 2 Given the network is at genesis And the network has "4" actors of type "Validator" diff --git a/e2e/tests/steps_init_test.go b/e2e/tests/steps_init_test.go index bf56d87dd..1f83171f1 100644 --- a/e2e/tests/steps_init_test.go +++ b/e2e/tests/steps_init_test.go @@ -66,7 +66,8 @@ func (s *rootSuite) Before() { // TestFeatures runs the e2e tests specified in any .features files in this directory // * This test suite assumes that a LocalNet is running that can be accessed by `kubectl` func TestFeatures(t *testing.T) { - gocuke.NewRunner(t, &rootSuite{}).Path("*.feature").Run() + e2eTestTags := os.Getenv("POCKET_E2E_TEST_TAGS") + gocuke.NewRunner(t, &rootSuite{}).Path("*.feature").Tags(e2eTestTags).Run() } // InitializeScenario registers step regexes to function handlers From f5c68ba089cb519fc5d4ddfe41a1874cad6dff9e Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Wed, 2 Aug 2023 17:31:07 -0700 Subject: [PATCH 12/15] Updated TODOs --- Makefile | 5 +++-- e2e/tests/state_sync.feature | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 5330a0ff2..e268d49d8 100644 --- a/Makefile +++ b/Makefile @@ -143,8 +143,9 @@ go_imports: ## Group imports using rinchsan/gosimports go_fmt: ## Format all the .go files in the project in place. gofmt -w -s . -# TODO(kdas): add `rsync_check`, `kubectl_check`, `docker_check` as a validation in `install_cli_deps`; https://github.com/pokt-network/pocket/assets/1892194/a7a24a11-f54d-46e2-a73e-9e8ea7d06726 - +# TODO(#964): add `rsync_check`, `kubectl_check`, `docker_check` as a validation in `install_cli_deps`; https://github.com/pokt-network/pocket/assets/1892194/a7a24a11-f54d-46e2-a73e-9e8ea7d06726 +# .PHONY: install_cli_deps +# install_cli_deps: rsync_check kubectl_check docker_check ## Installs `helm`, `tilt` and the underlying `ci_deps` .PHONY: install_cli_deps install_cli_deps: ## Installs `helm`, `tilt` and the underlying `ci_deps` make install_ci_deps diff --git a/e2e/tests/state_sync.feature b/e2e/tests/state_sync.feature index a412f033a..1aa85fe0e 100644 --- a/e2e/tests/state_sync.feature +++ b/e2e/tests/state_sync.feature @@ -1,8 +1,7 @@ Feature: State Sync Namespace # IMPROVE(#959): Remove time-based waits from tests - - + # TODO(#964): Remove the `skip_in_ci` tag for these tests @skip_in_ci Scenario: New FullNode does not sync to Blockchain at height 2 Given the network is at genesis From fa5577c4d8352334b33a38327d8a62adebc75031 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 3 Aug 2023 12:07:54 -0700 Subject: [PATCH 13/15] Added tags to the ./argo-linux-amd64 commands when running e2e-tests --- .github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 486ab2ba7..c2c58e235 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -150,7 +150,6 @@ jobs: needs: build-images if: contains(github.event.pull_request.labels.*.name, 'e2e-devnet-test') env: - POCKET_E2E_TEST_TAGS: "~@skip_in_ci" ARGO_HTTP1: true ARGO_SECURE: true ARGO_SERVER: ${{ vars.ARGO_SERVER }} @@ -198,4 +197,4 @@ jobs: - id: "run-e2e-tests" run: | - ./argo-linux-amd64 submit --wait --log --namespace devnet-issue-${{ github.event.pull_request.number }} --from 'wftmpl/dev-e2e-tests' --parameter gitsha="${{ github.event.pull_request.head.sha }}" + ./argo-linux-amd64 submit --wait --log --namespace devnet-issue-${{ github.event.pull_request.number }} --from 'wftmpl/dev-e2e-tests' --paramter tags="~@skip_in_ci" --parameter gitsha="${{ github.event.pull_request.head.sha }}" From 33f7d44b93222f9c415609f82db0822f3cccfeaa Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 3 Aug 2023 12:16:30 -0700 Subject: [PATCH 14/15] Empty commit From b9488f4ca80e9cc6fdc8984b6f1d551e39a69aac Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 3 Aug 2023 13:10:37 -0700 Subject: [PATCH 15/15] s/parameter/paramter --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c2c58e235..57ea68386 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -197,4 +197,4 @@ jobs: - id: "run-e2e-tests" run: | - ./argo-linux-amd64 submit --wait --log --namespace devnet-issue-${{ github.event.pull_request.number }} --from 'wftmpl/dev-e2e-tests' --paramter tags="~@skip_in_ci" --parameter gitsha="${{ github.event.pull_request.head.sha }}" + ./argo-linux-amd64 submit --wait --log --namespace devnet-issue-${{ github.event.pull_request.number }} --from 'wftmpl/dev-e2e-tests' --parameter tags="~@skip_in_ci" --parameter gitsha="${{ github.event.pull_request.head.sha }}"