Skip to content

Commit

Permalink
Update file upload tests WithFiles option
Browse files Browse the repository at this point in the history
Update the file upload tests to use the GQL test client and its
`WithFiles` option to remove the need for a custom raw HTTP post request
builder `createUploadRequest`.

- Also update `WithFiles` option to group & map identical files; e.g.

  ```
    { "0": ["variables.req.0.file", "variables.req.1.file"] }
  ```
  • Loading branch information
Sonna committed Dec 12, 2020
1 parent 6dfa3cb commit 486d9f1
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 142 deletions.
44 changes: 41 additions & 3 deletions client/withfilesoption.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ func findFiles(parentMapKey string, variables map[string]interface{}) []*fileFor
for key, value := range variables {
if v, ok := value.(map[string]interface{}); ok {
files = append(files, findFiles(parentMapKey+"."+key, v)...)
} else if v, ok := value.([]map[string]interface{}); ok {
for i, arr := range v {
files = append(files, findFiles(fmt.Sprintf(`%s.%s.%d`, parentMapKey, key, i), arr)...)
}
} else if v, ok := value.([]*os.File); ok {
for i, file := range v {
files = append(files, &fileFormDataMap{
Expand Down Expand Up @@ -59,16 +63,38 @@ func WithFiles() Option {
// `{ "0":["variables.input.file"] }`
// or
// `{ "0":["variables.input.files.0"], "1":["variables.input.files.1"] }`
// or
// `{ "0": ["variables.input.0.file"], "1": ["variables.input.1.file"] }`
// or
// `{ "0": ["variables.req.0.file", "variables.req.1.file"] }`
mapData := ""
filesData := findFiles("variables", bd.Variables)
if len(filesData) > 0 {
filesGroup := [][]*fileFormDataMap{}
for _, fd := range filesData {
foundDuplicate := false
for j, fg := range filesGroup {
f1, _ := fd.file.Stat()
f2, _ := fg[0].file.Stat()
if os.SameFile(f1, f2) {
foundDuplicate = true
filesGroup[j] = append(filesGroup[j], fd)
}
}

if !foundDuplicate {
filesGroup = append(filesGroup, []*fileFormDataMap{fd})
}
}
if len(filesGroup) > 0 {
mapDataFiles := []string{}
for i, fileData := range filesData {

for i, fileData := range filesGroup {
mapDataFiles = append(
mapDataFiles,
fmt.Sprintf(`"%d":["%s"]`, i, fileData.mapKey),
fmt.Sprintf(`"%d":[%s]`, i, strings.Join(collect(fileData, wrapMapKeyInQuotes)[:], ",")),
)
}

mapData = `{` + strings.Join(mapDataFiles, ",") + `}`
}
bodyWriter.WriteField("map", mapData)
Expand All @@ -93,3 +119,15 @@ func WithFiles() Option {
bd.HTTP.Header.Set("Content-Type", bodyWriter.FormDataContentType())
}
}

func collect(strArr []*fileFormDataMap, f func(s *fileFormDataMap) string) []string {
result := make([]string, len(strArr))
for i, str := range strArr {
result[i] = f(str)
}
return result
}

func wrapMapKeyInQuotes(s *fileFormDataMap) string {
return fmt.Sprintf("\"%s\"", s.mapKey)
}
47 changes: 47 additions & 0 deletions client/withfilesoption_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,51 @@ func TestWithFiles(t *testing.T) {
client.WithFiles(),
)
})

t.Run("with multiple files and file reuse", func(t *testing.T) {
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mediaType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
require.NoError(t, err)
require.True(t, strings.HasPrefix(mediaType, "multipart/"))

mr := multipart.NewReader(r.Body, params["boundary"])
for {
p, err := mr.NextPart()
if err == io.EOF {
break
}
require.NoError(t, err)

slurp, err := ioutil.ReadAll(p)
require.NoError(t, err)

contentDisposition := p.Header.Get("Content-Disposition")
fmt.Printf("Part %q: %q\n", contentDisposition, slurp)

if contentDisposition == `form-data; name="operations"` {
require.Equal(t, []byte(`{"query":"{ id }","variables":{"files":[{},{},{}]}}`), slurp)
}
if contentDisposition == `form-data; name="map"` {
require.Equal(t, []byte(`{"0":["variables.files.0","variables.files.2"],"1":["variables.files.1"]}`), slurp)
}
if regexp.MustCompile(`form-data; name="0"; filename=.*`).MatchString(contentDisposition) {
require.Equal(t, `text/plain; charset=utf-8`, p.Header.Get("Content-Type"))
require.Equal(t, []byte(`The quick brown fox jumps over the lazy dog`), slurp)
}
if regexp.MustCompile(`form-data; name="1"; filename=.*`).MatchString(contentDisposition) {
require.Equal(t, `text/plain; charset=utf-8`, p.Header.Get("Content-Type"))
require.Equal(t, []byte(`hello world`), slurp)
}
}
w.Write([]byte(`{}`))
})

c := client.New(h)

var resp struct{}
c.MustPost("{ id }", &resp,
client.Var("files", []*os.File{tempFile1, tempFile2, tempFile1}),
client.WithFiles(),
)
})
}
Loading

0 comments on commit 486d9f1

Please sign in to comment.