Skip to content

Commit 8982fa1

Browse files
authored
Merge branch 'main' into TT-1955-Create-page-for-flaky-e2e-tests-tips-tricks-and-share-with-developers-and-QA
2 parents dc2bb25 + bf19a54 commit 8982fa1

File tree

17 files changed

+837
-319
lines changed

17 files changed

+837
-319
lines changed

.github/workflows/docker-test.yaml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ on:
55
pull_request:
66
types: [labeled]
77
paths-ignore:
8-
- 'tools/**'
8+
- 'tools/**'
99

1010
jobs:
1111
eth_env:
@@ -26,12 +26,11 @@ jobs:
2626
- name: Checkout the Repo
2727
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
2828
- name: Install Go
29-
uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@d2f9642bcc24a73400568756f24b72c188ac7a9a # v2.3.31
29+
uses: smartcontractkit/.github/actions/setup-golang@01d931b0455a754d12e7143cc54a5a3521a8f6f6 #v 0.3.1
3030
with:
31-
test_download_vendor_packages_command: cd lib && go mod download
32-
go_mod_path: ./lib/go.mod
33-
cache_key_id: ctf-go
34-
cache_restore_only: 'false'
31+
# test_download_vendor_packages_command: cd lib && go mod download
32+
go-version-file: ./lib/go.mod
33+
use-go-cache: "true"
3534
- name: Install gotestloghelper
3635
working-directory: lib
3736
run: make gotestloghelper_build

book/src/SUMMARY.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44
- [Framework](./framework/overview.md)
55
- [Getting Started](./framework/getting_started.md)
66
- [Your First Test](./framework/first_test.md)
7-
- [Connecting Chainlink Node](./framework/connecting_chainlink_node.md)
8-
- [Connecting Chainlink Node (Multiple networks)]()
97
- [NodeSet Environment](./framework/nodeset_environment.md)
8+
- [NodeSet Environment (Import Keys)](./framework/nodeset_environment_import.md)
109
- [NodeSet with Capabilities](./framework/nodeset_capabilities.md)
1110
- [NodeSet (Local Docker builds)](./framework/nodeset_docker_rebuild.md)
1211
- [NodeSet Compat Environment](./framework/nodeset_compatibility.md)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# NodeSet Environment (Import Keys)
2+
3+
If your tests are designed to run not just within a Docker environment but also with external infrastructure, and you want to reuse the test logic across different environments or securely store private keys, refer to the example below.
4+
5+
[Import Keys Example](https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/framework/examples/myproject/smoke_import_keys_test.go)

framework/.changeset/v0.5.4.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- Update WASP doc (rate limiting numerator)
2+
- Expose config validator and translator, so that we can add custom validation functions and error messages

framework/.changeset/v0.5.5.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Add CLClient API to import P2P and EVM keys for a node set + example

framework/clclient/client.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
package clclient
22

33
import (
4+
"crypto/ecdsa"
5+
"crypto/rand"
46
"crypto/tls"
57
"fmt"
8+
"github.com/ethereum/go-ethereum/accounts/keystore"
9+
"github.com/ethereum/go-ethereum/crypto"
10+
"github.com/pkg/errors"
611
"github.com/smartcontractkit/chainlink-testing-framework/framework"
712
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/clnode"
813
"math/big"
@@ -1233,3 +1238,73 @@ func (c *ChainlinkClient) GetForwarders() (*Forwarders, *http.Response, error) {
12331238
}
12341239
return response, resp.RawResponse, err
12351240
}
1241+
1242+
func NewETHKey(password string) ([]byte, error) {
1243+
privateKey, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
1244+
if err != nil {
1245+
return nil, errors.Wrap(err, "failed to generate private key")
1246+
}
1247+
jsonKey, err := keystore.EncryptKey(&keystore.Key{
1248+
PrivateKey: privateKey,
1249+
Address: crypto.PubkeyToAddress(privateKey.PublicKey),
1250+
}, password, keystore.StandardScryptN, keystore.StandardScryptP)
1251+
if err != nil {
1252+
return nil, errors.Wrap(err, "failed to encrypt the keystore")
1253+
}
1254+
return jsonKey, nil
1255+
}
1256+
1257+
// ImportEVMKey imports EVM key to the node (encrypted go-ethereum JSON wallet format)
1258+
func (c *ChainlinkClient) ImportEVMKey(key []byte, chainID string) (*http.Response, error) {
1259+
framework.L.Info().Str(NodeURL, c.Config.URL).Str("Key", string(key)).Msg("Importing EVM key")
1260+
// empty response, nothing to marshal
1261+
resp, err := c.APIClient.R().SetBody(key).Post(fmt.Sprintf("/v2/keys/eth/import?evmChainID=%s", chainID))
1262+
if err != nil {
1263+
return nil, err
1264+
}
1265+
return resp.RawResponse, err
1266+
}
1267+
1268+
// ImportEVMKeys imports an array of EVM keys to the nodes
1269+
func ImportEVMKeys(cl []*ChainlinkClient, keys [][]byte, chainID string) error {
1270+
eg := &errgroup.Group{}
1271+
for i, c := range cl {
1272+
eg.Go(func() error {
1273+
_, err := c.ImportEVMKey(keys[i], chainID)
1274+
if err != nil {
1275+
return err
1276+
}
1277+
return nil
1278+
})
1279+
}
1280+
return eg.Wait()
1281+
}
1282+
1283+
// ImportP2PKey import P2P keys to the node (encrypted go-ethereum JSON wallet format, keystore.EncryptDataV3 + prefix)
1284+
func (c *ChainlinkClient) ImportP2PKey(encryptedJSONKey []byte) (*P2PKey, *http.Response, error) {
1285+
p2pKey := &P2PKey{}
1286+
framework.L.Info().Str(NodeURL, c.Config.URL).Msg("Importing P2P Key")
1287+
resp, err := c.APIClient.R().
1288+
SetBody(encryptedJSONKey).
1289+
SetResult(p2pKey).
1290+
Post("/v2/keys/p2p/import")
1291+
if err != nil {
1292+
return nil, nil, err
1293+
}
1294+
return p2pKey, resp.RawResponse, err
1295+
}
1296+
1297+
// ImportP2PKeys imports an array of P2P keys to the nodes
1298+
func ImportP2PKeys(cl []*ChainlinkClient, keys [][]byte) error {
1299+
eg := &errgroup.Group{}
1300+
for i, c := range cl {
1301+
eg.Go(func() error {
1302+
_, _, err := c.ImportP2PKey(keys[i])
1303+
if err != nil {
1304+
return err
1305+
}
1306+
return nil
1307+
})
1308+
}
1309+
return eg.Wait()
1310+
}

