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