Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,4 @@ Feature: Model deployment
Then the model eventually becomes not Ready
And the model status message should eventually be "ModelFailed"


Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
@ModelDeployment @Functional @Models @Explicit
Feature: Explicit Model deployment
I deploy a custom model spec, wait for model to be deployed to the servers
and send an inference request to that model

Scenario: Load model and send inference request to envoy
Given I deploy model spec:
"""
apiVersion: mlops.seldon.io/v1alpha1
kind: Model
metadata:
name: iris
spec:
replicas: 1
requirements:
- sklearn
- mlserver
storageUri: gs://seldon-models/scv2/samples/mlserver_1.3.5/iris-sklearn
"""
When the model "iris" should eventually become Ready with timeout "20s"
Then send HTTP inference request with timeout "20s" to model "iris" with payload:
"""
{
"inputs": [
{
"name": "predict",
"shape": [1, 4],
"datatype": "FP32",
"data": [[1, 2, 3, 4]]
}
]
}
"""
And expect http response status code "200"
And expect http response body to contain JSON:
"""
{ "outputs": [
{
"name": "predict",
"shape": [
1,
1
],
"datatype": "INT64",
"parameters": {
"content_type": "np"
},
"data": [
2
]
}
] }
"""
Then send gRPC inference request with timeout "20s" to model "iris" with payload:
"""
{
"inputs": [
{
"name": "predict",
"shape": [1, 4],
"datatype": "FP32",
"contents": {
"int64_contents" : [1, 2, 3, 4]
}
}
]
}
"""
And expect gRPC response body to contain JSON:
"""
{ "outputs": [
{
"name": "predict",
"shape": [
1,
1
],
"datatype": "INT64",
"parameters": {
"content_type": {"ParameterChoice":{"StringParam":"np"}}
},
"contents": {"int64_contents" : [2]}
}
] }
"""
11 changes: 6 additions & 5 deletions tests/integration/godog/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ go 1.24.4

