github.com/cloudfoundry/postgres-release/src/acceptance-tests@v0.0.0-20240511030151-872bdd2e0dba/testing/helpers/validator_test.go (about) 1 package helpers_test 2 3 import ( 4 "errors" 5 "fmt" 6 7 sqlmock "github.com/DATA-DOG/go-sqlmock" 8 "github.com/cloudfoundry/postgres-release/src/acceptance-tests/testing/helpers" 9 10 . "github.com/onsi/ginkgo/v2" 11 . "github.com/onsi/gomega" 12 ) 13 14 var _ = Describe("Validate deployment", func() { 15 var ( 16 validator helpers.Validator 17 mocks map[string]sqlmock.Sqlmock 18 ) 19 BeforeEach(func() { 20 manifestProps := helpers.Properties{ 21 Databases: helpers.PgProperties{ 22 Port: 5522, 23 Databases: []helpers.PgDBProperties{ 24 helpers.PgDBProperties{ 25 CITExt: true, 26 Name: "db1", 27 }, 28 }, 29 Roles: []helpers.PgRoleProperties{ 30 helpers.PgRoleProperties{ 31 Name: "pgadmin", 32 Password: "admin", 33 Permissions: []string{ 34 "NOSUPERUSER", 35 "CREATEDB", 36 "CREATEROLE", 37 "NOINHERIT", 38 "REPLICATION", 39 "CONNECTION LIMIT 20", 40 "VALID UNTIL 'May 5 12:00:00 2017 +1'", 41 }, 42 }, 43 }, 44 MaxConnections: 30, 45 LogLinePrefix: "xxx", 46 CollectStatementStats: true, 47 AdditionalConfig: helpers.PgAdditionalConfigMap{ 48 "max_wal_senders": 5, 49 "archive_timeout": "1800s", 50 }, 51 }, 52 } 53 postgresData := helpers.PGOutputData{ 54 Roles: map[string]helpers.PGRole{ 55 "vcap": helpers.PGRole{ 56 Name: "vcap", 57 }, 58 "pg_signal_backend": helpers.PGRole{ 59 Name: "pg_signal_backend", 60 }, 61 "pgadmin": helpers.PGRole{ 62 Name: "pgadmin", 63 Super: false, 64 Inherit: false, 65 CreateRole: true, 66 CreateDb: true, 67 CanLogin: true, 68 Replication: true, 69 ConnLimit: 20, 70 ValidUntil: "2017-05-05T11:00:00+00:00", 71 }, 72 }, 73 Databases: []helpers.PGDatabase{ 74 helpers.PGDatabase{ 75 Name: helpers.DefaultDB, 76 DBExts: []helpers.PGDatabaseExtensions{ 77 helpers.PGDatabaseExtensions{ 78 Name: "plpgsql", 79 }, 80 }, 81 }, 82 helpers.PGDatabase{ 83 Name: "db1", 84 DBExts: []helpers.PGDatabaseExtensions{ 85 helpers.PGDatabaseExtensions{ 86 Name: "pgcrypto", 87 }, 88 helpers.PGDatabaseExtensions{ 89 Name: "plpgsql", 90 }, 91 helpers.PGDatabaseExtensions{ 92 Name: "citext", 93 }, 94 helpers.PGDatabaseExtensions{ 95 Name: "pg_stat_statements", 96 }, 97 }, 98 Tables: []helpers.PGTable{}, 99 }, 100 }, 101 Settings: map[string]string{ 102 "log_line_prefix": "xxx", 103 "max_wal_senders": "5", 104 "archive_timeout": "1800s", 105 "port": "5522", 106 "other": "other", 107 "max_connections": "30", 108 }, 109 Version: helpers.PGVersion{Version: "PostgreSQL 9.4.9"}, 110 } 111 112 mocks = make(map[string]sqlmock.Sqlmock) 113 db, mock, err := sqlmock.New() 114 Expect(err).NotTo(HaveOccurred()) 115 mocks[helpers.DefaultDB] = mock 116 pg := helpers.PGData{ 117 Data: helpers.PGCommon{}, 118 DBs: []helpers.PGConn{ 119 helpers.PGConn{ 120 DB: db, 121 TargetDB: helpers.DefaultDB, 122 }, 123 }, 124 } 125 126 validator = helpers.Validator{ 127 ManifestProps: manifestProps, 128 PostgresData: postgresData, 129 PG: pg, 130 PostgreSQLVersion: "PostgreSQL 9.4.9", 131 } 132 }) 133 134 Describe("Validate a good deployment", func() { 135 Context("Validate all", func() { 136 It("Properly validates dbs", func() { 137 err := validator.ValidateDatabases() 138 Expect(err).NotTo(HaveOccurred()) 139 }) 140 It("Properly validates roles", func() { 141 input := "May 5 12:00:00 2017 +1" 142 expected := "2017-05-05T11:00:00+00:00" 143 err := mockDate(input, expected, mocks) 144 Expect(err).NotTo(HaveOccurred()) 145 err = validator.ValidateRoles() 146 Expect(err).NotTo(HaveOccurred()) 147 }) 148 It("Properly validates settings", func() { 149 err := validator.ValidateSettings() 150 Expect(err).NotTo(HaveOccurred()) 151 }) 152 It("Properly validates PostgreSQL version", func() { 153 err := validator.ValidatePostgreSQLVersion() 154 Expect(err).NotTo(HaveOccurred()) 155 }) 156 It("Properly validates all", func() { 157 input := "May 5 12:00:00 2017 +1" 158 expected := "2017-05-05T11:00:00+00:00" 159 err := mockDate(input, expected, mocks) 160 Expect(err).NotTo(HaveOccurred()) 161 err = validator.ValidateAll() 162 Expect(err).NotTo(HaveOccurred()) 163 }) 164 }) 165 }) 166 Describe("Validate a bad deployment", func() { 167 Context("Validate databases", func() { 168 It("Fails if DB missing", func() { 169 validator.ManifestProps.Databases.Databases = []helpers.PgDBProperties{ 170 helpers.PgDBProperties{ 171 CITExt: true, 172 Name: "db1", 173 }, 174 helpers.PgDBProperties{ 175 CITExt: true, 176 Name: "zz2", 177 }, 178 } 179 err := validator.ValidateDatabases() 180 Expect(err).To(MatchError(errors.New(fmt.Sprintf(helpers.MissingDatabaseValidationError, "zz2")))) 181 }) 182 It("Fails if DB extension missing", func() { 183 validator.PostgresData.Databases[1].DBExts = []helpers.PGDatabaseExtensions{} 184 err := validator.ValidateDatabases() 185 Expect(err).To(MatchError(errors.New(fmt.Sprintf(helpers.MissingExtensionValidationError, "pgcrypto", "db1")))) 186 }) 187 It("Fails if extra database present", func() { 188 validator.ManifestProps.Databases.Databases = []helpers.PgDBProperties{} 189 err := validator.ValidateDatabases() 190 Expect(err).To(MatchError(errors.New(fmt.Sprintf(helpers.ExtraDatabaseValidationError, "db1")))) 191 }) 192 It("Fails if extra extension present", func() { 193 validator.ManifestProps.Databases.Databases[0].CITExt = false 194 err := validator.ValidateDatabases() 195 Expect(err).To(MatchError(errors.New(fmt.Sprintf(helpers.ExtraExtensionValidationError, "citext", "db1")))) 196 }) 197 }) 198 Context("Validate PostgreSQL version", func() { 199 It("Fails if wrong PostgreSQL version", func() { 200 validator.PostgreSQLVersion = "wrong value" 201 err := validator.ValidatePostgreSQLVersion() 202 Expect(err).To(MatchError(errors.New(fmt.Sprintf(helpers.WrongPostreSQLVersionError, "PostgreSQL 9.4.9", "wrong value")))) 203 }) 204 }) 205 Context("Validate roles", func() { 206 It("Fails if role missing", func() { 207 validator.ManifestProps.Databases.Roles = []helpers.PgRoleProperties{ 208 helpers.PgRoleProperties{ 209 Name: "pgadmin2", 210 Password: "admin2", 211 }, 212 } 213 err := validator.ValidateRoles() 214 Expect(err).To(MatchError(errors.New(fmt.Sprintf(helpers.MissingRoleValidationError, "pgadmin2")))) 215 }) 216 It("Fails if incorrect role permission", func() { 217 validator.ManifestProps.Databases.Roles = []helpers.PgRoleProperties{ 218 helpers.PgRoleProperties{ 219 Name: "pgadmin", 220 Password: "admin", 221 Permissions: []string{ 222 "SUPERUSER", 223 "CREATEDB", 224 "CREATEROLE", 225 "NOINHERIT", 226 "REPLICATION", 227 "CONNECTION LIMIT 21", 228 "VALID UNTIL 'May 5 12:00:00 2017 +1'", 229 }, 230 }, 231 } 232 input := "May 5 12:00:00 2017 +1" 233 expected := "2017-05-05T11:00:00+00:00" 234 err := mockDate(input, expected, mocks) 235 Expect(err).NotTo(HaveOccurred()) 236 err = validator.ValidateRoles() 237 Expect(err).To(MatchError(errors.New(fmt.Sprintf(helpers.IncorrectRolePrmissionValidationError, "pgadmin")))) 238 }) 239 }) 240 Context("Validate settings", func() { 241 It("Fails if additional prop value is incorrect", func() { 242 validator.ManifestProps.Databases.AdditionalConfig["max_wal_senders"] = 10 243 err := validator.ValidateSettings() 244 Expect(err).To(MatchError(errors.New(fmt.Sprintf(helpers.IncorrectSettingValidationError, 10, 5, "max_wal_senders")))) 245 }) 246 It("Fails if additional prop value is missing", func() { 247 validator.ManifestProps.Databases.AdditionalConfig["some_prop"] = 10 248 err := validator.ValidateSettings() 249 Expect(err).To(MatchError(errors.New(fmt.Sprintf(helpers.MissingSettingValidationError, "some_prop")))) 250 }) 251 It("Fails if port is wrong", func() { 252 validator.ManifestProps.Databases.Port = 1111 253 err := validator.ValidateSettings() 254 Expect(err).To(MatchError(errors.New(fmt.Sprintf(helpers.IncorrectSettingValidationError, 1111, 5522, "port")))) 255 }) 256 It("Fails if max connextions setting is wrong", func() { 257 validator.ManifestProps.Databases.MaxConnections = 10 258 err := validator.ValidateSettings() 259 Expect(err).To(MatchError(errors.New(fmt.Sprintf(helpers.IncorrectSettingValidationError, 10, 30, "max_connections")))) 260 }) 261 It("Fails if log_line_prefix setting is wrong", func() { 262 validator.ManifestProps.Databases.LogLinePrefix = "yyy" 263 err := validator.ValidateSettings() 264 Expect(err).To(MatchError(errors.New(fmt.Sprintf(helpers.IncorrectSettingValidationError, "yyy", "xxx", "log_line_prefix")))) 265 }) 266 }) 267 }) 268 Describe("Check consistency after an upgrade", func() { 269 Context("Validate tables", func() { 270 var dataBefore helpers.PGOutputData 271 272 BeforeEach(func() { 273 dataBefore = helpers.PGOutputData{ 274 Roles: map[string]helpers.PGRole{}, 275 Databases: []helpers.PGDatabase{ 276 helpers.PGDatabase{ 277 Name: helpers.DefaultDB, 278 DBExts: []helpers.PGDatabaseExtensions{}, 279 Tables: []helpers.PGTable{}, 280 }, 281 helpers.PGDatabase{ 282 Name: "db1", 283 DBExts: []helpers.PGDatabaseExtensions{}, 284 Tables: []helpers.PGTable{ 285 helpers.PGTable{ 286 SchemaName: "myschema1", 287 TableName: "mytable1", 288 TableOwner: "myowner1", 289 TableColumns: []helpers.PGTableColumn{ 290 helpers.PGTableColumn{ 291 ColumnName: "column1", 292 DataType: "type1", 293 Position: 1, 294 }, 295 helpers.PGTableColumn{ 296 ColumnName: "column2", 297 DataType: "type2", 298 Position: 2, 299 }, 300 }, 301 TableRowsCount: helpers.PGCount{Num: 90}, 302 }, 303 helpers.PGTable{ 304 SchemaName: "myschema2", 305 TableName: "mytable2", 306 TableOwner: "myowner2", 307 TableColumns: []helpers.PGTableColumn{}, 308 TableRowsCount: helpers.PGCount{Num: 0}, 309 }, 310 }, 311 }, 312 }, 313 Settings: map[string]string{}, 314 } 315 validator.PostgresData = dataBefore 316 }) 317 It("Reports tables equals", func() { 318 dataAfter, err := dataBefore.CopyData() 319 Expect(err).NotTo(HaveOccurred()) 320 Expect(validator.CompareTablesTo(dataAfter)).To(BeTrue()) 321 }) 322 It("Reports tables equal if tables order differs", func() { 323 dataAfter, err := dataBefore.CopyData() 324 Expect(err).NotTo(HaveOccurred()) 325 dataAfter.Databases[1].Tables[0] = dataBefore.Databases[1].Tables[1] 326 dataAfter.Databases[1].Tables[1] = dataBefore.Databases[1].Tables[0] 327 328 Expect(validator.CompareTablesTo(dataAfter)).To(BeTrue()) 329 }) 330 It("Reports tables equal if tables columns order differs", func() { 331 dataAfter, err := dataBefore.CopyData() 332 Expect(err).NotTo(HaveOccurred()) 333 dataAfter.Databases[1].Tables[0].TableColumns[0] = dataBefore.Databases[1].Tables[0].TableColumns[1] 334 dataAfter.Databases[1].Tables[0].TableColumns[1] = dataBefore.Databases[1].Tables[0].TableColumns[0] 335 336 Expect(validator.CompareTablesTo(dataAfter)).To(BeTrue()) 337 }) 338 It("Reports table different if table missing", func() { 339 dataAfter, err := dataBefore.CopyData() 340 Expect(err).NotTo(HaveOccurred()) 341 dataAfter.Databases[1].Tables = []helpers.PGTable{ 342 helpers.PGTable{ 343 SchemaName: "myschema2", 344 TableName: "mytable2", 345 TableOwner: "myowner2", 346 TableColumns: []helpers.PGTableColumn{ 347 helpers.PGTableColumn{ 348 ColumnName: "column1", 349 DataType: "type1", 350 Position: 1, 351 }, 352 }, 353 TableRowsCount: helpers.PGCount{Num: 0}, 354 }, 355 } 356 Expect(validator.CompareTablesTo(dataAfter)).To(BeFalse()) 357 }) 358 359 }) 360 }) 361 })