44 "context"
55 "encoding/json"
66 "io"
7+ "strings"
78 "testing"
89
910 "gomodel/internal/core"
@@ -14,6 +15,9 @@ type providerMock struct {
1415 responsesReq * core.ResponsesRequest
1516 embeddingReq * core.EmbeddingRequest
1617 batchReq * core.BatchRequest
18+ fileContent * core.FileContentResponse
19+ fileCreates []* core.FileCreateRequest
20+ fileObject * core.FileObject
1721 modelsResp * core.ModelsResponse
1822 supported map [string ]bool
1923 providerType map [string ]string
@@ -85,6 +89,35 @@ func (m *providerMock) GetBatchResults(_ context.Context, _ string, _ string) (*
8589 return & core.BatchResultsResponse {Object : "list" , BatchID : "batch_1" }, nil
8690}
8791
92+ func (m * providerMock ) CreateFile (_ context.Context , _ string , req * core.FileCreateRequest ) (* core.FileObject , error ) {
93+ copy := * req
94+ copy .Content = append ([]byte (nil ), req .Content ... )
95+ m .fileCreates = append (m .fileCreates , & copy )
96+ if m .fileObject != nil {
97+ return m .fileObject , nil
98+ }
99+ return & core.FileObject {ID : "file_rewritten" , Object : "file" , Filename : req .Filename , Purpose : req .Purpose }, nil
100+ }
101+
102+ func (m * providerMock ) ListFiles (_ context.Context , _ string , _ string , _ int , _ string ) (* core.FileListResponse , error ) {
103+ return & core.FileListResponse {Object : "list" }, nil
104+ }
105+
106+ func (m * providerMock ) GetFile (_ context.Context , _ string , id string ) (* core.FileObject , error ) {
107+ return & core.FileObject {ID : id , Object : "file" }, nil
108+ }
109+
110+ func (m * providerMock ) DeleteFile (_ context.Context , _ string , id string ) (* core.FileDeleteResponse , error ) {
111+ return & core.FileDeleteResponse {ID : id , Object : "file" , Deleted : true }, nil
112+ }
113+
114+ func (m * providerMock ) GetFileContent (_ context.Context , _ string , id string ) (* core.FileContentResponse , error ) {
115+ if m .fileContent != nil {
116+ return m .fileContent , nil
117+ }
118+ return & core.FileContentResponse {ID : id , Filename : "batch.jsonl" , Data : []byte ("{}\n " )}, nil
119+ }
120+
88121func TestProviderResolvesRequestsAndExposesAliasModels (t * testing.T ) {
89122 catalog := newTestCatalog ()
90123 catalog .add ("gpt-4o" , "openai" , core.Model {ID : "gpt-4o" , Object : "model" , OwnedBy : "openai" })
@@ -221,3 +254,83 @@ func TestProviderRewritesBatchItemBodies(t *testing.T) {
221254 t .Fatalf ("rewritten batch item unexpectedly preserved provider hint: %s" , inner .batchReq .Requests [0 ].Body )
222255 }
223256}
257+
258+ func TestProviderRewritesBatchInputFiles (t * testing.T ) {
259+ catalog := newTestCatalog ()
260+ catalog .add ("openai/gpt-4o" , "openai" , core.Model {ID : "gpt-4o" , Object : "model" })
261+
262+ service , err := NewService (newMemoryStore (Alias {Name : "smart" , TargetModel : "gpt-4o" , TargetProvider : "openai" , Enabled : true }), catalog )
263+ if err != nil {
264+ t .Fatalf ("NewService() error = %v" , err )
265+ }
266+ if err := service .Refresh (context .Background ()); err != nil {
267+ t .Fatalf ("Refresh() error = %v" , err )
268+ }
269+
270+ inner := newProviderMock ()
271+ inner .fileContent = & core.FileContentResponse {
272+ ID : "file_source" ,
273+ Filename : "batch.jsonl" ,
274+ Data : []byte ("{\" custom_id\" :\" 1\" ,\" method\" :\" POST\" ,\" url\" :\" /v1/chat/completions\" ,\" body\" :{\" model\" :\" smart\" ,\" messages\" :[{\" role\" :\" user\" ,\" content\" :\" hi\" }]}}\n " ),
275+ }
276+ inner .fileObject = & core.FileObject {ID : "file_rewritten" , Object : "file" , Filename : "batch.jsonl" , Purpose : "batch" }
277+ provider := NewProvider (inner , service )
278+
279+ _ , err = provider .CreateBatch (context .Background (), "openai" , & core.BatchRequest {
280+ InputFileID : "file_source" ,
281+ Endpoint : "/v1/chat/completions" ,
282+ })
283+ if err != nil {
284+ t .Fatalf ("CreateBatch() error = %v" , err )
285+ }
286+ if inner .batchReq == nil {
287+ t .Fatal ("captured batch request = nil" )
288+ }
289+ if inner .batchReq .InputFileID != "file_rewritten" {
290+ t .Fatalf ("rewritten input_file_id = %q, want file_rewritten" , inner .batchReq .InputFileID )
291+ }
292+ if len (inner .fileCreates ) != 1 {
293+ t .Fatalf ("len(fileCreates) = %d, want 1" , len (inner .fileCreates ))
294+ }
295+ if got := string (inner .fileCreates [0 ].Content ); ! strings .Contains (got , "\" model\" :\" gpt-4o\" " ) {
296+ t .Fatalf ("rewritten file content = %s, want concrete model" , got )
297+ }
298+ }
299+
300+ func TestProviderBatchInputFileSkipsUploadWhenUnchanged (t * testing.T ) {
301+ catalog := newTestCatalog ()
302+ catalog .add ("openai/gpt-4o" , "openai" , core.Model {ID : "gpt-4o" , Object : "model" })
303+
304+ service , err := NewService (newMemoryStore (Alias {Name : "smart" , TargetModel : "gpt-4o" , TargetProvider : "openai" , Enabled : true }), catalog )
305+ if err != nil {
306+ t .Fatalf ("NewService() error = %v" , err )
307+ }
308+ if err := service .Refresh (context .Background ()); err != nil {
309+ t .Fatalf ("Refresh() error = %v" , err )
310+ }
311+
312+ inner := newProviderMock ()
313+ inner .fileContent = & core.FileContentResponse {
314+ ID : "file_source" ,
315+ Filename : "batch.jsonl" ,
316+ Data : []byte ("{\" custom_id\" :\" 1\" ,\" method\" :\" POST\" ,\" url\" :\" /v1/chat/completions\" ,\" body\" :{\" model\" :\" gpt-4o\" ,\" messages\" :[{\" role\" :\" user\" ,\" content\" :\" hi\" }]}}\n " ),
317+ }
318+ provider := NewProvider (inner , service )
319+
320+ _ , err = provider .CreateBatch (context .Background (), "openai" , & core.BatchRequest {
321+ InputFileID : "file_source" ,
322+ Endpoint : "/v1/chat/completions" ,
323+ })
324+ if err != nil {
325+ t .Fatalf ("CreateBatch() error = %v" , err )
326+ }
327+ if inner .batchReq == nil {
328+ t .Fatal ("captured batch request = nil" )
329+ }
330+ if inner .batchReq .InputFileID != "file_source" {
331+ t .Fatalf ("input_file_id = %q, want file_source" , inner .batchReq .InputFileID )
332+ }
333+ if len (inner .fileCreates ) != 0 {
334+ t .Fatalf ("len(fileCreates) = %d, want 0" , len (inner .fileCreates ))
335+ }
336+ }
0 commit comments