Skip to content

Commit f897c5a

Browse files
authored
Add Dockerized version of fake server, decouple it so it works with K8s (#1949)
Dockerized fake server
1 parent 543c96d commit f897c5a

File tree

23 files changed

+1332
-200
lines changed

23 files changed

+1332
-200
lines changed

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ jobs:
7171
config: local_s3.toml
7272
count: 1
7373
timeout: 10m
74+
- name: TestFakes
75+
config: fake.toml
76+
count: 1
77+
timeout: 10m
78+
# TODO: sdlc auth
79+
# - name: TestDockerFakes
80+
# config: fake_docker.toml
81+
# count: 1
82+
# timeout: 10m
7483
name: ${{ matrix.test.name }}
7584
steps:
7685
- name: Checkout repo

book/src/SUMMARY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
- [Components Caching](framework/components/caching.md)
2727
- [Components Resources](framework/components/resources.md)
2828
- [Containers Network Isolation](framework/components/network_isolation.md)
29-
- [Mocking Services](framework/components/mocking.md)
29+
- [Faking Services](framework/components/mocking.md)
3030
- [Copying Files](framework/copying_files.md)
3131
- [External Environment](framework/components/external.md)
3232
- [Troubleshooting](framework/components/troubleshooting.md)
Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,75 @@
1-
# Mocking Services
1+
# Faking Services
22

3-
The framework aims to equip you with all the necessary tools to write end-to-end system-level tests, while still allowing the flexibility to mock third-party services that are not critical to your testing scope.
3+
The framework aims to equip you with all the necessary tools to write end-to-end system-level tests, while still allowing the flexibility to fake third-party services that are not critical to your testing scope.
44

5-
## Configuration
5+
## Local Usage without Docker (Go runtime)
66
```toml
77
[fake]
88
# port to start Gin server
99
port = 9111
1010
```
1111

12-
## Usage
13-
1412
See [full](https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/framework/examples/myproject/fake_test.go) example.
1513

14+
Run it
15+
```
16+
CTF_CONFIGS=fake.toml go test -v -run TestFakes
17+
```
18+
1619
<div class="warning">
1720

18-
`host.docker.internal` is docker platform dependent!
21+
`host.docker.internal` is Docker platform dependent!
1922

2023
Use `framework.HostDockerInternal()` to reference `host.docker.internal` in your tests, so they can work in GHA CI
2124
</div>
25+
26+
## Dockerized Usage
27+
28+
Copy this example into your project, write the logic of fake using `fake.JSON` and `fake.Func`, build and upload it and run.
29+
30+
## Install
31+
32+
To handle some utility command please install `Taskfile`
33+
```
34+
brew install go-task
35+
```
36+
37+
## Private Repositories (Optional)
38+
39+
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
40+
```
41+
task new-ssh
42+
```
43+
44+
## Usage
45+
46+
Build it and run locally when developing fakes
47+
```
48+
task build -- ${product-name}-${tag} # ex. myproduct-1.0
49+
task run
50+
```
51+
52+
Test it
53+
```
54+
curl "http://localhost:9111/static-fake"
55+
curl "http://localhost:9111/dynamic-fake"
56+
```
57+
Publish it
58+
```
59+
task publish -- $tag
60+
```
61+
62+
See full [example](https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/framework/examples/myproject/fake_docker_test.go)
63+
64+
Run it
65+
```toml
66+
[fake]
67+
# the image you've built
68+
image = "test-fakes:myproduct-1.0"
69+
# port for Gin server
70+
port = 9111
71+
```
72+
73+
```
74+
CTF_CONFIGS=fake_docker.toml go test -v -run TestDockerFakes
75+
```

framework/.changeset/v0.10.0.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Dockerized version of fake server
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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+
"github.com/smartcontractkit/chainlink-testing-framework/framework"
13+
)
14+
15+
// NewDockerFakeDataProvider creates new fake data provider in Docker using testcontainers-go
16+
func NewDockerFakeDataProvider(in *Input) (*Output, error) {
17+
if in.Out != nil && in.Out.UseCache {
18+
return in.Out, nil
19+
}
20+
ctx := context.Background()
21+
bindPort := fmt.Sprintf("%d/tcp", in.Port)
22+
containerName := framework.DefaultTCName("fake")
23+
req := tc.ContainerRequest{
24+
Name: containerName,
25+
Image: in.Image,
26+
Labels: framework.DefaultTCLabels(),
27+
Networks: []string{framework.DefaultNetworkName},
28+
NetworkAliases: map[string][]string{
29+
framework.DefaultNetworkName: {containerName},
30+
},
31+
ExposedPorts: []string{bindPort},
32+
HostConfigModifier: func(h *container.HostConfig) {
33+
h.PortBindings = framework.MapTheSamePort(bindPort)
34+
},
35+
WaitingFor: tcwait.ForAll(
36+
tcwait.ForListeningPort(nat.Port(fmt.Sprintf("%d/tcp", in.Port))),
37+
),
38+
}
39+
_, err := tc.GenericContainer(ctx, tc.GenericContainerRequest{
40+
ContainerRequest: req,
41+
Started: true,
42+
})
43+
if err != nil {
44+
return nil, err
45+
}
46+
out := &Output{
47+
BaseURLHost: fmt.Sprintf("http://localhost:%d", in.Port),
48+
BaseURLDocker: fmt.Sprintf("%s:%d", HostDockerInternal(), in.Port),
49+
}
50+
in.Out = out
51+
return out, nil
52+
}

