Skip to content

Commit c7855f0

Browse files
committed
WIP: decouple fakes server and add container + README
1 parent 543c96d commit c7855f0

File tree

12 files changed

+745
-416
lines changed

12 files changed

+745
-416
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package fake
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/docker/docker/api/types/container"
8+
"github.com/docker/go-connections/nat"
9+
tc "github.com/testcontainers/testcontainers-go"
10+
tcwait "github.com/testcontainers/testcontainers-go/wait"
11+
)
12+
13+
type Input struct {
14+
Image string `toml:"image"`
15+
Port int `toml:"port" validate:"required"`
16+
Out *Output `toml:"out"`
17+
}
18+
19+
type Output struct {
20+
UseCache bool `toml:"use_cache"`
21+
BaseURLHost string `toml:"base_url_host"`
22+
BaseURLDocker string `toml:"base_url_docker"`
23+
}
24+
25+
func defaults(in *Input) {
26+
}
27+
28+
// NewFakeDataProvider creates new fake data provider
29+
func NewFakeDataProvider(in *Input) (*Output, error) {
30+
if in.Out != nil && in.Out.UseCache {
31+
return in.Out, nil
32+
}
33+
ctx := context.Background()
34+
defaults(in)
35+
bindPort := fmt.Sprintf("%d/tcp", in.Port)
36+
req := tc.ContainerRequest{
37+
Name: in.Image,
38+
Image: in.Image,
39+
//Labels: framework.DefaultTCLabels(),
40+
//Networks: []string{framework.DefaultNetworkName},
41+
//NetworkAliases: map[string][]string{
42+
// framework.DefaultNetworkName: {containerName},
43+
//},
44+
ExposedPorts: []string{bindPort},
45+
HostConfigModifier: func(h *container.HostConfig) {
46+
//h.PortBindings = framework.MapTheSamePort(bindPort)
47+
},
48+
Env: map[string]string{
49+
//"DATABASE_URL": pgOut.JDInternalURL,
50+
},
51+
WaitingFor: tcwait.ForAll(
52+
tcwait.ForListeningPort(nat.Port(fmt.Sprintf("%d/tcp", in.Port))),
53+
),
54+
}
55+
_, err := tc.GenericContainer(ctx, tc.GenericContainerRequest{
56+
ContainerRequest: req,
57+
Started: true,
58+
})
59+
if err != nil {
60+
return nil, err
61+
}
62+
out := &Output{
63+
BaseURLHost: fmt.Sprintf("http://localhost:%d", in.Port),
64+
BaseURLDocker: fmt.Sprintf("%s:%d", HostDockerInternal(), in.Port),
65+
}
66+
in.Out = out
67+
//out := &Output{
68+
// UseCache: true,
69+
// ContainerName: containerName,
70+
// DBContainerName: pgOut.ContainerName,
71+
// ExternalGRPCUrl: fmt.Sprintf("%s:%s", host, in.GRPCPort),
72+
// InternalGRPCUrl: fmt.Sprintf("%s:%s", containerName, in.GRPCPort),
73+
// ExternalWSRPCUrl: fmt.Sprintf("%s:%s", host, in.WSRPCPort),
74+
// InternalWSRPCUrl: fmt.Sprintf("%s:%s", containerName, in.WSRPCPort),
75+
//}
76+
//in.Out = out
77+
return out, nil
78+
}

framework/components/fake/fake.go

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,17 @@ package fake
22

33
import (
44
"fmt"
5+
"os"
56
"regexp"
67

78
"github.com/gin-gonic/gin"
8-
9-
"github.com/smartcontractkit/chainlink-testing-framework/framework"
109
)
1110

1211
var (
1312
Service *gin.Engine
1413
validMethod = regexp.MustCompile("GET|POST|PATCH|PUT|DELETE")
1514
)
1615

