Skip to content

Commit 0da4359

Browse files
committed
First draft and rename
1 parent 1b3b249 commit 0da4359

File tree

10 files changed

+903
-0
lines changed

10 files changed

+903
-0
lines changed

parrot/.dockerignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Dockerfile
2+
*.md
3+
*.log
4+
.gitignore
5+
.golangci-lint.yml
6+
.goreleaser.yml
7+
.pre-commit-config.yaml
8+
*_test.go
9+
LICENSE
10+
.vscode/
11+
dist/
12+
.github/
13+
save.json

parrot/.goreleaser.yaml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json
2+
version: 1
3+
project_name: parrotserver
4+
5+
monorepo:
6+
tag_prefix: parrotserver/
7+
dir: parrotserver
8+
9+
env:
10+
- IMG_PRE={{ if index .Env "IMAGE_PREFIX" }}{{ .Env.IMAGE_PREFIX }}{{ else }}local{{ end }}
11+
- TAG={{ if index .Env "IMAGE_TAG" }}{{ .Env.IMAGE_TAG }}{{ else }}latest{{ end }}
12+
13+
# Build settings for binaries
14+
builds:
15+
- id: parrotserver
16+
goos:
17+
- linux
18+
- darwin
19+
goarch:
20+
- amd64
21+
- arm64
22+
ldflags:
23+
- '-s -w'
24+
25+
archives:
26+
- format: binary
27+
28+
dockers:
29+
- id: linux-amd64-parrotserver
30+
goos: linux
31+
goarch: amd64
32+
image_templates:
33+
- '{{ .Env.IMG_PRE }}/parrotserver:{{ .Tag }}'
34+
- '{{ .Env.IMG_PRE }}/parrotserver:latest'
35+
build_flag_templates:
36+
- --platform=linux/amd64
37+
- --pull
38+
- --label=org.opencontainers.image.created={{.Date}}
39+
- --label=org.opencontainers.image.title={{.ProjectName}}
40+
- --label=org.opencontainers.image.revision={{.FullCommit}}
41+
- --label=org.opencontainers.image.version={{.Version}}
42+
- id: linux-arm64-parrotserver
43+
goos: linux
44+
goarch: arm64
45+
image_templates:
46+
- '{{ .Env.IMG_PRE }}/parrotserver:{{ .Tag }}-arm64'
47+
- '{{ .Env.IMG_PRE }}/parrotserver:latest-arm64'
48+
build_flag_templates:
49+
- --platform=linux/arm64
50+
- --pull
51+
- --label=org.opencontainers.image.created={{.Date}}
52+
- --label=org.opencontainers.image.title={{.ProjectName}}
53+
- --label=org.opencontainers.image.revision={{.FullCommit}}
54+
- --label=org.opencontainers.image.version={{.Version}}
55+
56+
before:
57+
hooks:
58+
- cd parrotserver && go mod tidy

parrot/Dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
FROM scratch
2+
COPY parrotserver /parrotserver
3+
ENTRYPOINT [ "parrotserver" ]

parrot/Makefile

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
.PHONY: lint
2+
lint:
3+
golangci-lint --color=always run ./... --fix -v
4+
5+
.PHONY: test
6+
test:
7+
go install github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest
8+
set -euo pipefail
9+
go test -json -cover -coverprofile cover.out -v ./... 2>&1 | tee /tmp/gotest.log | gotestfmt
10+
11+
.PHONY: test_race
12+
test_race:
13+
go install github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest
14+
set -euo pipefail
15+
go test -json -cover -count=1 -race -coverprofile cover.out -v ./... 2>&1 | tee /tmp/gotest.log | gotestfmt
16+
17+
.PHONY: test_unit
18+
test_unit:
19+
go test -coverprofile cover.out ./...
20+
21+
.PHONY: bench
22+
bench:
23+
go test -bench=. -run=^$$ ./...