framework/components/fake/fake.go

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,50 @@ package fake
22

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

78
"github.com/gin-gonic/gin"
89

910
"github.com/smartcontractkit/chainlink-testing-framework/framework"
1011
)
1112

12-
var (
13-
Service *gin.Engine
14-
validMethod = regexp.MustCompile("GET|POST|PATCH|PUT|DELETE")
13+
const (
14+
DefaultFakeServicePort = 9111
1515
)
1616

1717
type Input struct {
18-
Port int `toml:"port" validate:"required"`
19-
Out *Output `toml:"out"`
18+
Image string `toml:"image"`
19+
Port int `toml:"port" validate:"required"`
20+
Out *Output `toml:"out"`
2021
}
2122

2223
type Output struct {
24+
UseCache bool `toml:"use_cache"`
2325
BaseURLHost string `toml:"base_url_host"`
2426
BaseURLDocker string `toml:"base_url_docker"`
2527
}
2628

29+
var (
30+
Service *gin.Engine
31+
validMethod = regexp.MustCompile("GET|POST|PATCH|PUT|DELETE")
32+
)
33+
34+
// NewFakeDataProvider creates new fake data provider
35+
func NewFakeDataProvider(in *Input) (*Output, error) {
36+
Service = gin.Default()
37+
Service.Use(recordMiddleware())
38+
go func() {
39+
_ = Service.Run(fmt.Sprintf(":%d", in.Port))
40+
}()
41+
out := &Output{
42+
BaseURLHost: fmt.Sprintf("http://localhost:%d", in.Port),
43+
BaseURLDocker: fmt.Sprintf("%s:%d", framework.HostDockerInternal(), in.Port),
44+
}
45+
in.Out = out
46+
return out, nil
47+
}
48+
2749
// validate validates method and path, does not allow to override mock
2850
func validate(method, path string) error {
2951
if Service == nil {
@@ -40,7 +62,7 @@ func validate(method, path string) error {
4062
}
4163

4264
// Func fakes method and path with a custom func
43-
func Func(method string, path string, f func(ctx *gin.Context)) error {
65+
func Func(method, path string, f func(ctx *gin.Context)) error {
4466
if err := validate(method, path); err != nil {
4567
return err
4668
}
@@ -49,7 +71,7 @@ func Func(method string, path string, f func(ctx *gin.Context)) error {
4971
}
5072

5173
// JSON fakes for method, path, response and status code
52-
func JSON(method string, path string, response map[string]any, statusCode int) error {
74+
func JSON(method, path string, response map[string]any, statusCode int) error {
5375
if err := validate(method, path); err != nil {
5476
return err
5577
}
@@ -59,17 +81,10 @@ func JSON(method string, path string, response map[string]any, statusCode int) e
5981
return nil
6082
}
6183

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),
84+
// HostDockerInternal returns host.docker.internal that works both locally and in GHA
85+
func HostDockerInternal() string {
86+
if os.Getenv("CI") == "true" {
87+
return "http://172.17.0.1"
7288
}
73-
in.Out = out
74-
return out, nil
89+
return "http://host.docker.internal"
7590
}

framework/components/fake/go.mod

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
module github.com/smartcontractkit/chainlink-testing-framework/framework/components/fake
2+
3+
go 1.24.4
4+
5+
replace github.com/smartcontractkit/chainlink-testing-framework/framework => ../../../framework
6+
7+
require (
8+
github.com/docker/docker v28.3.1+incompatible
9+
github.com/docker/go-connections v0.5.0
10+
github.com/gin-gonic/gin v1.10.1
11+
github.com/go-resty/resty/v2 v2.16.5
12+
github.com/smartcontractkit/chainlink-testing-framework/framework v0.0.0-00010101000000-000000000000
13+
github.com/stretchr/testify v1.10.0
14+
github.com/testcontainers/testcontainers-go v0.37.0
15+
)
16+
17+
require (
18+
dario.cat/mergo v1.0.1 // indirect
19+
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
20+
github.com/Microsoft/go-winio v0.6.2 // indirect
21+
github.com/aws/aws-sdk-go-v2 v1.31.0 // indirect
22+
github.com/aws/aws-sdk-go-v2/config v1.27.39 // indirect
23+
github.com/aws/aws-sdk-go-v2/credentials v1.17.37 // indirect
24+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 // indirect
25+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 // indirect
26+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 // indirect
27+
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
28+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5 // indirect
29+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20 // indirect
30+
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.33.3 // indirect
31+
github.com/aws/aws-sdk-go-v2/service/sso v1.23.3 // indirect
32+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.3 // indirect
33+
github.com/aws/aws-sdk-go-v2/service/sts v1.31.3 // indirect
34+
github.com/aws/smithy-go v1.21.0 // indirect
35+
github.com/bytedance/sonic v1.12.3 // indirect
36+
github.com/bytedance/sonic/loader v0.2.0 // indirect
37+
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
38+
github.com/cloudwego/base64x v0.1.4 // indirect
39+
github.com/cloudwego/iasm v0.2.0 // indirect
40+
github.com/containerd/errdefs v1.0.0 // indirect
41+
github.com/containerd/errdefs/pkg v0.3.0 // indirect
42+
github.com/containerd/log v0.1.0 // indirect
43+
github.com/containerd/platforms v1.0.0-rc.1 // indirect
44+
github.com/cpuguy83/dockercfg v0.3.2 // indirect
45+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
46+
github.com/distribution/reference v0.6.0 // indirect
47+
github.com/docker/go-units v0.5.0 // indirect
48+
github.com/ebitengine/purego v0.8.2 // indirect
49+
github.com/felixge/httpsnoop v1.0.4 // indirect
50+
github.com/gabriel-vasile/mimetype v1.4.6 // indirect
51+
github.com/gin-contrib/sse v0.1.0 // indirect
52+
github.com/go-logr/logr v1.4.3 // indirect
53+
github.com/go-logr/stdr v1.2.2 // indirect
54+
github.com/go-ole/go-ole v1.3.0 // indirect
55+
github.com/go-playground/locales v0.14.1 // indirect
56+
github.com/go-playground/universal-translator v0.18.1 // indirect
57+
github.com/go-playground/validator/v10 v10.22.1 // indirect
58+
github.com/goccy/go-json v0.10.3 // indirect
59+
github.com/gogo/protobuf v1.3.2 // indirect
60+
github.com/google/uuid v1.6.0 // indirect
61+
github.com/json-iterator/go v1.1.12 // indirect
62+
github.com/klauspost/compress v1.18.0 // indirect
63+
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
64+
github.com/leodido/go-urn v1.4.0 // indirect
65+
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
66+
github.com/magiconair/properties v1.8.10 // indirect
67+
github.com/mattn/go-colorable v0.1.13 // indirect
68+
github.com/mattn/go-isatty v0.0.20 // indirect
69+
github.com/moby/docker-image-spec v1.3.1 // indirect
70+
github.com/moby/go-archive v0.1.0 // indirect
71+
github.com/moby/patternmatcher v0.6.0 // indirect
72+
github.com/moby/sys/atomicwriter v0.1.0 // indirect
73+
github.com/moby/sys/sequential v0.6.0 // indirect
74+
github.com/moby/sys/user v0.4.0 // indirect
75+
github.com/moby/sys/userns v0.1.0 // indirect
76+
github.com/moby/term v0.5.2 // indirect
77+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
78+
github.com/modern-go/reflect2 v1.0.2 // indirect
79+
github.com/morikuni/aec v1.0.0 // indirect
80+
github.com/opencontainers/go-digest v1.0.0 // indirect
81+
github.com/opencontainers/image-spec v1.1.1 // indirect
82+
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
83+
github.com/pkg/errors v0.9.1 // indirect
84+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
85+
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
86+
github.com/rs/zerolog v1.33.0 // indirect
87+
github.com/shirou/gopsutil/v4 v4.25.1 // indirect
88+
github.com/sirupsen/logrus v1.9.3 // indirect
89+
github.com/tklauser/go-sysconf v0.3.12 // indirect
90+
github.com/tklauser/numcpus v0.6.1 // indirect
91+
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
92+
github.com/ugorji/go/codec v1.2.12 // indirect
93+
github.com/yusufpapurcu/wmi v1.2.4 // indirect
94+
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
95+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect
96+
go.opentelemetry.io/otel v1.37.0 // indirect
97+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect
98+
go.opentelemetry.io/otel/metric v1.37.0 // indirect
99+
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
100+
go.opentelemetry.io/otel/trace v1.37.0 // indirect
101+
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
102+
golang.org/x/arch v0.11.0 // indirect
103+
golang.org/x/crypto v0.38.0 // indirect
104+
golang.org/x/net v0.40.0 // indirect
105+
golang.org/x/sync v0.14.0 // indirect
106+
golang.org/x/sys v0.33.0 // indirect
107+
golang.org/x/text v0.25.0 // indirect
108+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
109+
google.golang.org/protobuf v1.36.6 // indirect
110+
gopkg.in/yaml.v3 v3.0.1 // indirect
111+
)

0 commit comments

Comments
 (0)