From ff9138f9fc42a1f1fca14ffc7dfa7e4dbbae4583 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Thu, 4 Jun 2026 10:58:27 +0200 Subject: [PATCH] testserver: materialize postgres project status defaults A cloud run of the postgres_projects/purge_on_delete acceptance test (added in #5414) showed that the backend materializes default_endpoint_settings (1/1/86400s) and history_retention_duration (604800s) in the project status even when the spec omits them. The local testserver left these empty, diverging from cloud. PostgresProjectCreate now fills in these backend defaults when the spec doesn't provide them, with any spec-provided values overriding field-by-field. Co-authored-by: Isaac --- .../purge_on_delete/output.txt | 12 +++++++ libs/testserver/postgres.go | 36 ++++++++++++++++--- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/acceptance/bundle/resources/postgres_projects/purge_on_delete/output.txt b/acceptance/bundle/resources/postgres_projects/purge_on_delete/output.txt index ca49f906b6..60d3e4f7aa 100644 --- a/acceptance/bundle/resources/postgres_projects/purge_on_delete/output.txt +++ b/acceptance/bundle/resources/postgres_projects/purge_on_delete/output.txt @@ -20,8 +20,14 @@ Deployment complete! "status": { "branch_logical_size_limit_bytes": [NUMID], "default_branch": "projects/test-pg-proj-hard-[UNIQUE_NAME]/branches/production", + "default_endpoint_settings": { + "autoscaling_limit_max_cu": 1, + "autoscaling_limit_min_cu": 1, + "suspend_timeout_duration": "86400s" + }, "display_name": "purge_on_delete = true", "enable_pg_native_login": false, + "history_retention_duration": "604800s", "owner": "[USERNAME]", "pg_version": 16, "project_id": "test-pg-proj-hard-[UNIQUE_NAME]", @@ -36,8 +42,14 @@ Deployment complete! "status": { "branch_logical_size_limit_bytes": [NUMID], "default_branch": "projects/test-pg-proj-soft-[UNIQUE_NAME]/branches/production", + "default_endpoint_settings": { + "autoscaling_limit_max_cu": 1, + "autoscaling_limit_min_cu": 1, + "suspend_timeout_duration": "86400s" + }, "display_name": "purge_on_delete unset (soft delete)", "enable_pg_native_login": false, + "history_retention_duration": "604800s", "owner": "[USERNAME]", "pg_version": 16, "project_id": "test-pg-proj-soft-[UNIQUE_NAME]", diff --git a/libs/testserver/postgres.go b/libs/testserver/postgres.go index 4f7c4c4564..5853132ba5 100644 --- a/libs/testserver/postgres.go +++ b/libs/testserver/postgres.go @@ -15,6 +15,15 @@ func nowTime() *sdktime.Time { return sdktime.New(time.Now().UTC()) } +// Backend defaults applied to a project's status when the spec omits them. +// These mirror the values the real API materializes on create. +const ( + defaultHistoryRetention = 604800 * time.Second // 7 days + defaultSuspendTimeout = 86400 * time.Second // 1 day + defaultAutoscalingLimitMinCu = 1 + defaultAutoscalingLimitMaxCu = 1 +) + // postgresErrorResponse creates an error response with error code for postgres API. func postgresErrorResponse(statusCode int, errorCode, message string) Response { return Response{ @@ -103,23 +112,40 @@ func (s *FakeWorkspace) PostgresProjectCreate(req Request, projectID string) Res // Copy spec fields to status (API returns status as materialized view) if project.Spec != nil { + // The backend materializes a default retention when the spec omits it. + historyRetention := project.Spec.HistoryRetentionDuration + if historyRetention == nil { + historyRetention = duration.New(defaultHistoryRetention) + } + project.Status = &postgres.ProjectStatus{ ProjectId: projectID, DefaultBranch: name + "/branches/production", DisplayName: project.Spec.DisplayName, PgVersion: project.Spec.PgVersion, - HistoryRetentionDuration: project.Spec.HistoryRetentionDuration, + HistoryRetentionDuration: historyRetention, EnablePgNativeLogin: false, Owner: TestUser.UserName, BranchLogicalSizeLimitBytes: 8796093022208, // 8 TB (real API default) SyntheticStorageSizeBytes: 0, ForceSendFields: []string{"EnablePgNativeLogin", "SyntheticStorageSizeBytes"}, } + + // The backend materializes default endpoint settings when the spec omits them. + project.Status.DefaultEndpointSettings = &postgres.ProjectDefaultEndpointSettings{ + AutoscalingLimitMinCu: defaultAutoscalingLimitMinCu, + AutoscalingLimitMaxCu: defaultAutoscalingLimitMaxCu, + SuspendTimeoutDuration: duration.New(defaultSuspendTimeout), + } if project.Spec.DefaultEndpointSettings != nil { - project.Status.DefaultEndpointSettings = &postgres.ProjectDefaultEndpointSettings{ - AutoscalingLimitMinCu: project.Spec.DefaultEndpointSettings.AutoscalingLimitMinCu, - AutoscalingLimitMaxCu: project.Spec.DefaultEndpointSettings.AutoscalingLimitMaxCu, - SuspendTimeoutDuration: project.Spec.DefaultEndpointSettings.SuspendTimeoutDuration, + if project.Spec.DefaultEndpointSettings.AutoscalingLimitMinCu != 0 { + project.Status.DefaultEndpointSettings.AutoscalingLimitMinCu = project.Spec.DefaultEndpointSettings.AutoscalingLimitMinCu + } + if project.Spec.DefaultEndpointSettings.AutoscalingLimitMaxCu != 0 { + project.Status.DefaultEndpointSettings.AutoscalingLimitMaxCu = project.Spec.DefaultEndpointSettings.AutoscalingLimitMaxCu + } + if project.Spec.DefaultEndpointSettings.SuspendTimeoutDuration != nil { + project.Status.DefaultEndpointSettings.SuspendTimeoutDuration = project.Spec.DefaultEndpointSettings.SuspendTimeoutDuration } } // Clear spec so it's not returned in response (API only returns status)