Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TT-1275] Add retreiving of requests from killgrave #994

Merged
merged 2 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
Loading