Skip to content

Commit

Permalink
[TT-1275] Add retreiving of requests from killgrave (#994)
Browse files Browse the repository at this point in the history
Note: This requires approval of: friendsofgo/killgrave#170 which may still need changes.
  • Loading branch information
tateexon authored Jun 20, 2024
1 parent 1b37b28 commit 44dea25
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/update-internal-mirrors.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: ethereum/client-go
expression: '^(alltools-v|v)[0-9]\.[0-9]+\.[0-9]+$'
- name: friendsofgo/killgrave
expression: '^[0-9]+\.[0-9]+\.[0-9]+$'
expression: '^v?[0-9]+\.[0-9]+\.[0-9]+$'
- name: mockserver/mockserver
expression: '^[0-9]+\.[0-9]+\.[0-9]+$'
- name: testcontainers/ryuk
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ chaosmesh: ## there is currently a bug on JS side to import all CRDs from one ya
gotestloghelper_build:
cd ./tools/gotestloghelper && go build -o ../../gotestloghelper . && cd -

.PHONY: typos
typos:
pre-commit run detect-typos --all-files --show-diff-on-failure --color=always

.PHONY: nix_shell
nix_shell:
nix develop
101 changes: 90 additions & 11 deletions docker/test_env/killgrave.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,23 @@ import (
tc "github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"

"github.com/smartcontractkit/chainlink-testing-framework/k8s/config"
"github.com/smartcontractkit/chainlink-testing-framework/logging"
"github.com/smartcontractkit/chainlink-testing-framework/mirror"
"github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext"
)

const defaultKillgraveImage = "friendsofgo/killgrave:0.4.1"
const defaultKillgraveImage = "friendsofgo/killgrave:v0.5.1-request-dump"

type Killgrave struct {
EnvComponent
ExternalEndpoint string
InternalPort string
InternalEndpoint string
impostersPath string
impostersDirBinding string
t *testing.T
l zerolog.Logger
ExternalEndpoint string
InternalPort string
InternalEndpoint string
impostersPath string
impostersDirBinding string
requestDumpDirBinding string
t *testing.T
l zerolog.Logger
}

// Imposter define an imposter structure
Expand Down Expand Up @@ -106,6 +107,10 @@ func (k *Killgrave) StartContainer() error {
if err != nil {
return err
}
err = k.setupRequestDump()
if err != nil {
return err
}
if k.t != nil {
k.t.Cleanup(func() {
os.RemoveAll(k.impostersDirBinding)
Expand Down Expand Up @@ -141,19 +146,33 @@ func (k *Killgrave) StartContainer() error {
}

func (k *Killgrave) getContainerRequest() (tc.ContainerRequest, error) {
killgraveImage := mirror.AddMirrorToImageIfSet(defaultKillgraveImage)
// TT-1290 Temporary work around using fork of killgrave, uncomment line below when fork is merged
// killgraveImage := mirror.AddMirrorToImageIfSet(defaultKillgraveImage)
// TT-1290 Temporary code to set image to the fork or the ecr mirror depending on the config
killgraveImage := "tateexon/killgrave:v0.5.1-request-dump"
ecr := os.Getenv(config.EnvVarInternalDockerRepo)
if ecr != "" {
killgraveImage = fmt.Sprintf("%s/%s", ecr, defaultKillgraveImage)
}
// end temporary code

return tc.ContainerRequest{
Name: k.ContainerName,
Networks: k.Networks,
Image: killgraveImage,
ExposedPorts: []string{NatPortFormat(k.InternalPort)},
Cmd: []string{"-host=0.0.0.0", "-imposters=/imposters", "-watcher"},
Cmd: []string{"-H=0.0.0.0", "-i=/imposters", "-w", "-v", "-d=/requestDump/requestDump.log"},
HostConfigModifier: func(hostConfig *container.HostConfig) {
hostConfig.Mounts = append(hostConfig.Mounts, mount.Mount{
Type: mount.TypeBind,
Source: k.impostersDirBinding,
Target: "/imposters",
ReadOnly: false,
}, mount.Mount{
Type: mount.TypeBind,
Source: k.requestDumpDirBinding,
Target: "/requestDump",
ReadOnly: false,
})
},
WaitingFor: wait.ForLog("The fake server is on tap now"),
Expand Down Expand Up @@ -187,6 +206,13 @@ func (k *Killgrave) setupImposters() error {
return k.SetAdapterBasedIntValuePath("/five", []string{http.MethodGet, http.MethodPost}, 5)
}

func (k *Killgrave) setupRequestDump() error {
// create temporary directory for request dumps
var err error
k.requestDumpDirBinding, err = os.MkdirTemp(k.requestDumpDirBinding, "requestDump*")
return err
}

// AddImposter adds an imposter to the killgrave container
func (k *Killgrave) AddImposter(imposters []KillgraveImposter) error {
// if the endpoint paths do not start with '/' then add it
Expand Down Expand Up @@ -282,3 +308,56 @@ func (k *Killgrave) SetAnyValueResponse(path string, methods []string, v interfa
func (k *Killgrave) SetAdapterBasedIntValuePath(path string, methods []string, v int) error {
return k.SetAdapterBasedAnyValuePath(path, methods, v)
}

type RequestData struct {
Method string `json:"method"`
Host string `json:"host"`
URL string `json:"url"`
Header map[string][]string `json:"header"`
Body string `json:"body"`
}

func (k *Killgrave) GetReceivedRequests() ([]RequestData, error) {
// killgrave uses a channel to write the request data to a file so we want to make sure
// all requests have been written before reading the file
time.Sleep(1 * time.Second)

// Read the directory entries
files, err := os.ReadDir(k.requestDumpDirBinding)
if err != nil {
return nil, err
}

// Iterate over the directory entries
fmt.Println("Files Start")
for _, file := range files {
fmt.Println(file.Name())
}
fmt.Println("Files End")

fileContent, err := os.ReadFile(filepath.Join(k.requestDumpDirBinding, "requestDump.log"))
if err != nil {
return nil, fmt.Errorf("error reading file: %w", err)
}

fmt.Println("File Content Start")
fmt.Println(string(fileContent))
fmt.Println("File Content End")

// Split the contents by the newline separator
requestDumps := strings.Split(string(fileContent), "\n")
requestsData := []RequestData{}
for _, requestDump := range requestDumps {
if requestDump == "" {
continue
}

rd := RequestData{}
err := json.Unmarshal([]byte(requestDump), &rd)
if err != nil {
return nil, fmt.Errorf("error unmarshalling JSON: %w", err)
}
requestsData = append(requestsData, rd)
}
return requestsData, nil
}
53 changes: 51 additions & 2 deletions docker/test_env/killgrave_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@ func runTestWithExpectations(t *testing.T, k *Killgrave, expectations []kgTest)
})
var err error
// Check the different kinds of responses
for _, e := range expectations {
test := e
for _, test := range expectations {
test := test

t.Run(test.Name, func(t *testing.T) {
t.Parallel()
m := []string{http.MethodGet}
Expand Down Expand Up @@ -163,3 +164,51 @@ func runTestWithExpectations(t *testing.T, k *Killgrave, expectations []kgTest)
})
}
}

func TestKillgraveRequestDump(t *testing.T) {
t.Parallel()
l := logging.GetTestLogger(t)
network, err := docker.CreateNetwork(l)
require.NoError(t, err)

k := NewKillgrave([]string{network.Name}, "./killgrave_imposters").
WithTestInstance(t)
err = k.StartContainer()
require.NoError(t, err)

path := "/stringany"
m := []string{http.MethodGet}
headers := map[string]string{"Content-Type": "text/plain"}
err = k.SetStringValuePath("/stringany", m, headers, "{\"id\":\"\",\"data\":{\"result\":5},\"error\":null}")
require.NoError(t, err)
var url string
if strings.HasPrefix(path, "/") {
url = fmt.Sprintf("%s%s", k.ExternalEndpoint, path)
} else {
url = fmt.Sprintf("%s/%s", k.ExternalEndpoint, path)
}
bodyRequest := []byte("{\n\"a\":5,\n\"b\":6\n}")
req1, err := http.NewRequest(m[0], url, bytes.NewBuffer(bodyRequest))
require.NoError(t, err)
req1.Header.Set("Content-Type", "application/json")
req2, err := http.NewRequest(m[0], url, bytes.NewBuffer(bodyRequest))
require.NoError(t, err)
client := &http.Client{
Timeout: 10 * time.Second,
}
resp1, err := client.Do(req1)
require.NoError(t, err)
defer resp1.Body.Close()
require.Equal(t, http.StatusOK, resp1.StatusCode, fmt.Sprintf("url: %s", url))
resp2, err := client.Do(req2)
require.NoError(t, err)
defer resp2.Body.Close()
require.Equal(t, http.StatusOK, resp2.StatusCode, fmt.Sprintf("url: %s", url))

requests, err := k.GetReceivedRequests()
require.NoError(t, err)
fmt.Printf("Requests: %+v\n", requests)
require.Equal(t, 2, len(requests))
require.Equal(t, string(bodyRequest), requests[0].Body)
require.Equal(t, string(bodyRequest), requests[1].Body)
}

0 comments on commit 44dea25

Please sign in to comment.