Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
ollama
Commits
f40bb398
Unverified
Commit
f40bb398
authored
Oct 01, 2024
by
Alex Mavrogiannis
Committed by
GitHub
Oct 01, 2024
Browse files
Stop model before deletion if loaded (fixed #6957) (#7050)
parent
79d3b1e2
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
310 additions
and
58 deletions
+310
-58
cmd/cmd.go
cmd/cmd.go
+11
-0
cmd/cmd_test.go
cmd/cmd_test.go
+66
-0
server/routes.go
server/routes.go
+6
-1
server/routes_test.go
server/routes_test.go
+227
-57
No files found.
cmd/cmd.go
View file @
f40bb398
...
@@ -680,6 +680,17 @@ func DeleteHandler(cmd *cobra.Command, args []string) error {
...
@@ -680,6 +680,17 @@ func DeleteHandler(cmd *cobra.Command, args []string) error {
return
err
return
err
}
}
// Unload the model if it's running before deletion
opts
:=
&
runOptions
{
Model
:
args
[
0
],
KeepAlive
:
&
api
.
Duration
{
Duration
:
0
},
}
if
err
:=
loadOrUnloadModel
(
cmd
,
opts
);
err
!=
nil
{
if
!
strings
.
Contains
(
err
.
Error
(),
"not found"
)
{
return
fmt
.
Errorf
(
"unable to stop existing running model
\"
%s
\"
: %s"
,
args
[
0
],
err
)
}
}
for
_
,
name
:=
range
args
{
for
_
,
name
:=
range
args
{
req
:=
api
.
DeleteRequest
{
Name
:
name
}
req
:=
api
.
DeleteRequest
{
Name
:
name
}
if
err
:=
client
.
Delete
(
cmd
.
Context
(),
&
req
);
err
!=
nil
{
if
err
:=
client
.
Delete
(
cmd
.
Context
(),
&
req
);
err
!=
nil
{
...
...
cmd/cmd_test.go
View file @
f40bb398
...
@@ -2,11 +2,17 @@ package cmd
...
@@ -2,11 +2,17 @@ package cmd
import
(
import
(
"bytes"
"bytes"
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"os"
"os"
"path/filepath"
"path/filepath"
"strings"
"testing"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp"
"github.com/spf13/cobra"
"github.com/ollama/ollama/api"
"github.com/ollama/ollama/api"
)
)
...
@@ -204,3 +210,63 @@ Weigh anchor!
...
@@ -204,3 +210,63 @@ Weigh anchor!
}
}
})
})
}
}
func
TestDeleteHandler
(
t
*
testing
.
T
)
{
stopped
:=
false
mockServer
:=
httptest
.
NewServer
(
http
.
HandlerFunc
(
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
if
r
.
URL
.
Path
==
"/api/delete"
&&
r
.
Method
==
http
.
MethodDelete
{
var
req
api
.
DeleteRequest
if
err
:=
json
.
NewDecoder
(
r
.
Body
)
.
Decode
(
&
req
);
err
!=
nil
{
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusBadRequest
)
return
}
if
req
.
Name
==
"test-model"
{
w
.
WriteHeader
(
http
.
StatusOK
)
}
else
{
w
.
WriteHeader
(
http
.
StatusNotFound
)
}
return
}
if
r
.
URL
.
Path
==
"/api/generate"
&&
r
.
Method
==
http
.
MethodPost
{
var
req
api
.
GenerateRequest
if
err
:=
json
.
NewDecoder
(
r
.
Body
)
.
Decode
(
&
req
);
err
!=
nil
{
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusBadRequest
)
return
}
if
req
.
Model
==
"test-model"
{
w
.
WriteHeader
(
http
.
StatusOK
)
if
err
:=
json
.
NewEncoder
(
w
)
.
Encode
(
api
.
GenerateResponse
{
Done
:
true
,
});
err
!=
nil
{
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusInternalServerError
)
}
stopped
=
true
return
}
else
{
w
.
WriteHeader
(
http
.
StatusNotFound
)
if
err
:=
json
.
NewEncoder
(
w
)
.
Encode
(
api
.
GenerateResponse
{
Done
:
false
,
});
err
!=
nil
{
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusInternalServerError
)
}
}
}
}))
t
.
Setenv
(
"OLLAMA_HOST"
,
mockServer
.
URL
)
t
.
Cleanup
(
mockServer
.
Close
)
cmd
:=
&
cobra
.
Command
{}
cmd
.
SetContext
(
context
.
TODO
())
if
err
:=
DeleteHandler
(
cmd
,
[]
string
{
"test-model"
});
err
!=
nil
{
t
.
Fatalf
(
"DeleteHandler failed: %v"
,
err
)
}
if
!
stopped
{
t
.
Fatal
(
"Model was not stopped before deletion"
)
}
err
:=
DeleteHandler
(
cmd
,
[]
string
{
"test-model-not-found"
})
if
err
==
nil
||
!
strings
.
Contains
(
err
.
Error
(),
"unable to stop existing running model
\"
test-model-not-found
\"
"
)
{
t
.
Fatalf
(
"DeleteHandler failed: expected error about stopping non-existent model, got %v"
,
err
)
}
}
server/routes.go
View file @
f40bb398
...
@@ -693,7 +693,12 @@ func (s *Server) DeleteHandler(c *gin.Context) {
...
@@ -693,7 +693,12 @@ func (s *Server) DeleteHandler(c *gin.Context) {
m
,
err
:=
ParseNamedManifest
(
n
)
m
,
err
:=
ParseNamedManifest
(
n
)
if
err
!=
nil
{
if
err
!=
nil
{
c
.
JSON
(
http
.
StatusInternalServerError
,
gin
.
H
{
"error"
:
err
.
Error
()})
switch
{
case
os
.
IsNotExist
(
err
)
:
c
.
JSON
(
http
.
StatusNotFound
,
gin
.
H
{
"error"
:
fmt
.
Sprintf
(
"model '%s' not found"
,
cmp
.
Or
(
r
.
Model
,
r
.
Name
))})
default
:
c
.
JSON
(
http
.
StatusInternalServerError
,
gin
.
H
{
"error"
:
err
.
Error
()})
}
return
return
}
}
...
...
server/routes_test.go
View file @
f40bb398
...
@@ -15,9 +15,6 @@ import (
...
@@ -15,9 +15,6 @@ import (
"strings"
"strings"
"testing"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ollama/ollama/api"
"github.com/ollama/ollama/api"
"github.com/ollama/ollama/llm"
"github.com/ollama/ollama/llm"
"github.com/ollama/ollama/openai"
"github.com/ollama/ollama/openai"
...
@@ -30,24 +27,47 @@ func createTestFile(t *testing.T, name string) string {
...
@@ -30,24 +27,47 @@ func createTestFile(t *testing.T, name string) string {
t
.
Helper
()
t
.
Helper
()
f
,
err
:=
os
.
CreateTemp
(
t
.
TempDir
(),
name
)
f
,
err
:=
os
.
CreateTemp
(
t
.
TempDir
(),
name
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create temp file: %v"
,
err
)
}
defer
f
.
Close
()
defer
f
.
Close
()
err
=
binary
.
Write
(
f
,
binary
.
LittleEndian
,
[]
byte
(
"GGUF"
))
err
=
binary
.
Write
(
f
,
binary
.
LittleEndian
,
[]
byte
(
"GGUF"
))
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to write to file: %v"
,
err
)
}
err
=
binary
.
Write
(
f
,
binary
.
LittleEndian
,
uint32
(
3
))
err
=
binary
.
Write
(
f
,
binary
.
LittleEndian
,
uint32
(
3
))
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to write to file: %v"
,
err
)
}
err
=
binary
.
Write
(
f
,
binary
.
LittleEndian
,
uint64
(
0
))
err
=
binary
.
Write
(
f
,
binary
.
LittleEndian
,
uint64
(
0
))
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to write to file: %v"
,
err
)
}
err
=
binary
.
Write
(
f
,
binary
.
LittleEndian
,
uint64
(
0
))
err
=
binary
.
Write
(
f
,
binary
.
LittleEndian
,
uint64
(
0
))
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to write to file: %v"
,
err
)
}
return
f
.
Name
()
return
f
.
Name
()
}
}
// equalStringSlices checks if two slices of strings are equal.
func
equalStringSlices
(
a
,
b
[]
string
)
bool
{
if
len
(
a
)
!=
len
(
b
)
{
return
false
}
for
i
:=
range
a
{
if
a
[
i
]
!=
b
[
i
]
{
return
false
}
}
return
true
}
func
Test_Routes
(
t
*
testing
.
T
)
{
func
Test_Routes
(
t
*
testing
.
T
)
{
type
testCase
struct
{
type
testCase
struct
{
Name
string
Name
string
...
@@ -64,12 +84,16 @@ func Test_Routes(t *testing.T) {
...
@@ -64,12 +84,16 @@ func Test_Routes(t *testing.T) {
r
:=
strings
.
NewReader
(
fmt
.
Sprintf
(
"FROM %s
\n
PARAMETER seed 42
\n
PARAMETER top_p 0.9
\n
PARAMETER stop foo
\n
PARAMETER stop bar"
,
fname
))
r
:=
strings
.
NewReader
(
fmt
.
Sprintf
(
"FROM %s
\n
PARAMETER seed 42
\n
PARAMETER top_p 0.9
\n
PARAMETER stop foo
\n
PARAMETER stop bar"
,
fname
))
modelfile
,
err
:=
parser
.
ParseFile
(
r
)
modelfile
,
err
:=
parser
.
ParseFile
(
r
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to parse file: %v"
,
err
)
}
fn
:=
func
(
resp
api
.
ProgressResponse
)
{
fn
:=
func
(
resp
api
.
ProgressResponse
)
{
t
.
Logf
(
"Status: %s"
,
resp
.
Status
)
t
.
Logf
(
"Status: %s"
,
resp
.
Status
)
}
}
err
=
CreateModel
(
context
.
TODO
(),
model
.
ParseName
(
name
),
""
,
""
,
modelfile
,
fn
)
err
=
CreateModel
(
context
.
TODO
(),
model
.
ParseName
(
name
),
""
,
""
,
modelfile
,
fn
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create model: %v"
,
err
)
}
}
}
testCases
:=
[]
testCase
{
testCases
:=
[]
testCase
{
...
@@ -81,10 +105,17 @@ func Test_Routes(t *testing.T) {
...
@@ -81,10 +105,17 @@ func Test_Routes(t *testing.T) {
},
},
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
assert
.
Equal
(
t
,
"application/json; charset=utf-8"
,
contentType
)
if
contentType
!=
"application/json; charset=utf-8"
{
t
.
Errorf
(
"expected content type application/json; charset=utf-8, got %s"
,
contentType
)
}
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
assert
.
Equal
(
t
,
fmt
.
Sprintf
(
`{"version":"%s"}`
,
version
.
Version
),
string
(
body
))
t
.
Fatalf
(
"failed to read response body: %v"
,
err
)
}
expectedBody
:=
fmt
.
Sprintf
(
`{"version":"%s"}`
,
version
.
Version
)
if
string
(
body
)
!=
expectedBody
{
t
.
Errorf
(
"expected body %s, got %s"
,
expectedBody
,
string
(
body
))
}
},
},
},
},
{
{
...
@@ -93,17 +124,24 @@ func Test_Routes(t *testing.T) {
...
@@ -93,17 +124,24 @@ func Test_Routes(t *testing.T) {
Path
:
"/api/tags"
,
Path
:
"/api/tags"
,
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
assert
.
Equal
(
t
,
"application/json; charset=utf-8"
,
contentType
)
if
contentType
!=
"application/json; charset=utf-8"
{
t
.
Errorf
(
"expected content type application/json; charset=utf-8, got %s"
,
contentType
)
}
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to read response body: %v"
,
err
)
}
var
modelList
api
.
ListResponse
var
modelList
api
.
ListResponse
err
=
json
.
Unmarshal
(
body
,
&
modelList
)
err
=
json
.
Unmarshal
(
body
,
&
modelList
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to unmarshal response body: %v"
,
err
)
}
assert
.
NotNil
(
t
,
modelList
.
Models
)
if
modelList
.
Models
==
nil
||
len
(
modelList
.
Models
)
!=
0
{
assert
.
Empty
(
t
,
len
(
modelList
.
Models
))
t
.
Errorf
(
"expected empty model list, got %v"
,
modelList
.
Models
)
}
},
},
},
},
{
{
...
@@ -112,16 +150,23 @@ func Test_Routes(t *testing.T) {
...
@@ -112,16 +150,23 @@ func Test_Routes(t *testing.T) {
Path
:
"/v1/models"
,
Path
:
"/v1/models"
,
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
assert
.
Equal
(
t
,
"application/json"
,
contentType
)
if
contentType
!=
"application/json"
{
t
.
Errorf
(
"expected content type application/json, got %s"
,
contentType
)
}
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to read response body: %v"
,
err
)
}
var
modelList
openai
.
ListCompletion
var
modelList
openai
.
ListCompletion
err
=
json
.
Unmarshal
(
body
,
&
modelList
)
err
=
json
.
Unmarshal
(
body
,
&
modelList
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to unmarshal response body: %v"
,
err
)
}
assert
.
Equal
(
t
,
"list"
,
modelList
.
Object
)
if
modelList
.
Object
!=
"list"
||
len
(
modelList
.
Data
)
!=
0
{
assert
.
Empty
(
t
,
modelList
.
Data
)
t
.
Errorf
(
"expected empty model list, got %v"
,
modelList
.
Data
)
}
},
},
},
},
{
{
...
@@ -133,18 +178,92 @@ func Test_Routes(t *testing.T) {
...
@@ -133,18 +178,92 @@ func Test_Routes(t *testing.T) {
},
},
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
assert
.
Equal
(
t
,
"application/json; charset=utf-8"
,
contentType
)
if
contentType
!=
"application/json; charset=utf-8"
{
t
.
Errorf
(
"expected content type application/json; charset=utf-8, got %s"
,
contentType
)
}
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to read response body: %v"
,
err
)
}
assert
.
NotContains
(
t
,
string
(
body
),
"expires_at"
)
if
strings
.
Contains
(
string
(
body
),
"expires_at"
)
{
t
.
Errorf
(
"response body should not contain 'expires_at'"
)
}
var
modelList
api
.
ListResponse
var
modelList
api
.
ListResponse
err
=
json
.
Unmarshal
(
body
,
&
modelList
)
err
=
json
.
Unmarshal
(
body
,
&
modelList
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to unmarshal response body: %v"
,
err
)
}
if
len
(
modelList
.
Models
)
!=
1
||
modelList
.
Models
[
0
]
.
Name
!=
"test-model:latest"
{
t
.
Errorf
(
"expected model 'test-model:latest', got %v"
,
modelList
.
Models
)
}
},
},
{
Name
:
"Delete Model Handler"
,
Method
:
http
.
MethodDelete
,
Path
:
"/api/delete"
,
Setup
:
func
(
t
*
testing
.
T
,
req
*
http
.
Request
)
{
createTestModel
(
t
,
"model-to-delete"
)
assert
.
Len
(
t
,
modelList
.
Models
,
1
)
deleteReq
:=
api
.
DeleteRequest
{
assert
.
Equal
(
t
,
"test-model:latest"
,
modelList
.
Models
[
0
]
.
Name
)
Name
:
"model-to-delete"
,
}
jsonData
,
err
:=
json
.
Marshal
(
deleteReq
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to marshal delete request: %v"
,
err
)
}
req
.
Body
=
io
.
NopCloser
(
bytes
.
NewReader
(
jsonData
))
},
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
if
resp
.
StatusCode
!=
http
.
StatusOK
{
t
.
Errorf
(
"expected status code 200, got %d"
,
resp
.
StatusCode
)
}
// Verify the model was deleted
_
,
err
:=
GetModel
(
"model-to-delete"
)
if
err
==
nil
||
!
os
.
IsNotExist
(
err
)
{
t
.
Errorf
(
"expected model to be deleted, got error %v"
,
err
)
}
},
},
{
Name
:
"Delete Non-existent Model"
,
Method
:
http
.
MethodDelete
,
Path
:
"/api/delete"
,
Setup
:
func
(
t
*
testing
.
T
,
req
*
http
.
Request
)
{
deleteReq
:=
api
.
DeleteRequest
{
Name
:
"non-existent-model"
,
}
jsonData
,
err
:=
json
.
Marshal
(
deleteReq
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to marshal delete request: %v"
,
err
)
}
req
.
Body
=
io
.
NopCloser
(
bytes
.
NewReader
(
jsonData
))
},
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
if
resp
.
StatusCode
!=
http
.
StatusNotFound
{
t
.
Errorf
(
"expected status code 404, got %d"
,
resp
.
StatusCode
)
}
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to read response body: %v"
,
err
)
}
var
errorResp
map
[
string
]
string
err
=
json
.
Unmarshal
(
body
,
&
errorResp
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to unmarshal response body: %v"
,
err
)
}
if
!
strings
.
Contains
(
errorResp
[
"error"
],
"not found"
)
{
t
.
Errorf
(
"expected error message to contain 'not found', got %s"
,
errorResp
[
"error"
])
}
},
},
},
},
{
{
...
@@ -153,17 +272,23 @@ func Test_Routes(t *testing.T) {
...
@@ -153,17 +272,23 @@ func Test_Routes(t *testing.T) {
Path
:
"/v1/models"
,
Path
:
"/v1/models"
,
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
assert
.
Equal
(
t
,
"application/json"
,
contentType
)
if
contentType
!=
"application/json"
{
t
.
Errorf
(
"expected content type application/json, got %s"
,
contentType
)
}
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to read response body: %v"
,
err
)
}
var
modelList
openai
.
ListCompletion
var
modelList
openai
.
ListCompletion
err
=
json
.
Unmarshal
(
body
,
&
modelList
)
err
=
json
.
Unmarshal
(
body
,
&
modelList
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to unmarshal response body: %v"
,
err
)
}
assert
.
Len
(
t
,
modelList
.
Data
,
1
)
if
len
(
modelList
.
Data
)
!=
1
||
modelList
.
Data
[
0
]
.
Id
!=
"test-model:latest"
||
modelList
.
Data
[
0
]
.
OwnedBy
!=
"library"
{
assert
.
Equal
(
t
,
"test-model:latest
"
,
modelList
.
Data
[
0
]
.
Id
)
t
.
Errorf
(
"expected model 'test-model:latest' owned by 'library', got %v
"
,
modelList
.
Data
)
assert
.
Equal
(
t
,
"library"
,
modelList
.
Data
[
0
]
.
OwnedBy
)
}
},
},
},
},
{
{
...
@@ -180,20 +305,32 @@ func Test_Routes(t *testing.T) {
...
@@ -180,20 +305,32 @@ func Test_Routes(t *testing.T) {
Stream
:
&
stream
,
Stream
:
&
stream
,
}
}
jsonData
,
err
:=
json
.
Marshal
(
createReq
)
jsonData
,
err
:=
json
.
Marshal
(
createReq
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to marshal create request: %v"
,
err
)
}
req
.
Body
=
io
.
NopCloser
(
bytes
.
NewReader
(
jsonData
))
req
.
Body
=
io
.
NopCloser
(
bytes
.
NewReader
(
jsonData
))
},
},
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
assert
.
Equal
(
t
,
"application/json"
,
contentType
)
if
contentType
!=
"application/json"
{
t
.
Errorf
(
"expected content type application/json, got %s"
,
contentType
)
}
_
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
_
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
assert
.
Equal
(
t
,
200
,
resp
.
StatusCode
)
t
.
Fatalf
(
"failed to read response body: %v"
,
err
)
}
if
resp
.
StatusCode
!=
http
.
StatusOK
{
// Updated line
t
.
Errorf
(
"expected status code 200, got %d"
,
resp
.
StatusCode
)
}
model
,
err
:=
GetModel
(
"t-bone"
)
model
,
err
:=
GetModel
(
"t-bone"
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
assert
.
Equal
(
t
,
"t-bone:latest"
,
model
.
ShortName
)
t
.
Fatalf
(
"failed to get model: %v"
,
err
)
}
if
model
.
ShortName
!=
"t-bone:latest"
{
t
.
Errorf
(
"expected model name 't-bone:latest', got %s"
,
model
.
ShortName
)
}
},
},
},
},
{
{
...
@@ -207,14 +344,20 @@ func Test_Routes(t *testing.T) {
...
@@ -207,14 +344,20 @@ func Test_Routes(t *testing.T) {
Destination
:
"beefsteak"
,
Destination
:
"beefsteak"
,
}
}
jsonData
,
err
:=
json
.
Marshal
(
copyReq
)
jsonData
,
err
:=
json
.
Marshal
(
copyReq
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to marshal copy request: %v"
,
err
)
}
req
.
Body
=
io
.
NopCloser
(
bytes
.
NewReader
(
jsonData
))
req
.
Body
=
io
.
NopCloser
(
bytes
.
NewReader
(
jsonData
))
},
},
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
model
,
err
:=
GetModel
(
"beefsteak"
)
model
,
err
:=
GetModel
(
"beefsteak"
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
assert
.
Equal
(
t
,
"beefsteak:latest"
,
model
.
ShortName
)
t
.
Fatalf
(
"failed to get model: %v"
,
err
)
}
if
model
.
ShortName
!=
"beefsteak:latest"
{
t
.
Errorf
(
"expected model name 'beefsteak:latest', got %s"
,
model
.
ShortName
)
}
},
},
},
},
{
{
...
@@ -225,18 +368,26 @@ func Test_Routes(t *testing.T) {
...
@@ -225,18 +368,26 @@ func Test_Routes(t *testing.T) {
createTestModel
(
t
,
"show-model"
)
createTestModel
(
t
,
"show-model"
)
showReq
:=
api
.
ShowRequest
{
Model
:
"show-model"
}
showReq
:=
api
.
ShowRequest
{
Model
:
"show-model"
}
jsonData
,
err
:=
json
.
Marshal
(
showReq
)
jsonData
,
err
:=
json
.
Marshal
(
showReq
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to marshal show request: %v"
,
err
)
}
req
.
Body
=
io
.
NopCloser
(
bytes
.
NewReader
(
jsonData
))
req
.
Body
=
io
.
NopCloser
(
bytes
.
NewReader
(
jsonData
))
},
},
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
assert
.
Equal
(
t
,
"application/json; charset=utf-8"
,
contentType
)
if
contentType
!=
"application/json; charset=utf-8"
{
t
.
Errorf
(
"expected content type application/json; charset=utf-8, got %s"
,
contentType
)
}
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to read response body: %v"
,
err
)
}
var
showResp
api
.
ShowResponse
var
showResp
api
.
ShowResponse
err
=
json
.
Unmarshal
(
body
,
&
showResp
)
err
=
json
.
Unmarshal
(
body
,
&
showResp
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to unmarshal response body: %v"
,
err
)
}
var
params
[]
string
var
params
[]
string
paramsSplit
:=
strings
.
Split
(
showResp
.
Parameters
,
"
\n
"
)
paramsSplit
:=
strings
.
Split
(
showResp
.
Parameters
,
"
\n
"
)
...
@@ -250,8 +401,16 @@ func Test_Routes(t *testing.T) {
...
@@ -250,8 +401,16 @@ func Test_Routes(t *testing.T) {
"stop
\"
foo
\"
"
,
"stop
\"
foo
\"
"
,
"top_p 0.9"
,
"top_p 0.9"
,
}
}
assert
.
Equal
(
t
,
expectedParams
,
params
)
if
!
equalStringSlices
(
params
,
expectedParams
)
{
assert
.
InDelta
(
t
,
0
,
showResp
.
ModelInfo
[
"general.parameter_count"
],
1e-9
,
"Parameter count should be 0"
)
t
.
Errorf
(
"expected parameters %v, got %v"
,
expectedParams
,
params
)
}
paramCount
,
ok
:=
showResp
.
ModelInfo
[
"general.parameter_count"
]
.
(
float64
)
if
!
ok
{
t
.
Fatalf
(
"expected parameter count to be a float64, got %T"
,
showResp
.
ModelInfo
[
"general.parameter_count"
])
}
if
math
.
Abs
(
paramCount
)
>
1e-9
{
t
.
Errorf
(
"expected parameter count to be 0, got %f"
,
paramCount
)
}
},
},
},
},
{
{
...
@@ -260,16 +419,23 @@ func Test_Routes(t *testing.T) {
...
@@ -260,16 +419,23 @@ func Test_Routes(t *testing.T) {
Path
:
"/v1/models/show-model"
,
Path
:
"/v1/models/show-model"
,
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
Expected
:
func
(
t
*
testing
.
T
,
resp
*
http
.
Response
)
{
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
contentType
:=
resp
.
Header
.
Get
(
"Content-Type"
)
assert
.
Equal
(
t
,
"application/json"
,
contentType
)
if
contentType
!=
"application/json"
{
t
.
Errorf
(
"expected content type application/json, got %s"
,
contentType
)
}
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to read response body: %v"
,
err
)
}
var
retrieveResp
api
.
RetrieveModelResponse
var
retrieveResp
api
.
RetrieveModelResponse
err
=
json
.
Unmarshal
(
body
,
&
retrieveResp
)
err
=
json
.
Unmarshal
(
body
,
&
retrieveResp
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to unmarshal response body: %v"
,
err
)
}
assert
.
Equal
(
t
,
"show-model"
,
retrieveResp
.
Id
)
if
retrieveResp
.
Id
!=
"show-model"
||
retrieveResp
.
OwnedBy
!=
"library"
{
assert
.
Equal
(
t
,
"library"
,
retrieveResp
.
OwnedBy
)
t
.
Errorf
(
"expected model 'show-model' owned by 'library', got %v"
,
retrieveResp
)
}
},
},
},
},
}
}
...
@@ -286,14 +452,18 @@ func Test_Routes(t *testing.T) {
...
@@ -286,14 +452,18 @@ func Test_Routes(t *testing.T) {
t
.
Run
(
tc
.
Name
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
tc
.
Name
,
func
(
t
*
testing
.
T
)
{
u
:=
httpSrv
.
URL
+
tc
.
Path
u
:=
httpSrv
.
URL
+
tc
.
Path
req
,
err
:=
http
.
NewRequestWithContext
(
context
.
TODO
(),
tc
.
Method
,
u
,
nil
)
req
,
err
:=
http
.
NewRequestWithContext
(
context
.
TODO
(),
tc
.
Method
,
u
,
nil
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create request: %v"
,
err
)
}
if
tc
.
Setup
!=
nil
{
if
tc
.
Setup
!=
nil
{
tc
.
Setup
(
t
,
req
)
tc
.
Setup
(
t
,
req
)
}
}
resp
,
err
:=
httpSrv
.
Client
()
.
Do
(
req
)
resp
,
err
:=
httpSrv
.
Client
()
.
Do
(
req
)
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to do request: %v"
,
err
)
}
defer
resp
.
Body
.
Close
()
defer
resp
.
Body
.
Close
()
if
tc
.
Expected
!=
nil
{
if
tc
.
Expected
!=
nil
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment