github.com/cloudfoundry/postgres-release/src/acceptance-tests@v0.0.0-20240511030151-872bdd2e0dba/testing/helpers/postgres_test.go (about)

     1  package helpers_test
     2  
     3  import (
     4  	"database/sql"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"strings"
     9  
    10  	sqlmock "github.com/DATA-DOG/go-sqlmock"
    11  	"github.com/cloudfoundry/postgres-release/src/acceptance-tests/testing/helpers"
    12  
    13  	. "github.com/onsi/ginkgo/v2"
    14  	. "github.com/onsi/gomega"
    15  )
    16  
    17  var expectedcolumns = []string{"row_to_json"}
    18  var genericError = fmt.Errorf("some error")
    19  
    20  func convertQuery(query string) string {
    21  	//return helpers.GetFormattedQuery(query)
    22  	result := strings.Replace(helpers.GetFormattedQuery(query), ")", "\\)", -1)
    23  	result = strings.Replace(result, "(", "\\(", -1)
    24  	result = strings.Replace(result, ":", "\\:", -1)
    25  	result = strings.Replace(result, "+", "\\+", -1)
    26  	result = strings.Replace(result, "'", "\\'", -1)
    27  	return strings.Replace(result, "*", "(.+)", -1)
    28  }
    29  
    30  func mockSettings(expected map[string]string, mocks map[string]sqlmock.Sqlmock) {
    31  	if expected == nil {
    32  		mocks[helpers.DefaultDB].ExpectQuery(convertQuery(helpers.GetSettingsQuery)).WillReturnError(genericError)
    33  	} else {
    34  		rows := sqlmock.NewRows(expectedcolumns)
    35  		for key, value := range expected {
    36  			ff := "{\"name\": \"%s\", \"setting\": \"%s\", \"some1\": \"%s\",\"vartype\": \"%s\"}"
    37  			row := fmt.Sprintf(ff, key, value, "some0", "string")
    38  			rows = rows.AddRow(row)
    39  		}
    40  		mocks[helpers.DefaultDB].ExpectQuery(convertQuery(helpers.GetSettingsQuery)).WillReturnRows(rows)
    41  	}
    42  }
    43  
    44  func mockDatabases(expected []helpers.PGDatabase, mocks map[string]sqlmock.Sqlmock) {
    45  	if expected == nil {
    46  		mocks["dbsuper"].ExpectQuery(convertQuery(helpers.ListDatabasesQuery)).WillReturnError(genericError)
    47  	} else {
    48  		rows := sqlmock.NewRows(expectedcolumns)
    49  		for _, elem := range expected {
    50  			ff := "{\"datname\": \"%s\"}"
    51  			row := fmt.Sprintf(ff, elem.Name)
    52  			rows = rows.AddRow(row)
    53  			extrows := sqlmock.NewRows(expectedcolumns)
    54  			for _, elem := range elem.DBExts {
    55  				xx := "{\"extname\": \"%s\"}"
    56  				extrow := fmt.Sprintf(xx, elem.Name)
    57  				extrows = extrows.AddRow(extrow)
    58  			}
    59  			mocks[elem.Name+"super"].ExpectQuery(convertQuery(helpers.ListDBExtensionsQuery)).WillReturnRows(extrows)
    60  			tableRows := sqlmock.NewRows(expectedcolumns)
    61  			for _, tElem := range elem.Tables {
    62  				xx := "{\"schemaname\": \"%s\", \"tablename\":\"%s\",\"tableowner\":\"%s\"}"
    63  				tableRow := fmt.Sprintf(xx, tElem.SchemaName, tElem.TableName, tElem.TableOwner)
    64  				tableRows = tableRows.AddRow(tableRow)
    65  			}
    66  			mocks[elem.Name+"super"].ExpectQuery(convertQuery(helpers.ListTablesQuery)).WillReturnRows(tableRows)
    67  			for _, tElem := range elem.Tables {
    68  				columnRows := sqlmock.NewRows(expectedcolumns)
    69  				for _, col := range tElem.TableColumns {
    70  					xx := "{\"column_name\": \"%s\", \"data_type\":\"%s\",\"ordinal_position\":%d}"
    71  					columnRow := fmt.Sprintf(xx, col.ColumnName, col.DataType, col.Position)
    72  					columnRows = columnRows.AddRow(columnRow)
    73  				}
    74  				mocks[elem.Name+"super"].ExpectQuery(convertQuery(fmt.Sprintf(helpers.ListTableColumnsQuery, tElem.SchemaName, tElem.TableName))).WillReturnRows(columnRows)
    75  				countRows := sqlmock.NewRows(expectedcolumns)
    76  				countRows = countRows.AddRow(fmt.Sprintf("{\"count\": %d}", tElem.TableRowsCount.Num))
    77  				mocks[elem.Name+"super"].ExpectQuery(convertQuery(fmt.Sprintf(helpers.CountTableRowsQuery, tElem.TableName))).WillReturnRows(countRows)
    78  			}
    79  		}
    80  		mocks["dbsuper"].ExpectQuery(convertQuery(helpers.ListDatabasesQuery)).WillReturnRows(rows)
    81  	}
    82  }
    83  func mockRoles(expected map[string]helpers.PGRole, mocks map[string]sqlmock.Sqlmock) error {
    84  	if expected == nil {
    85  		mocks[helpers.DefaultDB].ExpectQuery(convertQuery(helpers.ListRolesQuery)).WillReturnError(genericError)
    86  	} else {
    87  		rows := sqlmock.NewRows(expectedcolumns)
    88  		for _, elem := range expected {
    89  			row, err := json.Marshal(elem)
    90  			if err != nil {
    91  				return err
    92  			}
    93  			rows = rows.AddRow(row)
    94  		}
    95  		mocks[helpers.DefaultDB].ExpectQuery(convertQuery(helpers.ListRolesQuery)).WillReturnRows(rows)
    96  	}
    97  	return nil
    98  }
    99  func mockGetTable(expected map[string]helpers.PGTable, mocks map[string]sqlmock.Sqlmock, table_name string) error {
   100  	if expected == nil {
   101  		mocks["dbsuper"].ExpectQuery(convertQuery(fmt.Sprintf(helpers.GetTableQuery, table_name))).WillReturnError(genericError)
   102  	} else {
   103  		rows := sqlmock.NewRows(expectedcolumns)
   104  		for _, elem := range expected {
   105  			row, err := json.Marshal(elem)
   106  			if err != nil {
   107  				return err
   108  			}
   109  			rows = rows.AddRow(row)
   110  		}
   111  		mocks["dbsuper"].ExpectQuery(convertQuery(fmt.Sprintf(helpers.GetTableQuery, table_name))).WillReturnRows(rows)
   112  		fmt.Println(convertQuery(fmt.Sprintf(helpers.GetTableQuery, table_name)))
   113  	}
   114  	return nil
   115  }
   116  func mockGetRole(expected map[string]helpers.PGRole, mocks map[string]sqlmock.Sqlmock, role_name string) error {
   117  	if expected == nil {
   118  		mocks[helpers.DefaultDB].ExpectQuery(convertQuery(fmt.Sprintf(helpers.GetRoleQuery, role_name))).WillReturnError(genericError)
   119  	} else {
   120  		rows := sqlmock.NewRows(expectedcolumns)
   121  		for _, elem := range expected {
   122  			row, err := json.Marshal(elem)
   123  			if err != nil {
   124  				return err
   125  			}
   126  			rows = rows.AddRow(row)
   127  		}
   128  		mocks[helpers.DefaultDB].ExpectQuery(convertQuery(fmt.Sprintf(helpers.GetRoleQuery, role_name))).WillReturnRows(rows)
   129  	}
   130  	return nil
   131  }
   132  func mockDate(current string, expected string, mocks map[string]sqlmock.Sqlmock) error {
   133  	sqlCommand := convertQuery(fmt.Sprintf(helpers.ConvertToDateCommand, current))
   134  	if expected == "" {
   135  		mocks[helpers.DefaultDB].ExpectQuery(sqlCommand).WillReturnError(genericError)
   136  	} else {
   137  		row := fmt.Sprintf("{\"timestamptz\": \"%s\"}", expected)
   138  		rows := sqlmock.NewRows(expectedcolumns).AddRow(row)
   139  		mocks[helpers.DefaultDB].ExpectQuery(sqlCommand).WillReturnRows(rows)
   140  	}
   141  	return nil
   142  }
   143  func mockPostgreSQLVersion(expected helpers.PGVersion, mocks map[string]sqlmock.Sqlmock) error {
   144  	sqlCommand := convertQuery(helpers.GetPostgreSQLVersionQuery)
   145  	if expected.Version == "" {
   146  		mocks[helpers.DefaultDB].ExpectQuery(sqlCommand).WillReturnError(genericError)
   147  	} else {
   148  		row := fmt.Sprintf("{\"version\": \"%s\"}", expected.Version)
   149  		rows := sqlmock.NewRows(expectedcolumns).AddRow(row)
   150  		mocks[helpers.DefaultDB].ExpectQuery(sqlCommand).WillReturnRows(rows)
   151  	}
   152  	return nil
   153  }
   154  
   155  var _ = Describe("Postgres", func() {
   156  	Describe("Copy output data", func() {
   157  		Context("Validate that data is copied", func() {
   158  			var from helpers.PGOutputData
   159  
   160  			BeforeEach(func() {
   161  
   162  				from = helpers.PGOutputData{
   163  					Roles: map[string]helpers.PGRole{
   164  						"role1": helpers.PGRole{
   165  							Name: "role1",
   166  						},
   167  					},
   168  					Databases: []helpers.PGDatabase{
   169  						helpers.PGDatabase{
   170  							Name: "db1",
   171  							DBExts: []helpers.PGDatabaseExtensions{
   172  								helpers.PGDatabaseExtensions{
   173  									Name: "exta",
   174  								},
   175  							},
   176  							Tables: []helpers.PGTable{
   177  								helpers.PGTable{
   178  									SchemaName: "myschema1",
   179  									TableName:  "mytable1",
   180  									TableOwner: "myowner1",
   181  									TableColumns: []helpers.PGTableColumn{
   182  										helpers.PGTableColumn{
   183  											ColumnName: "column1",
   184  											DataType:   "type1",
   185  											Position:   1,
   186  										},
   187  									},
   188  									TableRowsCount: helpers.PGCount{Num: 90},
   189  								},
   190  							},
   191  						},
   192  					},
   193  					Settings: map[string]string{
   194  						"max_connections": "30",
   195  					},
   196  				}
   197  			})
   198  			It("Correctly copies roles", func() {
   199  				to, err := from.CopyData()
   200  				Expect(err).NotTo(HaveOccurred())
   201  				Expect(to).To(Equal(from))
   202  				r := to.Roles["role1"]
   203  				r.Name = "role2"
   204  				to.Roles["role1"] = r
   205  				Expect(to).NotTo(Equal(from))
   206  			})
   207  			It("Correctly copies settings", func() {
   208  				to, err := from.CopyData()
   209  				Expect(err).NotTo(HaveOccurred())
   210  				Expect(to).To(Equal(from))
   211  				to.Settings["max_connections"] = "xxx"
   212  				Expect(to).NotTo(Equal(from))
   213  			})
   214  			It("Correctly copies tables", func() {
   215  				to, err := from.CopyData()
   216  				Expect(err).NotTo(HaveOccurred())
   217  				Expect(to).To(Equal(from))
   218  				to.Databases[0].Tables[0].SchemaName = "xxxx"
   219  				Expect(to).NotTo(Equal(from))
   220  			})
   221  			It("Correctly copies columns", func() {
   222  				to, err := from.CopyData()
   223  				Expect(err).NotTo(HaveOccurred())
   224  				Expect(to).To(Equal(from))
   225  				to.Databases[0].Tables[0].TableColumns[0].ColumnName = "xxxx"
   226  				Expect(to).NotTo(Equal(from))
   227  			})
   228  		})
   229  	})
   230  	Describe("Validate common data", func() {
   231  		Context("Fail if common data is invalid", func() {
   232  			It("Fail if no address provided", func() {
   233  				props := helpers.PGCommon{
   234  					Port: 10,
   235  					DefUser: helpers.User{
   236  						Name:     "uu",
   237  						Password: "pp",
   238  					},
   239  				}
   240  				_, err := helpers.NewPostgres(props)
   241  				Expect(err).To(MatchError(errors.New(helpers.MissingDBAddressErr)))
   242  			})
   243  			It("Fail if no port provided", func() {
   244  				props := helpers.PGCommon{
   245  					Address: "bb.example.com",
   246  					DefUser: helpers.User{
   247  						Name:     "uu",
   248  						Password: "pp",
   249  					},
   250  				}
   251  				_, err := helpers.NewPostgres(props)
   252  				Expect(err).To(MatchError(errors.New(helpers.MissingDBPortErr)))
   253  			})
   254  			It("Fail if no default user provided", func() {
   255  				props := helpers.PGCommon{
   256  					Address: "bb.example.com",
   257  					Port:    10,
   258  					DefUser: helpers.User{
   259  						Password: "pp",
   260  					},
   261  				}
   262  				_, err := helpers.NewPostgres(props)
   263  				Expect(err).To(MatchError(errors.New(helpers.MissingDefaultUserErr)))
   264  			})
   265  			It("Fail if no default password provided", func() {
   266  				props := helpers.PGCommon{
   267  					Address: "bb.example.com",
   268  					Port:    10,
   269  					DefUser: helpers.User{
   270  						Name: "uu",
   271  					},
   272  				}
   273  				_, err := helpers.NewPostgres(props)
   274  				Expect(err).To(MatchError(errors.New(helpers.MissingDefaultPasswordErr)))
   275  			})
   276  			It("Fail if incorrect data provided", func() {
   277  				props := helpers.PGCommon{
   278  					Address: "bb.example.com",
   279  					Port:    10,
   280  					DefUser: helpers.User{
   281  						Name:     "uu",
   282  						Password: "pp",
   283  					},
   284  				}
   285  				pg, err := helpers.NewPostgres(props)
   286  				Expect(err).NotTo(HaveOccurred())
   287  				_, err = pg.GetDefaultConnection()
   288  				Expect(err).To(MatchError(ContainSubstring("no such host")))
   289  			})
   290  			It("Fail if getting super user connection and no super user provided", func() {
   291  				props := helpers.PGCommon{
   292  					Address: "bb.example.com",
   293  					Port:    10,
   294  					DefUser: helpers.User{
   295  						Name:     "uu",
   296  						Password: "pp",
   297  					},
   298  				}
   299  				pg, err := helpers.NewPostgres(props)
   300  				Expect(err).NotTo(HaveOccurred())
   301  				_, err = pg.GetSuperUserConnection()
   302  				Expect(err).To(MatchError(helpers.NoSuperUserProvidedErr))
   303  			})
   304  			It("Fail if incorrect sslmode provided", func() {
   305  				props := helpers.PGCommon{
   306  					Address: "xx",
   307  					SSLMode: "unknown",
   308  					Port:    10,
   309  					DefUser: helpers.User{
   310  						Name:     "uu",
   311  						Password: "pp",
   312  					},
   313  				}
   314  				_, err := helpers.NewPostgres(props)
   315  				Expect(err).To(MatchError(errors.New(helpers.IncorrectSSLModeErr)))
   316  			})
   317  		})
   318  	})
   319  	Describe("Validate SSL mode", func() {
   320  		var (
   321  			mocks map[string]sqlmock.Sqlmock
   322  			pg    *helpers.PGData
   323  		)
   324  		BeforeEach(func() {
   325  			mocks = make(map[string]sqlmock.Sqlmock)
   326  			db, mock, err := sqlmock.New()
   327  			Expect(err).NotTo(HaveOccurred())
   328  			mocks[helpers.DefaultDB] = mock
   329  			pg = &helpers.PGData{
   330  				Data: helpers.PGCommon{
   331  					SSLMode: "disable",
   332  				},
   333  				DBs: []helpers.PGConn{
   334  					helpers.PGConn{
   335  						DB:       db,
   336  						TargetDB: helpers.DefaultDB,
   337  					},
   338  				},
   339  			}
   340  		})
   341  		AfterEach(func() {
   342  			pg.CloseConnections()
   343  		})
   344  		Context("Changing SSL mode", func() {
   345  			It("Fails to change to an invalid ssl mode", func() {
   346  				err := pg.ChangeSSLMode("unknown", "")
   347  				Expect(err).To(MatchError(errors.New(helpers.IncorrectSSLModeErr)))
   348  			})
   349  			It("Correctly change to a valid ssl mode", func() {
   350  				err := pg.ChangeSSLMode("require", "")
   351  				Expect(err).NotTo(HaveOccurred())
   352  				Expect(pg.Data.SSLMode).To(Equal("require"))
   353  			})
   354  			It("Fails to change to stronger SSL modes if missing root cert", func() {
   355  				err := pg.ChangeSSLMode("verify-ca", "")
   356  				Expect(err).To(MatchError(errors.New(helpers.MissingSSLRootCertErr)))
   357  			})
   358  			It("Correctly change to SSL modes that require root cert", func() {
   359  				err := pg.ChangeSSLMode("verify-ca", "/somepath")
   360  				Expect(err).NotTo(HaveOccurred())
   361  				Expect(pg.Data.SSLMode).To(Equal("verify-ca"))
   362  			})
   363  			It("Correctly close connections when changing ssl mode", func() {
   364  				_, err := pg.GetDefaultConnection()
   365  				Expect(err).NotTo(HaveOccurred())
   366  				Expect(pg.DBs).NotTo(BeNil())
   367  				err = pg.ChangeSSLMode("verify-full", "/some-path")
   368  				Expect(err).NotTo(HaveOccurred())
   369  				Expect(pg.Data.SSLMode).To(Equal("verify-full"))
   370  				conns := 0
   371  				if pg.DBs != nil {
   372  					conns = len(pg.DBs)
   373  				}
   374  				Expect(conns).To(BeZero())
   375  			})
   376  		})
   377  	})
   378  	Describe("Run read-only queries", func() {
   379  		var (
   380  			mocks map[string]sqlmock.Sqlmock
   381  			pg    *helpers.PGData
   382  		)
   383  
   384  		BeforeEach(func() {
   385  			mocks = make(map[string]sqlmock.Sqlmock)
   386  			db, mock, err := sqlmock.New()
   387  			Expect(err).NotTo(HaveOccurred())
   388  			mocks[helpers.DefaultDB] = mock
   389  			db1, mock1, err := sqlmock.New()
   390  			Expect(err).NotTo(HaveOccurred())
   391  			mocks["db1"] = mock1
   392  			db2, mock2, err := sqlmock.New()
   393  			Expect(err).NotTo(HaveOccurred())
   394  			mocks["db2"] = mock2
   395  			dbsuper, mocksuper, err := sqlmock.New()
   396  			Expect(err).NotTo(HaveOccurred())
   397  			mocks["dbsuper"] = mocksuper
   398  			db1super, mock1super, err := sqlmock.New()
   399  			Expect(err).NotTo(HaveOccurred())
   400  			mocks["db1super"] = mock1super
   401  			db2super, mock2super, err := sqlmock.New()
   402  			Expect(err).NotTo(HaveOccurred())
   403  			mocks["db2super"] = mock2super
   404  			pg = &helpers.PGData{
   405  				Data: helpers.PGCommon{
   406  					DefUser: helpers.User{
   407  						Name:     "defUser",
   408  						Password: "defPassword",
   409  					},
   410  					AdminUser: helpers.User{
   411  						Name:     "superUser",
   412  						Password: "superPassword",
   413  					},
   414  				},
   415  				DBs: []helpers.PGConn{
   416  					helpers.PGConn{
   417  						DB:       db,
   418  						User:     "defUser",
   419  						TargetDB: helpers.DefaultDB,
   420  					},
   421  					helpers.PGConn{
   422  						DB:       db1,
   423  						User:     "defUser",
   424  						TargetDB: "db1",
   425  					},
   426  					helpers.PGConn{
   427  						DB:       db2,
   428  						User:     "defUser",
   429  						TargetDB: "db2",
   430  					},
   431  					helpers.PGConn{
   432  						DB:       dbsuper,
   433  						User:     "superUser",
   434  						TargetDB: helpers.DefaultDB,
   435  					},
   436  					helpers.PGConn{
   437  						DB:       db1super,
   438  						User:     "superUser",
   439  						TargetDB: "db1",
   440  					},
   441  					helpers.PGConn{
   442  						DB:       db2super,
   443  						User:     "superUser",
   444  						TargetDB: "db2",
   445  					},
   446  				},
   447  			}
   448  		})
   449  		AfterEach(func() {
   450  			pg.CloseConnections()
   451  		})
   452  		Context("Run a generic query", func() {
   453  			It("Returns all the lines", func() {
   454  				expected := []string{
   455  					"{\"name\": \"pgadmin1\", \"role\": \"admin\"}",
   456  					"{\"name\": \"pgadmin2\", \"role\": \"admin\"}",
   457  				}
   458  				rows := sqlmock.NewRows(expectedcolumns).
   459  					AddRow(expected[0]).
   460  					AddRow(expected[1])
   461  				query := "SELECT name,role FROM table"
   462  				mocks[helpers.DefaultDB].ExpectQuery(convertQuery(query)).WillReturnRows(rows)
   463  				conn, err := pg.GetDefaultConnection()
   464  				Expect(err).NotTo(HaveOccurred())
   465  				result, err := conn.Run(query)
   466  				Expect(err).NotTo(HaveOccurred())
   467  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   468  					Expect(err).NotTo(HaveOccurred())
   469  				}
   470  				Expect(result).To(Equal(expected))
   471  			})
   472  			It("Properly reports a failure", func() {
   473  				query := "SELECT name,role FROM table"
   474  				mocks[helpers.DefaultDB].ExpectQuery(convertQuery(query)).WillReturnError(genericError)
   475  				conn, err := pg.GetDefaultConnection()
   476  				Expect(err).NotTo(HaveOccurred())
   477  				_, err = conn.Run(query)
   478  				Expect(err).To(MatchError(genericError))
   479  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   480  					Expect(err).NotTo(HaveOccurred())
   481  				}
   482  			})
   483  		})
   484  		Context("Fail to retrieve env info", func() {
   485  			It("Fails to read postgresql version", func() {
   486  				mockPostgreSQLVersion(helpers.PGVersion{Version: ""}, mocks)
   487  				_, err := pg.GetPostgreSQLVersion()
   488  				Expect(err).To(MatchError(genericError))
   489  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   490  					Expect(err).NotTo(HaveOccurred())
   491  				}
   492  			})
   493  			It("Fails to read pg_settings", func() {
   494  				mockSettings(nil, mocks)
   495  				_, err := pg.ReadAllSettings()
   496  				Expect(err).To(MatchError(genericError))
   497  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   498  					Expect(err).NotTo(HaveOccurred())
   499  				}
   500  			})
   501  			It("Fails to list databases", func() {
   502  				mockDatabases(nil, mocks)
   503  				_, err := pg.ListDatabases()
   504  				Expect(err).To(MatchError(genericError))
   505  				if err = mocks["dbsuper"].ExpectationsWereMet(); err != nil {
   506  					Expect(err).NotTo(HaveOccurred())
   507  				}
   508  			})
   509  			It("Fails to list roles", func() {
   510  				err := mockRoles(nil, mocks)
   511  				Expect(err).NotTo(HaveOccurred())
   512  				_, err = pg.ListRoles()
   513  				Expect(err).To(MatchError(genericError))
   514  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   515  					Expect(err).NotTo(HaveOccurred())
   516  				}
   517  			})
   518  			It("Fails to convert date to postgres date", func() {
   519  				err := mockDate("xxx", "", mocks)
   520  				Expect(err).NotTo(HaveOccurred())
   521  				_, err = pg.ConvertToPostgresDate("xxx")
   522  				Expect(err).To(MatchError(genericError))
   523  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   524  					Expect(err).NotTo(HaveOccurred())
   525  				}
   526  			})
   527  			It("Fails to check that role exist", func() {
   528  				expected := map[string]helpers.PGRole{}
   529  				err := mockGetRole(expected, mocks, "role1")
   530  				Expect(err).NotTo(HaveOccurred())
   531  				result, err := pg.CheckRoleExist("role1")
   532  				Expect(err).NotTo(HaveOccurred())
   533  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   534  					Expect(err).NotTo(HaveOccurred())
   535  				}
   536  				Expect(result).To(BeFalse())
   537  			})
   538  			It("Fails to check that table exist", func() {
   539  				expected := map[string]helpers.PGTable{}
   540  				err := mockGetTable(expected, mocks, "table1")
   541  				Expect(err).NotTo(HaveOccurred())
   542  				result, err := pg.CheckTableExist("table1", helpers.DefaultDB)
   543  				Expect(err).NotTo(HaveOccurred())
   544  				if err = mocks["dbsuper"].ExpectationsWereMet(); err != nil {
   545  					Expect(err).NotTo(HaveOccurred())
   546  				}
   547  				Expect(result).To(BeFalse())
   548  			})
   549  		})
   550  		Context("Correctly retrieve env info", func() {
   551  			It("Correctly get postgresql version", func() {
   552  				version := "PostgreSQL 9.4.9"
   553  				mockPostgreSQLVersion(helpers.PGVersion{Version: version}, mocks)
   554  				result, err := pg.GetPostgreSQLVersion()
   555  				Expect(err).NotTo(HaveOccurred())
   556  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   557  					Expect(err).NotTo(HaveOccurred())
   558  				}
   559  				Expect(result.Version).To(Equal(version))
   560  			})
   561  			It("Correctly read pg_settings", func() {
   562  				expected := map[string]string{
   563  					"a1": "a2",
   564  					"b1": "b2",
   565  				}
   566  				mockSettings(expected, mocks)
   567  				result, err := pg.ReadAllSettings()
   568  				Expect(err).NotTo(HaveOccurred())
   569  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   570  					Expect(err).NotTo(HaveOccurred())
   571  				}
   572  				Expect(result).NotTo(BeZero())
   573  				Expect(result).To(Equal(expected))
   574  			})
   575  			It("Correctly lists databases without extensions", func() {
   576  				expected := []helpers.PGDatabase{
   577  					helpers.PGDatabase{
   578  						Name:   "db1",
   579  						DBExts: []helpers.PGDatabaseExtensions{},
   580  						Tables: []helpers.PGTable{},
   581  					},
   582  					helpers.PGDatabase{
   583  						Name:   "db2",
   584  						DBExts: []helpers.PGDatabaseExtensions{},
   585  						Tables: []helpers.PGTable{},
   586  					},
   587  				}
   588  				mockDatabases(expected, mocks)
   589  				result, err := pg.ListDatabases()
   590  				Expect(err).NotTo(HaveOccurred())
   591  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   592  					Expect(err).NotTo(HaveOccurred())
   593  				}
   594  				if err = mocks["db1"].ExpectationsWereMet(); err != nil {
   595  					Expect(err).NotTo(HaveOccurred())
   596  				}
   597  				if err = mocks["db2"].ExpectationsWereMet(); err != nil {
   598  					Expect(err).NotTo(HaveOccurred())
   599  				}
   600  				Expect(result).To(Equal(expected))
   601  			})
   602  			It("Correctly lists databases with extensions", func() {
   603  				expected := []helpers.PGDatabase{
   604  					helpers.PGDatabase{
   605  						Name: "db1",
   606  						DBExts: []helpers.PGDatabaseExtensions{
   607  							helpers.PGDatabaseExtensions{
   608  								Name: "exta",
   609  							},
   610  							helpers.PGDatabaseExtensions{
   611  								Name: "extb",
   612  							},
   613  						},
   614  						Tables: []helpers.PGTable{},
   615  					},
   616  				}
   617  				mockDatabases(expected, mocks)
   618  				result, err := pg.ListDatabases()
   619  				Expect(err).NotTo(HaveOccurred())
   620  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   621  					Expect(err).NotTo(HaveOccurred())
   622  				}
   623  				if err = mocks["db1"].ExpectationsWereMet(); err != nil {
   624  					Expect(err).NotTo(HaveOccurred())
   625  				}
   626  				Expect(result).To(Equal(expected))
   627  			})
   628  			It("Correctly lists databases with tables", func() {
   629  				expected := []helpers.PGDatabase{
   630  					helpers.PGDatabase{
   631  						Name:   "db1",
   632  						DBExts: []helpers.PGDatabaseExtensions{},
   633  						Tables: []helpers.PGTable{
   634  							helpers.PGTable{
   635  								SchemaName: "myschema1",
   636  								TableName:  "mytable1",
   637  								TableOwner: "myowner1",
   638  								TableColumns: []helpers.PGTableColumn{
   639  									helpers.PGTableColumn{
   640  										ColumnName: "column1",
   641  										DataType:   "type1",
   642  										Position:   1,
   643  									},
   644  									helpers.PGTableColumn{
   645  										ColumnName: "column2",
   646  										DataType:   "type2",
   647  										Position:   2,
   648  									},
   649  								},
   650  								TableRowsCount: helpers.PGCount{Num: 90},
   651  							},
   652  							helpers.PGTable{
   653  								SchemaName: "myschema2",
   654  								TableName:  "mytable2",
   655  								TableOwner: "myowner2",
   656  								TableColumns: []helpers.PGTableColumn{
   657  									helpers.PGTableColumn{
   658  										ColumnName: "column3",
   659  										DataType:   "type3",
   660  										Position:   0,
   661  									},
   662  								},
   663  								TableRowsCount: helpers.PGCount{Num: 0},
   664  							},
   665  						},
   666  					},
   667  				}
   668  				mockDatabases(expected, mocks)
   669  				result, err := pg.ListDatabases()
   670  				Expect(err).NotTo(HaveOccurred())
   671  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   672  					Expect(err).NotTo(HaveOccurred())
   673  				}
   674  				if err = mocks["db1"].ExpectationsWereMet(); err != nil {
   675  					Expect(err).NotTo(HaveOccurred())
   676  				}
   677  				Expect(result).To(Equal(expected))
   678  			})
   679  			It("Correctly lists roles with properties", func() {
   680  				expected := map[string]helpers.PGRole{
   681  					"role1": helpers.PGRole{
   682  						Name:        "role1",
   683  						Super:       true,
   684  						Inherit:     false,
   685  						CreateRole:  false,
   686  						CreateDb:    true,
   687  						CanLogin:    true,
   688  						Replication: false,
   689  						ConnLimit:   10,
   690  						ValidUntil:  "",
   691  					},
   692  					"role2": helpers.PGRole{
   693  						Name:        "role2",
   694  						Super:       false,
   695  						Inherit:     true,
   696  						CreateRole:  true,
   697  						CreateDb:    false,
   698  						CanLogin:    false,
   699  						Replication: true,
   700  						ConnLimit:   100,
   701  						ValidUntil:  "xxx",
   702  					},
   703  				}
   704  				err := mockRoles(expected, mocks)
   705  				Expect(err).NotTo(HaveOccurred())
   706  				result, err := pg.ListRoles()
   707  				Expect(err).NotTo(HaveOccurred())
   708  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   709  					Expect(err).NotTo(HaveOccurred())
   710  				}
   711  				Expect(result).To(Equal(expected))
   712  			})
   713  			It("Correctly checks that role exists", func() {
   714  				expected := map[string]helpers.PGRole{
   715  					"role1": helpers.PGRole{
   716  						Name: "role1",
   717  					},
   718  				}
   719  				err := mockGetRole(expected, mocks, "role1")
   720  				Expect(err).NotTo(HaveOccurred())
   721  				result, err := pg.CheckRoleExist("role1")
   722  				Expect(err).NotTo(HaveOccurred())
   723  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   724  					Expect(err).NotTo(HaveOccurred())
   725  				}
   726  				Expect(result).To(BeTrue())
   727  			})
   728  			It("Correctly checks that table exists", func() {
   729  				var table1 helpers.PGTable
   730  				table1.TableName = "table1"
   731  				expected := map[string]helpers.PGTable{
   732  					"table1": table1,
   733  				}
   734  				err := mockGetTable(expected, mocks, "table1")
   735  				Expect(err).NotTo(HaveOccurred())
   736  				result, err := pg.CheckTableExist("table1", helpers.DefaultDB)
   737  				Expect(err).NotTo(HaveOccurred())
   738  				if err = mocks["dbsuper"].ExpectationsWereMet(); err != nil {
   739  					Expect(err).NotTo(HaveOccurred())
   740  				}
   741  				Expect(result).To(BeTrue())
   742  			})
   743  			It("Correctly retrieves all postgres data", func() {
   744  				expected := helpers.PGOutputData{
   745  					Roles: map[string]helpers.PGRole{
   746  						"pgadmin": helpers.PGRole{
   747  							Name:      "pgadmin",
   748  							CanLogin:  true,
   749  							ConnLimit: 20,
   750  						},
   751  					},
   752  					Databases: []helpers.PGDatabase{
   753  						helpers.PGDatabase{
   754  							Name:   "db1",
   755  							DBExts: []helpers.PGDatabaseExtensions{},
   756  							Tables: []helpers.PGTable{},
   757  						},
   758  					},
   759  					Settings: map[string]string{
   760  						"max_connections": "30",
   761  					},
   762  					Version: helpers.PGVersion{
   763  						Version: "PostgreSQL 9.4.9",
   764  					},
   765  				}
   766  				mockSettings(expected.Settings, mocks)
   767  				mockDatabases(expected.Databases, mocks)
   768  				err := mockRoles(expected.Roles, mocks)
   769  				Expect(err).NotTo(HaveOccurred())
   770  				mockPostgreSQLVersion(expected.Version, mocks)
   771  				result, err := pg.GetData()
   772  				Expect(err).NotTo(HaveOccurred())
   773  				if err = mocks[helpers.DefaultDB].ExpectationsWereMet(); err != nil {
   774  					Expect(err).NotTo(HaveOccurred())
   775  				}
   776  				if err = mocks["db1"].ExpectationsWereMet(); err != nil {
   777  					Expect(err).NotTo(HaveOccurred())
   778  				}
   779  				Expect(result).NotTo(BeZero())
   780  				Expect(result).To(Equal(expected))
   781  			})
   782  			It("Correctly converts date to postgres date", func() {
   783  				input := "May 5 12:00:00 2017 +1"
   784  				expected := "2017-05-05 11:00:00"
   785  				err := mockDate(input, expected, mocks)
   786  				Expect(err).NotTo(HaveOccurred())
   787  				result, err := pg.ConvertToPostgresDate(input)
   788  				Expect(err).NotTo(HaveOccurred())
   789  				Expect(result).To(Equal(expected))
   790  			})
   791  			It("Correctly converts date with quotes to postgres date", func() {
   792  				input := "May 5 12:00:00 2017 +1"
   793  				inputQuotes := fmt.Sprintf("'%s'", input)
   794  				expected := "2017-05-05 11:00:00"
   795  				err := mockDate(input, expected, mocks)
   796  				Expect(err).NotTo(HaveOccurred())
   797  				result, err := pg.ConvertToPostgresDate(inputQuotes)
   798  				Expect(err).NotTo(HaveOccurred())
   799  				Expect(result).To(Equal(expected))
   800  			})
   801  		})
   802  	})
   803  	Describe("Load DB", func() {
   804  		var (
   805  			mock     sqlmock.Sqlmock
   806  			pg       *helpers.PGData
   807  			prepared string
   808  		)
   809  		Context("Load DB with a table", func() {
   810  
   811  			BeforeEach(func() {
   812  				var db *sql.DB
   813  				var err error
   814  				db, mock, err = sqlmock.New()
   815  				Expect(err).NotTo(HaveOccurred())
   816  				pg = &helpers.PGData{
   817  					Data: helpers.PGCommon{},
   818  					DBs: []helpers.PGConn{
   819  						helpers.PGConn{DB: db, TargetDB: "db1"},
   820  					},
   821  				}
   822  				prepared = `COPY "pgats_table_0" ("column0") FROM STDIN`
   823  				prepared = strings.Replace(prepared, ")", "\\)", -1)
   824  				prepared = strings.Replace(prepared, "(", "\\(", -1)
   825  			})
   826  			AfterEach(func() {
   827  				for _, conn := range pg.DBs {
   828  					conn.DB.Close()
   829  				}
   830  			})
   831  			It("Correctly create and drop the table", func() {
   832  				mock.ExpectExec("CREATE TABLE pgats_table_0").WillReturnResult(sqlmock.NewResult(1, 1))
   833  				mock.ExpectExec("CREATE INDEX pgats_table_0_index ON pgats_table_0 USING hash").WillReturnResult(sqlmock.NewResult(1, 1))
   834  				mock.ExpectBegin()
   835  				mock.ExpectPrepare(prepared)
   836  				mock.ExpectExec(prepared).WithArgs("short_string0").WillReturnResult(sqlmock.NewResult(1, 1))
   837  				mock.ExpectExec("").WillReturnResult(sqlmock.NewResult(1, 1))
   838  				mock.ExpectCommit()
   839  				mock.ExpectExec("DROP TABLE pgats_table_0").WillReturnResult(sqlmock.NewResult(1, 1))
   840  
   841  				err := pg.CreateAndPopulateTablesWithPrefix("db1", helpers.Test1Load, "pgats_table")
   842  				Expect(err).NotTo(HaveOccurred())
   843  				err = pg.DropTable("db1", "pgats_table_0")
   844  				Expect(err).NotTo(HaveOccurred())
   845  
   846  				Expect(mock.ExpectationsWereMet()).NotTo(HaveOccurred())
   847  			})
   848  			It("Fails to create the table", func() {
   849  				mock.ExpectExec("CREATE TABLE pgats_table_0").WillReturnError(genericError)
   850  
   851  				err := pg.CreateAndPopulateTables("db1", helpers.Test1Load)
   852  				Expect(err).To(MatchError(genericError))
   853  				Expect(mock.ExpectationsWereMet()).NotTo(HaveOccurred())
   854  			})
   855  			It("Fails to create the index", func() {
   856  				mock.ExpectExec("CREATE TABLE pgats_table_0").WillReturnResult(sqlmock.NewResult(1, 1))
   857  				mock.ExpectExec("CREATE INDEX pgats_table_0_index ON pgats_table_0 USING hash").WillReturnError(genericError)
   858  
   859  				err := pg.CreateAndPopulateTables("db1", helpers.Test1Load)
   860  				Expect(err).To(MatchError(genericError))
   861  				Expect(mock.ExpectationsWereMet()).NotTo(HaveOccurred())
   862  			})
   863  			It("Fails to begin the connection", func() {
   864  				mock.ExpectExec("CREATE TABLE pgats_table_0").WillReturnResult(sqlmock.NewResult(1, 1))
   865  				mock.ExpectExec("CREATE INDEX pgats_table_0_index ON pgats_table_0 USING hash").WillReturnResult(sqlmock.NewResult(1, 1))
   866  				mock.ExpectBegin().WillReturnError(genericError)
   867  
   868  				err := pg.CreateAndPopulateTables("db1", helpers.Test1Load)
   869  				Expect(err).To(MatchError(genericError))
   870  				Expect(mock.ExpectationsWereMet()).NotTo(HaveOccurred())
   871  			})
   872  			It("Fails to prepare the statement", func() {
   873  				mock.ExpectExec("CREATE TABLE pgats_table_0").WillReturnResult(sqlmock.NewResult(1, 1))
   874  				mock.ExpectExec("CREATE INDEX pgats_table_0_index ON pgats_table_0 USING hash").WillReturnResult(sqlmock.NewResult(1, 1))
   875  				mock.ExpectBegin()
   876  				mock.ExpectPrepare(prepared).WillReturnError(genericError)
   877  
   878  				err := pg.CreateAndPopulateTables("db1", helpers.Test1Load)
   879  				Expect(err).To(MatchError(genericError))
   880  				Expect(mock.ExpectationsWereMet()).NotTo(HaveOccurred())
   881  			})
   882  			It("Fails to populate row", func() {
   883  				mock.ExpectExec("CREATE TABLE pgats_table_0").WillReturnResult(sqlmock.NewResult(1, 1))
   884  				mock.ExpectExec("CREATE INDEX pgats_table_0_index ON pgats_table_0 USING hash").WillReturnResult(sqlmock.NewResult(1, 1))
   885  				mock.ExpectBegin()
   886  				mock.ExpectPrepare(prepared)
   887  				mock.ExpectExec(prepared).WithArgs("short_string0").WillReturnError(genericError)
   888  
   889  				err := pg.CreateAndPopulateTables("db1", helpers.Test1Load)
   890  				Expect(err).To(MatchError(genericError))
   891  				Expect(mock.ExpectationsWereMet()).NotTo(HaveOccurred())
   892  			})
   893  			It("Fails to flush buffered data", func() {
   894  				mock.ExpectExec("CREATE TABLE pgats_table_0").WillReturnResult(sqlmock.NewResult(1, 1))
   895  				mock.ExpectExec("CREATE INDEX pgats_table_0_index ON pgats_table_0 USING hash").WillReturnResult(sqlmock.NewResult(1, 1))
   896  				mock.ExpectBegin()
   897  				mock.ExpectPrepare(prepared)
   898  				mock.ExpectExec(prepared).WithArgs("short_string0").WillReturnResult(sqlmock.NewResult(1, 1))
   899  				mock.ExpectExec("").WillReturnError(genericError)
   900  
   901  				err := pg.CreateAndPopulateTables("db1", helpers.Test1Load)
   902  				Expect(err).To(MatchError(genericError))
   903  				Expect(mock.ExpectationsWereMet()).NotTo(HaveOccurred())
   904  			})
   905  			It("Fails to commit", func() {
   906  				mock.ExpectExec("CREATE TABLE pgats_table_0").WillReturnResult(sqlmock.NewResult(1, 1))
   907  				mock.ExpectExec("CREATE INDEX pgats_table_0_index ON pgats_table_0 USING hash").WillReturnResult(sqlmock.NewResult(1, 1))
   908  				mock.ExpectBegin()
   909  				mock.ExpectPrepare(prepared)
   910  				mock.ExpectExec(prepared).WithArgs("short_string0").WillReturnResult(sqlmock.NewResult(1, 1))
   911  				mock.ExpectExec("").WillReturnResult(sqlmock.NewResult(1, 1))
   912  				mock.ExpectCommit().WillReturnError(genericError)
   913  
   914  				err := pg.CreateAndPopulateTables("db1", helpers.Test1Load)
   915  				Expect(err).To(MatchError(genericError))
   916  				Expect(mock.ExpectationsWereMet()).NotTo(HaveOccurred())
   917  			})
   918  		})
   919  	})
   920  })