@@ -2,10 +2,12 @@ package llmd
22
33import (
44 "context"
5+ "strings"
56 "testing"
67
78 airunwayv1alpha1 "github.com/kaito-project/airunway/controller/api/v1alpha1"
89 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
911 "k8s.io/apimachinery/pkg/runtime"
1012 "k8s.io/apimachinery/pkg/types"
1113 ctrl "sigs.k8s.io/controller-runtime"
@@ -107,7 +109,7 @@ func TestValidateCompatibility(t *testing.T) {
107109 name : "disaggregated without prefill is incompatible" ,
108110 md : & airunwayv1alpha1.ModelDeployment {
109111 Spec : airunwayv1alpha1.ModelDeploymentSpec {
110- Engine : airunwayv1alpha1.EngineSpec {Type : airunwayv1alpha1 .EngineTypeVLLM },
112+ Engine : airunwayv1alpha1.EngineSpec {Type : airunwayv1alpha1 .EngineTypeVLLM },
111113 Serving : & airunwayv1alpha1.ServingSpec {Mode : airunwayv1alpha1 .ServingModeDisaggregated },
112114 Scaling : & airunwayv1alpha1.ScalingSpec {
113115 Decode : & airunwayv1alpha1.ComponentScalingSpec {
@@ -123,7 +125,7 @@ func TestValidateCompatibility(t *testing.T) {
123125 name : "disaggregated without decode is incompatible" ,
124126 md : & airunwayv1alpha1.ModelDeployment {
125127 Spec : airunwayv1alpha1.ModelDeploymentSpec {
126- Engine : airunwayv1alpha1.EngineSpec {Type : airunwayv1alpha1 .EngineTypeVLLM },
128+ Engine : airunwayv1alpha1.EngineSpec {Type : airunwayv1alpha1 .EngineTypeVLLM },
127129 Serving : & airunwayv1alpha1.ServingSpec {Mode : airunwayv1alpha1 .ServingModeDisaggregated },
128130 Scaling : & airunwayv1alpha1.ScalingSpec {
129131 Prefill : & airunwayv1alpha1.ComponentScalingSpec {
@@ -139,7 +141,7 @@ func TestValidateCompatibility(t *testing.T) {
139141 name : "disaggregated with both prefill and decode is compatible" ,
140142 md : & airunwayv1alpha1.ModelDeployment {
141143 Spec : airunwayv1alpha1.ModelDeploymentSpec {
142- Engine : airunwayv1alpha1.EngineSpec {Type : airunwayv1alpha1 .EngineTypeVLLM },
144+ Engine : airunwayv1alpha1.EngineSpec {Type : airunwayv1alpha1 .EngineTypeVLLM },
143145 Serving : & airunwayv1alpha1.ServingSpec {Mode : airunwayv1alpha1 .ServingModeDisaggregated },
144146 Scaling : & airunwayv1alpha1.ScalingSpec {
145147 Prefill : & airunwayv1alpha1.ComponentScalingSpec {
@@ -159,7 +161,7 @@ func TestValidateCompatibility(t *testing.T) {
159161 name : "disaggregated without GPU on prefill is incompatible" ,
160162 md : & airunwayv1alpha1.ModelDeployment {
161163 Spec : airunwayv1alpha1.ModelDeploymentSpec {
162- Engine : airunwayv1alpha1.EngineSpec {Type : airunwayv1alpha1 .EngineTypeVLLM },
164+ Engine : airunwayv1alpha1.EngineSpec {Type : airunwayv1alpha1 .EngineTypeVLLM },
163165 Serving : & airunwayv1alpha1.ServingSpec {Mode : airunwayv1alpha1 .ServingModeDisaggregated },
164166 Scaling : & airunwayv1alpha1.ScalingSpec {
165167 Prefill : & airunwayv1alpha1.ComponentScalingSpec {
@@ -178,7 +180,7 @@ func TestValidateCompatibility(t *testing.T) {
178180 name : "disaggregated without GPU on decode is incompatible" ,
179181 md : & airunwayv1alpha1.ModelDeployment {
180182 Spec : airunwayv1alpha1.ModelDeploymentSpec {
181- Engine : airunwayv1alpha1.EngineSpec {Type : airunwayv1alpha1 .EngineTypeVLLM },
183+ Engine : airunwayv1alpha1.EngineSpec {Type : airunwayv1alpha1 .EngineTypeVLLM },
182184 Serving : & airunwayv1alpha1.ServingSpec {Mode : airunwayv1alpha1 .ServingModeDisaggregated },
183185 Scaling : & airunwayv1alpha1.ScalingSpec {
184186 Prefill : & airunwayv1alpha1.ComponentScalingSpec {
@@ -197,7 +199,7 @@ func TestValidateCompatibility(t *testing.T) {
197199 name : "disaggregated without top-level resources is compatible" ,
198200 md : & airunwayv1alpha1.ModelDeployment {
199201 Spec : airunwayv1alpha1.ModelDeploymentSpec {
200- Engine : airunwayv1alpha1.EngineSpec {Type : airunwayv1alpha1 .EngineTypeVLLM },
202+ Engine : airunwayv1alpha1.EngineSpec {Type : airunwayv1alpha1 .EngineTypeVLLM },
201203 Serving : & airunwayv1alpha1.ServingSpec {Mode : airunwayv1alpha1 .ServingModeDisaggregated },
202204 Scaling : & airunwayv1alpha1.ScalingSpec {
203205 Prefill : & airunwayv1alpha1.ComponentScalingSpec {
@@ -273,3 +275,46 @@ func TestReconcileIgnoresNoProvider(t *testing.T) {
273275 t .Error ("expected no requeue when no provider assigned" )
274276 }
275277}
278+
279+ // TestSyncStatusRunningUpdatesMessage reproduces issue #289: once the upstream
280+ // Deployment is Available the phase flips to Running, but the status message
281+ // must no longer claim it is "waiting for pods to be ready".
282+ func TestSyncStatusRunningUpdatesMessage (t * testing.T ) {
283+ scheme := newScheme ()
284+
285+ deploy := & unstructured.Unstructured {}
286+ deploy .SetAPIVersion ("apps/v1" )
287+ deploy .SetKind ("Deployment" )
288+ deploy .SetName ("test" )
289+ deploy .SetNamespace ("default" )
290+ deploy .Object ["status" ] = map [string ]interface {}{
291+ "conditions" : []interface {}{
292+ map [string ]interface {}{"type" : "Available" , "status" : "True" },
293+ },
294+ }
295+
296+ c := fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (deploy ).Build ()
297+ r := NewLLMDProviderReconciler (c , scheme )
298+
299+ md := & airunwayv1alpha1.ModelDeployment {}
300+ md .Status .Message = "Deployments created, waiting for pods to be ready"
301+
302+ desired := & unstructured.Unstructured {}
303+ desired .SetAPIVersion ("apps/v1" )
304+ desired .SetKind ("Deployment" )
305+ desired .SetName ("test" )
306+ desired .SetNamespace ("default" )
307+
308+ if err := r .syncStatus (context .Background (), md , desired ); err != nil {
309+ t .Fatalf ("unexpected error: %v" , err )
310+ }
311+ if md .Status .Phase != airunwayv1alpha1 .DeploymentPhaseRunning {
312+ t .Fatalf ("expected Running phase, got %s" , md .Status .Phase )
313+ }
314+ if strings .Contains (md .Status .Message , "waiting for pods" ) {
315+ t .Errorf ("status message still claims waiting for pods while Running: %q" , md .Status .Message )
316+ }
317+ if md .Status .Message == "" {
318+ t .Errorf ("expected a non-empty status message in Running phase" )
319+ }
320+ }
0 commit comments