github.com/cloudberrydb/gpbackup@v1.0.3-0.20240118031043-5410fd45eed6/utils/gpexpand_sensor_test.go (about) 1 package utils_test 2 3 import ( 4 "path/filepath" 5 "regexp" 6 7 "github.com/DATA-DOG/go-sqlmock" 8 "github.com/blang/vfs" 9 "github.com/blang/vfs/memfs" 10 "github.com/cloudberrydb/gp-common-go-libs/testhelper" 11 "github.com/cloudberrydb/gpbackup/utils" 12 "github.com/pkg/errors" 13 14 . "github.com/onsi/ginkgo/v2" 15 . "github.com/onsi/gomega" 16 ) 17 18 var _ = Describe("gpexpand_sensor", func() { 19 const sampleCoordinatorDataDir = "/my_fake_database/demoDataDir-1" 20 var ( 21 memoryfs vfs.Filesystem 22 mddPathRow *sqlmock.Rows 23 tableExistsRow *sqlmock.Rows 24 ) 25 26 BeforeEach(func() { 27 memoryfs = memfs.Create() 28 mddPathRow = sqlmock.NewRows([]string{"datadir"}).AddRow(sampleCoordinatorDataDir) 29 tableExistsRow = sqlmock.NewRows([]string{"relname"}).AddRow("some table name") 30 connectionPool.DBName = "postgres" 31 }) 32 Context("IsGpexpandRunning", func() { 33 Describe("happy path", func() { 34 It("senses when gpexpand is in phase 1, as determined by existence of a file 'gpexpand.status' in coordinator data directory", func() { 35 mock.ExpectQuery(utils.CoordinatorDataDirQuery).WillReturnRows(mddPathRow) 36 Expect(vfs.MkdirAll(memoryfs, sampleCoordinatorDataDir, 0755)).To(Succeed()) 37 path := filepath.Join(sampleCoordinatorDataDir, utils.GpexpandStatusFilename) 38 Expect(vfs.WriteFile(memoryfs, path, []byte{0}, 0400)).To(Succeed()) 39 gpexpandSensor := utils.NewGpexpandSensor(memoryfs, connectionPool) 40 41 result, err := gpexpandSensor.IsGpexpandRunning() 42 43 Expect(err).ToNot(HaveOccurred()) 44 Expect(result).To(BeTrue()) 45 }) 46 It("senses gpexpand is in phase 2, as determined by database query to postgres database for gpexpand's temporary table", func() { 47 mock.ExpectQuery(utils.CoordinatorDataDirQuery).WillReturnRows(mddPathRow) 48 49 mock.ExpectQuery(regexp.QuoteMeta(utils.GpexpandStatusTableExistsQuery)).WillReturnRows(tableExistsRow) 50 hasGpexpandPhase2StatusRow := sqlmock.NewRows([]string{"status"}).AddRow("some gpexpand status that is not finished") 51 mock.ExpectQuery(utils.GpexpandTemporaryTableStatusQuery).WillReturnRows(hasGpexpandPhase2StatusRow) 52 gpexpandSensor := utils.NewGpexpandSensor(memoryfs, connectionPool) 53 54 result, err := gpexpandSensor.IsGpexpandRunning() 55 56 Expect(err).ToNot(HaveOccurred()) 57 Expect(result).To(BeTrue()) 58 }) 59 It("senses when all indications are that gpexpand status does not exist", func() { 60 mock.ExpectQuery(utils.CoordinatorDataDirQuery).WillReturnRows(mddPathRow) 61 tableDoesNotExistsRow := sqlmock.NewRows([]string{"relname"}).AddRow("") 62 63 mock.ExpectQuery(regexp.QuoteMeta(utils.GpexpandStatusTableExistsQuery)).WillReturnRows(tableDoesNotExistsRow) 64 gpexpandSensor := utils.NewGpexpandSensor(memoryfs, connectionPool) 65 66 result, err := gpexpandSensor.IsGpexpandRunning() 67 68 Expect(err).ToNot(HaveOccurred()) 69 Expect(result).To(BeFalse()) 70 }) 71 It("senses when gpexpand status indicates stoppage", func() { 72 mock.ExpectQuery(utils.CoordinatorDataDirQuery).WillReturnRows(mddPathRow) 73 mock.ExpectQuery(regexp.QuoteMeta(utils.GpexpandStatusTableExistsQuery)).WillReturnRows(tableExistsRow) 74 finishedGpexpandPhase2StatusRow := sqlmock.NewRows([]string{"status"}).AddRow("EXPANSION STOPPED") 75 mock.ExpectQuery(utils.GpexpandTemporaryTableStatusQuery).WillReturnRows(finishedGpexpandPhase2StatusRow) 76 gpexpandSensor := utils.NewGpexpandSensor(memoryfs, connectionPool) 77 78 result, err := gpexpandSensor.IsGpexpandRunning() 79 80 Expect(err).ToNot(HaveOccurred()) 81 Expect(result).To(BeFalse()) 82 }) 83 It("senses when gpexpand status indicates completion", func() { 84 mock.ExpectQuery(utils.CoordinatorDataDirQuery).WillReturnRows(mddPathRow) 85 mock.ExpectQuery(regexp.QuoteMeta(utils.GpexpandStatusTableExistsQuery)).WillReturnRows(tableExistsRow) 86 finishedGpexpandPhase2StatusRow := sqlmock.NewRows([]string{"status"}).AddRow("EXPANSION COMPLETE") 87 mock.ExpectQuery(utils.GpexpandTemporaryTableStatusQuery).WillReturnRows(finishedGpexpandPhase2StatusRow) 88 gpexpandSensor := utils.NewGpexpandSensor(memoryfs, connectionPool) 89 90 result, err := gpexpandSensor.IsGpexpandRunning() 91 92 Expect(err).ToNot(HaveOccurred()) 93 Expect(result).To(BeFalse()) 94 }) 95 It("senses when gpexpand status indicates completion", func() { 96 mock.ExpectQuery(utils.CoordinatorDataDirQuery).WillReturnRows(mddPathRow) 97 mock.ExpectQuery(regexp.QuoteMeta(utils.GpexpandStatusTableExistsQuery)).WillReturnRows(tableExistsRow) 98 finishedGpexpandPhase2StatusRow := sqlmock.NewRows([]string{"status"}).AddRow("SETUP DONE") 99 mock.ExpectQuery(utils.GpexpandTemporaryTableStatusQuery).WillReturnRows(finishedGpexpandPhase2StatusRow) 100 gpexpandSensor := utils.NewGpexpandSensor(memoryfs, connectionPool) 101 102 result, err := gpexpandSensor.IsGpexpandRunning() 103 104 Expect(err).ToNot(HaveOccurred()) 105 Expect(result).To(BeFalse()) 106 }) 107 }) 108 Describe("sad paths", func() { 109 It("returns an error when MDD query fails", func() { 110 mock.ExpectQuery(utils.CoordinatorDataDirQuery).WillReturnError(errors.New("query error")) 111 gpexpandSensor := utils.NewGpexpandSensor(memoryfs, connectionPool) 112 113 _, err := gpexpandSensor.IsGpexpandRunning() 114 115 Expect(err).To(HaveOccurred()) 116 Expect(err.Error()).To(Equal("query error")) 117 }) 118 It("returns an error when Stat for file fails for a reason besides 'does not exist'", func() { 119 mock.ExpectQuery(utils.CoordinatorDataDirQuery).WillReturnRows(mddPathRow) 120 gpexpandSensor := utils.NewGpexpandSensor(vfs.Dummy(errors.New("fs error")), connectionPool) 121 122 _, err := gpexpandSensor.IsGpexpandRunning() 123 124 Expect(err).To(HaveOccurred()) 125 Expect(err.Error()).To(Equal("fs error")) 126 }) 127 It("returns an error when supplied with a connection to a database != postgres", func() { 128 connectionPool.DBName = "notThePostgresDatabase" 129 gpexpandSensor := utils.NewGpexpandSensor(memoryfs, connectionPool) 130 131 _, err := gpexpandSensor.IsGpexpandRunning() 132 133 Expect(err).To(HaveOccurred()) 134 Expect(err.Error()).To(Equal("gpexpand sensor requires a connection to the postgres database")) 135 }) 136 It("returns an error when supplied with Greenplum version < 6", func() { 137 Skip("Test is not applicable to cloudberry 1.0+") 138 testhelper.SetDBVersion(connectionPool, "5.3.0") 139 gpexpandSensor := utils.NewGpexpandSensor(memoryfs, connectionPool) 140 141 _, err := gpexpandSensor.IsGpexpandRunning() 142 143 Expect(err).To(HaveOccurred()) 144 Expect(err.Error()).To(Equal("gpexpand sensor requires a connection to Greenplum version >= 6")) 145 }) 146 }) 147 }) 148 })