Skip to content

Commit 9c837f8

Browse files
committed
Merge remote-tracking branch 'origin/main' into dx-2789-cre-profiling
2 parents 5a7a992 + 44d9575 commit 9c837f8

13 files changed

Lines changed: 218 additions & 79 deletions

File tree

.github/workflows/framework-golden-tests.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,11 @@ jobs:
5555
config: parallel_ton.toml
5656
count: 1
5757
timeout: 10m
58-
- name: TestUpgrade
59-
config: upgrade.toml
60-
count: 1
61-
timeout: 10m
58+
# Disabled for now, we need to replace Pumba chaos driver
59+
# - name: TestUpgrade
60+
# config: upgrade.toml
61+
# count: 1
62+
# timeout: 10m
6263
- name: TestPerformanceBaseline
6364
config: performance_baseline.toml
6465
count: 1

.github/workflows/test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,4 @@ jobs:
100100
just-version: '1.39.0'
101101
- name: Run tests
102102
run: |
103-
just test ${{ matrix.test.path }} ${{ matrix.test.regex }}
103+
just test ${{ matrix.test.path }} ${{ matrix.test.regex }}

framework/.changeset/v0.14.1.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Forwarder API for clients

framework/clclient/client.go

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ import (
1818
"github.com/ethereum/go-ethereum/accounts/keystore"
1919
"github.com/ethereum/go-ethereum/crypto"
2020
"github.com/pkg/errors"
21+
"github.com/rs/zerolog/log"
2122

2223
"github.com/smartcontractkit/chainlink-testing-framework/framework"
2324
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/clnode"
2425

2526
"github.com/ethereum/go-ethereum/common"
2627
"github.com/go-resty/resty/v2"
27-
"github.com/rs/zerolog/log"
2828
"golang.org/x/sync/errgroup"
2929
)
3030

@@ -33,6 +33,14 @@ const (
3333
ChainlinkKeyPassword string = "twochains"
3434
// NodeURL string for logging
3535
NodeURL string = "Node URL"
36+
// DefaultRetries default CL node client retries
37+
DefaultRetries = 30
38+
// DefaultRetryInterval default CL node client retry interval
39+
DefaultRetryInterval = 5 * time.Second
40+
// DefaultTimeout is a default CL node client timeout
41+
DefaultTimeout = 10 * time.Second
42+
// DefaultAuthRetryCount is a default CL node authorization retry count
43+
DefaultAuthRetryCount = 20
3644
)
3745

3846
var (
@@ -82,36 +90,56 @@ func New(outs []*clnode.Output) ([]*ChainlinkClient, error) {
8290
return clients, nil
8391
}
8492

85-
func initRestyClient(url string, email string, password string, headers map[string]string, timeout *time.Duration) (*resty.Client, error) {
93+
func initRestyClient(url string, email string, password string, headers map[string]string, _ *time.Duration) (*resty.Client, error) {
8694
isDebug := os.Getenv("RESTY_DEBUG") == "true"
8795
// G402 - TODO: certificates
8896
//nolint
89-
rc := resty.New().SetBaseURL(url).SetHeaders(headers).SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).SetDebug(isDebug)
90-
if timeout != nil {
91-
rc.SetTimeout(*timeout)
92-
}
93-
session := &Session{Email: email, Password: password}
94-
// Retry the connection on boot up, sometimes pods can still be starting up and not ready to accept connections
95-
var resp *resty.Response
97+
s := &Session{Email: email, Password: password}
98+
rc := resty.New().
99+
SetBaseURL(url).
100+
SetHeaders(headers).
101+
SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}). //nolint:gosec
102+
SetDebug(isDebug).
103+
SetRetryWaitTime(DefaultRetryInterval).
104+
SetRetryCount(DefaultRetries).
105+
SetRetryAfter(func(c *resty.Client, r *resty.Response) (time.Duration, error) {
106+
return DefaultRetryInterval, nil
107+
}).
108+
SetTimeout(DefaultTimeout)
109+
110+
rc.AddRetryCondition(func(r *resty.Response, err error) bool {
111+
return r.StatusCode() == http.StatusNotFound
112+
})
113+
114+
// Retry the connection on boot up, retrying authorization every time slows down AddRetryCondition too much
96115
var err error
97-
retryCount := 20
98-
for i := 0; i < retryCount; i++ {
99-
resp, err = rc.R().SetBody(session).Post("/sessions")
116+
for i := 0; i < DefaultAuthRetryCount; i++ {
117+
err = Authorize(rc, s)
100118
if err != nil {
101-
log.Warn().Err(err).Str("URL", url).Interface("Session Details", session).Msg("Error connecting to Chainlink node, retrying")
102-
time.Sleep(5 * time.Second)
119+
log.Warn().Err(err).Str("URL", url).Interface("Session Details", s).Msg("Error connecting to Chainlink node, retrying")
120+
time.Sleep(DefaultRetryInterval)
103121
} else {
104122
break
105123
}
106124
}
107125
if err != nil {
108-
return nil, fmt.Errorf("error connecting to chainlink node after %d attempts: %w", retryCount, err)
126+
return nil, fmt.Errorf("error connecting to chainlink node after %d attempts: %w", DefaultAuthRetryCount, err)
109127
}
110-
rc.SetCookies(resp.Cookies())
111128
framework.L.Debug().Str("URL", url).Msg("Connected to Chainlink node")
112129
return rc, nil
113130
}
114131