framework/config.go

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,23 @@ import (
66
"encoding/json"
77
"errors"
88
"fmt"
9-
"github.com/davecgh/go-spew/spew"
10-
"github.com/go-playground/validator/v10"
11-
"github.com/pelletier/go-toml/v2"
12-
"github.com/rs/zerolog"
13-
"github.com/stretchr/testify/require"
14-
"github.com/testcontainers/testcontainers-go"
15-
"github.com/testcontainers/testcontainers-go/network"
169
"os"
1710
"path/filepath"
1811
"strings"
1912
"sync"
2013
"testing"
2114
"text/template"
2215
"time"
16+
17+
"github.com/davecgh/go-spew/spew"
18+
"github.com/go-playground/locales/en"
19+
ut "github.com/go-playground/universal-translator"
20+
"github.com/go-playground/validator/v10"
21+
"github.com/pelletier/go-toml/v2"
22+
"github.com/rs/zerolog"
23+
"github.com/stretchr/testify/require"
24+
"github.com/testcontainers/testcontainers-go"
25+
"github.com/testcontainers/testcontainers-go/network"
2326
)
2427

2528
const (
@@ -48,8 +51,18 @@ var (
4851
DefaultNetworkName string
4952

5053
AllowedEmptyConfigurationFields = []string{OutputFieldName, OverridesFieldName}
54+
55+
Validator *validator.Validate = validator.New(validator.WithRequiredStructEnabled())
56+
57+
ValidatorTranslator ut.Translator
5158
)
5259

60+
func init() {
61+
eng := en.New()
62+
uni := ut.New(eng, eng)
63+
ValidatorTranslator, _ = uni.GetTranslator("en")
64+
}
65+
5366
type ValidationError struct {
5467
Field string
5568
Value interface{}
@@ -94,14 +107,21 @@ func mergeInputs[T any]() (*T, error) {
94107

95108
func validateWithCustomErr(cfg interface{}) []ValidationError {
96109
var validationErrors []ValidationError
97-
validate := validator.New(validator.WithRequiredStructEnabled())
98-
err := validate.Struct(cfg)
110+
err := Validator.Struct(cfg)
99111
if err != nil {
100112
for _, err := range err.(validator.ValidationErrors) {
113+
customMessage := err.Translate(ValidatorTranslator)
114+
defaultMessage := fmt.Sprintf("validation failed on '%s' with tag '%s'", err.Field(), err.Tag())
115+
116+
messageToUse := customMessage
117+
if strings.HasPrefix(customMessage, "validation failed") {
118+
messageToUse = defaultMessage
119+
}
120+
101121
validationErrors = append(validationErrors, ValidationError{
102122
Field: err.StructNamespace(),
103123
Value: err.Value(),
104-
Message: fmt.Sprintf("validation failed on '%s' with tag '%s'", err.Field(), err.Tag()),
124+
Message: messageToUse,
105125
})
106126
}
107127
}

0 commit comments

Comments
 (0)