Skip to content

Commit

Permalink
fix(proxy): empty response body should skip writing a response file.
Browse files Browse the repository at this point in the history
  • Loading branch information
outofcoffee committed Jan 1, 2023
1 parent 4f3602d commit 8114b07
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 13 deletions.
41 changes: 28 additions & 13 deletions proxy/recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ func StartRecorder(upstream string, dir string, options RecorderOptions) (chan H
var responseFilePrefix string
requestHash := getRequestHash(exchange.Request)
if stringutil.Contains(requestHashes, requestHash) {
responseFilePrefix = uuid.New().String() + "-"
if options.IgnoreDuplicateRequests {
logger.Debugf("skipping recording of duplicate request %s %v", exchange.Request.Method, exchange.Request.URL)
continue
}
responseFilePrefix = uuid.New().String() + "-"
} else {
responseFilePrefix = ""
}
Expand Down Expand Up @@ -106,7 +106,14 @@ func formatUpstreamHostPort(upstream string) (string, error) {
}
}

func record(upstreamHost string, dir string, responseHashes *map[string]string, prefix string, exchange HttpExchange, options RecorderOptions) (resource *impostermodel.Resource, err error) {
func record(
upstreamHost string,
dir string,
responseHashes *map[string]string,
prefix string,
exchange HttpExchange,
options RecorderOptions,
) (resource *impostermodel.Resource, err error) {
respFile, err := getResponseFile(upstreamHost, dir, options, exchange, responseHashes, prefix)
if err != nil {
return nil, err
Expand All @@ -118,8 +125,9 @@ func record(upstreamHost string, dir string, responseHashes *map[string]string,
return &r, nil
}

// getResponseFile checks the map for the hash of the response body to see if it has already been
// written. If not, a new file is written and its hash stored in the map.
// getResponseFile checks if there is a response body. If not, an empty string is returned.
// If a body is not empty, the file hashes are checked for the hash of the response body to
// see if it has already been written. If not, a new file is written and its hash stored in the map.
func getResponseFile(
upstreamHost string,
dir string,
Expand All @@ -130,6 +138,10 @@ func getResponseFile(
) (string, error) {
req := exchange.Request
respBody := *exchange.ResponseBody
if len(respBody) == 0 {
logger.Debugf("empty response body for %s %v", req.Method, req.URL)
return "", nil
}
bodyHash := stringutil.Sha1hash(respBody)

if existing := (*fileHashes)[bodyHash]; existing != "" {
Expand All @@ -152,17 +164,20 @@ func getResponseFile(

func buildResource(dir string, options RecorderOptions, exchange HttpExchange, respFile string) (impostermodel.Resource, error) {
req := *exchange.Request
relResponseFile, err := filepath.Rel(dir, respFile)
if err != nil {
return impostermodel.Resource{}, fmt.Errorf("failed to get relative path for response file: %s: %v", respFile, err)
response := &impostermodel.ResponseConfig{
StatusCode: exchange.StatusCode,
}
if len(respFile) > 0 {
relResponseFile, err := filepath.Rel(dir, respFile)
if err != nil {
return impostermodel.Resource{}, fmt.Errorf("failed to get relative path for response file: %s: %v", respFile, err)
}
response.StaticFile = relResponseFile
}
resource := impostermodel.Resource{
Path: req.URL.Path,
Method: req.Method,
Response: &impostermodel.ResponseConfig{
StatusCode: exchange.StatusCode,
StaticFile: relResponseFile,
},
Path: req.URL.Path,
Method: req.Method,
Response: response,
}
if len(req.URL.Query()) > 0 {
queryParams := make(map[string]string)
Expand Down
105 changes: 105 additions & 0 deletions proxy/recorder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package proxy

import (
"fmt"
"net/http"
"net/url"
"os"
"path"
"testing"
)

func Test_getResponseFile(t *testing.T) {
outputDir, err := os.MkdirTemp(os.TempDir(), "imposter-cli")
if err != nil {
panic(err)
}
rootUrl, _ := url.Parse("https://example.com")

responseBody := []byte("test")
bodyHash := "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"

type args struct {
upstreamHost string
dir string
options RecorderOptions
exchange HttpExchange
fileHashes *map[string]string
prefix string
}
tests := []struct {
name string
args args
want string
wantErr bool
}{
{
name: "empty response body",
args: args{
upstreamHost: "example.com",
dir: outputDir,
options: RecorderOptions{FlatResponseFileStructure: false},
exchange: HttpExchange{
Request: &http.Request{Method: "GET", URL: rootUrl},
ResponseBody: &[]byte{},
},
fileHashes: buildMap(outputDir, []string{}),
},
want: "",
wantErr: false,
},
{
name: "existing response body",
args: args{
upstreamHost: "example.com",
dir: outputDir,
options: RecorderOptions{FlatResponseFileStructure: false},
exchange: HttpExchange{
Request: &http.Request{Method: "GET", URL: rootUrl},
ResponseBody: &responseBody,
ResponseHeaders: &http.Header{},
},
fileHashes: buildMap(outputDir, []string{bodyHash}),
},
want: path.Join(outputDir, "existing-file-0.txt"),
wantErr: false,
},
{
name: "new response body",
args: args{
upstreamHost: "example.com",
dir: outputDir,
options: RecorderOptions{FlatResponseFileStructure: false},
exchange: HttpExchange{
Request: &http.Request{Method: "GET", URL: rootUrl},
ResponseBody: &responseBody,
ResponseHeaders: &http.Header{},
},
fileHashes: buildMap(outputDir, []string{}),
},
want: path.Join(outputDir, "GET-index.txt"),
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := getResponseFile(tt.args.upstreamHost, tt.args.dir, tt.args.options, tt.args.exchange, tt.args.fileHashes, tt.args.prefix)
if (err != nil) != tt.wantErr {
t.Errorf("getResponseFile() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("getResponseFile() got = %v, want %v", got, tt.want)
}
})
}
}

func buildMap(dir string, hashes []string) *map[string]string {
m := make(map[string]string)
for i, hash := range hashes {
filename := fmt.Sprintf("existing-file-%d.txt", i)
m[hash] = path.Join(dir, filename)
}
return &m
}

0 comments on commit 8114b07

Please sign in to comment.