Skip to content

Commit 33ca1da

Browse files
authored
Add files api tests (#238)
* drop support for downloading files * use form builder to submit files * update doc * add form builder tests
1 parent 4dc1eda commit 33ca1da

File tree

2 files changed

+60
-54
lines changed

2 files changed

+60
-54
lines changed

files.go

Lines changed: 9 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ import (
44
"bytes"
55
"context"
66
"fmt"
7-
"io"
8-
"mime/multipart"
97
"net/http"
10-
"net/url"
118
"os"
129
)
1310

@@ -33,77 +30,38 @@ type FilesList struct {
3330
Files []File `json:"data"`
3431
}
3532

36-
// isUrl is a helper function that determines whether the given FilePath
37-
// is a remote URL or a local file path.
38-
func isURL(path string) bool {
39-
_, err := url.ParseRequestURI(path)
40-
if err != nil {
41-
return false
42-
}
43-
44-
u, err := url.Parse(path)
45-
if err != nil || u.Scheme == "" || u.Host == "" {
46-
return false
47-
}
48-
49-
return true
50-
}
51-
5233
// CreateFile uploads a jsonl file to GPT3
53-
// FilePath can be either a local file path or a URL.
34+
// FilePath must be a local file path.
5435
func (c *Client) CreateFile(ctx context.Context, request FileRequest) (file File, err error) {
5536
var b bytes.Buffer
56-
w := multipart.NewWriter(&b)
57-
58-
var fw io.Writer
37+
builder := c.createFormBuilder(&b)
5938

60-
err = w.WriteField("purpose", request.Purpose)
39+
err = builder.writeField("purpose", request.Purpose)
6140
if err != nil {
6241
return
6342
}
6443

65-
fw, err = w.CreateFormFile("file", request.FileName)
44+
fileData, err := os.Open(request.FilePath)
6645
if err != nil {
6746
return
6847
}
6948

70-
var fileData io.ReadCloser
71-
if isURL(request.FilePath) {
72-
var remoteFile *http.Response
73-
remoteFile, err = http.Get(request.FilePath)
74-
if err != nil {
75-
return
76-
}
77-
78-
defer remoteFile.Body.Close()
79-
80-
// Check server response
81-
if remoteFile.StatusCode != http.StatusOK {
82-
err = fmt.Errorf("error, status code: %d, message: failed to fetch file", remoteFile.StatusCode)
83-
return
84-
}
85-
86-
fileData = remoteFile.Body
87-
} else {
88-
fileData, err = os.Open(request.FilePath)
89-
if err != nil {
90-
return
91-
}
49+
err = builder.createFormFile("file", fileData)
50+
if err != nil {
51+
return
9252
}
9353

94-
_, err = io.Copy(fw, fileData)
54+
err = builder.close()
9555
if err != nil {
9656
return
9757
}
9858

99-
w.Close()
100-
10159
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.fullURL("/files"), &b)
10260
if err != nil {
10361
return
10462
}
10563

106-
req.Header.Set("Content-Type", w.FormDataContentType())
64+
req.Header.Set("Content-Type", builder.formDataContentType())
10765

10866
err = c.sendRequest(req, &file)
10967

files_test.go

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
package openai_test
1+
package openai //nolint:testpackage // testing private field
22

33
import (
4-
. "github.com/sashabaranov/go-openai"
54
"github.com/sashabaranov/go-openai/internal/test"
65
"github.com/sashabaranov/go-openai/internal/test/checks"
76

87
"context"
98
"encoding/json"
109
"fmt"
10+
"io"
1111
"net/http"
12+
"os"
1213
"strconv"
1314
"testing"
1415
"time"
@@ -34,7 +35,7 @@ func TestFileUpload(t *testing.T) {
3435
Purpose: "fine-tune",
3536
}
3637
_, err = client.CreateFile(ctx, req)
37-
checks.NoError(t, err, "CreateFile erro")
38+
checks.NoError(t, err, "CreateFile error")
3839
}
3940

4041
// handleCreateFile Handles the images endpoint by the test server.
@@ -78,3 +79,50 @@ func handleCreateFile(w http.ResponseWriter, r *http.Request) {
7879
resBytes, _ = json.Marshal(fileReq)
7980
fmt.Fprint(w, string(resBytes))
8081
}
82+
83+
func TestFileUploadWithFailingFormBuilder(t *testing.T) {
84+
config := DefaultConfig("")
85+
config.BaseURL = ""
86+
client := NewClientWithConfig(config)
87+
mockBuilder := &mockFormBuilder{}
88+
client.createFormBuilder = func(io.Writer) formBuilder {
89+
return mockBuilder
90+
}
91+
92+
ctx := context.Background()
93+
req := FileRequest{
94+
FileName: "test.go",
95+
FilePath: "client.go",
96+
Purpose: "fine-tune",
97+
}
98+
99+
mockError := fmt.Errorf("mockWriteField error")
100+
mockBuilder.mockWriteField = func(string, string) error {
101+
return mockError
102+
}
103+
_, err := client.CreateFile(ctx, req)
104+
checks.ErrorIs(t, err, mockError, "CreateFile should return error if form builder fails")
105+
106+
mockError = fmt.Errorf("mockCreateFormFile error")
107+
mockBuilder.mockWriteField = func(string, string) error {
108+
return nil
109+
}
110+
mockBuilder.mockCreateFormFile = func(string, *os.File) error {
111+
return mockError
112+
}
113+
_, err = client.CreateFile(ctx, req)
114+
checks.ErrorIs(t, err, mockError, "CreateFile should return error if form builder fails")
115+
116+
mockError = fmt.Errorf("mockClose error")
117+
mockBuilder.mockWriteField = func(string, string) error {
118+
return nil
119+
}
120+
mockBuilder.mockCreateFormFile = func(string, *os.File) error {
121+
return nil
122+
}
123+
mockBuilder.mockClose = func() error {
124+
return mockError
125+
}
126+
_, err = client.CreateFile(ctx, req)
127+
checks.ErrorIs(t, err, mockError, "CreateFile should return error if form builder fails")
128+
}

0 commit comments

Comments
 (0)