From 3a467c0aa7db15d4450a7b912ae79d4c14505f0a Mon Sep 17 00:00:00 2001 From: Darren Kelly Date: Mon, 15 Jan 2024 16:26:43 +0000 Subject: [PATCH] feat: enabling e2e tests --- .dockerignore | 4 ++ .github/CONTRIBUTING.md | 54 ++++++++++++++++++- .github/workflows/lint-go.yaml | 31 +++++++++++ .github/workflows/test-e2e.yaml | 91 +++++++++++++++++++++++++++++++++ .gitmodules | 3 ++ .golangci.pull-request.yml | 13 +++++ .golangci.yml | 15 ++++++ Makefile | 26 +++++++--- README.md | 4 ++ api/accounts/types.go | 4 +- api/transactions/types.go | 4 +- cmd/thor/main.go | 8 +-- cmd/thor/utils.go | 11 ++-- p2psrv/bootstrap_nodes.go | 3 +- tests/thor-e2e-tests | 1 + txpool/blocklist.go | 3 +- vm/bn256/cloudflare/optate.go | 2 + vm/contracts.go | 3 +- 18 files changed, 251 insertions(+), 29 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/lint-go.yaml create mode 100644 .github/workflows/test-e2e.yaml create mode 100644 .golangci.pull-request.yml create mode 100644 .golangci.yml create mode 160000 tests/thor-e2e-tests diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..85376b5eb --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +tests +README.md +thorest.png +CODE_OF_CONDUCT.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 8f2cb4c9d..7c11002f0 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -34,7 +34,8 @@ current development landscape. ```bash make test ``` - - **Note:**: Please refer to the [README](https://github.com/vechain/thor/blob/master/README.md) for information on how to start the node and interact with the + - **Note:**: Please refer to the [README](https://github.com/vechain/thor/blob/master/README.md) for information on + how to start the node and interact with the API. 5. Make your changes and commit them with a clear and concise commit message. 6. Push your changes to your forked repository: @@ -57,3 +58,54 @@ current development landscape. - We follow the [Effective Go](https://golang.org/doc/effective_go) guidelines. Please make sure your code is idiomatic and follows the guidelines. + +### Code Linting + +- We employ `golangci-lint` for code linting in our development process. It ensures that code adheres to established standards, and any changes that do not pass the linting checks will trigger an error during the Continuous Integration (CI) process. +- You can run it locally by installing the `golangci-lint` binary and running `make lint` in the root directory of the repository. + +## Testing + +### Unit Tests + +```bash +make test +``` + +### Unit Tests with Coverage + +```bash +make test-coverage +``` + +### E2E Tests + +Our E2E tests are written in TypeScript, utilizing hardhat contract solidity development tools. Before running the E2E +tests, ensure you have the following prerequisites installed: + +- [Docker](https://docs.docker.com/get-docker/) +- [Node.js](https://nodejs.org/en/download/) +- [Yarn](https://classic.yarnpkg.com/en/docs/install/) +- [Git](https://git-scm.com/downloads) + + +The E2E tests are located in the tests/thor-e2e-tests directory as a submodule. If you haven't initialized the submodule yet, run: + +```bash +git submodule update --init --recursive +``` + +To run the E2E tests, build the Docker image first: + +```bash +docker build -t vechain/thor-e2e . +export THOR_IMAGE=vechain/thor-e2e +``` + +Then, you can run the tests: + +```bash +cd tests/thor-e2e-tests +yarn install +yarn test +``` diff --git a/.github/workflows/lint-go.yaml b/.github/workflows/lint-go.yaml new file mode 100644 index 000000000..30eb70d7b --- /dev/null +++ b/.github/workflows/lint-go.yaml @@ -0,0 +1,31 @@ +name: Lint + +on: + push: + branches: + - master + pull_request: + +permissions: + contents: read + +jobs: + golangci: + name: golangci-lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v4 + with: + go-version: '1.21' + cache: false + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + version: v1.54 + # use the default if on main branch, otherwise use the pull request config + args: --timeout=30m --config=${{ github.event_name == 'pull_request' && '.golangci.pull-request.yml' || '.golangci.yml' }} + only-new-issues: true + skip-cache: true + skip-pkg-cache: true + skip-build-cache: true diff --git a/.github/workflows/test-e2e.yaml b/.github/workflows/test-e2e.yaml new file mode 100644 index 000000000..b9151fabf --- /dev/null +++ b/.github/workflows/test-e2e.yaml @@ -0,0 +1,91 @@ +name: E2E Tests + +on: + pull_request: + branches: + - master + push: + branches: + - master + +jobs: + build-docker-image: + name: Build Docker image + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and export + uses: docker/build-push-action@v5 + with: + context: . + tags: vechain/thor:${{ github.sha }} + outputs: type=docker,dest=/tmp/vechain-thor.tar + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: vechain-thor-image + path: /tmp/vechain-thor.tar + retention-days: 7 + + run-tests: + runs-on: ubuntu-latest + needs: build-docker-image + env: + THOR_IMAGE: vechain/thor:${{ github.sha }} + name: Run E2E Tests + steps: + + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: true + + - name: Download artifact + uses: actions/download-artifact@v3 + with: + name: vechain-thor-image + path: /tmp + + - name: Setup Node JS + uses: actions/setup-node@v4 + with: + node-version: '18.x' + + - name: Load image + run: | + docker load --input /tmp/vechain-thor.tar + docker image ls -a + + - name: Run Tests + working-directory: ./tests/thor-e2e-tests + run: | + export THOR_IMAGE=vechain/thor:${{ github.sha }} + yarn install + yarn test + + - name: Publish Results + uses: dorny/test-reporter@v1 + id: test-reporter + if: success() || failure() + with: + name: E2E Test Results + only-summary: 'false' + list-suites: 'all' + list-tests: 'failed' + fail-on-error: 'true' + reporter: "jest-junit" + path: | + ./tests/thor-e2e-tests/junit.xml + + - name: Echo Report URL + run: | + echo ${{steps.test-reporter.outputs.url_html}} diff --git a/.gitmodules b/.gitmodules index e69de29bb..3441a15eb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tests/thor-e2e-tests"] + path = tests/thor-e2e-tests + url = https://github.com/vechain/thor-e2e-tests.git diff --git a/.golangci.pull-request.yml b/.golangci.pull-request.yml new file mode 100644 index 000000000..4626647a3 --- /dev/null +++ b/.golangci.pull-request.yml @@ -0,0 +1,13 @@ +# Please refer to the official golangci-lint config documentation for more details: +# https://golangci-lint.run/usage/configuration/ +# https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml + +linters: + enable-all: true + +run: + timeout: 10m + tests: false + +issues: + max-issues-per-linter: 1000 diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 000000000..92c987a7d --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,15 @@ +# Please refer to the official golangci-lint config documentation for more details: +# https://golangci-lint.run/usage/configuration/ +# https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml + +linters: + disable: + - unused + - errcheck + +run: + timeout: 10m + tests: false + +issues: + max-issues-per-linter: 1000 diff --git a/Makefile b/Makefile index 60e01cee8..91b76c140 100644 --- a/Makefile +++ b/Makefile @@ -13,12 +13,15 @@ export GO111MODULE=on .PHONY: thor disco all clean test -thor:| go_version_check +help: + @egrep -h '\s#@\s' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?#@ "}; {printf "\033[36m %-30s\033[0m %s\n", $$1, $$2}' + +thor:| go_version_check #@ Build the `thor` executable @echo "building $@..." @go build -v -o $(CURDIR)/bin/$@ -ldflags "-X main.version=$(THOR_VERSION) -X main.gitCommit=$(GIT_COMMIT) -X main.gitTag=$(GIT_TAG)" ./cmd/thor @echo "done. executable created at 'bin/$@'" -disco:| go_version_check +disco:| go_version_check #@ Build the `disco` executable @echo "building $@..." @go build -v -o $(CURDIR)/bin/$@ -ldflags "-X main.version=$(DISCO_VERSION) -X main.gitCommit=$(GIT_COMMIT) -X main.gitTag=$(GIT_TAG)" ./cmd/disco @echo "done. executable created at 'bin/$@'" @@ -37,16 +40,25 @@ go_version_check: fi \ fi -all: thor disco +all: thor disco #@ Build the `thor` and `disco` executables -clean: +clean: #@ Clean the build artifacts -rm -rf \ $(CURDIR)/bin/thor \ -$(CURDIR)/bin/disco +$(CURDIR)/bin/disco -test:| go_version_check +test:| go_version_check #@ Run the tests @go test -cover $(PACKAGES) -test-coverage:| go_version_check +test-coverage:| go_version_check #@ Run the tests with coverage @go test -race -coverprofile=coverage.out -covermode=atomic $(PACKAGES) @go tool cover -html=coverage.out + +lint_command_check: + @command -v golangci-lint || (echo "golangci-lint not found, please install it from https://golangci-lint.run/usage/install/" && exit 1) + +lint: | go_version_check lint_command_check #@ Run 'golangci-lint' on new code changes + @golangci-lint run --new --config .golangci.pull-request.yml + +lint-all: | go_version_check lint_command_check #@ Run 'golangci-lint' on the entire codebase + @golangci-lint run --config .golangci.yml diff --git a/README.md b/README.md index 00d0f523f..bcb640230 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,8 @@ git clone https://github.com/vechain/thor.git cd thor ``` +To see a list of all available commands, run `make help` + ### Building To build the main app `thor`, just run @@ -209,3 +211,5 @@ A special shout out to following projects: Vechain Thor is licensed under the [GNU Lesser General Public License v3.0](https://www.gnu.org/licenses/lgpl-3.0.html), also included in *LICENSE* file in repository. + + diff --git a/api/accounts/types.go b/api/accounts/types.go index d54b9f462..d220232bb 100644 --- a/api/accounts/types.go +++ b/api/accounts/types.go @@ -59,9 +59,7 @@ func convertCallResultWithInputGas(vo *runtime.Output, inputGas uint64) *CallRes Data: hexutil.Encode(txEvent.Data), } event.Topics = make([]thor.Bytes32, len(txEvent.Topics)) - for k, topic := range txEvent.Topics { - event.Topics[k] = topic - } + copy(event.Topics, txEvent.Topics) events[j] = event } for j, txTransfer := range vo.Transfers { diff --git a/api/transactions/types.go b/api/transactions/types.go index 34644f942..cb2380694 100644 --- a/api/transactions/types.go +++ b/api/transactions/types.go @@ -205,9 +205,7 @@ func convertReceipt(txReceipt *tx.Receipt, header *block.Header, tx *tx.Transact Data: hexutil.Encode(txEvent.Data), } event.Topics = make([]thor.Bytes32, len(txEvent.Topics)) - for k, topic := range txEvent.Topics { - event.Topics[k] = topic - } + copy(event.Topics, txEvent.Topics) otp.Events[j] = event } diff --git a/cmd/thor/main.go b/cmd/thor/main.go index f18150fc9..66118c9e7 100644 --- a/cmd/thor/main.go +++ b/cmd/thor/main.go @@ -8,7 +8,7 @@ package main import ( "encoding/json" "fmt" - "io/ioutil" + "io" "os" "path/filepath" "time" @@ -16,7 +16,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/crypto" "github.com/inconshreveable/log15" - isatty "github.com/mattn/go-isatty" + "github.com/mattn/go-isatty" "github.com/pborman/uuid" "github.com/pkg/errors" "github.com/vechain/thor/v2/api" @@ -30,7 +30,7 @@ import ( "github.com/vechain/thor/v2/state" "github.com/vechain/thor/v2/thor" "github.com/vechain/thor/v2/txpool" - cli "gopkg.in/urfave/cli.v1" + "gopkg.in/urfave/cli.v1" // Force-load the tracer engines to trigger registration _ "github.com/vechain/thor/v2/tracers/js" @@ -355,7 +355,7 @@ func masterKeyAction(ctx *cli.Context) error { if isatty.IsTerminal(os.Stdin.Fd()) { fmt.Println("Input JSON keystore (end with ^d):") } - keyjson, err := ioutil.ReadAll(os.Stdin) + keyjson, err := io.ReadAll(os.Stdin) if err != nil { return err } diff --git a/cmd/thor/utils.go b/cmd/thor/utils.go index 9765705c5..be6a62b45 100644 --- a/cmd/thor/utils.go +++ b/cmd/thor/utils.go @@ -11,7 +11,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "math" "net" "net/http" @@ -34,7 +33,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/rlp" "github.com/inconshreveable/log15" - tty "github.com/mattn/go-tty" + "github.com/mattn/go-tty" "github.com/pkg/errors" "github.com/vechain/thor/v2/api/doc" "github.com/vechain/thor/v2/chain" @@ -49,7 +48,7 @@ import ( "github.com/vechain/thor/v2/thor" "github.com/vechain/thor/v2/tx" "github.com/vechain/thor/v2/txpool" - cli "gopkg.in/urfave/cli.v1" + "gopkg.in/urfave/cli.v1" ) func initLogger(ctx *cli.Context) { @@ -146,7 +145,7 @@ func handleXGenesisID(h http.Handler, genesisID thor.Bytes32) http.Handler { } w.Header().Set(headerKey, expectedID) if actualID != "" && actualID != expectedID { - io.Copy(ioutil.Discard, r.Body) + io.Copy(io.Discard, r.Body) http.Error(w, "genesis id mismatch", http.StatusForbidden) return } @@ -445,7 +444,7 @@ func newP2PComm(ctx *cli.Context, repo *chain.Repository, txPool *txpool.TxPool, peersCachePath := filepath.Join(instanceDir, "peers.cache") - if data, err := ioutil.ReadFile(peersCachePath); err != nil { + if data, err := os.ReadFile(peersCachePath); err != nil { if !os.IsNotExist(err) { log.Warn("failed to load peers cache", "err", err) } @@ -500,7 +499,7 @@ func (p *p2pComm) Stop() { log.Warn("failed to encode cached peers", "err", err) return } - if err := ioutil.WriteFile(p.peersCachePath, data, 0600); err != nil { + if err := os.WriteFile(p.peersCachePath, data, 0600); err != nil { log.Warn("failed to write peers cache", "err", err) } } diff --git a/p2psrv/bootstrap_nodes.go b/p2psrv/bootstrap_nodes.go index 209e1bb9b..a52391b74 100644 --- a/p2psrv/bootstrap_nodes.go +++ b/p2psrv/bootstrap_nodes.go @@ -5,7 +5,6 @@ import ( "context" "fmt" "io" - "io/ioutil" "net/http" "github.com/ethereum/go-ethereum/p2p/discv5" @@ -22,7 +21,7 @@ func fetchRemoteBootstrapNodes(ctx context.Context, remoteURL string) ([]*discv5 return nil, err } defer resp.Body.Close() - defer io.Copy(ioutil.Discard, resp.Body) + defer io.Copy(io.Discard, resp.Body) if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("http fetch failed: statusCode=%d", resp.StatusCode) diff --git a/tests/thor-e2e-tests b/tests/thor-e2e-tests new file mode 160000 index 000000000..c33c98529 --- /dev/null +++ b/tests/thor-e2e-tests @@ -0,0 +1 @@ +Subproject commit c33c985298bb70406cdacbd51fce80e6dd50c3d7 diff --git a/txpool/blocklist.go b/txpool/blocklist.go index b87238410..0f9f6b5c1 100644 --- a/txpool/blocklist.go +++ b/txpool/blocklist.go @@ -10,7 +10,6 @@ import ( "context" "fmt" "io" - "io/ioutil" "net/http" "os" "strings" @@ -83,7 +82,7 @@ func (bl *blocklist) Fetch(ctx context.Context, url string, eTag *string) error return err } defer resp.Body.Close() - defer io.Copy(ioutil.Discard, resp.Body) + defer io.Copy(io.Discard, resp.Body) if resp.StatusCode == http.StatusNotModified { return nil diff --git a/vm/bn256/cloudflare/optate.go b/vm/bn256/cloudflare/optate.go index b71e50e3a..fca297353 100644 --- a/vm/bn256/cloudflare/optate.go +++ b/vm/bn256/cloudflare/optate.go @@ -199,8 +199,10 @@ func miller(q *twistPoint, p *curvePoint) *gfP12 { r = newR r2.Square(&minusQ2.y) + //nolint: staticcheck a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2) mulLine(ret, a, b, c) + //nolint: staticcheck r = newR return ret diff --git a/vm/contracts.go b/vm/contracts.go index 36fa3b0f3..2e099f3d2 100644 --- a/vm/contracts.go +++ b/vm/contracts.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" + // nolint:staticcheck "golang.org/x/crypto/ripemd160" "github.com/vechain/thor/v2/blake2b" @@ -473,7 +474,7 @@ func (c *blake2F) Run(input []byte) ([]byte, error) { // Parse the input into the Blake2b call parameters var ( rounds = binary.BigEndian.Uint32(input[0:4]) - final = (input[212] == blake2FFinalBlockBytes) + final = input[212] == blake2FFinalBlockBytes h [8]uint64 m [16]uint64