diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1dc750fb60..c53c8ab6ae 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -27,6 +27,40 @@ guidelines: - Commit messages should be prefixed with the package(s) they modify. - E.g. "eth, rpc: make trace configs optional" +### Mocks + +Mocks are auto-generated using [mockgen](https://pkg.go.dev/go.uber.org/mock/mockgen) and `//go:generate` commands in the code. + +- To **re-generate all mocks**, use the command below from the root of the project: + + ```sh + go generate -run "go.uber.org/mock/mockgen" ./... + ``` + +- To **add** an interface that needs a corresponding mock generated: + - if the file `mocks_generate_test.go` exists in the package where the interface is located, either: + - modify its `//go:generate go run go.uber.org/mock/mockgen` to generate a mock for your interface (preferred); or + - add another `//go:generate go run go.uber.org/mock/mockgen` to generate a mock for your interface according to specific mock generation settings + - if the file `mocks_generate_test.go` does not exist in the package where the interface is located, create it with content (adapt as needed): + + ```go + // Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. + // See the file LICENSE for licensing terms. + + package mypackage + + //go:generate go run go.uber.org/mock/mockgen -package=${GOPACKAGE} -destination=mocks_test.go . YourInterface + ``` + + Notes: + 1. Ideally generate all mocks to `mocks_test.go` for the package you need to use the mocks for and do not export mocks to other packages. This reduces package dependencies, reduces production code pollution and forces to have locally defined narrow interfaces. + 1. Prefer using reflect mode to generate mocks than source mode, unless you need a mock for an unexported interface, which should be rare. +- To **remove** an interface from having a corresponding mock generated: + 1. Edit the `mocks_generate_test.go` file in the directory where the interface is defined + 1. If the `//go:generate` mockgen command line: + - generates a mock file for multiple interfaces, remove your interface from the line + - generates a mock file only for the interface, remove the entire line. If the file is empty, remove `mocks_generate_test.go` as well. + ## Documentation guidelines - Code should be well commented, so it is easier to read and maintain. @@ -35,7 +69,7 @@ guidelines: [commentary](https://go.dev/doc/effective_go#commentary) guidelines. - Changes with user facing impact (e.g., addition or modification of flags and options) should be accompanied by a link to a pull request to the [avalanche-docs](https://github.com/ava-labs/avalanche-docs) - repository. [example](https://github.com/ava-labs/avalanche-docs/pull/1119/files). + repository. [example](https://github.com/ava-labs/avalanche-docs/pull/1119/files). - Changes that modify a package significantly or add new features should either update the existing or include a new `README.md` file in that package. diff --git a/.github/workflows/check-clean-branch.sh b/.github/workflows/check-clean-branch.sh deleted file mode 100755 index 1eec74803a..0000000000 --- a/.github/workflows/check-clean-branch.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -# Exits if any uncommitted changes are found. - -set -o errexit -set -o nounset -set -o pipefail - -git update-index --really-refresh >> /dev/null -git diff-index --quiet HEAD diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 896b97c969..693b148805 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -54,6 +54,13 @@ jobs: run: echo "TIMEOUT=1200s" >> "$GITHUB_ENV" - run: go mod download shell: bash + - name: Mocks are up to date + shell: bash + run: | + grep -lr -E '^// Code generated by MockGen\. DO NOT EDIT\.$' . | xargs -r rm + go generate -run "go.uber.org/mock/mockgen" ./... + git add --intent-to-add --all + git diff --exit-code - run: ./scripts/build.sh shell: bash - run: ./scripts/build_test.sh @@ -179,18 +186,6 @@ jobs: if: always() with: name: load-tmpnet-data - mock_gen: - name: MockGen Check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v4 - with: - go-version: ${{ env.min_go_version }} - - shell: bash - run: scripts/mock.gen.sh - - shell: bash - run: .github/workflows/check-clean-branch.sh test_build_image: name: Image build runs-on: ubuntu-latest diff --git a/go.mod b/go.mod index bc313fa633..c53bd1a4a6 100644 --- a/go.mod +++ b/go.mod @@ -44,6 +44,7 @@ require ( go.uber.org/zap v1.26.0 golang.org/x/crypto v0.31.0 golang.org/x/exp v0.0.0-20231127185646-65229373498e + golang.org/x/mod v0.17.0 golang.org/x/sync v0.10.0 golang.org/x/sys v0.28.0 golang.org/x/text v0.21.0 diff --git a/go.sum b/go.sum index 75eb7e874e..e989b5c81d 100644 --- a/go.sum +++ b/go.sum @@ -719,6 +719,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/plugin/evm/validators/state/interfaces/mock_listener.go b/plugin/evm/validators/state/interfaces/mock_listener.go index 053a371d16..d556ebcab8 100644 --- a/plugin/evm/validators/state/interfaces/mock_listener.go +++ b/plugin/evm/validators/state/interfaces/mock_listener.go @@ -3,7 +3,7 @@ // // Generated by this command: // -// mockgen -package=interfaces -destination=plugin/evm/validators/state/interfaces/mock_listener.go github.com/ava-labs/subnet-evm/plugin/evm/validators/state/interfaces StateCallbackListener +// mockgen -package=interfaces -destination=mock_listener.go . StateCallbackListener // // Package interfaces is a generated GoMock package. diff --git a/plugin/evm/validators/state/interfaces/mocks_generate_test.go b/plugin/evm/validators/state/interfaces/mocks_generate_test.go new file mode 100644 index 0000000000..fb08084d17 --- /dev/null +++ b/plugin/evm/validators/state/interfaces/mocks_generate_test.go @@ -0,0 +1,3 @@ +package interfaces + +//go:generate go run go.uber.org/mock/mockgen -package=$GOPACKAGE -destination=mock_listener.go . StateCallbackListener diff --git a/precompile/contract/mocks.go b/precompile/contract/mocks.go index 86943cf6e4..c82db74e3f 100644 --- a/precompile/contract/mocks.go +++ b/precompile/contract/mocks.go @@ -3,7 +3,7 @@ // // Generated by this command: // -// mockgen -package=contract -destination=precompile/contract/mocks.go github.com/ava-labs/subnet-evm/precompile/contract BlockContext,AccessibleState,StateDB +// mockgen -package=contract -destination=mocks.go . BlockContext,AccessibleState,StateDB // // Package contract is a generated GoMock package. diff --git a/precompile/contract/mocks_generate_test.go b/precompile/contract/mocks_generate_test.go new file mode 100644 index 0000000000..4903b47c7c --- /dev/null +++ b/precompile/contract/mocks_generate_test.go @@ -0,0 +1,3 @@ +package contract + +//go:generate go run go.uber.org/mock/mockgen -package=$GOPACKAGE -destination=mocks.go . BlockContext,AccessibleState,StateDB diff --git a/precompile/precompileconfig/mocks.go b/precompile/precompileconfig/mocks.go index 614ec5a522..17ef64a708 100644 --- a/precompile/precompileconfig/mocks.go +++ b/precompile/precompileconfig/mocks.go @@ -3,7 +3,7 @@ // // Generated by this command: // -// mockgen -package=precompileconfig -destination=precompile/precompileconfig/mocks.go github.com/ava-labs/subnet-evm/precompile/precompileconfig Predicater,Config,ChainConfig,Accepter +// mockgen -package=precompileconfig -destination=mocks.go . Predicater,Config,ChainConfig,Accepter // // Package precompileconfig is a generated GoMock package. diff --git a/precompile/precompileconfig/mocks_generate_test.go b/precompile/precompileconfig/mocks_generate_test.go new file mode 100644 index 0000000000..7dcdbbdde0 --- /dev/null +++ b/precompile/precompileconfig/mocks_generate_test.go @@ -0,0 +1,3 @@ +package precompileconfig + +//go:generate go run go.uber.org/mock/mockgen -package=$GOPACKAGE -destination=mocks.go . Predicater,Config,ChainConfig,Accepter diff --git a/scripts/mock.gen.sh b/scripts/mock.gen.sh deleted file mode 100755 index 3550cba16f..0000000000 --- a/scripts/mock.gen.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -# Root directory -SUBNET_EVM_PATH=$( - cd "$(dirname "${BASH_SOURCE[0]}")" - cd .. && pwd -) - -if ! [[ "$0" =~ scripts/mock.gen.sh ]]; then - echo "must be run from repository root" - exit 255 -fi - -# https://github.com/uber-go/mock -go install -v go.uber.org/mock/mockgen@v0.4.0 - -if ! command -v go-license &>/dev/null; then - echo "go-license not found, installing..." - # https://github.com/palantir/go-license - go install -v github.com/palantir/go-license@v1.25.0 -fi - -# Load the constants -source "$SUBNET_EVM_PATH"/scripts/constants.sh - -# tuples of (source interface import path, comma-separated interface names, output file path) -input="scripts/mocks.mockgen.txt" -while IFS= read -r line; do - IFS='=' read -r src_import_path interface_name output_path <<<"${line}" - package_name=$(basename "$(dirname "$output_path")") - echo "Generating ${output_path}..." - mockgen -package="${package_name}" -destination="${output_path}" "${src_import_path}" "${interface_name}" - - go-license \ - --config=./header.yml \ - "${output_path}" -done <"$input" - -echo "SUCCESS" diff --git a/scripts/mocks.mockgen.txt b/scripts/mocks.mockgen.txt deleted file mode 100644 index aba87c80da..0000000000 --- a/scripts/mocks.mockgen.txt +++ /dev/null @@ -1,3 +0,0 @@ -github.com/ava-labs/subnet-evm/precompile/precompileconfig=Predicater,Config,ChainConfig,Accepter=precompile/precompileconfig/mocks.go -github.com/ava-labs/subnet-evm/precompile/contract=BlockContext,AccessibleState,StateDB=precompile/contract/mocks.go -github.com/ava-labs/subnet-evm/plugin/evm/validators/state/interfaces=StateCallbackListener=plugin/evm/validators/state/interfaces/mock_listener.go diff --git a/tools.go b/tools.go new file mode 100644 index 0000000000..312a2d6302 --- /dev/null +++ b/tools.go @@ -0,0 +1,8 @@ +// (c) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package subnetevm + +import ( + _ "golang.org/x/mod/modfile" // golang.org/x/mod to satisfy requirement for go.uber.org/mock/mockgen@v0.4 +) diff --git a/warp/aggregator/mock_signature_getter.go b/warp/aggregator/mock_signature_getter.go index 537e3ae2e1..dcc88564b5 100644 --- a/warp/aggregator/mock_signature_getter.go +++ b/warp/aggregator/mock_signature_getter.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/ava-labs/subnet-evm/warp/aggregator (interfaces: SignatureGetter) +// Source: signature_getter.go +// +// Generated by this command: +// +// mockgen -package=aggregator -source=signature_getter.go -destination=mock_signature_getter.go -exclude_interfaces=NetworkClient +// // Package aggregator is a generated GoMock package. package aggregator @@ -38,16 +43,16 @@ func (m *MockSignatureGetter) EXPECT() *MockSignatureGetterMockRecorder { } // GetSignature mocks base method. -func (m *MockSignatureGetter) GetSignature(arg0 context.Context, arg1 ids.NodeID, arg2 *warp.UnsignedMessage) (*bls.Signature, error) { +func (m *MockSignatureGetter) GetSignature(ctx context.Context, nodeID ids.NodeID, unsignedWarpMessage *warp.UnsignedMessage) (*bls.Signature, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSignature", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetSignature", ctx, nodeID, unsignedWarpMessage) ret0, _ := ret[0].(*bls.Signature) ret1, _ := ret[1].(error) return ret0, ret1 } // GetSignature indicates an expected call of GetSignature. -func (mr *MockSignatureGetterMockRecorder) GetSignature(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockSignatureGetterMockRecorder) GetSignature(ctx, nodeID, unsignedWarpMessage any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSignature", reflect.TypeOf((*MockSignatureGetter)(nil).GetSignature), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSignature", reflect.TypeOf((*MockSignatureGetter)(nil).GetSignature), ctx, nodeID, unsignedWarpMessage) } diff --git a/warp/aggregator/mocks_generate_test.go b/warp/aggregator/mocks_generate_test.go new file mode 100644 index 0000000000..de176f9074 --- /dev/null +++ b/warp/aggregator/mocks_generate_test.go @@ -0,0 +1,3 @@ +package aggregator + +//go:generate go run go.uber.org/mock/mockgen -package=$GOPACKAGE -source=signature_getter.go -destination=mock_signature_getter.go -exclude_interfaces=NetworkClient