blob: 2590bc0f7906f4d77369f088a10c307f78c60cb6 [file]
package filepath_test
import (
"os"
path "path/filepath"
"testing"
"github.com/apache/cloudberry-go-libs/cluster"
"github.com/apache/cloudberry-go-libs/operating"
"github.com/apache/cloudberry-go-libs/testhelper"
. "github.com/apache/cloudberry-backup/filepath"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
func TestBackupFilepath(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Filepath Suite")
}
var _ = BeforeSuite(func() {
_, _, _ = testhelper.SetupTestLogger()
operating.System = operating.InitializeSystemFunctions()
})
var _ = Describe("filepath tests", func() {
coordinatorDir := "/data/gpseg-1"
standbyDir := "/data/gpseg_mirror-1"
segDirOne := "/data/gpseg0"
segDirTwo := "/data/gpseg1"
mirrorDirOne := "/data/gpseg_mirror0"
mirrorDirTwo := "/data/gpseg_mirror1"
var c *cluster.Cluster
BeforeEach(func() {
c = cluster.NewCluster([]cluster.SegConfig{
{ContentID: -1, DataDir: coordinatorDir},
})
})
Describe("Backup Filepath setup and accessors", func() {
It("returns content dir for a single-host, single-segment nodes", func() {
c = cluster.NewCluster([]cluster.SegConfig{
{ContentID: -1, DataDir: coordinatorDir},
{ContentID: 0, DataDir: segDirOne},
})
fpInfo := NewFilePathInfo(c, "", "20170101010101", "gpseg", false)
Expect(fpInfo.SegDirMap).To(HaveLen(2))
Expect(fpInfo.GetDirForContent(-1)).To(Equal("/data/gpseg-1/backups/20170101/20170101010101"))
Expect(fpInfo.GetDirForContent(0)).To(Equal("/data/gpseg0/backups/20170101/20170101010101"))
})
It("sets up the configuration for a single-host, multi-segment fpInfo", func() {
c = cluster.NewCluster([]cluster.SegConfig{
{ContentID: -1, DataDir: coordinatorDir},
{ContentID: 0, DataDir: segDirOne},
{ContentID: 1, DataDir: segDirTwo},
})
fpInfo := NewFilePathInfo(c, "", "20170101010101", "gpseg", false)
Expect(fpInfo.SegDirMap).To(HaveLen(3))
Expect(fpInfo.GetDirForContent(-1)).To(Equal("/data/gpseg-1/backups/20170101/20170101010101"))
Expect(fpInfo.GetDirForContent(0)).To(Equal("/data/gpseg0/backups/20170101/20170101010101"))
Expect(fpInfo.GetDirForContent(1)).To(Equal("/data/gpseg1/backups/20170101/20170101010101"))
})
It("sets up the configuration for a single-host, multi-segment fpInfo using primaries when the cluster has mirrors", func() {
c = cluster.NewCluster([]cluster.SegConfig{
{ContentID: -1, Role: "p", DataDir: coordinatorDir},
{ContentID: 0, Role: "p", DataDir: segDirOne},
{ContentID: 1, Role: "p", DataDir: segDirTwo},
{ContentID: 0, Role: "m", DataDir: mirrorDirOne},
{ContentID: 1, Role: "m", DataDir: mirrorDirTwo},
{ContentID: -1, Role: "m", DataDir: standbyDir},
})
fpInfo := NewFilePathInfo(c, "", "20170101010101", "gpseg", false)
Expect(fpInfo.SegDirMap).To(HaveLen(3))
Expect(fpInfo.GetDirForContent(-1)).To(Equal("/data/gpseg-1/backups/20170101/20170101010101"))
Expect(fpInfo.GetDirForContent(0)).To(Equal("/data/gpseg0/backups/20170101/20170101010101"))
Expect(fpInfo.GetDirForContent(1)).To(Equal("/data/gpseg1/backups/20170101/20170101010101"))
})
It("sets up the configuration for a single-host, multi-segment fpInfo using mirrors", func() {
c = cluster.NewCluster([]cluster.SegConfig{
{ContentID: -1, Role: "p", DataDir: coordinatorDir},
{ContentID: 0, Role: "p", DataDir: segDirOne},
{ContentID: 1, Role: "p", DataDir: segDirTwo},
{ContentID: 0, Role: "m", DataDir: mirrorDirOne},
{ContentID: 1, Role: "m", DataDir: mirrorDirTwo},
{ContentID: -1, Role: "m", DataDir: standbyDir},
})
fpInfo := NewFilePathInfo(c, "", "20170101010101", "gpseg", false, true)
Expect(fpInfo.SegDirMap).To(HaveLen(3))
Expect(fpInfo.GetDirForContent(-1)).To(Equal("/data/gpseg_mirror-1/backups/20170101/20170101010101"))
Expect(fpInfo.GetDirForContent(0)).To(Equal("/data/gpseg_mirror0/backups/20170101/20170101010101"))
Expect(fpInfo.GetDirForContent(1)).To(Equal("/data/gpseg_mirror1/backups/20170101/20170101010101"))
})
It("returns the content directory based on the user specified path", func() {
fpInfo := NewFilePathInfo(c, "/foo/bar", "20170101010101", "gpseg", false)
Expect(fpInfo.SegDirMap).To(HaveLen(1))
Expect(fpInfo.GetDirForContent(-1)).To(Equal("/foo/bar/gpseg-1/backups/20170101/20170101010101"))
})
})
Describe("GetTableBackupFilePathForCopyCommand()", func() {
It("returns table file path for copy command", func() {
fpInfo := NewFilePathInfo(c, "", "20170101010101", "gpseg", false)
Expect(fpInfo.GetTableBackupFilePathForCopyCommand(1234, "", false)).To(Equal("<SEG_DATA_DIR>/backups/20170101/20170101010101/gpbackup_<SEGID>_20170101010101_1234"))
})
It("returns table file path for copy command based on user specified path", func() {
fpInfo := NewFilePathInfo(c, "/foo/bar", "20170101010101", "gpseg", false)
Expect(fpInfo.GetTableBackupFilePathForCopyCommand(1234, "", false)).To(Equal("/foo/bar/gpseg<SEGID>/backups/20170101/20170101010101/gpbackup_<SEGID>_20170101010101_1234"))
})
It("returns table file path for copy command in single-file mode", func() {
fpInfo := NewFilePathInfo(c, "", "20170101010101", "gpseg", false)
Expect(fpInfo.GetTableBackupFilePathForCopyCommand(1234, "", true)).To(Equal("<SEG_DATA_DIR>/backups/20170101/20170101010101/gpbackup_<SEGID>_20170101010101"))
})
It("returns table file path for copy command based on user specified path in single-file mode", func() {
fpInfo := NewFilePathInfo(c, "/foo/bar", "20170101010101", "gpseg", false)
Expect(fpInfo.GetTableBackupFilePathForCopyCommand(1234, "", true)).To(Equal("/foo/bar/gpseg<SEGID>/backups/20170101/20170101010101/gpbackup_<SEGID>_20170101010101"))
})
It("returns table file path for copy command with extension", func() {
fpInfo := NewFilePathInfo(c, "", "20170101010101", "gpseg", false)
Expect(fpInfo.GetTableBackupFilePathForCopyCommand(1234, ".gzip", false)).To(Equal("<SEG_DATA_DIR>/backups/20170101/20170101010101/gpbackup_<SEGID>_20170101010101_1234.gzip"))
})
It("returns table file path for copy command based on user specified path with extension", func() {
fpInfo := NewFilePathInfo(c, "/foo/bar", "20170101010101", "gpseg", false)
Expect(fpInfo.GetTableBackupFilePathForCopyCommand(1234, ".gzip", false)).To(Equal("/foo/bar/gpseg<SEGID>/backups/20170101/20170101010101/gpbackup_<SEGID>_20170101010101_1234.gzip"))
})
It("returns table file path for copy command in single-file mode with extension", func() {
fpInfo := NewFilePathInfo(c, "", "20170101010101", "gpseg", false)
Expect(fpInfo.GetTableBackupFilePathForCopyCommand(1234, ".gzip", true)).To(Equal("<SEG_DATA_DIR>/backups/20170101/20170101010101/gpbackup_<SEGID>_20170101010101.gzip"))
})
It("returns table file path for copy command based on user specified path in single-file mode with extension", func() {
fpInfo := NewFilePathInfo(c, "/foo/bar", "20170101010101", "gpseg", false)
Expect(fpInfo.GetTableBackupFilePathForCopyCommand(1234, ".gzip", true)).To(Equal("/foo/bar/gpseg<SEGID>/backups/20170101/20170101010101/gpbackup_<SEGID>_20170101010101.gzip"))
})
})
Describe("GetReportFilePath", func() {
It("returns report file path", func() {
fpInfo := NewFilePathInfo(c, "", "20170101010101", "gpseg", false)
Expect(fpInfo.GetBackupReportFilePath()).To(Equal("/data/gpseg-1/backups/20170101/20170101010101/gpbackup_20170101010101_report"))
})
It("returns report file path based on user specified path", func() {
fpInfo := NewFilePathInfo(c, "/foo/bar", "20170101010101", "gpseg", false)
Expect(fpInfo.GetBackupReportFilePath()).To(Equal("/foo/bar/gpseg-1/backups/20170101/20170101010101/gpbackup_20170101010101_report"))
})
It("returns report file path for restore command", func() {
fpInfo := NewFilePathInfo(c, "", "20170101010101", "gpseg", false)
Expect(fpInfo.GetRestoreReportFilePath("20200101010101")).To(Equal("/data/gpseg-1/backups/20170101/20170101010101/gprestore_20170101010101_20200101010101_report"))
})
It("returns report file path based on user specified path for restore command", func() {
fpInfo := NewFilePathInfo(c, "/foo/bar", "20170101010101", "gpseg", false)
Expect(fpInfo.GetRestoreReportFilePath("20200101010101")).To(Equal("/foo/bar/gpseg-1/backups/20170101/20170101010101/gprestore_20170101010101_20200101010101_report"))
})
It("returns different report file paths based on user specified report path for backup and restore command", func() {
fpInfo := NewFilePathInfo(c, "/foo/bar", "20170101010101", "gpseg", false)
fpInfo.SingleBackupDir = true
fpInfo.UserSpecifiedReportDir = "/bar/foo"
Expect(fpInfo.GetBackupReportFilePath()).To(Equal("/foo/bar/gpseg-1/backups/20170101/20170101010101/gpbackup_20170101010101_report"))
Expect(fpInfo.GetRestoreReportFilePath("20200101010101")).To(Equal("/bar/foo/gprestore_20170101010101_20200101010101_report"))
fpInfo.SingleBackupDir = false
Expect(fpInfo.GetRestoreReportFilePath("20200101010101")).To(Equal("/bar/foo/gpseg-1/backups/20170101/20170101010101/gprestore_20170101010101_20200101010101_report"))
})
})
Describe("GetTableBackupFilePath", func() {
It("returns table file path", func() {
fpInfo := NewFilePathInfo(c, "", "20170101010101", "gpseg", false)
Expect(fpInfo.GetTableBackupFilePath(-1, 1234, "", false)).To(Equal("/data/gpseg-1/backups/20170101/20170101010101/gpbackup_-1_20170101010101_1234"))
})
It("returns table file path based on user specified path", func() {
fpInfo := NewFilePathInfo(c, "/foo/bar", "20170101010101", "gpseg", false)
Expect(fpInfo.GetTableBackupFilePath(-1, 1234, "", false)).To(Equal("/foo/bar/gpseg-1/backups/20170101/20170101010101/gpbackup_-1_20170101010101_1234"))
})
It("returns single data file path", func() {
fpInfo := NewFilePathInfo(c, "", "20170101010101", "gpseg", false)
Expect(fpInfo.GetTableBackupFilePath(-1, 1234, "", true)).To(Equal("/data/gpseg-1/backups/20170101/20170101010101/gpbackup_-1_20170101010101"))
})
It("returns single data file path based on user specified path", func() {
fpInfo := NewFilePathInfo(c, "/foo/bar", "20170101010101", "gpseg", false)
Expect(fpInfo.GetTableBackupFilePath(-1, 1234, "", true)).To(Equal("/foo/bar/gpseg-1/backups/20170101/20170101010101/gpbackup_-1_20170101010101"))
})
})
Describe("ParseSegPrefix", func() {
AfterEach(func() {
operating.System.Glob = path.Glob
})
It("returns segment prefix from directory path if coordinator backup directory exists", func() {
operating.System.Glob = func(pattern string) (matches []string, err error) {
return []string{"/tmp/foo/gpseg-1/backups"}, nil
}
res, _, err := ParseSegPrefix("/tmp/foo", "00000000000000")
Expect(err).ToNot(HaveOccurred())
Expect(res).To(Equal("gpseg"))
})
It("returns empty string if backup directory is empty", func() {
res, _, err := ParseSegPrefix("", "00000000000000")
Expect(err).ToNot(HaveOccurred())
Expect(res).To(Equal(""))
})
It("returns an error when coordinator backup directory does not exist", func() {
operating.System.Glob = func(pattern string) (matches []string, err error) { return []string{}, nil }
_, _, err := ParseSegPrefix("/tmp/foo", "00000000000000")
Expect(err.Error()).To(Equal("Backup directory in /tmp/foo missing"))
})
It("returns an error when there is an error accessing coordinator backup directory", func() {
operating.System.Glob = func(pattern string) (matches []string, err error) {
return []string{""}, os.ErrPermission
}
_, _, err := ParseSegPrefix("/tmp/foo", "00000000000000")
Expect(err.Error()).To(Equal("Failure while trying to locate backup directory in /tmp/foo. Error: permission denied"))
})
It("returns an error when multiple coordinator backup directories", func() {
operating.System.Glob = func(pattern string) (matches []string, err error) {
if pattern == "/tmp/foo/*-1/backups" {
return []string{"/tmp/foo/foo-1/backups", "/tmp/foo/foo-1/backups"}, nil
} else {
return []string{}, nil
}
}
_, _, err := ParseSegPrefix("/tmp/foo", "00000000000000")
Expect(err.Error()).To(Equal("Multiple backup directories in /tmp/foo"))
})
Describe("IsValidTimestamp", func() {
It("allows a valid timestamp", func() {
timestamp := "20170101010101"
isValid := IsValidTimestamp(timestamp)
Expect(isValid).To(BeTrue())
})
It("invalidates a non-numeric timestamp", func() {
timestamp := "2017ababababab"
isValid := IsValidTimestamp(timestamp)
Expect(isValid).To(BeFalse())
})
It("invalidates a timestamp that is too short", func() {
timestamp := "201701010101"
isValid := IsValidTimestamp(timestamp)
Expect(isValid).To(BeFalse())
})
It("invalidates a timestamp that is too long", func() {
timestamp := "2017010101010101"
isValid := IsValidTimestamp(timestamp)
Expect(isValid).To(BeFalse())
})
})
})
})