17-
type Input struct {
18-
Port int `toml:"port" validate:"required"`
19-
Out *Output `toml:"out"`
20-
}
21-
22-
type Output struct {
23-
BaseURLHost string `toml:"base_url_host"`
24-
BaseURLDocker string `toml:"base_url_docker"`
25-
}
26-
2716
// validate validates method and path, does not allow to override mock
2817
func validate(method, path string) error {
2918
if Service == nil {
@@ -40,7 +29,7 @@ func validate(method, path string) error {
4029
}
4130

4231
// Func fakes method and path with a custom func
43-
func Func(method string, path string, f func(ctx *gin.Context)) error {
32+
func Func(method, path string, f func(ctx *gin.Context)) error {
4433
if err := validate(method, path); err != nil {
4534
return err
4635
}
@@ -49,7 +38,7 @@ func Func(method string, path string, f func(ctx *gin.Context)) error {
4938
}
5039

5140
// JSON fakes for method, path, response and status code
52-
func JSON(method string, path string, response map[string]any, statusCode int) error {
41+
func JSON(method, path string, response map[string]any, statusCode int) error {
5342
if err := validate(method, path); err != nil {
5443
return err
5544
}
@@ -59,17 +48,10 @@ func JSON(method string, path string, response map[string]any, statusCode int) e
5948
return nil
6049
}
6150

62-
// NewFakeDataProvider creates new fake data provider
63-
func NewFakeDataProvider(in *Input) (*Output, error) {
64-
Service = gin.Default()
65-
Service.Use(recordMiddleware())
66-
go func() {
67-
_ = Service.Run(fmt.Sprintf(":%d", in.Port))
68-
}()
69-
out := &Output{
70-
BaseURLHost: fmt.Sprintf("http://localhost:%d", in.Port),
71-
BaseURLDocker: fmt.Sprintf("%s:%d", framework.HostDockerInternal(), in.Port),
51+
// HostDockerInternal returns host.docker.internal that works both locally and in GHA
52+
func HostDockerInternal() string {
53+
if os.Getenv("CI") == "true" {
54+
return "http://172.17.0.1"
7255
}
73-
in.Out = out
74-
return out, nil
56+
return "http://host.docker.internal"
7557
}

framework/components/fake/go.mod

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
module github.com/smartcontractkit/chainlink-testing-framework/framework/components/fake
2+
3+
go 1.24.4
4+
5+
require (
6+
github.com/docker/docker v28.3.1+incompatible
7+
github.com/docker/go-connections v0.5.0
8+
github.com/gin-gonic/gin v1.10.1
9+
github.com/go-resty/resty/v2 v2.16.5
10+
github.com/stretchr/testify v1.10.0
11+
github.com/testcontainers/testcontainers-go v0.37.0
12+
)
13+
14+
require (
15+
dario.cat/mergo v1.0.1 // indirect
16+
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
17+
github.com/Microsoft/go-winio v0.6.2 // indirect
18+
github.com/bytedance/sonic v1.11.6 // indirect
19+
github.com/bytedance/sonic/loader v0.1.1 // indirect
20+
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
21+
github.com/cloudwego/base64x v0.1.4 // indirect
22+
github.com/cloudwego/iasm v0.2.0 // indirect
23+
github.com/containerd/errdefs v1.0.0 // indirect
24+
github.com/containerd/errdefs/pkg v0.3.0 // indirect
25+
github.com/containerd/log v0.1.0 // indirect
26+
github.com/containerd/platforms v0.2.1 // indirect
27+
github.com/cpuguy83/dockercfg v0.3.2 // indirect
28+
github.com/davecgh/go-spew v1.1.1 // indirect
29+
github.com/distribution/reference v0.6.0 // indirect
30+
github.com/docker/go-units v0.5.0 // indirect
31+
github.com/ebitengine/purego v0.8.2 // indirect
32+
github.com/felixge/httpsnoop v1.0.4 // indirect
33+
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
34+
github.com/gin-contrib/sse v0.1.0 // indirect
35+
github.com/go-logr/logr v1.4.3 // indirect
36+
github.com/go-logr/stdr v1.2.2 // indirect
37+
github.com/go-ole/go-ole v1.2.6 // indirect
38+
github.com/go-playground/locales v0.14.1 // indirect
39+
github.com/go-playground/universal-translator v0.18.1 // indirect
40+
github.com/go-playground/validator/v10 v10.20.0 // indirect
41+
github.com/goccy/go-json v0.10.2 // indirect
42+
github.com/gogo/protobuf v1.3.2 // indirect
43+
github.com/google/uuid v1.6.0 // indirect
44+
github.com/json-iterator/go v1.1.12 // indirect
45+
github.com/klauspost/compress v1.18.0 // indirect
46+
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
47+
github.com/leodido/go-urn v1.4.0 // indirect
48+
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
49+
github.com/magiconair/properties v1.8.10 // indirect
50+
github.com/mattn/go-isatty v0.0.20 // indirect
51+
github.com/moby/docker-image-spec v1.3.1 // indirect
52+
github.com/moby/go-archive v0.1.0 // indirect
53+
github.com/moby/patternmatcher v0.6.0 // indirect
54+
github.com/moby/sys/atomicwriter v0.1.0 // indirect
55+
github.com/moby/sys/sequential v0.6.0 // indirect
56+
github.com/moby/sys/user v0.4.0 // indirect
57+
github.com/moby/sys/userns v0.1.0 // indirect
58+
github.com/moby/term v0.5.0 // indirect
59+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
60+
github.com/modern-go/reflect2 v1.0.2 // indirect
61+
github.com/morikuni/aec v1.0.0 // indirect
62+
github.com/opencontainers/go-digest v1.0.0 // indirect
63+
github.com/opencontainers/image-spec v1.1.1 // indirect
64+
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
65+
github.com/pkg/errors v0.9.1 // indirect
66+
github.com/pmezard/go-difflib v1.0.0 // indirect
67+
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
68+
github.com/shirou/gopsutil/v4 v4.25.1 // indirect
69+
github.com/sirupsen/logrus v1.9.3 // indirect
70+
github.com/tklauser/go-sysconf v0.3.12 // indirect
71+
github.com/tklauser/numcpus v0.6.1 // indirect
72+
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
73+
github.com/ugorji/go/codec v1.2.12 // indirect
74+
github.com/yusufpapurcu/wmi v1.2.4 // indirect
75+
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
76+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
77+
go.opentelemetry.io/otel v1.37.0 // indirect
78+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect
79+
go.opentelemetry.io/otel/metric v1.37.0 // indirect
80+
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
81+
go.opentelemetry.io/otel/trace v1.37.0 // indirect
82+
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
83+
golang.org/x/arch v0.8.0 // indirect
84+
golang.org/x/crypto v0.38.0 // indirect
85+
golang.org/x/net v0.40.0 // indirect
86+
golang.org/x/sys v0.33.0 // indirect
87+
golang.org/x/text v0.25.0 // indirect
88+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
89+
google.golang.org/protobuf v1.36.6 // indirect
90+
gopkg.in/yaml.v3 v3.0.1 // indirect
91+
)

framework/examples/myproject/fake_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
type CfgFake struct {
1818
BlockchainA *blockchain.Input `toml:"blockchain_a" validate:"required"`
1919
Fake *fake.Input `toml:"fake" validate:"required"`
20-
NodeSet *ns.Input `toml:"nodeset" validate:"required"`
20+
NodeSets []*ns.Input `toml:"nodesets" validate:"required"`
2121
}
2222

2323
func TestFakes(t *testing.T) {
@@ -28,7 +28,7 @@ func TestFakes(t *testing.T) {
2828
require.NoError(t, err)
2929
fakeOut, err := fake.NewFakeDataProvider(in.Fake)
3030
require.NoError(t, err)
31-
_, err = ns.NewSharedDBNodeSet(in.NodeSet, bc)
31+
_, err = ns.NewSharedDBNodeSet(in.NodeSets[0], bc)
3232
require.NoError(t, err)
3333

3434
t.Run("test fake on host machine", func(t *testing.T) {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
FROM golang:1.24 AS builder
2+
3+
# SSH setup, copy the key you've created for this guide
4+
RUN apt-get update && \
5+
apt-get install -y openssh-client git && \
6+
mkdir -p ~/.ssh && \
7+
chmod 700 ~/.ssh && \
8+
touch ~/.ssh/known_hosts && \
9+
chmod 600 ~/.ssh/known_hosts
10+
RUN ssh-keyscan github.com >> ~/.ssh/known_hosts
11+
RUN --mount=type=secret,id=ssh_key \
12+
cp /run/secrets/ssh_key ~/.ssh/id && \
13+
chmod 600 ~/.ssh/id && \
14+
echo "Host github.com\n IdentityFile ~/.ssh/id\n IdentitiesOnly yes" > ~/.ssh/config && \
15+
chmod 600 ~/.ssh/config
16+
RUN git config --global url."[email protected]:".insteadOf "https://github.com/"
17+
18+
ENV GOPRIVATE=github.com/smartcontractkit/*
19+
20+
WORKDIR /app
21+
COPY go.mod go.sum ./
22+
RUN --mount=type=secret,id=ssh_key go mod download
23+
COPY ../.. .
24+
RUN --mount=type=secret,id=ssh_key CGO_ENABLED=0 GOOS=linux go build -o /fake main.go
25+
26+
FROM alpine:latest
27+
RUN apk --no-cache add ca-certificates
28+
COPY --from=builder /fake /fake
29+
EXPOSE 9111
30+
CMD ["/fake"]
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Example Fakes
2+
3+
This example demonstrate how to write fake services for testing.
4+
5+
Copy this example into your project, write the logic of fake, build and upload it and run.
6+
7+
## Install
8+
9+
To handle some utility command please install `Taskfile`
10+
```
11+
brew install go-task
12+
```
13+
14+
## Private Repositories (Optional)
15+
16+
If your tests are in a private repository please generate a new SSH key and add it on [GitHub](https://github.com/settings/keys). Don't forget to click `Configure SSO` in UI
17+
```
18+
task new-ssh
19+
```
20+
21+
## Usage
22+
23+
Build it and run locally when developing fakes
24+
```
25+
task build -- ${product-name}-${tag} # ex. myproduct-1.0
26+
task run
27+
```
28+
29+
Test it
30+
```
31+
curl "http://localhost:9111/static-fake"
32+
curl "http://localhost:9111/dynamic-fake"
33+
```
34+
Publish it
35+
```
36+
task publish -- $tag
37+
```
38+
39+
Image name is `795953128386.dkr.ecr.us-west-2.amazonaws.com/ccip-fakes:test`
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
version: '3'
3+
4+
tasks:
5+
default:
6+
cmds:
7+
- task --list-all
8+
silent: true
9+
10+
build:
11+
desc: Build the fake server
12+
cmds:
13+
- docker build --secret id=ssh_key,src=$HOME/.ssh/id-dctl --platform linux/amd64 -t test-fakes:{{.CLI_ARGS}} .
14+
- docker tag test-fakes:{{.CLI_ARGS}} localhost:5000/test-fakes:{{.CLI_ARGS}}
15+
- docker tag test-fakes:{{.CLI_ARGS}} 795953128386.dkr.ecr.us-west-2.amazonaws.com/test-fakes:{{.CLI_ARGS}}
16+
silent: false
17+
18+
run:
19+
desc: Run the fake server
20+
cmds:
21+
- docker run --rm -it -p 9111:9111 fake
22+
silent: false
23+
test:
24+
desc: Execute test requests
25+
cmds:
26+
- curl "http://localhost:9111/static-fake"
27+
- echo
28+
- curl "http://localhost:9111/dynamic-fake"
29+
silent: false
30+
31+
publish:
32+
desc: Publish the updated image
33+
cmds:
34+
- aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin 795953128386.dkr.ecr.us-west-2.amazonaws.com
35+
- docker tag test-fakes:{{.CLI_ARGS}} 795953128386.dkr.ecr.us-west-2.amazonaws.com/test-fakes:{{.CLI_ARGS}}
36+
- docker push 795953128386.dkr.ecr.us-west-2.amazonaws.com/test-fakes:{{.CLI_ARGS}}
37+
silent: false
38+
39+
aws-sdlc:
40+
desc: Login to AWS and update K8s config
41+
cmds:
42+
- aws --profile=secure.ci sso login
43+
- aws eks update-kubeconfig --name main-sdlc-cluster --profile secure.ci --alias secure.ci
44+
45+
new-ssh:
46+
desc: Generate new SSH key to access private repositories from the inside of K8s
47+
cmds:
48+
- ssh-keygen -t ed25519 -f ~/.ssh/id-dctl -N "" -q
49+
- echo "Go to GitHub profile, open Settings -> SSH and GPG keys, click 'New SSH Key'"
50+
- echo "Select 'Authentication key' and paste your public key below:"
51+
- cat ~/.ssh/id-dctl.pub
52+
silent: true

0 commit comments

Comments
 (0)