require (
github.com/cucumber/godog v0.15.1
github.com/seldonio/seldon-core/apis/go/v2 v2.9.1
github.com/seldonio/seldon-core/operator/v2 v2.10.1
github.com/sirupsen/logrus v1.9.3
github.com/spf13/pflag v1.0.7
google.golang.org/grpc v1.73.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.34.2
k8s.io/apimachinery v0.34.2
k8s.io/client-go v0.34.2
sigs.k8s.io/controller-runtime v0.22.4
Expand Down Expand Up @@ -36,8 +42,6 @@ require (
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/seldonio/seldon-core/apis/go/v2 v2.9.1 // indirect
github.com/spf13/pflag v1.0.7 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
Expand All @@ -49,11 +53,8 @@ require (
golang.org/x/time v0.12.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/grpc v1.73.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.34.2 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
Expand Down
4 changes: 4 additions & 0 deletions tests/integration/godog/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ github.com/seldonio/seldon-core/apis/go/v2 v2.9.1 h1:9UcxnTFRuCDApZqy7cy3Rm6B/aa
github.com/seldonio/seldon-core/apis/go/v2 v2.9.1/go.mod h1:ptbV8xxTT6DI5hWGcOx74bizYhms/LhXBJ/04RD41jk=
github.com/seldonio/seldon-core/operator/v2 v2.10.1 h1:Btn8xcFt5rPd4+xCMFAKwcuXGHAq4/nzE5EuYuNg0uI=
github.com/seldonio/seldon-core/operator/v2 v2.10.1/go.mod h1:WMy17S3Q6QZTR2IP1OaIgRdh36RiNboT8jqCajJ6X9A=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
Expand All @@ -125,6 +127,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
Expand Down Expand Up @@ -186,6 +189,7 @@ golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
Expand Down
9 changes: 9 additions & 0 deletions tests/integration/godog/k8sclient/client.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
Copyright (c) 2024 Seldon Technologies Ltd.

Use of this software is governed BY
(1) the license included in the LICENSE file or
(2) if the license included in the LICENSE file is the Business Source License 1.1,
the Change License after the Change Date as each is defined in accordance with the LICENSE file.
*/

package k8sclient

import (
Expand Down
9 changes: 9 additions & 0 deletions tests/integration/godog/k8sclient/watcher.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
Copyright (c) 2024 Seldon Technologies Ltd.

Use of this software is governed BY
(1) the license included in the LICENSE file or
(2) if the license included in the LICENSE file is the Business Source License 1.1,
the Change License after the Change Date as each is defined in accordance with the LICENSE file.
*/

package k8sclient

import (
Expand Down
9 changes: 9 additions & 0 deletions tests/integration/godog/main_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
Copyright (c) 2024 Seldon Technologies Ltd.

Use of this software is governed BY
(1) the license included in the LICENSE file or
(2) if the license included in the LICENSE file is the Business Source License 1.1,
the Change License after the Change Date as each is defined in accordance with the LICENSE file.
*/

package main

import (
Expand Down
9 changes: 9 additions & 0 deletions tests/integration/godog/scenario/assertions/model.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
Copyright (c) 2024 Seldon Technologies Ltd.

Use of this software is governed BY
(1) the license included in the LICENSE file or
(2) if the license included in the LICENSE file is the Business Source License 1.1,
the Change License after the Change Date as each is defined in accordance with the LICENSE file.
*/

package assertions

import (
Expand Down
28 changes: 24 additions & 4 deletions tests/integration/godog/scenario/scenario.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
Copyright (c) 2024 Seldon Technologies Ltd.

Use of this software is governed BY
(1) the license included in the LICENSE file or
(2) if the license included in the LICENSE file is the Business Source License 1.1,
the Change License after the Change Date as each is defined in accordance with the LICENSE file.
*/

package scenario

import (
Expand All @@ -7,6 +16,7 @@ import (
"github.com/cucumber/godog"
"github.com/seldonio/seldon-core/godog/k8sclient"
"github.com/seldonio/seldon-core/godog/steps"
"github.com/sirupsen/logrus"
)

type SuiteDeps struct {
Expand Down Expand Up @@ -72,13 +82,21 @@ func InitializeTestSuite(ctx *godog.TestSuiteContext) {

func InitializeScenario(scenarioCtx *godog.ScenarioContext) {
// Create the world with long-lived deps once per scenario context
world := &steps.World{
world, err := steps.NewWorld(steps.Config{
Namespace: "seldon-mesh", //TODO configurable
Logger: logrus.New().WithField("test_type", "godog"),
KubeClient: suiteDeps.K8sClient,
WatcherStorage: suiteDeps.WatcherStore,
// initialise any other long-lived deps here, e.g. loggers, config, etc.
IngressHost: "localhost", //TODO configurable
HTTPPort: 9000, //TODO configurable
GRPCPort: 9000, //TODO configurable
SSL: false, //TODO configurable
})
if err != nil {
panic(fmt.Errorf("failed to create world: %w", err))
}

world.CurrentModel = steps.NewModel(world)
world.CurrentModel = steps.NewModel()

// Before: reset state and prep cluster before each scenario
scenarioCtx.Before(func(ctx context.Context, scenario *godog.Scenario) (context.Context, error) {
Expand All @@ -104,7 +122,9 @@ func InitializeScenario(scenarioCtx *godog.ScenarioContext) {
})

// Register step definitions with access to world + k8sClient
steps.LoadModelSteps(scenarioCtx, world.CurrentModel)
steps.LoadModelSteps(scenarioCtx, world)
steps.LoadExplicitModelSteps(scenarioCtx, world)
steps.LoadInferenceSteps(scenarioCtx, world)
// TODO: load other steps, e.g. pipeline, experiment, etc.

}
63 changes: 63 additions & 0 deletions tests/integration/godog/steps/explicit_model_steps.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
Copyright (c) 2024 Seldon Technologies Ltd.

Use of this software is governed BY
(1) the license included in the LICENSE file or
(2) if the license included in the LICENSE file is the Business Source License 1.1,
the Change License after the Change Date as each is defined in accordance with the LICENSE file.
*/

package steps

import "context"

func (m *Model) waitForModelReady(ctx context.Context, model string) error {
// TODO: uncomment when auto-gen k8s client merged

//foundModel, err := w.k8sClient.MlopsV1alpha1().Models(w.namespace).Get(ctx, model, metav1.GetOptions{})
//if err != nil {
// return fmt.Errorf("failed getting model: %w", err)
//}
//
//if foundModel.Status.IsReady() {
// return nil
//}
//
//watcher, err := w.k8sClient.MlopsV1alpha1().Models(w.namespace).Watch(ctx, metav1.ListOptions{
// FieldSelector: fmt.Sprintf("metadata.name=%s", model),
// ResourceVersion: foundModel.ResourceVersion,
// Watch: true,
//})
//if err != nil {
// return fmt.Errorf("failed subscribed to watch model: %w", err)
//}
//defer watcher.Stop()
//
//for {
// select {
// case <-ctx.Done():
// return ctx.Err()
// case event, ok := <-watcher.ResultChan():
// if !ok {
// return fmt.Errorf("watch channel closed")
// }
//
// if event.Type == watch.Error {
// return fmt.Errorf("watch error: %v", event.Object)
// }
//
// if event.Type == watch.Added || event.Type == watch.Modified {
// model := event.Object.(*v1alpha1.Model)
// if model.Status.IsReady() {
// return nil
// }
// }
//
// if event.Type == watch.Deleted {
// return fmt.Errorf("resource was deleted")
// }
// }
//}

return nil
}
Loading
Loading