132+
func Authorize(rc *resty.Client, session *Session) error {
133+
resp, err := rc.R().
134+
SetBody(session).
135+
Post("/sessions")
136+
if err != nil {
137+
return fmt.Errorf("error authorizing in CL node: %w", err)
138+
}
139+
rc.SetCookies(resp.Cookies())
140+
return nil
141+
}
142+
115143
// URL Chainlink instance http url
116144
func (c *ChainlinkClient) URL() string {
117145
return c.Config.URL
@@ -192,7 +220,6 @@ func (c *ChainlinkClient) WaitHealthy(pattern, status string, attempts uint) err
192220
Msg("Retrying health check")
193221
}),
194222
)
195-
196223
if err != nil {
197224
return fmt.Errorf("health check failed after %d attempts: %w", attempts, err)
198225
}

framework/components/blockchain/anvil.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func newAnvil(ctx context.Context, in *Input) (*Output, error) {
5959
framework.L.Info().Any("Cmd", strings.Join(entryPoint, " ")).Msg("Creating anvil with command")
6060

6161
if pods.K8sEnabled() {
62-
_, err := pods.Run(ctx, &pods.Config{
62+
_, svc, err := pods.Run(ctx, &pods.Config{
6363
Pods: []*pods.PodConfig{
6464
{
6565
Name: pods.Ptr(in.ContainerName),
@@ -86,8 +86,9 @@ func newAnvil(ctx context.Context, in *Input) (*Output, error) {
8686
ContainerName: in.ContainerName,
8787
Nodes: []*Node{
8888
{
89-
ExternalWSUrl: fmt.Sprintf("ws://%s:%s", fmt.Sprintf("%s-svc", in.ContainerName), in.Port),
90-
ExternalHTTPUrl: fmt.Sprintf("http://%s:%s", fmt.Sprintf("%s-svc", in.ContainerName), in.Port),
89+
K8sService: svc,
90+
ExternalWSUrl: fmt.Sprintf("ws://%s:%s", "localhost", in.Port),
91+
ExternalHTTPUrl: fmt.Sprintf("http://%s:%s", "localhost", in.Port),
9192
InternalWSUrl: fmt.Sprintf("ws://%s:%s", fmt.Sprintf("%s-svc", in.ContainerName), in.Port),
9293
InternalHTTPUrl: fmt.Sprintf("http://%s:%s", fmt.Sprintf("%s-svc", in.ContainerName), in.Port),
9394
},

framework/components/blockchain/blockchain.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"context"
55
"fmt"
66

7+
v1 "k8s.io/api/core/v1"
8+
79
"github.com/testcontainers/testcontainers-go"
810

911
"github.com/smartcontractkit/chainlink-testing-framework/framework"
@@ -101,6 +103,8 @@ type Node struct {
101103
ExternalHTTPUrl string `toml:"http_url" comment:"External blockchain node HTTP URL"`
102104
InternalWSUrl string `toml:"internal_ws_url" comment:"Internal blockchain node WebSocket URL"`
103105
InternalHTTPUrl string `toml:"internal_http_url" comment:"Internal blockchain node HTTP URL"`
106+
// K8sService is a Kubernetes service spec used to connect locally
107+
K8sService *v1.Service `toml:"k8s_service" comment:"Kubernetes service spec used to connect locally"`
104108
}
105109

106110
func NewBlockchainNetwork(in *Input) (*Output, error) {

framework/components/clnode/clnode.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ type NodeOut struct {
117117
InternalP2PUrl string `toml:"p2p_internal_url" comment:"Node internal P2P URL"`
118118
// InternalIP node internal IP
119119
InternalIP string `toml:"internal_ip" comment:"Node internal IP"`
120+
// K8sService is a Kubernetes service spec used to connect locally
121+
K8sService *v1.Service `toml:"k8s_service" comment:"Kubernetes service spec used to connect locally"`
120122
}
121123

122124
// NewNodeWithDB create a new Chainlink node with some image:tag and one or several configs
@@ -198,14 +200,21 @@ func natPortsToK8sFormat(nat nat.PortMap) []string {
198200
// exposes custom_ports in format "host:docker" or map 1-to-1 if only "host" port is provided
199201
func generatePortBindings(in *Input) ([]string, nat.PortMap, error) {
200202
httpPort := fmt.Sprintf("%s/tcp", DefaultHTTPPort)
201-
exposedPorts := []string{httpPort}
203+
p2pPort := fmt.Sprintf("%s/udp", DefaultP2PPort)
204+
exposedPorts := []string{httpPort, p2pPort}
202205
portBindings := nat.PortMap{
203206
nat.Port(httpPort): []nat.PortBinding{
204207
{
205208
HostIP: "0.0.0.0",
206209
HostPort: strconv.Itoa(in.Node.HTTPPort),
207210
},
208211
},
212+
nat.Port(p2pPort): []nat.PortBinding{
213+
{
214+
HostIP: "0.0.0.0",
215+
HostPort: strconv.Itoa(in.Node.P2PPort),
216+
},
217+
},
209218
}
210219
if os.Getenv("CTF_CLNODE_DLV") == "true" {
211220
innerDebuggerPort := fmt.Sprintf("%d/tcp", DefaultDebuggerPort)
@@ -304,9 +313,14 @@ func newNode(ctx context.Context, in *Input, pgOut *postgres.Output) (*NodeOut,
304313
return nil, err
305314
}
306315

316+
defaultHTTPPortInt, err := strconv.Atoi(DefaultHTTPPort)
317+
if err != nil {
318+
return nil, err
319+
}
320+
307321
// k8s deployment
308322
if pods.K8sEnabled() {
309-
_, err := pods.Run(ctx, &pods.Config{
323+
_, svc, err := pods.Run(ctx, &pods.Config{
310324
Pods: []*pods.PodConfig{
311325
{
312326
Name: pods.Ptr(containerName),
@@ -321,6 +335,7 @@ func newNode(ctx context.Context, in *Input, pgOut *postgres.Output) (*NodeOut,
321335
RunAsUser: pods.Ptr[int64](14933),
322336
RunAsGroup: pods.Ptr[int64](999),
323337
},
338+
ReadinessProbe: pods.TCPReadyProbe(defaultHTTPPortInt),
324339
ConfigMap: map[string]string{
325340
"config.toml": cfg,
326341
"overrides.toml": in.Node.TestConfigOverrides,
@@ -357,9 +372,10 @@ func newNode(ctx context.Context, in *Input, pgOut *postgres.Output) (*NodeOut,
357372
APIAuthUser: DefaultAPIUser,
358373
APIAuthPassword: DefaultAPIPassword,
359374
ContainerName: containerName,
360-
ExternalURL: fmt.Sprintf("http://%s:%d", fmt.Sprintf("%s-svc", containerName), in.Node.HTTPPort),
375+
ExternalURL: fmt.Sprintf("http://%s:%d", "localhost", in.Node.HTTPPort),
361376
InternalURL: fmt.Sprintf("http://%s:%s", containerName, DefaultHTTPPort),
362377
InternalP2PUrl: fmt.Sprintf("http://%s:%s", containerName, DefaultP2PPort),
378+
K8sService: svc,
363379
}, nil
364380
}
365381
// local deployment

framework/components/fake/container.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ type Output struct {
2525
UseCache bool `toml:"use_cache" comment:"Whether to respect caching or not, if cache = true component won't be deployed again"`
2626
BaseURLHost string `toml:"base_url_host" comment:"Base URL which can be used when running locally"`
2727
BaseURLDocker string `toml:"base_url_docker" comment:"Base URL to reach fakes service from other Docker containers"`
28+
// K8sService is a Kubernetes service spec used to connect locally
29+
K8sService *v1.Service `toml:"k8s_service" comment:"Kubernetes service spec used to connect locally"`
2830
}
2931

3032
// NewDockerFakeDataProvider creates new fake data provider in Docker using testcontainers-go
@@ -40,7 +42,7 @@ func NewWithContext(ctx context.Context, in *Input) (*Output, error) {
4042
bindPort := fmt.Sprintf("%d/tcp", in.Port)
4143
containerName := framework.DefaultTCName("fake")
4244
if pods.K8sEnabled() {
43-
_, err := pods.Run(ctx, &pods.Config{
45+
_, svc, err := pods.Run(ctx, &pods.Config{
4446
Pods: []*pods.PodConfig{
4547
{
4648
Name: pods.Ptr(containerName),
@@ -59,13 +61,12 @@ func NewWithContext(ctx context.Context, in *Input) (*Output, error) {
5961
return nil, err
6062
}
6163
in.Out = &Output{
62-
BaseURLHost: fmt.Sprintf("http://%s:%d", fmt.Sprintf("%s-svc", containerName), in.Port),
63-
BaseURLDocker: fmt.Sprintf("http://%s:%d", containerName, in.Port),
64+
K8sService: svc,
65+
BaseURLHost: fmt.Sprintf("http://%s:%d", "localhost", in.Port),
66+
BaseURLDocker: fmt.Sprintf("http://%s:%d", fmt.Sprintf("%s-svc", containerName), in.Port),
6467
}
6568
return in.Out, nil
6669
}
67-
// if pods.K8sEnabled() {
68-
// }
6970
req := tc.ContainerRequest{
7071
Name: containerName,
7172
Image: in.Image,

framework/components/postgres/postgres.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ type Output struct {
6464
JDUrl string `toml:"jd_url" comment:"PostgreSQL internal connection URL to JobDistributor database"`
6565
// JDInternalURL PostgreSQL internal connection URL to JobDistributor database
6666
JDInternalURL string `toml:"jd_internal_url" comment:"PostgreSQL internal connection URL to JobDistributor database"`
67+
// K8sService is a Kubernetes service spec used to connect locally
68+
K8sService *v1.Service `toml:"k8s_service" comment:"Kubernetes service spec used to connect locally"`
6769
}
6870

6971
func NewPostgreSQL(in *Input) (*Output, error) {
@@ -127,7 +129,7 @@ func NewWithContext(ctx context.Context, in *Input) (*Output, error) {
127129

128130
// k8s deployment
129131
if pods.K8sEnabled() {
130-
_, err := pods.Run(ctx, &pods.Config{
132+
_, svc, err := pods.Run(ctx, &pods.Config{
131133
Pods: []*pods.PodConfig{
132134
{
133135
Name: pods.Ptr(in.Name),
@@ -147,8 +149,8 @@ func NewWithContext(ctx context.Context, in *Input) (*Output, error) {
147149
Value: Database,
148150
},
149151
},
150-
Requests: pods.ResourcesLarge(),
151-
Limits: pods.ResourcesLarge(),
152+
Requests: pods.ResourcesMedium(),
153+
Limits: pods.ResourcesMedium(),
152154
// container and pod security settings are specific to
153155
// 'postgres' Docker image
154156
ContainerSecurityContext: &v1.SecurityContext{
@@ -172,6 +174,7 @@ func NewWithContext(ctx context.Context, in *Input) (*Output, error) {
172174
return nil, err
173175
}
174176
o = &Output{
177+
K8sService: svc,
175178
ContainerName: containerName,
176179
InternalURL: fmt.Sprintf(
177180
"postgresql://%s:%s@%s:%d/%s?sslmode=disable",
@@ -186,7 +189,7 @@ func NewWithContext(ctx context.Context, in *Input) (*Output, error) {
186189
"postgresql://%s:%s@%s:%d/%s?sslmode=disable",
187190
User,
188191
Password,
189-
fmt.Sprintf("%s-svc", in.Name),
192+
"localhost",
190193
portToExpose,
191194
Database,
192195
),
@@ -204,7 +207,7 @@ func NewWithContext(ctx context.Context, in *Input) (*Output, error) {
204207
"postgresql://%s:%s@%s:%d/%s?sslmode=disable",
205208
User,
206209
Password,
207-
fmt.Sprintf("%s-svc", in.Name),
210+
"localhost",
208211
portToExpose,
209212
JDDatabase,
210213
)

framework/pods/defaults.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,25 @@ import (
66
v1 "k8s.io/api/core/v1"
77
"k8s.io/apimachinery/pkg/api/resource"
88
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
"k8s.io/apimachinery/pkg/util/intstr"
910
)
1011

12+
// TCPReadyProbe is a default TCP port probe
13+
func TCPReadyProbe(port int) *v1.Probe {
14+
return &v1.Probe{
15+
ProbeHandler: v1.ProbeHandler{
16+
TCPSocket: &v1.TCPSocketAction{
17+
Port: intstr.FromInt(port),
18+
},
19+
},
20+
InitialDelaySeconds: 5,
21+
PeriodSeconds: 10,
22+
FailureThreshold: 3,
23+
SuccessThreshold: 1,
24+
TimeoutSeconds: 5,
25+
}
26+
}
27+
1128
func Resources(cpu, mem string) map[string]string {
1229
return map[string]string{
1330
"cpu": cpu,

0 commit comments

Comments
 (0)