blob: dd42df5174fccf774f037474c99c0bb717453de5 [file]
package backup_test
import (
"fmt"
"github.com/apache/cloudberry-backup/backup"
"github.com/apache/cloudberry-backup/testutils"
"github.com/apache/cloudberry-backup/toc"
"github.com/apache/cloudberry-go-libs/testhelper"
. "github.com/onsi/ginkgo/v2"
)
var _ = Describe("backup/metadata_globals tests", func() {
emptyDB := backup.Database{}
BeforeEach(func() {
tocfile, backupfile = testutils.InitializeTestTOC(buffer, "global")
})
Describe("PrintSessionGUCs", func() {
It("prints session GUCs", func() {
gucs := backup.SessionGUCs{ClientEncoding: "UTF8"}
backup.PrintSessionGUCs(backupfile, tocfile, gucs)
testhelper.ExpectRegexp(buffer, `SET client_encoding = 'UTF8';
`)
})
})
Describe("PrintCreateDatabaseStatement", func() {
It("prints a basic CREATE DATABASE statement", func() {
db := backup.Database{Oid: 1, Name: "testdb", Tablespace: "pg_default"}
emptyMetadataMap := backup.MetadataMap{}
backup.PrintCreateDatabaseStatement(backupfile, tocfile, emptyDB, db, emptyMetadataMap)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "testdb", toc.OBJ_DATABASE)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `CREATE DATABASE testdb TEMPLATE template0;`)
})
It("prints a CREATE DATABASE statement for a reserved keyword named database", func() {
db := backup.Database{Oid: 1, Name: `"table"`, Tablespace: "pg_default"}
emptyMetadataMap := backup.MetadataMap{}
backup.PrintCreateDatabaseStatement(backupfile, tocfile, emptyDB, db, emptyMetadataMap)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", `"table"`, toc.OBJ_DATABASE)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `CREATE DATABASE "table" TEMPLATE template0;`)
})
It("prints a CREATE DATABASE statement with privileges, an owner, security label, and a comment", func() {
db := backup.Database{Oid: 1, Name: "testdb", Tablespace: "pg_default"}
dbMetadataMap := testutils.DefaultMetadataMap(toc.OBJ_DATABASE, true, true, true, true)
dbMetadata := dbMetadataMap[db.GetUniqueID()]
dbMetadata.Privileges[0].Create = false
dbMetadataMap[db.GetUniqueID()] = dbMetadata
backup.PrintCreateDatabaseStatement(backupfile, tocfile, emptyDB, db, dbMetadataMap)
expectedStatements := []string{
`CREATE DATABASE testdb TEMPLATE template0;`,
`COMMENT ON DATABASE testdb IS 'This is a database comment.';`,
`ALTER DATABASE testdb OWNER TO testrole;`,
`REVOKE ALL ON DATABASE testdb FROM PUBLIC;
REVOKE ALL ON DATABASE testdb FROM testrole;
GRANT TEMPORARY,CONNECT ON DATABASE testdb TO testrole;`,
`SECURITY LABEL FOR dummy ON DATABASE testdb IS 'unclassified';`}
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, expectedStatements...)
})
It("prints a CREATE DATABASE statement with all modifiers", func() {
db := backup.Database{Oid: 1, Name: "testdb", Tablespace: "test_tablespace", Encoding: "UTF8", Collate: "en_US.utf-8", CType: "en_US.utf-8"}
emptyMetadataMap := backup.MetadataMap{}
backup.PrintCreateDatabaseStatement(backupfile, tocfile, emptyDB, db, emptyMetadataMap)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `CREATE DATABASE testdb TEMPLATE template0 TABLESPACE test_tablespace ENCODING 'UTF8' LC_COLLATE 'en_US.utf-8' LC_CTYPE 'en_US.utf-8';`)
})
It("does not print encoding information if it is the same as defaults", func() {
defaultDB := backup.Database{Oid: 0, Name: "", Tablespace: "", Encoding: "UTF8", Collate: "en_US.utf-8", CType: "en_US.utf-8"}
db := backup.Database{Oid: 1, Name: "testdb", Tablespace: "test_tablespace", Encoding: "UTF8", Collate: "en_US.utf-8", CType: "en_US.utf-8"}
emptyMetadataMap := backup.MetadataMap{}
backup.PrintCreateDatabaseStatement(backupfile, tocfile, defaultDB, db, emptyMetadataMap)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `CREATE DATABASE testdb TEMPLATE template0 TABLESPACE test_tablespace;`)
})
})
Describe("PrintDatabaseGUCs", func() {
dbname := "testdb"
defaultOidGUC := "SET default_with_oids TO 'true'"
searchPathGUC := "SET search_path TO pg_catalog, public"
defaultStorageGUC := "SET gp_default_storage_options TO 'appendonly=true,blocksize=32768'"
It("prints single database GUC", func() {
gucs := []string{defaultOidGUC}
backup.PrintDatabaseGUCs(backupfile, tocfile, gucs, dbname)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "testdb", toc.OBJ_DATABASE_GUC)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `ALTER DATABASE testdb SET default_with_oids TO 'true';`)
})
It("prints multiple database GUCs", func() {
gucs := []string{defaultOidGUC, searchPathGUC, defaultStorageGUC}
backup.PrintDatabaseGUCs(backupfile, tocfile, gucs, dbname)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer,
`ALTER DATABASE testdb SET default_with_oids TO 'true';`,
`ALTER DATABASE testdb SET search_path TO pg_catalog, public;`,
`ALTER DATABASE testdb SET gp_default_storage_options TO 'appendonly=true,blocksize=32768';`)
})
})
Describe("PrintCreateResourceQueueStatements", func() {
var emptyResQueueMetadata = backup.MetadataMap{}
It("prints resource queues", func() {
someQueue := backup.ResourceQueue{Oid: 1, Name: "some_queue", ActiveStatements: 1, MaxCost: "-1.00", CostOvercommit: false, MinCost: "0.00", Priority: "medium", MemoryLimit: "-1"}
maxCostQueue := backup.ResourceQueue{Oid: 1, Name: `"someMaxCostQueue"`, ActiveStatements: -1, MaxCost: "99.9", CostOvercommit: true, MinCost: "0.00", Priority: "medium", MemoryLimit: "-1"}
resQueues := []backup.ResourceQueue{someQueue, maxCostQueue}
backup.PrintCreateResourceQueueStatements(backupfile, tocfile, resQueues, emptyResQueueMetadata)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "some_queue", toc.OBJ_RESOURCE_QUEUE)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer,
`CREATE RESOURCE QUEUE some_queue WITH (ACTIVE_STATEMENTS=1);`,
`CREATE RESOURCE QUEUE "someMaxCostQueue" WITH (MAX_COST=99.9, COST_OVERCOMMIT=TRUE);`)
})
It("prints a resource queue with active statements and max cost", func() {
someActiveMaxCostQueue := backup.ResourceQueue{Oid: 1, Name: `"someActiveMaxCostQueue"`, ActiveStatements: 5, MaxCost: "62.03", CostOvercommit: false, MinCost: "0.00", Priority: "medium", MemoryLimit: "-1"}
resQueues := []backup.ResourceQueue{someActiveMaxCostQueue}
backup.PrintCreateResourceQueueStatements(backupfile, tocfile, resQueues, emptyResQueueMetadata)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `CREATE RESOURCE QUEUE "someActiveMaxCostQueue" WITH (ACTIVE_STATEMENTS=5, MAX_COST=62.03);`)
})
It("prints a resource queue with all properties", func() {
everythingQueue := backup.ResourceQueue{Oid: 1, Name: `"everythingQueue"`, ActiveStatements: 7, MaxCost: "32.80", CostOvercommit: true, MinCost: "1.34", Priority: "low", MemoryLimit: "2GB"}
resQueues := []backup.ResourceQueue{everythingQueue}
backup.PrintCreateResourceQueueStatements(backupfile, tocfile, resQueues, emptyResQueueMetadata)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `CREATE RESOURCE QUEUE "everythingQueue" WITH (ACTIVE_STATEMENTS=7, MAX_COST=32.80, COST_OVERCOMMIT=TRUE, MIN_COST=1.34, PRIORITY=LOW, MEMORY_LIMIT='2GB');`)
})
It("prints a resource queue with a comment", func() {
commentQueue := backup.ResourceQueue{Oid: 1, Name: `"commentQueue"`, ActiveStatements: 1, MaxCost: "-1.00", CostOvercommit: false, MinCost: "0.00", Priority: "medium", MemoryLimit: "-1"}
resQueues := []backup.ResourceQueue{commentQueue}
resQueueMetadata := testutils.DefaultMetadataMap(toc.OBJ_RESOURCE_QUEUE, false, false, true, false)
backup.PrintCreateResourceQueueStatements(backupfile, tocfile, resQueues, resQueueMetadata)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `CREATE RESOURCE QUEUE "commentQueue" WITH (ACTIVE_STATEMENTS=1);`,
`COMMENT ON RESOURCE QUEUE "commentQueue" IS 'This is a resource queue comment.';`)
})
It("prints ALTER statement for pg_default resource queue", func() {
pgDefault := backup.ResourceQueue{Oid: 1, Name: "pg_default", ActiveStatements: 1, MaxCost: "-1.00", CostOvercommit: false, MinCost: "0.00", Priority: "medium", MemoryLimit: "-1"}
resQueues := []backup.ResourceQueue{pgDefault}
backup.PrintCreateResourceQueueStatements(backupfile, tocfile, resQueues, emptyResQueueMetadata)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `ALTER RESOURCE QUEUE pg_default WITH (ACTIVE_STATEMENTS=1);`)
})
})
Describe("PrintCreateResourceGroupStatements", func() {
var emptyResGroupMetadata = backup.MetadataMap{}
It("prints resource groups", func() {
testhelper.SetDBVersion(connectionPool, "5.9.0")
someGroup := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 1, Name: "some_group", Concurrency: "15"}, CPURateLimit: "10", MemoryLimit: "20", MemorySharedQuota: "25", MemorySpillRatio: "30"}
someGroup2 := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 2, Name: "some_group2", Concurrency: "25"}, CPURateLimit: "20", MemoryLimit: "30", MemorySharedQuota: "35", MemorySpillRatio: "10"}
resGroups := []backup.ResourceGroupBefore7{someGroup, someGroup2}
backup.PrintCreateResourceGroupStatementsBefore7(backupfile, tocfile, resGroups, emptyResGroupMetadata)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "some_group", toc.OBJ_RESOURCE_GROUP)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer,
`CREATE RESOURCE GROUP some_group WITH (CPU_RATE_LIMIT=10, MEMORY_AUDITOR=vmtracker, MEMORY_LIMIT=20, MEMORY_SHARED_QUOTA=25, MEMORY_SPILL_RATIO=30, CONCURRENCY=15);`,
`CREATE RESOURCE GROUP some_group2 WITH (CPU_RATE_LIMIT=20, MEMORY_AUDITOR=vmtracker, MEMORY_LIMIT=30, MEMORY_SHARED_QUOTA=35, MEMORY_SPILL_RATIO=10, CONCURRENCY=25);`)
})
It("prints ALTER statement for default_group resource group", func() {
defaultGroup := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 1, Name: "default_group", Concurrency: "15"}, CPURateLimit: "10", MemoryLimit: "20", MemorySharedQuota: "25", MemorySpillRatio: "30"}
resGroups := []backup.ResourceGroupBefore7{defaultGroup}
backup.PrintCreateResourceGroupStatementsBefore7(backupfile, tocfile, resGroups, emptyResGroupMetadata)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "default_group", toc.OBJ_RESOURCE_GROUP)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer,
`ALTER RESOURCE GROUP default_group SET MEMORY_LIMIT 20;`,
`ALTER RESOURCE GROUP default_group SET MEMORY_SHARED_QUOTA 25;`,
`ALTER RESOURCE GROUP default_group SET MEMORY_SPILL_RATIO 30;`,
`ALTER RESOURCE GROUP default_group SET CONCURRENCY 15;`,
`ALTER RESOURCE GROUP default_group SET CPU_RATE_LIMIT 10;`)
})
It("prints memory_auditor resource groups", func() {
testhelper.SetDBVersion(connectionPool, "5.8.0")
someGroup := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 1, Name: "some_group", Concurrency: "15"}, CPURateLimit: "10", MemoryLimit: "20", MemorySharedQuota: "25", MemorySpillRatio: "30"}
someGroup2 := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 2, Name: "some_group2", Concurrency: "0"}, CPURateLimit: "10", MemoryLimit: "30", MemorySharedQuota: "35", MemorySpillRatio: "10", MemoryAuditor: "1"}
someGroup3 := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 3, Name: "some_group3", Concurrency: "25"}, CPURateLimit: "10", MemoryLimit: "30", MemorySharedQuota: "35", MemorySpillRatio: "10", MemoryAuditor: "0"}
resGroups := []backup.ResourceGroupBefore7{someGroup, someGroup2, someGroup3}
backup.PrintCreateResourceGroupStatementsBefore7(backupfile, tocfile, resGroups, emptyResGroupMetadata)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "some_group", toc.OBJ_RESOURCE_GROUP)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer,
`CREATE RESOURCE GROUP some_group WITH (CPU_RATE_LIMIT=10, MEMORY_AUDITOR=vmtracker, MEMORY_LIMIT=20, MEMORY_SHARED_QUOTA=25, MEMORY_SPILL_RATIO=30, CONCURRENCY=15);`,
`CREATE RESOURCE GROUP some_group2 WITH (CPU_RATE_LIMIT=10, MEMORY_AUDITOR=cgroup, MEMORY_LIMIT=30, MEMORY_SHARED_QUOTA=35, MEMORY_SPILL_RATIO=10, CONCURRENCY=0);`,
`CREATE RESOURCE GROUP some_group3 WITH (CPU_RATE_LIMIT=10, MEMORY_AUDITOR=vmtracker, MEMORY_LIMIT=30, MEMORY_SHARED_QUOTA=35, MEMORY_SPILL_RATIO=10, CONCURRENCY=25);`)
})
It("prints cpuset resource groups", func() {
testhelper.SetDBVersion(connectionPool, "5.9.0")
someGroup := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 1, Name: "some_group", Concurrency: "15"}, CPURateLimit: "10", MemoryLimit: "20", MemorySharedQuota: "25", MemorySpillRatio: "30"}
someGroup2 := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 2, Name: "some_group2", Concurrency: "25", Cpuset: "0-3"}, CPURateLimit: "-1", MemoryLimit: "30", MemorySharedQuota: "35", MemorySpillRatio: "10"}
resGroups := []backup.ResourceGroupBefore7{someGroup, someGroup2}
backup.PrintCreateResourceGroupStatementsBefore7(backupfile, tocfile, resGroups, emptyResGroupMetadata)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "some_group", toc.OBJ_RESOURCE_GROUP)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer,
`CREATE RESOURCE GROUP some_group WITH (CPU_RATE_LIMIT=10, MEMORY_AUDITOR=vmtracker, MEMORY_LIMIT=20, MEMORY_SHARED_QUOTA=25, MEMORY_SPILL_RATIO=30, CONCURRENCY=15);`,
`CREATE RESOURCE GROUP some_group2 WITH (CPUSET='0-3', MEMORY_AUDITOR=vmtracker, MEMORY_LIMIT=30, MEMORY_SHARED_QUOTA=35, MEMORY_SPILL_RATIO=10, CONCURRENCY=25);`)
})
// Test for GPDB5x, 'retired' in 6X+ #temp5xResGroup
It("prints memory_spill_ratio resource groups in new syntax", func() {
testhelper.SetDBVersion(connectionPool, "5.2.0")
defaultGroup := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 1, Name: "default_group", Concurrency: "15"}, CPURateLimit: "10", MemoryLimit: "20", MemorySharedQuota: "25", MemorySpillRatio: "30 MB"}
adminGroup := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 2, Name: "admin_group", Concurrency: "15"}, CPURateLimit: "10", MemoryLimit: "20", MemorySharedQuota: "25", MemorySpillRatio: "30"}
someGroup := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 3, Name: "some_group", Concurrency: "25"}, CPURateLimit: "20", MemoryLimit: "30", MemorySharedQuota: "35", MemorySpillRatio: "40 MB"}
someGroup2 := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 4, Name: "some_group2", Concurrency: "25"}, CPURateLimit: "20", MemoryLimit: "30", MemorySharedQuota: "35", MemorySpillRatio: "40"}
resGroups := []backup.ResourceGroupBefore7{defaultGroup, adminGroup, someGroup, someGroup2}
backup.PrintCreateResourceGroupStatementsBefore7(backupfile, tocfile, resGroups, emptyResGroupMetadata)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "default_group", toc.OBJ_RESOURCE_GROUP)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer,
`ALTER RESOURCE GROUP default_group SET MEMORY_LIMIT 20;`,
`ALTER RESOURCE GROUP default_group SET MEMORY_SHARED_QUOTA 25;`,
`ALTER RESOURCE GROUP default_group SET MEMORY_SPILL_RATIO '30 MB';`,
`ALTER RESOURCE GROUP default_group SET CONCURRENCY 15;`,
`ALTER RESOURCE GROUP default_group SET CPU_RATE_LIMIT 10;`,
`ALTER RESOURCE GROUP admin_group SET MEMORY_LIMIT 20;`,
`ALTER RESOURCE GROUP admin_group SET MEMORY_SHARED_QUOTA 25;`,
`ALTER RESOURCE GROUP admin_group SET MEMORY_SPILL_RATIO 30;`,
`ALTER RESOURCE GROUP admin_group SET CONCURRENCY 15;`,
`ALTER RESOURCE GROUP admin_group SET CPU_RATE_LIMIT 10;`,
`CREATE RESOURCE GROUP some_group WITH (CPU_RATE_LIMIT=20, MEMORY_LIMIT=30, MEMORY_SHARED_QUOTA=35, MEMORY_SPILL_RATIO='40 MB', CONCURRENCY=25);`,
`CREATE RESOURCE GROUP some_group2 WITH (CPU_RATE_LIMIT=20, MEMORY_LIMIT=30, MEMORY_SHARED_QUOTA=35, MEMORY_SPILL_RATIO=40, CONCURRENCY=25);`)
})
It("prints correct CREATE RESOURCE GROUP syntax for old resource groups on GPDB 5.8", func() {
// Memory Auditor reslimittype was added in GPDB 5.8. Make sure the older resource group object will have the proper default.
testhelper.SetDBVersion(connectionPool, "5.8.0")
resGroup52 := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 3, Name: "resGroup52", Concurrency: "25"}, CPURateLimit: "20", MemoryLimit: "30", MemorySharedQuota: "35", MemorySpillRatio: "40"}
resGroup58 := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 4, Name: "resGroup58", Concurrency: "25"}, CPURateLimit: "20", MemoryLimit: "30", MemorySharedQuota: "35", MemorySpillRatio: "40", MemoryAuditor: "1"}
resGroups := []backup.ResourceGroupBefore7{resGroup52, resGroup58}
backup.PrintCreateResourceGroupStatementsBefore7(backupfile, tocfile, resGroups, emptyResGroupMetadata)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer,
`CREATE RESOURCE GROUP resGroup52 WITH (CPU_RATE_LIMIT=20, MEMORY_AUDITOR=vmtracker, MEMORY_LIMIT=30, MEMORY_SHARED_QUOTA=35, MEMORY_SPILL_RATIO=40, CONCURRENCY=25);`,
`CREATE RESOURCE GROUP resGroup58 WITH (CPU_RATE_LIMIT=20, MEMORY_AUDITOR=cgroup, MEMORY_LIMIT=30, MEMORY_SHARED_QUOTA=35, MEMORY_SPILL_RATIO=40, CONCURRENCY=25);`)
})
It("prints correct CREATE RESOURCE GROUP syntax for old resource groups on GPDB 5.9", func() {
// Cpuset reslimittype was added in GPDB 5.9. Make sure the older resource group objects
// will have the proper default. In this case, you either have cpu_rate_limit or cpuset.
testhelper.SetDBVersion(connectionPool, "5.9.0")
resGroup52 := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 3, Name: "resGroup52", Concurrency: "25"}, CPURateLimit: "20", MemoryLimit: "30", MemorySharedQuota: "35", MemorySpillRatio: "40"}
resGroup58 := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 4, Name: "resGroup58", Concurrency: "25"}, CPURateLimit: "20", MemoryLimit: "30", MemorySharedQuota: "35", MemorySpillRatio: "40", MemoryAuditor: "1"}
resGroup59 := backup.ResourceGroupBefore7{ResourceGroup: backup.ResourceGroup{Oid: 5, Name: "resGroup59", Concurrency: "25", Cpuset: "1"}, CPURateLimit: "-1", MemoryLimit: "30", MemorySharedQuota: "35", MemorySpillRatio: "40", MemoryAuditor: "1"}
resGroups := []backup.ResourceGroupBefore7{resGroup52, resGroup58, resGroup59}
backup.PrintCreateResourceGroupStatementsBefore7(backupfile, tocfile, resGroups, emptyResGroupMetadata)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer,
`CREATE RESOURCE GROUP resGroup52 WITH (CPU_RATE_LIMIT=20, MEMORY_AUDITOR=vmtracker, MEMORY_LIMIT=30, MEMORY_SHARED_QUOTA=35, MEMORY_SPILL_RATIO=40, CONCURRENCY=25);`,
`CREATE RESOURCE GROUP resGroup58 WITH (CPU_RATE_LIMIT=20, MEMORY_AUDITOR=cgroup, MEMORY_LIMIT=30, MEMORY_SHARED_QUOTA=35, MEMORY_SPILL_RATIO=40, CONCURRENCY=25);`,
`CREATE RESOURCE GROUP resGroup59 WITH (CPUSET='1', MEMORY_AUDITOR=cgroup, MEMORY_LIMIT=30, MEMORY_SHARED_QUOTA=35, MEMORY_SPILL_RATIO=40, CONCURRENCY=25);`)
})
})
Describe("PrintResetResourceGroupStatements", func() {
It("prints prepare resource groups", func() {
backup.PrintResetResourceGroupStatements(backupfile, tocfile)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "admin_group", toc.OBJ_RESOURCE_GROUP)
if connectionPool.Version.IsGPDB() && connectionPool.Version.Before("7") {
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer,
`ALTER RESOURCE GROUP admin_group SET CPU_RATE_LIMIT 1;`,
`ALTER RESOURCE GROUP admin_group SET MEMORY_LIMIT 1;`,
`ALTER RESOURCE GROUP default_group SET CPU_RATE_LIMIT 1;`,
`ALTER RESOURCE GROUP default_group SET MEMORY_LIMIT 1;`)
} else { // GPDB7+
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer,
`ALTER RESOURCE GROUP admin_group SET CPU_MAX_PERCENT 1;`,
`ALTER RESOURCE GROUP admin_group SET CPU_WEIGHT 100;`,
`ALTER RESOURCE GROUP default_group SET CPU_MAX_PERCENT 1;`,
`ALTER RESOURCE GROUP default_group SET CPU_WEIGHT 100;`,
`ALTER RESOURCE GROUP system_group SET CPU_MAX_PERCENT 1;`,
`ALTER RESOURCE GROUP system_group SET CPU_WEIGHT 100;`)
}
})
})
Describe("PrintCreateRoleStatements", func() {
testrole1 := backup.Role{
Oid: 1,
Name: "testrole1",
Super: false,
Inherit: false,
CreateRole: false,
CreateDB: false,
CanLogin: false,
Replication: false,
ConnectionLimit: -1,
Password: "",
ValidUntil: "",
ResQueue: "pg_default",
ResGroup: "default_group",
Createrexthttp: false,
Createrextgpfd: false,
Createwextgpfd: false,
Createrexthdfs: false,
Createwexthdfs: false,
TimeConstraints: []backup.TimeConstraint{},
}
testrole2 := backup.Role{
Oid: 1,
Name: `"testRole2"`,
Super: true,
Inherit: true,
CreateRole: true,
CreateDB: true,
CanLogin: true,
Replication: true,
ConnectionLimit: 4,
Password: "md5a8b2c77dfeba4705f29c094592eb3369",
ValidUntil: "2099-01-01 00:00:00-08",
ResQueue: `"testQueue"`,
ResGroup: `"testGroup"`,
Createrexthttp: true,
Createrextgpfd: true,
Createwextgpfd: true,
Createrexthdfs: true,
Createwexthdfs: true,
TimeConstraints: []backup.TimeConstraint{
{
StartDay: 0,
StartTime: "13:30:00",
EndDay: 3,
EndTime: "14:30:00",
}, {
StartDay: 5,
StartTime: "00:00:00",
EndDay: 5,
EndTime: "24:00:00",
},
},
}
getResourceGroupReplace := func() (string, string) {
resourceGroupReplace1 := ` RESOURCE GROUP default_group`
resourceGroupReplace2 := `RESOURCE GROUP "testGroup" `
return resourceGroupReplace1, resourceGroupReplace2
}
It("prints basic role", func() {
roleMetadataMap := testutils.DefaultMetadataMap(toc.OBJ_ROLE, false, false, true, false)
backup.PrintCreateRoleStatements(backupfile, tocfile, []backup.Role{testrole1}, roleMetadataMap)
resourceGroupReplace, _ := getResourceGroupReplace()
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "testrole1", toc.OBJ_ROLE)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, fmt.Sprintf(`CREATE ROLE testrole1;
ALTER ROLE testrole1 WITH NOSUPERUSER NOINHERIT NOCREATEROLE NOCREATEDB NOLOGIN RESOURCE QUEUE pg_default%s;`, resourceGroupReplace),
`COMMENT ON ROLE testrole1 IS 'This is a role comment.';`)
})
It("prints roles with non-defaults and security label", func() {
roleMetadataMap := testutils.DefaultMetadataMap(toc.OBJ_ROLE, false, false, true, true)
backup.PrintCreateRoleStatements(backupfile, tocfile, []backup.Role{testrole2}, roleMetadataMap)
_, resourceGroupReplace := getResourceGroupReplace()
expectedStatements := []string{
fmt.Sprintf(`CREATE ROLE "testRole2";
ALTER ROLE "testRole2" WITH SUPERUSER INHERIT CREATEROLE CREATEDB LOGIN REPLICATION CONNECTION LIMIT 4 PASSWORD 'md5a8b2c77dfeba4705f29c094592eb3369' VALID UNTIL '2099-01-01 00:00:00-08' RESOURCE QUEUE "testQueue" %sCREATEEXTTABLE (protocol='http') CREATEEXTTABLE (protocol='gpfdist', type='readable') CREATEEXTTABLE (protocol='gpfdist', type='writable') CREATEEXTTABLE (protocol='gphdfs', type='readable') CREATEEXTTABLE (protocol='gphdfs', type='writable');`, resourceGroupReplace),
`ALTER ROLE "testRole2" DENY BETWEEN DAY 0 TIME '13:30:00' AND DAY 3 TIME '14:30:00';`,
`ALTER ROLE "testRole2" DENY BETWEEN DAY 5 TIME '00:00:00' AND DAY 5 TIME '24:00:00';`,
`COMMENT ON ROLE "testRole2" IS 'This is a role comment.';`,
`SECURITY LABEL FOR dummy ON ROLE "testRole2" IS 'unclassified';`}
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, expectedStatements...)
})
It("prints multiple roles", func() {
emptyMetadataMap := backup.MetadataMap{}
backup.PrintCreateRoleStatements(backupfile, tocfile, []backup.Role{testrole1, testrole2}, emptyMetadataMap)
resourceGroupReplace1, resourceGroupReplace2 := getResourceGroupReplace()
expectedStatements := []string{
fmt.Sprintf(`CREATE ROLE testrole1;
ALTER ROLE testrole1 WITH NOSUPERUSER NOINHERIT NOCREATEROLE NOCREATEDB NOLOGIN RESOURCE QUEUE pg_default%s;`, resourceGroupReplace1),
fmt.Sprintf(`CREATE ROLE "testRole2";
ALTER ROLE "testRole2" WITH SUPERUSER INHERIT CREATEROLE CREATEDB LOGIN REPLICATION CONNECTION LIMIT 4 PASSWORD 'md5a8b2c77dfeba4705f29c094592eb3369' VALID UNTIL '2099-01-01 00:00:00-08' RESOURCE QUEUE "testQueue" %sCREATEEXTTABLE (protocol='http') CREATEEXTTABLE (protocol='gpfdist', type='readable') CREATEEXTTABLE (protocol='gpfdist', type='writable') CREATEEXTTABLE (protocol='gphdfs', type='readable') CREATEEXTTABLE (protocol='gphdfs', type='writable');`, resourceGroupReplace2),
`ALTER ROLE "testRole2" DENY BETWEEN DAY 0 TIME '13:30:00' AND DAY 3 TIME '14:30:00';`,
`ALTER ROLE "testRole2" DENY BETWEEN DAY 5 TIME '00:00:00' AND DAY 5 TIME '24:00:00';`}
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, expectedStatements...)
})
})
Describe("PrintRoleMembershipStatements", func() {
roleWith := backup.RoleMember{Role: "group", Member: "rolewith", Grantor: "grantor", IsAdmin: true}
roleWithout := backup.RoleMember{Role: "group", Member: "rolewithout", Grantor: "grantor", IsAdmin: false}
roleWithoutGrantor := backup.RoleMember{Role: "group", Member: "rolewithoutgrantor", Grantor: "", IsAdmin: false}
It("prints a role without ADMIN OPTION", func() {
backup.PrintRoleMembershipStatements(backupfile, tocfile, []backup.RoleMember{roleWithout})
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "rolewithout", toc.OBJ_ROLE_GRANT)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `GRANT group TO rolewithout GRANTED BY grantor;`)
})
It("prints a role WITH ADMIN OPTION", func() {
backup.PrintRoleMembershipStatements(backupfile, tocfile, []backup.RoleMember{roleWith})
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `GRANT group TO rolewith WITH ADMIN OPTION GRANTED BY grantor;`)
})
It("prints multiple roles", func() {
backup.PrintRoleMembershipStatements(backupfile, tocfile, []backup.RoleMember{roleWith, roleWithout})
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer,
`GRANT group TO rolewith WITH ADMIN OPTION GRANTED BY grantor;`,
`GRANT group TO rolewithout GRANTED BY grantor;`)
})
It("prints a role without a grantor", func() {
backup.PrintRoleMembershipStatements(backupfile, tocfile, []backup.RoleMember{roleWithoutGrantor})
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `GRANT group TO rolewithoutgrantor;`)
})
})
Describe("PrintRoleGUCStatements", func() {
It("Prints guc statements for a role", func() {
roleConfigMap := map[string][]backup.RoleGUC{
"testrole1": {
{RoleName: "testrole1", Config: "SET search_path TO public"},
{RoleName: "testrole1", DbName: "testdb", Config: "SET client_min_messages TO 'error'"},
{RoleName: "testrole1", Config: "SET gp_default_storage_options TO 'appendonly=true, compresslevel=6, orientation=row, compresstype=none'"}},
}
backup.PrintRoleGUCStatements(backupfile, tocfile, roleConfigMap)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "testrole1", toc.OBJ_ROLE_GUC)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `ALTER ROLE testrole1 SET search_path TO public;`,
`ALTER ROLE testrole1 IN DATABASE testdb SET client_min_messages TO 'error';`,
`ALTER ROLE testrole1 SET gp_default_storage_options TO 'appendonly=true, compresslevel=6, orientation=row, compresstype=none';`)
})
})
Describe("PrintCreateTablespaceStatements", func() {
expectedTablespace := backup.Tablespace{Oid: 1, Tablespace: "test_tablespace", FileLocation: "test_filespace"}
It("prints a basic tablespace with a filespace", func() {
emptyMetadataMap := backup.MetadataMap{}
backup.PrintCreateTablespaceStatements(backupfile, tocfile, []backup.Tablespace{expectedTablespace}, emptyMetadataMap)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "test_tablespace", toc.OBJ_TABLESPACE)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `CREATE TABLESPACE test_tablespace FILESPACE test_filespace;`)
})
It("prints a tablespace with privileges, an owner, security label, and a comment", func() {
tablespaceMetadataMap := testutils.DefaultMetadataMap(toc.OBJ_TABLESPACE, true, true, true, true)
backup.PrintCreateTablespaceStatements(backupfile, tocfile, []backup.Tablespace{expectedTablespace}, tablespaceMetadataMap)
expectedStatements := []string{
`CREATE TABLESPACE test_tablespace FILESPACE test_filespace;`,
`COMMENT ON TABLESPACE test_tablespace IS 'This is a tablespace comment.';`,
`ALTER TABLESPACE test_tablespace OWNER TO testrole;`,
`REVOKE ALL ON TABLESPACE test_tablespace FROM PUBLIC;
REVOKE ALL ON TABLESPACE test_tablespace FROM testrole;
GRANT ALL ON TABLESPACE test_tablespace TO testrole;`,
`SECURITY LABEL FOR dummy ON TABLESPACE test_tablespace IS 'unclassified';`}
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, expectedStatements...)
})
It("prints a tablespace with no per-segment tablespaces", func() {
expectedTablespace := backup.Tablespace{
Oid: 1, Tablespace: "test_tablespace", FileLocation: "'/data/dir'",
SegmentLocations: []string{},
}
emptyMetadataMap := backup.MetadataMap{}
backup.PrintCreateTablespaceStatements(backupfile, tocfile, []backup.Tablespace{expectedTablespace}, emptyMetadataMap)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "test_tablespace", toc.OBJ_TABLESPACE)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `CREATE TABLESPACE test_tablespace LOCATION '/data/dir';`)
})
It("prints a tablespace with per-segment tablespaces", func() {
expectedTablespace := backup.Tablespace{
Oid: 1, Tablespace: "test_tablespace", FileLocation: "'/data/dir'",
SegmentLocations: []string{"content1='/data/dir1'", "content2='/data/dir2'", "content3='/data/dir3'"},
}
emptyMetadataMap := backup.MetadataMap{}
backup.PrintCreateTablespaceStatements(backupfile, tocfile, []backup.Tablespace{expectedTablespace}, emptyMetadataMap)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "test_tablespace", toc.OBJ_TABLESPACE)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `CREATE TABLESPACE test_tablespace LOCATION '/data/dir'
WITH (content1='/data/dir1', content2='/data/dir2', content3='/data/dir3');`)
})
It("prints a tablespace with options", func() {
expectedTablespace := backup.Tablespace{
Oid: 1, Tablespace: "test_tablespace", FileLocation: "'/data/dir'",
SegmentLocations: []string{},
Options: "param1=val1, param2=val2",
}
emptyMetadataMap := backup.MetadataMap{}
backup.PrintCreateTablespaceStatements(backupfile, tocfile, []backup.Tablespace{expectedTablespace}, emptyMetadataMap)
testutils.ExpectEntry(tocfile.GlobalEntries, 0, "", "", "test_tablespace", toc.OBJ_TABLESPACE)
testutils.ExpectEntry(tocfile.GlobalEntries, 1, "", "", "test_tablespace", toc.OBJ_TABLESPACE)
expectedStatements := []string{`CREATE TABLESPACE test_tablespace LOCATION '/data/dir';`,
`ALTER TABLESPACE test_tablespace SET (param1 = val1, param2 = val2);`}
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, expectedStatements...)
})
It("prints a remote tablespace with server, path and handler options", func() {
expectedTablespace := backup.Tablespace{
Oid: 1,
Tablespace: "remote_ts",
FileLocation: "", // Ignored when path is present
Options: "server=s3_server, path='/bucket/path', random_page_cost=4",
Spcfilehandlerbin: "$libdir/dfs_tablespace",
Spcfilehandlersrc: "remote_file_handler",
}
emptyMetadataMap := backup.MetadataMap{}
backup.PrintCreateTablespaceStatements(backupfile, tocfile, []backup.Tablespace{expectedTablespace}, emptyMetadataMap)
expectedStatements := []string{
`CREATE TABLESPACE remote_ts LOCATION '/bucket/path' SERVER s3_server HANDLER '$libdir/dfs_tablespace, remote_file_handler';`,
`ALTER TABLESPACE remote_ts SET (random_page_cost = 4);`,
}
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, expectedStatements...)
})
})
Describe("PrintCreateStorageServerStatements", func() {
It("prints a storage server without options", func() {
expectedServer := backup.StorageServer{Oid: 1, Server: "test_server"}
emptyMetadataMap := backup.MetadataMap{}
backup.PrintCreateStorageServerStatements(backupfile, tocfile, []backup.StorageServer{expectedServer}, emptyMetadataMap)
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `CREATE STORAGE SERVER test_server;`)
})
It("prints a storage server with options", func() {
expectedServer := backup.StorageServer{
Oid: 1,
Server: "test_server",
ServerOptions: "protocol=s3, region=us-east-1, endpoint=s3.example.com",
}
emptyMetadataMap := backup.MetadataMap{}
backup.PrintCreateStorageServerStatements(backupfile, tocfile, []backup.StorageServer{expectedServer}, emptyMetadataMap)
// Note: The order is deterministic because we sort the keys.
expectedStatements := []string{`CREATE STORAGE SERVER test_server OPTIONS(endpoint 's3.example.com', protocol 's3', region 'us-east-1');`}
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, expectedStatements...)
})
})
Describe("PrintCreateStorageUserMappingStatements", func() {
It("prints a storage user mapping without options", func() {
expectedUserMapping := backup.StorageUserMapping{Oid: 1, User: "testrole", Server: "test_server"}
backup.PrintCreateStorageUserMappingStatements(backupfile, tocfile, []backup.StorageUserMapping{expectedUserMapping})
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, `CREATE STORAGE USER MAPPING FOR testrole STORAGE SERVER test_server;`)
})
It("prints a storage user mapping with options", func() {
expectedUserMapping := backup.StorageUserMapping{
Oid: 1,
User: "testrole",
Server: "test_server",
Options: "secretkey=mysecret, accesskey=mykey",
}
backup.PrintCreateStorageUserMappingStatements(backupfile, tocfile, []backup.StorageUserMapping{expectedUserMapping})
// Note: The order is deterministic because we sort the keys.
expectedStatements := []string{`CREATE STORAGE USER MAPPING FOR testrole STORAGE SERVER test_server OPTIONS (accesskey 'mykey', secretkey 'mysecret');`}
testutils.AssertBufferContents(tocfile.GlobalEntries, buffer, expectedStatements...)
})
})
})