|
9 | 9 | kubeairunwayv1alpha1 "github.com/kaito-project/kubeairunway/controller/api/v1alpha1" |
10 | 10 | batchv1 "k8s.io/api/batch/v1" |
11 | 11 | corev1 "k8s.io/api/core/v1" |
| 12 | + "k8s.io/apimachinery/pkg/api/meta" |
12 | 13 | "k8s.io/apimachinery/pkg/api/resource" |
13 | 14 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
14 | 15 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" |
@@ -52,6 +53,21 @@ func setDGDGVK(u *unstructured.Unstructured) { |
52 | 53 | u.SetKind("DynamoGraphDeployment") |
53 | 54 | } |
54 | 55 |
|
| 56 | +func assertCondition(t *testing.T, conditions []metav1.Condition, condType string, status metav1.ConditionStatus, reason string) { |
| 57 | + t.Helper() |
| 58 | + cond := meta.FindStatusCondition(conditions, condType) |
| 59 | + if cond == nil { |
| 60 | + t.Errorf("expected condition %s to be set", condType) |
| 61 | + return |
| 62 | + } |
| 63 | + if cond.Status != status { |
| 64 | + t.Errorf("condition %s: expected status %s, got %s", condType, status, cond.Status) |
| 65 | + } |
| 66 | + if cond.Reason != reason { |
| 67 | + t.Errorf("condition %s: expected reason %q, got %q", condType, reason, cond.Reason) |
| 68 | + } |
| 69 | +} |
| 70 | + |
55 | 71 | func TestValidateCompatibility(t *testing.T) { |
56 | 72 | r := &DynamoProviderReconciler{} |
57 | 73 |
|
@@ -407,7 +423,7 @@ func TestReconcileDeletionWithUpstreamResource(t *testing.T) { |
407 | 423 | dgd.SetName("test") |
408 | 424 | dgd.SetNamespace("default") |
409 | 425 | dgd.SetLabels(map[string]string{ |
410 | | - kubeairunwayv1alpha1.LabelManagedBy: "kubeairunway", |
| 426 | + kubeairunwayv1alpha1.LabelManagedBy: "kubeairunway", |
411 | 427 | }) |
412 | 428 | dgd.SetOwnerReferences([]metav1.OwnerReference{ |
413 | 429 | {APIVersion: "kubeairunway.ai/v1alpha1", Kind: "ModelDeployment", Name: "test", UID: "test-uid"}, |
@@ -456,7 +472,7 @@ func TestCreateOrUpdateResourceUpdate(t *testing.T) { |
456 | 472 | existing.SetName("test") |
457 | 473 | existing.SetNamespace("default") |
458 | 474 | existing.SetLabels(map[string]string{ |
459 | | - kubeairunwayv1alpha1.LabelManagedBy: "kubeairunway", |
| 475 | + kubeairunwayv1alpha1.LabelManagedBy: "kubeairunway", |
460 | 476 | }) |
461 | 477 | existing.SetOwnerReferences([]metav1.OwnerReference{ |
462 | 478 | {APIVersion: "kubeairunway.ai/v1alpha1", Kind: "ModelDeployment", Name: "test", UID: "test-uid"}, |
@@ -491,7 +507,7 @@ func TestCreateOrUpdateResourceNoChange(t *testing.T) { |
491 | 507 | existing.SetName("test") |
492 | 508 | existing.SetNamespace("default") |
493 | 509 | existing.SetLabels(map[string]string{ |
494 | | - kubeairunwayv1alpha1.LabelManagedBy: "kubeairunway", |
| 510 | + kubeairunwayv1alpha1.LabelManagedBy: "kubeairunway", |
495 | 511 | }) |
496 | 512 | existing.SetOwnerReferences([]metav1.OwnerReference{ |
497 | 513 | {APIVersion: "kubeairunway.ai/v1alpha1", Kind: "ModelDeployment", Name: "test", UID: "test-uid"}, |
@@ -685,6 +701,17 @@ func TestReconcilePVCNotBound(t *testing.T) { |
685 | 701 | if err == nil { |
686 | 702 | t.Error("DGD should NOT be created before PVCs are bound") |
687 | 703 | } |
| 704 | + |
| 705 | + // Verify conditions were set correctly |
| 706 | + var updated kubeairunwayv1alpha1.ModelDeployment |
| 707 | + if err := c.Get(context.Background(), types.NamespacedName{Name: "test", Namespace: "default"}, &updated); err != nil { |
| 708 | + t.Fatalf("failed to get updated MD: %v", err) |
| 709 | + } |
| 710 | + assertCondition(t, updated.Status.Conditions, kubeairunwayv1alpha1.ConditionTypeStorageReady, metav1.ConditionFalse, "PVCsPending") |
| 711 | + // ModelDownloaded should NOT be set (download phase was never reached) |
| 712 | + if meta.FindStatusCondition(updated.Status.Conditions, kubeairunwayv1alpha1.ConditionTypeModelDownloaded) != nil { |
| 713 | + t.Error("expected ModelDownloaded condition to NOT be set (download phase not reached)") |
| 714 | + } |
688 | 715 | } |
689 | 716 |
|
690 | 717 | func TestReconcileDownloadNotComplete(t *testing.T) { |
@@ -743,6 +770,14 @@ func TestReconcileDownloadNotComplete(t *testing.T) { |
743 | 770 | if err == nil { |
744 | 771 | t.Error("DGD should NOT be created before download completes") |
745 | 772 | } |
| 773 | + |
| 774 | + // Verify conditions were set correctly |
| 775 | + var updated kubeairunwayv1alpha1.ModelDeployment |
| 776 | + if err := c.Get(context.Background(), types.NamespacedName{Name: "test", Namespace: "default"}, &updated); err != nil { |
| 777 | + t.Fatalf("failed to get updated MD: %v", err) |
| 778 | + } |
| 779 | + assertCondition(t, updated.Status.Conditions, kubeairunwayv1alpha1.ConditionTypeStorageReady, metav1.ConditionTrue, "PVCsBound") |
| 780 | + assertCondition(t, updated.Status.Conditions, kubeairunwayv1alpha1.ConditionTypeModelDownloaded, metav1.ConditionFalse, "DownloadInProgress") |
746 | 781 | } |
747 | 782 |
|
748 | 783 | func TestReconcileFullPipeline(t *testing.T) { |
@@ -810,6 +845,14 @@ func TestReconcileFullPipeline(t *testing.T) { |
810 | 845 | if err != nil { |
811 | 846 | t.Fatalf("expected DGD to be created: %v", err) |
812 | 847 | } |
| 848 | + |
| 849 | + // Verify conditions were set correctly |
| 850 | + var updated kubeairunwayv1alpha1.ModelDeployment |
| 851 | + if err := c.Get(context.Background(), types.NamespacedName{Name: "test", Namespace: "default"}, &updated); err != nil { |
| 852 | + t.Fatalf("failed to get updated MD: %v", err) |
| 853 | + } |
| 854 | + assertCondition(t, updated.Status.Conditions, kubeairunwayv1alpha1.ConditionTypeStorageReady, metav1.ConditionTrue, "PVCsBound") |
| 855 | + assertCondition(t, updated.Status.Conditions, kubeairunwayv1alpha1.ConditionTypeModelDownloaded, metav1.ConditionTrue, "DownloadComplete") |
813 | 856 | } |
814 | 857 |
|
815 | 858 | func TestReconcileNoStorageSkipsPhases(t *testing.T) { |
|
0 commit comments