parrot/README.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Parrot Server
2+
3+
A simple, high-performing mockserver that can dynamically build new routes with customized responses, parroting back whatever you tell it to.
4+
5+
## Use
6+
7+
Call the `/register` endpoint to define a route.
8+
9+
### Curl
10+
11+
```sh
12+
curl -X POST http://localhost:8080/register -d '{
13+
"method": "GET",
14+
"path": "/hello",
15+
"response": "{\"message\": \"Hello, world!\"}",
16+
"status_code": 200,
17+
"content_type": "application/json"
18+
}' -H "Content-Type: application/json"
19+
```
20+
21+
### Go and [Resty](https://github.com/go-resty/resty)
22+
23+
```go
24+
client := resty.New()
25+
26+
route := map[string]any{
27+
"method": "GET",
28+
"path": "/hello",
29+
"response": "{\"message\":\"Hello, world!\"}",
30+
"status_code": 200,
31+
"content_type": "application/json",
32+
}
33+
34+
resp, _ := client.R().
35+
SetHeader("Content-Type", "application/json").
36+
SetBody(route).
37+
Post("http://localhost:8080/register")
38+
```
39+
40+
You can now call your endpoint and receive the JSON response back.
41+
42+
```sh
43+
curl -X GET http://localhost:8080/hello -H "Content-Type: application/json"
44+
# {"message":"Hello, world!"}
45+
```
46+
47+
## Configure
48+
49+
Config is through environment variables.
50+
51+
| **Environment Variable** | **Description** | **Default Value** |
52+
| ------------------------ | -------------------------------------------------------------- | ----------------- |
53+
| `LOG_LEVEL` | Controls the logging level (`debug`, `info`, `warn`, `error`). | `debug` |
54+
| `SAVE_FILE` | Path to the file where routes are saved and loaded. | `save.json` |
55+
56+
## Run
57+
58+
```sh
59+
go run .
60+
```
61+
62+
## Test
63+
64+
```sh
65+
go test -cover -race ./...
66+
```
67+
68+
## Benchmark
69+
70+
```sh
71+
LOG_LEVEL=disabled go test -bench=. -benchmem -run=^$
72+
```
73+
74+
Benchmark run on an Apple M3 Max.
75+
76+
```sh
77+
goos: darwin
78+
goarch: arm64
79+
pkg: github.com/smartcontractkit/chainlink-testing-framework/parrotserver
80+
BenchmarkRegisterRoute-14 604978 1967 ns/op 6263 B/op 29 allocs/op
81+
BenchmarkRouteResponse-14 16561670 70.62 ns/op 80 B/op 1 allocs/op
82+
BenchmarkSaveRoutes-14 1245 956784 ns/op 636042 B/op 2014 allocs/op
83+
BenchmarkLoadRoutes-14 1020 1185990 ns/op 348919 B/op 9020 allocs/op
84+
```

parrot/cmd/main.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"os"
6+
"os/signal"
7+
"syscall"
8+
9+
"github.com/rs/zerolog/log"
10+
"github.com/smartcontractkit/chainlink-testing-framework/parrot"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
func main() {
15+
var (
16+
port int
17+
debug bool
18+
trace bool
19+
silent bool
20+
json bool
21+
)
22+
23+
rootCmd := &cobra.Command{
24+
Use: "parrotserver",
25+
Short: "a server that can set and parrrot back dynamic requests",
26+
RunE: func(cmd *cobra.Command, args []string) error {
27+
options := []parrot.ServerOption{parrot.WithPort(port)}
28+
if debug {
29+
options = append(options, parrot.WithDebug())
30+
}
31+
if trace {
32+
options = append(options, parrot.WithTrace())
33+
}
34+
if silent {
35+
options = append(options, parrot.Silent())
36+
}
37+
if json {
38+
options = append(options, parrot.WithJSONLogs())
39+
}
40+
41+
ctx, cancel := context.WithCancel(context.Background())
42+
defer cancel()
43+
44+
p, err := parrot.Wake(options...)
45+
if err != nil {
46+
return err
47+
}
48+
49+
c := make(chan os.Signal, 1)
50+
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
51+
<-c
52+
err = p.Shutdown(ctx)
53+
if err != nil {
54+
log.Error().Err(err).Msg("error shutting down server")
55+
}
56+
return nil
57+
},
58+
}
59+
60+
rootCmd.Flags().IntVarP(&port, "port", "p", 0, "Port to run the parrot on")
61+
rootCmd.Flags().BoolVarP(&debug, "debug", "d", false, "Enable debug output")
62+
rootCmd.Flags().BoolVarP(&trace, "trace", "t", false, "Enable trace and debug output")
63+
rootCmd.Flags().BoolVarP(&silent, "silent", "s", false, "Disable all output")
64+
rootCmd.Flags().BoolVarP(&json, "json", "j", false, "Output logs in JSON format")
65+
66+
if err := rootCmd.Execute(); err != nil {
67+
log.Error().Err(err).Msg("error executing command")
68+
os.Exit(1)
69+
}
70+
}

parrot/go.mod

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module github.com/smartcontractkit/chainlink-testing-framework/parrot
2+
3+
go 1.23.4
4+
5+
require (
6+
github.com/rs/zerolog v1.33.0
7+
github.com/spf13/cobra v1.8.1
8+
github.com/stretchr/testify v1.9.0
9+
)
10+
11+
require (
12+
github.com/davecgh/go-spew v1.1.1 // indirect
13+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
14+
github.com/mattn/go-colorable v0.1.13 // indirect
15+
github.com/mattn/go-isatty v0.0.19 // indirect
16+
github.com/pmezard/go-difflib v1.0.0 // indirect
17+
github.com/spf13/pflag v1.0.5 // indirect
18+
golang.org/x/sys v0.12.0 // indirect
19+
gopkg.in/yaml.v3 v3.0.1 // indirect
20+
)

parrot/go.sum

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
2+
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
3+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
4+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
6+
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
7+
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
8+
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
9+
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
10+
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
11+
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
12+
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
13+
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
14+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
15+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
16+
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
17+
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
18+
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
19+
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
20+
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
21+
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
22+
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
23+
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
24+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
25+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
26+
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
27+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
28+
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
29+
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
30+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
31+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
32+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
33+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 commit comments

Comments
 (0)