Skip to content

Commit 229012b

Browse files
authored
fix model infer (#7018)
1 parent 035e037 commit 229012b

File tree

7 files changed

+207
-61
lines changed

7 files changed

+207
-61
lines changed

tests/integration/godog/features/model/inference.feature

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ Feature: Basic model inferencing
77
Then the model should eventually become Ready
88
When I send a valid HTTP inference request with timeout "20s"
99
Then expect http response status code "200"
10+
And expect http response body to contain valid JSON
1011
When I send a valid gRPC inference request with timeout "20s"
12+
And expect gRPC response to not return an error
1113

1214
Examples:
13-
| model |
14-
| iris |
15-
# | income-xgb | having errors with GRPC
16-
# | mnist-onnx |
17-
# | income-lgb | having errors with response
18-
| tfsimple1 |
19-
| wine |
20-
# | mnist-pytorch | having errors with response
15+
| model |
16+
| mnist-pytorch |
17+
| wine |
18+
| tfsimple1 |
19+
| iris |
20+
| income-xgb |
21+
| income-lgb |
22+
| mnist-onnx |

tests/integration/godog/features/model/server_setup.feature

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
@Server
1+
@ServerSetup
22
Feature: Server setup
33
Deploys an mlserver with one replica. We ensure the pods
44
become ready and remove any other server pods for different
55
servers.
66

7-
@ServerSetup
7+
@ServerSetup @ServerSetupMLServer
88
Scenario: Deploy mlserver Server and remove other servers
99
Given I deploy server spec with timeout "10s":
1010
"""
@@ -15,14 +15,29 @@ Feature: Server setup
1515
spec:
1616
replicas: 1
1717
serverConfig: mlserver
18-
requirements:
19-
- sklearn
20-
- mlserver
21-
storageUri: gs://seldon-models/scv2/samples/mlserver_1.3.5/iris-sklearn
2218
"""
2319
When the server should eventually become Ready with timeout "30s"
2420
Then ensure only "1" pod(s) are deployed for server and they are Ready
25-
And remove any other server deployments
21+
22+
@ServerSetup @ServerSetupTritonServer
23+
Scenario: Deploy triton Server
24+
Given I deploy server spec with timeout "10s":
25+
"""
26+
apiVersion: mlops.seldon.io/v1alpha1
27+
kind: Server
28+
metadata:
29+
name: godog-triton
30+
spec:
31+
replicas: 1
32+
serverConfig: triton
33+
"""
34+
When the server should eventually become Ready with timeout "30s"
35+
Then ensure only "1" pod(s) are deployed for server and they are Ready
36+
37+
38+
@ServerSetup @ServerClean
39+
Scenario: Remove any other pre-existing servers
40+
Given I remove any other server deployments which are not "godog-mlserver,godog-triton"
2641

2742
# TODO decide if we want to keep this, if we keep testers will need to ensure they don't run this tag when running all
2843
# all features in this directory, as tests will fail when server is deleted. We can not delete and it's up to the

tests/integration/godog/steps/infer_steps.go

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ import (
2222

2323
"github.com/cucumber/godog"
2424
"github.com/seldonio/seldon-core/apis/go/v2/mlops/v2_dataplane"
25+
"github.com/sirupsen/logrus"
2526
"google.golang.org/grpc/metadata"
27+
"google.golang.org/protobuf/encoding/protojson"
2628
)
2729

2830
type inference struct {
@@ -33,6 +35,7 @@ type inference struct {
3335
httpPort uint
3436
lastHTTPResponse *http.Response
3537
lastGRPCResponse lastGRPCResponse
38+
log logrus.FieldLogger
3639
}
3740

3841
func LoadInferenceSteps(scenario *godog.ScenarioContext, w *World) {
@@ -61,6 +64,14 @@ func LoadInferenceSteps(scenario *godog.ScenarioContext, w *World) {
6164
scenario.Step(`^expect http response body to contain JSON:$`, w.infer.httpRespCheckBodyContainsJSON)
6265
scenario.Step(`^expect gRPC response body to contain JSON:$`, w.infer.gRPCRespCheckBodyContainsJSON)
6366
scenario.Step(`^expect gRPC response error to contain "([^"]+)"`, w.infer.gRPCRespContainsError)
67+
scenario.Step(`^expect gRPC response to not return an error$`, w.infer.gRPCRespContainsNoError)
68+
scenario.Step(`^expect http response body to contain valid JSON$`, func() error {
69+
testModel, ok := testModels[w.currentModel.modelType]
70+
if !ok {
71+
return fmt.Errorf("model %s not found", w.currentModel.modelType)
72+
}
73+
return w.infer.doHttpRespCheckBodyContainsJSON(testModel.ValidJSONResponse)
74+
})
6475
}
6576

6677
func (i *inference) doHTTPModelInferenceRequest(ctx context.Context, modelName, body string) error {
@@ -102,7 +113,7 @@ func (i *inference) sendHTTPModelInferenceRequestFromModel(ctx context.Context,
102113
return fmt.Errorf("could not find test model %s", m.model.Name)
103114
}
104115

105-
return i.doHTTPModelInferenceRequest(ctx, m.modelName, testModel.ValidInferenceRequest)
116+
return i.doHTTPModelInferenceRequest(ctx, m.modelName, testModel.ValidHTTPInferenceRequest)
106117
}
107118

108119
func httpScheme(useSSL bool) string {
@@ -121,7 +132,7 @@ func (i *inference) sendGRPCModelInferenceRequestFromModel(ctx context.Context,
121132
if !ok {
122133
return fmt.Errorf("could not find test model %s", m.model.Name)
123134
}
124-
return i.doGRPCModelInferenceRequest(ctx, m.modelName, testModel.ValidInferenceRequest)
135+
return i.doGRPCModelInferenceRequest(ctx, m.modelName, testModel.ValidGRPCInferenceRequest)
125136
}
126137

127138
func (i *inference) doGRPCModelInferenceRequest(
@@ -130,15 +141,19 @@ func (i *inference) doGRPCModelInferenceRequest(
130141
payload string,
131142
) error {
132143
var req v2_dataplane.ModelInferRequest
133-
if err := json.Unmarshal([]byte(payload), &req); err != nil {
144+
if err := protojson.Unmarshal([]byte(payload), &req); err != nil {
134145
return fmt.Errorf("could not unmarshal gRPC json payload: %w", err)
135146
}
136147
req.ModelName = model
137148

138149
md := metadata.Pairs("seldon-model", model)
139150
ctx = metadata.NewOutgoingContext(ctx, md)
140151

152+
i.log.Debugf("sending gRPC model inference %+v", &req)
153+
141154
resp, err := i.grpc.ModelInfer(ctx, &req)
155+
i.log.Debugf("grpc model infer response: %+v", resp)
156+
i.log.Debugf("grpc model infer error: %+v", err)
142157

143158
i.lastGRPCResponse.response = resp
144159
i.lastGRPCResponse.err = err
@@ -212,6 +227,16 @@ func jsonContainsObjectSubset(jsonStr, needleStr string) (bool, error) {
212227
return containsSubset(needle, hay), nil
213228
}
214229

230+
func (i *inference) gRPCRespContainsNoError() error {
231+
if i.lastGRPCResponse.err != nil {
232+
return fmt.Errorf("grpc response contains error: %w", i.lastGRPCResponse.err)
233+
}
234+
if i.lastGRPCResponse.response == nil {
235+
return errors.New("grpc contains no response")
236+
}
237+
return nil
238+
}
239+
215240
func (i *inference) gRPCRespContainsError(err string) error {
216241
if i.lastGRPCResponse.err == nil {
217242
return errors.New("no gRPC response error found")
@@ -226,6 +251,9 @@ func (i *inference) gRPCRespContainsError(err string) error {
226251

227252
func (i *inference) gRPCRespCheckBodyContainsJSON(expectJSON *godog.DocString) error {
228253
if i.lastGRPCResponse.response == nil {
254+
if i.lastGRPCResponse.err != nil {
255+
return fmt.Errorf("no gRPC response, error found: %s", i.lastGRPCResponse.err.Error())
256+
}
229257
return errors.New("no gRPC response found")
230258
}
231259

@@ -234,6 +262,7 @@ func (i *inference) gRPCRespCheckBodyContainsJSON(expectJSON *godog.DocString) e
234262
return fmt.Errorf("could not marshal gRPC json: %w", err)
235263
}
236264

265+
i.log.Debugf("checking gRPC response: %s contains %s", string(gotJson), expectJSON.Content)
237266
ok, err := jsonContainsObjectSubset(string(gotJson), expectJSON.Content)
238267
if err != nil {
239268
return fmt.Errorf("could not check if json contains object: %w", err)
@@ -247,6 +276,10 @@ func (i *inference) gRPCRespCheckBodyContainsJSON(expectJSON *godog.DocString) e
247276
}
248277

249278
func (i *inference) httpRespCheckBodyContainsJSON(expectJSON *godog.DocString) error {
279+
return i.doHttpRespCheckBodyContainsJSON(expectJSON.Content)
280+
}
281+
282+
func (i *inference) doHttpRespCheckBodyContainsJSON(expectJSON string) error {
250283
if i.lastHTTPResponse == nil {
251284
return errors.New("no http response found")
252285
}
@@ -256,7 +289,8 @@ func (i *inference) httpRespCheckBodyContainsJSON(expectJSON *godog.DocString) e
256289
return fmt.Errorf("could not read response body: %w", err)
257290
}
258291

259-
ok, err := jsonContainsObjectSubset(string(body), expectJSON.Content)
292+
i.log.Debugf("checking HTTP response: %s contains %s", string(body), expectJSON)
293+
ok, err := jsonContainsObjectSubset(string(body), expectJSON)
260294
if err != nil {
261295
return fmt.Errorf("could not check if json contains object: %w", err)
262296
}

0 commit comments

Comments
 (0)