|
4 | 4 | "context" |
5 | 5 | "encoding/json" |
6 | 6 | "fmt" |
| 7 | + "strconv" |
7 | 8 | "testing" |
8 | 9 |
|
9 | 10 | "github.com/spf13/cobra" |
@@ -921,3 +922,286 @@ func TestBackupList(t *testing.T) { |
921 | 922 | assert.Equal(t, "backup-1", backups[0].Id) |
922 | 923 | assert.Equal(t, "backup-2", backups[1].Id) |
923 | 924 | } |
| 925 | + |
| 926 | +// Test PG major version validation logic |
| 927 | +func TestPGMajorVersionValidation(t *testing.T) { |
| 928 | + tests := []struct { |
| 929 | + name string |
| 930 | + version int |
| 931 | + expectError bool |
| 932 | + errorMsg string |
| 933 | + }{ |
| 934 | + { |
| 935 | + name: "valid version 16", |
| 936 | + version: 16, |
| 937 | + expectError: false, |
| 938 | + }, |
| 939 | + { |
| 940 | + name: "valid version 17", |
| 941 | + version: 17, |
| 942 | + expectError: false, |
| 943 | + }, |
| 944 | + { |
| 945 | + name: "invalid version 15", |
| 946 | + version: 15, |
| 947 | + expectError: true, |
| 948 | + errorMsg: "invalid Postgres major version: 15. Supported versions are 16 and 17", |
| 949 | + }, |
| 950 | + { |
| 951 | + name: "invalid version 18", |
| 952 | + version: 18, |
| 953 | + expectError: true, |
| 954 | + errorMsg: "invalid Postgres major version: 18. Supported versions are 16 and 17", |
| 955 | + }, |
| 956 | + { |
| 957 | + name: "invalid version 14", |
| 958 | + version: 14, |
| 959 | + expectError: true, |
| 960 | + errorMsg: "invalid Postgres major version: 14. Supported versions are 16 and 17", |
| 961 | + }, |
| 962 | + { |
| 963 | + name: "invalid version 0", |
| 964 | + version: 0, |
| 965 | + expectError: true, |
| 966 | + errorMsg: "invalid Postgres major version: 0. Supported versions are 16 and 17", |
| 967 | + }, |
| 968 | + } |
| 969 | + |
| 970 | + for _, tt := range tests { |
| 971 | + t.Run(tt.name, func(t *testing.T) { |
| 972 | + // Test the validation logic directly (matching lines 119-122 in create.go) |
| 973 | + if tt.version != 16 && tt.version != 17 { |
| 974 | + if !tt.expectError { |
| 975 | + t.Errorf("expected error for version %d", tt.version) |
| 976 | + return |
| 977 | + } |
| 978 | + err := fmt.Errorf("invalid Postgres major version: %d. Supported versions are 16 and 17", tt.version) |
| 979 | + if tt.errorMsg != "" && err.Error() != tt.errorMsg { |
| 980 | + t.Errorf("expected error message '%s', got '%s'", tt.errorMsg, err.Error()) |
| 981 | + } |
| 982 | + } else { |
| 983 | + if tt.expectError { |
| 984 | + t.Errorf("did not expect error for version %d", tt.version) |
| 985 | + } |
| 986 | + } |
| 987 | + }) |
| 988 | + } |
| 989 | +} |
| 990 | + |
| 991 | +// Test that PG major version is correctly passed to CreateClusterParams |
| 992 | +func TestCreateClusterParams_PGMajorVersion(t *testing.T) { |
| 993 | + tests := []struct { |
| 994 | + name string |
| 995 | + pgMajorVersion int |
| 996 | + expectedVersion int |
| 997 | + }{ |
| 998 | + { |
| 999 | + name: "version 16", |
| 1000 | + pgMajorVersion: 16, |
| 1001 | + expectedVersion: 16, |
| 1002 | + }, |
| 1003 | + { |
| 1004 | + name: "version 17", |
| 1005 | + pgMajorVersion: 17, |
| 1006 | + expectedVersion: 17, |
| 1007 | + }, |
| 1008 | + } |
| 1009 | + |
| 1010 | + for _, tt := range tests { |
| 1011 | + t.Run(tt.name, func(t *testing.T) { |
| 1012 | + params := &CreateClusterParams{ |
| 1013 | + Name: "test-db", |
| 1014 | + OrgSlug: "test-org", |
| 1015 | + Region: "ord", |
| 1016 | + Plan: "basic", |
| 1017 | + VolumeSizeGB: 10, |
| 1018 | + PostGISEnabled: false, |
| 1019 | + PGMajorVersion: tt.pgMajorVersion, |
| 1020 | + } |
| 1021 | + |
| 1022 | + assert.Equal(t, tt.expectedVersion, params.PGMajorVersion) |
| 1023 | + }) |
| 1024 | + } |
| 1025 | +} |
| 1026 | + |
| 1027 | +// Test that PG major version is correctly converted to string in CreateClusterInput |
| 1028 | +func TestCreateClusterInput_PGMajorVersion(t *testing.T) { |
| 1029 | + tests := []struct { |
| 1030 | + name string |
| 1031 | + pgMajorVersion int |
| 1032 | + expectedVersion string |
| 1033 | + }{ |
| 1034 | + { |
| 1035 | + name: "version 16 as string", |
| 1036 | + pgMajorVersion: 16, |
| 1037 | + expectedVersion: "16", |
| 1038 | + }, |
| 1039 | + { |
| 1040 | + name: "version 17 as string", |
| 1041 | + pgMajorVersion: 17, |
| 1042 | + expectedVersion: "17", |
| 1043 | + }, |
| 1044 | + } |
| 1045 | + |
| 1046 | + for _, tt := range tests { |
| 1047 | + t.Run(tt.name, func(t *testing.T) { |
| 1048 | + params := &CreateClusterParams{ |
| 1049 | + PGMajorVersion: tt.pgMajorVersion, |
| 1050 | + } |
| 1051 | + |
| 1052 | + // Simulate the conversion that happens in create.go line 224 |
| 1053 | + input := uiex.CreateClusterInput{ |
| 1054 | + PGMajorVersion: strconv.Itoa(params.PGMajorVersion), |
| 1055 | + } |
| 1056 | + |
| 1057 | + assert.Equal(t, tt.expectedVersion, input.PGMajorVersion) |
| 1058 | + }) |
| 1059 | + } |
| 1060 | +} |
| 1061 | + |
| 1062 | +// Test CreateCluster command with pg-major-version flag |
| 1063 | +func TestCreateCommand_WithPGMajorVersion(t *testing.T) { |
| 1064 | + tests := []struct { |
| 1065 | + name string |
| 1066 | + pgMajorVersion int |
| 1067 | + expectError bool |
| 1068 | + expectedVersion string |
| 1069 | + }{ |
| 1070 | + { |
| 1071 | + name: "default version 16", |
| 1072 | + pgMajorVersion: 16, |
| 1073 | + expectError: false, |
| 1074 | + expectedVersion: "16", |
| 1075 | + }, |
| 1076 | + { |
| 1077 | + name: "explicit version 16", |
| 1078 | + pgMajorVersion: 16, |
| 1079 | + expectError: false, |
| 1080 | + expectedVersion: "16", |
| 1081 | + }, |
| 1082 | + { |
| 1083 | + name: "version 17", |
| 1084 | + pgMajorVersion: 17, |
| 1085 | + expectError: false, |
| 1086 | + expectedVersion: "17", |
| 1087 | + }, |
| 1088 | + } |
| 1089 | + |
| 1090 | + for _, tt := range tests { |
| 1091 | + t.Run(tt.name, func(t *testing.T) { |
| 1092 | + ctx := setupTestContext() |
| 1093 | + |
| 1094 | + // Add pg-major-version flag to the flag set |
| 1095 | + flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError) |
| 1096 | + flagSet.Int("pg-major-version", tt.pgMajorVersion, "PG major version") |
| 1097 | + flagSet.String("name", "test-db", "Cluster name") |
| 1098 | + flagSet.String("region", "ord", "Region") |
| 1099 | + flagSet.String("plan", "basic", "Plan") |
| 1100 | + flagSet.Int("volume-size", 10, "Volume size") |
| 1101 | + flagSet.Bool("enable-postgis-support", false, "PostGIS") |
| 1102 | + ctx = flagctx.NewContext(ctx, flagSet) |
| 1103 | + |
| 1104 | + // Add macaroon tokens for MPG compatibility |
| 1105 | + macaroonTokens := tokens.Parse("fm1r_macaroon_token") |
| 1106 | + configWithMacaroonTokens := &config.Config{ |
| 1107 | + Tokens: macaroonTokens, |
| 1108 | + } |
| 1109 | + ctx = config.NewContext(ctx, configWithMacaroonTokens) |
| 1110 | + |
| 1111 | + mpgRegions := []uiex.MPGRegion{ |
| 1112 | + {Code: "ord", Available: true}, |
| 1113 | + } |
| 1114 | + |
| 1115 | + var capturedInput uiex.CreateClusterInput |
| 1116 | + mockUiex := &mock.UiexClient{ |
| 1117 | + ListMPGRegionsFunc: func(ctx context.Context, orgSlug string) (uiex.ListMPGRegionsResponse, error) { |
| 1118 | + return uiex.ListMPGRegionsResponse{ |
| 1119 | + Data: mpgRegions, |
| 1120 | + }, nil |
| 1121 | + }, |
| 1122 | + CreateClusterFunc: func(ctx context.Context, input uiex.CreateClusterInput) (uiex.CreateClusterResponse, error) { |
| 1123 | + capturedInput = input |
| 1124 | + return uiex.CreateClusterResponse{ |
| 1125 | + Data: struct { |
| 1126 | + Id string `json:"id"` |
| 1127 | + Name string `json:"name"` |
| 1128 | + Status *string `json:"status"` |
| 1129 | + Plan string `json:"plan"` |
| 1130 | + Environment *string `json:"environment"` |
| 1131 | + Region string `json:"region"` |
| 1132 | + Organization fly.Organization `json:"organization"` |
| 1133 | + Replicas int `json:"replicas"` |
| 1134 | + Disk int `json:"disk"` |
| 1135 | + IpAssignments uiex.ManagedClusterIpAssignments `json:"ip_assignments"` |
| 1136 | + PostGISEnabled bool `json:"postgis_enabled"` |
| 1137 | + }{ |
| 1138 | + Id: "test-cluster-123", |
| 1139 | + Name: "test-db", |
| 1140 | + Region: "ord", |
| 1141 | + Plan: "basic", |
| 1142 | + PostGISEnabled: false, |
| 1143 | + }, |
| 1144 | + }, nil |
| 1145 | + }, |
| 1146 | + GetManagedClusterByIdFunc: func(ctx context.Context, id string) (uiex.GetManagedClusterResponse, error) { |
| 1147 | + status := "ready" |
| 1148 | + return uiex.GetManagedClusterResponse{ |
| 1149 | + Data: uiex.ManagedCluster{ |
| 1150 | + Id: id, |
| 1151 | + Status: status, |
| 1152 | + }, |
| 1153 | + Credentials: uiex.GetManagedClusterCredentialsResponse{ |
| 1154 | + ConnectionUri: "postgresql://test", |
| 1155 | + }, |
| 1156 | + }, nil |
| 1157 | + }, |
| 1158 | + } |
| 1159 | + |
| 1160 | + ctx = uiexutil.NewContextWithClient(ctx, mockUiex) |
| 1161 | + |
| 1162 | + // Test the validation logic |
| 1163 | + pgMajorVersion := tt.pgMajorVersion |
| 1164 | + if pgMajorVersion != 16 && pgMajorVersion != 17 { |
| 1165 | + if !tt.expectError { |
| 1166 | + t.Errorf("expected error for version %d", pgMajorVersion) |
| 1167 | + } |
| 1168 | + return |
| 1169 | + } |
| 1170 | + |
| 1171 | + // Test that the version is correctly passed to CreateClusterInput |
| 1172 | + params := &CreateClusterParams{ |
| 1173 | + PGMajorVersion: pgMajorVersion, |
| 1174 | + } |
| 1175 | + |
| 1176 | + input := uiex.CreateClusterInput{ |
| 1177 | + PGMajorVersion: strconv.Itoa(params.PGMajorVersion), |
| 1178 | + } |
| 1179 | + |
| 1180 | + assert.Equal(t, tt.expectedVersion, input.PGMajorVersion, "PG major version should be correctly converted to string") |
| 1181 | + |
| 1182 | + // Verify the version would be passed correctly in actual CreateCluster call |
| 1183 | + _, err := mockUiex.CreateCluster(ctx, input) |
| 1184 | + if tt.expectError { |
| 1185 | + assert.Error(t, err) |
| 1186 | + } else { |
| 1187 | + require.NoError(t, err) |
| 1188 | + assert.Equal(t, tt.expectedVersion, capturedInput.PGMajorVersion, "PG major version should be correctly passed to CreateCluster") |
| 1189 | + } |
| 1190 | + }) |
| 1191 | + } |
| 1192 | +} |
| 1193 | + |
| 1194 | +// Test invalid PG major version error message |
| 1195 | +func TestInvalidPGMajorVersion_Error(t *testing.T) { |
| 1196 | + invalidVersions := []int{15, 18, 14, 13, 19, 0, -1} |
| 1197 | + |
| 1198 | + for _, version := range invalidVersions { |
| 1199 | + t.Run(fmt.Sprintf("version_%d", version), func(t *testing.T) { |
| 1200 | + err := fmt.Errorf("invalid Postgres major version: %d. Supported versions are 16 and 17", version) |
| 1201 | + assert.Error(t, err) |
| 1202 | + assert.Contains(t, err.Error(), "invalid Postgres major version") |
| 1203 | + assert.Contains(t, err.Error(), "Supported versions are 16 and 17") |
| 1204 | + assert.Contains(t, err.Error(), fmt.Sprintf("%d", version)) |
| 1205 | + }) |
| 1206 | + } |
| 1207 | +} |
0 commit comments