package edgedb import ( "context" "fmt" "testing" "time" "github.com/google/uuid" "edge-infra.dev/pkg/edge/api/testutils/seededpostgres" bannerApi "edge-infra.dev/pkg/edge/apis/banner/v1alpha1" clusterApi "edge-infra.dev/pkg/edge/apis/cluster/v1alpha1" gkeclusterApi "edge-infra.dev/pkg/edge/apis/gkecluster/v1alpha1" "edge-infra.dev/pkg/edge/controllers/dbmetrics" "edge-infra.dev/pkg/k8s/runtime/conditions" "edge-infra.dev/pkg/lib/build/bazel" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) var edb *EdgeDB func TestRecordInfraStatus(t *testing.T) { if !bazel.IsBazelTest() && !bazel.IsBazelRun() { t.Skip() return } sp, err := seededpostgres.New() if err != nil { t.Fatal(err) } db, err := sp.DB() if err != nil { t.Fatal(err) } edb = &EdgeDB{DB: db} defer func() { _ = db.Close() _ = sp.Close() }() t.Run("banner", testStatusForBannerAPI) t.Run("cluster", testStatusForClusterAPI) t.Run("gkecluster", testStatusForGKEClusterAPI) t.Run("store", testStoreClusterArtifacts) } // nolint: dupl func testStatusForBannerAPI(t *testing.T) { // Get a banner_edge_id var bannerEdgeID string row := edb.DB.QueryRow("SELECT banner_edge_id FROM banners LIMIT 1") if err := row.Err(); err != nil { t.Fatal(err) } else if err = row.Scan(&bannerEdgeID); err != nil { t.Fatal(err) } var now = time.Now().UTC().Round(time.Second) var banner = &bannerApi.Banner{ TypeMeta: metav1.TypeMeta{ Kind: bannerApi.BannerKind, }, ObjectMeta: metav1.ObjectMeta{ Name: bannerEdgeID, }, Status: bannerApi.BannerStatus{ Conditions: make([]metav1.Condition, 1), }, } // Test InfraStatusReady banner.Status.Conditions[0] = metav1.Condition{ Type: "Ready", Status: metav1.ConditionTrue, Message: "banner reconciled successfully", Reason: bannerApi.ProvisionSucceededReason, ObservedGeneration: 1, LastTransitionTime: metav1.Time{Time: now}, } edb.RecordInfraStatus(context.Background(), banner, dbmetrics.DBMetrics{}) validateExpectedInfraStatus(t, banner) // Test InfraStatusError banner.Status.Conditions[0] = metav1.Condition{ Type: "Ready", Status: metav1.ConditionFalse, Message: "oof", Reason: "OofReason", ObservedGeneration: 1, LastTransitionTime: metav1.Time{Time: now}, } edb.RecordInfraStatus(context.Background(), banner, dbmetrics.DBMetrics{}) validateExpectedInfraStatus(t, banner) } // nolint: dupl func testStatusForGKEClusterAPI(t *testing.T) { var ( clusterEdgeID = uuid.NewString() clusterName = "gkeclusterFooName" ) // Setup cluster in database. result, err := edb.DB.Exec("INSERT INTO clusters (cluster_edge_id, cluster_name) VALUES ($1, $2)", clusterEdgeID, clusterName) if err != nil { t.Logf("Got result: %v", result) t.Fatal(err) } else if ra, err := result.RowsAffected(); err != nil { t.Fatal(err) } else if ra != 1 { t.Fatalf("Got %d rows affected by insert", ra) } var now = time.Now().UTC().Round(time.Second) var cluster = &gkeclusterApi.GKECluster{ TypeMeta: metav1.TypeMeta{ Kind: gkeclusterApi.Kind, }, ObjectMeta: metav1.ObjectMeta{ Name: clusterEdgeID, }, Status: gkeclusterApi.GKEClusterStatus{ Conditions: make([]metav1.Condition, 1), }, } // Test InfraStatusReady cluster.Status.Conditions[0] = metav1.Condition{ Type: "Ready", Status: metav1.ConditionTrue, Message: "gkecluster reconciled successfully", Reason: gkeclusterApi.GKEClusterReadyReason, ObservedGeneration: 1, LastTransitionTime: metav1.Time{Time: now}, } edb.RecordInfraStatus(context.Background(), cluster, dbmetrics.DBMetrics{}) validateExpectedInfraStatus(t, cluster) // Test InfraStatusError cluster.Status.Conditions[0] = metav1.Condition{ Type: "Ready", Status: metav1.ConditionFalse, Message: "oof", Reason: "OofReason", ObservedGeneration: 1, LastTransitionTime: metav1.Time{Time: now}, } edb.RecordInfraStatus(context.Background(), cluster, dbmetrics.DBMetrics{}) validateExpectedInfraStatus(t, cluster) } // nolint: dupl func testStatusForClusterAPI(t *testing.T) { var ( clusterEdgeID = uuid.NewString() clusterName = "clusterNameFoo" ) // Setup cluster in database. result, err := edb.DB.Exec("INSERT INTO clusters (cluster_edge_id, cluster_name) VALUES ($1, $2)", clusterEdgeID, clusterName) if err != nil { t.Logf("Got result: %v", result) t.Fatal(err) } else if ra, err := result.RowsAffected(); err != nil { t.Fatal(err) } else if ra != 1 { t.Fatalf("Got %d rows affected by insert", ra) } var now = time.Now().UTC().Round(time.Second) var cluster = &clusterApi.Cluster{ TypeMeta: metav1.TypeMeta{ Kind: clusterApi.Kind, }, ObjectMeta: metav1.ObjectMeta{ Name: clusterEdgeID, }, Status: clusterApi.ClusterStatus{ Conditions: make([]metav1.Condition, 1), }, } // Test InfraStatusReady cluster.Status.Conditions[0] = metav1.Condition{ Type: "Ready", Status: metav1.ConditionTrue, Message: "cluster reconciled successfully", Reason: clusterApi.ClusterReadyReason, ObservedGeneration: 1, LastTransitionTime: metav1.Time{Time: now}, } edb.RecordInfraStatus(context.Background(), cluster, dbmetrics.DBMetrics{}) validateExpectedInfraStatus(t, cluster) // Test InfraStatusError cluster.Status.Conditions[0] = metav1.Condition{ Type: "Ready", Status: metav1.ConditionFalse, Message: "oof", Reason: "OofReason", ObservedGeneration: 1, LastTransitionTime: metav1.Time{Time: now}, } edb.RecordInfraStatus(context.Background(), cluster, dbmetrics.DBMetrics{}) validateExpectedInfraStatus(t, cluster) } const ( sqlSelectClusterInfraStatus = "SELECT infra_status, infra_status_details, infra_status_updated_at FROM clusters WHERE cluster_edge_id=$1" sqlSelectBannerInfraStatus = "SELECT infra_status, infra_status_details, infra_status_updated_at FROM banners WHERE banner_edge_id=$1" ) func validateExpectedInfraStatus(t *testing.T, obj conditions.Getter) { var stmt string switch obj.GetObjectKind().GroupVersionKind().Kind { case clusterApi.Kind, gkeclusterApi.Kind: stmt = sqlSelectClusterInfraStatus case bannerApi.BannerKind: stmt = sqlSelectBannerInfraStatus default: t.Fatalf("Unknown object %v", obj) } var edgeID = obj.GetName() row := edb.DB.QueryRow(stmt, edgeID) if err := row.Err(); err != nil { t.Fatal(err) } var got struct { Status string Details string UpdatedAt time.Time } err := row.Scan(&got.Status, &got.Details, &got.UpdatedAt) if err != nil { t.Fatal(err) } // Expected details (formatted using the same code as the controller) cond := obj.GetConditions()[0] var enum InfraStatus if cond.Status == metav1.ConditionTrue { enum = InfraStatusReady } else { enum = InfraStatusError } var details = fmt.Sprintf("%s: %s", cond.Reason, cond.Message) var when = cond.LastTransitionTime.Time if got.Status != string(enum) { t.Fatalf("Got infra_status %q and expected %q", got.Status, enum) } else if got.Details != details { t.Fatalf("Got infra_status_details %q and expected %q", got.Details, details) } else if !got.UpdatedAt.Equal(when) { t.Fatalf("Got infra_status_updated_at %q and expeceted %q", got.UpdatedAt, when) } t.Logf("successfully set InfraStatus=%q for %s", enum, obj.GetObjectKind().GroupVersionKind().Kind) } func testStoreClusterArtifacts(t *testing.T) { storeID := "dc8e59c3-6338-4c28-a776-f54e93a19ff4" artifacts, err := edb.GetClusterArtifactVersions(context.Background(), storeID) if err != nil { t.Fatal(err) } if len(artifacts) != 1 { t.Fatalf("got %d artifact for store and expected 1", len(artifacts)) } name := artifacts[0].Name version := artifacts[0].Version if name != "store" || version != "0.14.0-seed" { t.Fatalf("got %s:%s artifact for store and expected store:0.14.0-seed", name, version) } }