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  })