Skip to content

Commit

Permalink
First draft and rename
Browse files Browse the repository at this point in the history
  • Loading branch information
kalverra committed Jan 14, 2025
1 parent 1b3b249 commit 0da4359
Show file tree
Hide file tree
Showing 10 changed files with 903 additions and 0 deletions.
13 changes: 13 additions & 0 deletions parrot/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Dockerfile
*.md
*.log
.gitignore
.golangci-lint.yml
.goreleaser.yml
.pre-commit-config.yaml
*_test.go
LICENSE
.vscode/
dist/
.github/
save.json
58 changes: 58 additions & 0 deletions parrot/.goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json
version: 1
project_name: parrotserver

monorepo:
tag_prefix: parrotserver/
dir: parrotserver

env:
- IMG_PRE={{ if index .Env "IMAGE_PREFIX" }}{{ .Env.IMAGE_PREFIX }}{{ else }}local{{ end }}
- TAG={{ if index .Env "IMAGE_TAG" }}{{ .Env.IMAGE_TAG }}{{ else }}latest{{ end }}

# Build settings for binaries
builds:
- id: parrotserver
goos:
- linux
- darwin
goarch:
- amd64
- arm64
ldflags:
- '-s -w'

archives:
- format: binary

dockers:
- id: linux-amd64-parrotserver
goos: linux
goarch: amd64
image_templates:
- '{{ .Env.IMG_PRE }}/parrotserver:{{ .Tag }}'
- '{{ .Env.IMG_PRE }}/parrotserver:latest'
build_flag_templates:
- --platform=linux/amd64
- --pull
- --label=org.opencontainers.image.created={{.Date}}
- --label=org.opencontainers.image.title={{.ProjectName}}
- --label=org.opencontainers.image.revision={{.FullCommit}}
- --label=org.opencontainers.image.version={{.Version}}
- id: linux-arm64-parrotserver
goos: linux
goarch: arm64
image_templates:
- '{{ .Env.IMG_PRE }}/parrotserver:{{ .Tag }}-arm64'
- '{{ .Env.IMG_PRE }}/parrotserver:latest-arm64'
build_flag_templates:
- --platform=linux/arm64
- --pull
- --label=org.opencontainers.image.created={{.Date}}
- --label=org.opencontainers.image.title={{.ProjectName}}
- --label=org.opencontainers.image.revision={{.FullCommit}}
- --label=org.opencontainers.image.version={{.Version}}

before:
hooks:
- cd parrotserver && go mod tidy
3 changes: 3 additions & 0 deletions parrot/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM scratch
COPY parrotserver /parrotserver
ENTRYPOINT [ "parrotserver" ]
23 changes: 23 additions & 0 deletions parrot/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.PHONY: lint
lint:
golangci-lint --color=always run ./... --fix -v

.PHONY: test
test:
go install github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest
set -euo pipefail
go test -json -cover -coverprofile cover.out -v ./... 2>&1 | tee /tmp/gotest.log | gotestfmt

.PHONY: test_race
test_race:
go install github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest
set -euo pipefail
go test -json -cover -count=1 -race -coverprofile cover.out -v ./... 2>&1 | tee /tmp/gotest.log | gotestfmt

.PHONY: test_unit
test_unit:
go test -coverprofile cover.out ./...

.PHONY: bench
bench:
go test -bench=. -run=^$$ ./...
84 changes: 84 additions & 0 deletions parrot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Parrot Server

A simple, high-performing mockserver that can dynamically build new routes with customized responses, parroting back whatever you tell it to.

## Use

Call the `/register` endpoint to define a route.

### Curl

```sh
curl -X POST http://localhost:8080/register -d '{
"method": "GET",
"path": "/hello",
"response": "{\"message\": \"Hello, world!\"}",
"status_code": 200,
"content_type": "application/json"
}' -H "Content-Type: application/json"
```

### Go and [Resty](https://github.com/go-resty/resty)

```go
client := resty.New()

route := map[string]any{
"method": "GET",
"path": "/hello",
"response": "{\"message\":\"Hello, world!\"}",
"status_code": 200,
"content_type": "application/json",
}

resp, _ := client.R().
SetHeader("Content-Type", "application/json").
SetBody(route).
Post("http://localhost:8080/register")
```

You can now call your endpoint and receive the JSON response back.

```sh
curl -X GET http://localhost:8080/hello -H "Content-Type: application/json"
# {"message":"Hello, world!"}
```

## Configure

Config is through environment variables.

| **Environment Variable** | **Description** | **Default Value** |
| ------------------------ | -------------------------------------------------------------- | ----------------- |
| `LOG_LEVEL` | Controls the logging level (`debug`, `info`, `warn`, `error`). | `debug` |
| `SAVE_FILE` | Path to the file where routes are saved and loaded. | `save.json` |

## Run

```sh
go run .
```

## Test

```sh
go test -cover -race ./...
```

## Benchmark

```sh
LOG_LEVEL=disabled go test -bench=. -benchmem -run=^$
```

Benchmark run on an Apple M3 Max.

```sh
goos: darwin
goarch: arm64
pkg: github.com/smartcontractkit/chainlink-testing-framework/parrotserver
BenchmarkRegisterRoute-14 604978 1967 ns/op 6263 B/op 29 allocs/op
BenchmarkRouteResponse-14 16561670 70.62 ns/op 80 B/op 1 allocs/op
BenchmarkSaveRoutes-14 1245 956784 ns/op 636042 B/op 2014 allocs/op
BenchmarkLoadRoutes-14 1020 1185990 ns/op 348919 B/op 9020 allocs/op
```
70 changes: 70 additions & 0 deletions parrot/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package main

import (
"context"
"os"
"os/signal"
"syscall"

"github.com/rs/zerolog/log"
"github.com/smartcontractkit/chainlink-testing-framework/parrot"
"github.com/spf13/cobra"
)

func main() {
var (
port int
debug bool
trace bool
silent bool
json bool
)

rootCmd := &cobra.Command{
Use: "parrotserver",
Short: "a server that can set and parrrot back dynamic requests",
RunE: func(cmd *cobra.Command, args []string) error {
options := []parrot.ServerOption{parrot.WithPort(port)}
if debug {
options = append(options, parrot.WithDebug())
}
if trace {
options = append(options, parrot.WithTrace())
}
if silent {
options = append(options, parrot.Silent())
}
if json {
options = append(options, parrot.WithJSONLogs())
}

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

p, err := parrot.Wake(options...)
if err != nil {
return err
}

c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
<-c
err = p.Shutdown(ctx)
if err != nil {
log.Error().Err(err).Msg("error shutting down server")
}
return nil
},
}

rootCmd.Flags().IntVarP(&port, "port", "p", 0, "Port to run the parrot on")
rootCmd.Flags().BoolVarP(&debug, "debug", "d", false, "Enable debug output")
rootCmd.Flags().BoolVarP(&trace, "trace", "t", false, "Enable trace and debug output")
rootCmd.Flags().BoolVarP(&silent, "silent", "s", false, "Disable all output")
rootCmd.Flags().BoolVarP(&json, "json", "j", false, "Output logs in JSON format")

if err := rootCmd.Execute(); err != nil {
log.Error().Err(err).Msg("error executing command")
os.Exit(1)
}
}
20 changes: 20 additions & 0 deletions parrot/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module github.com/smartcontractkit/chainlink-testing-framework/parrot

go 1.23.4

require (
github.com/rs/zerolog v1.33.0
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
)

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

0 comments on commit 0da4359

Please sign in to comment.