github.com/tuhaihe/gpbackup@v1.0.3/integration/metadata_globals_create_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"regexp"
     6  
     7  	"github.com/tuhaihe/gp-common-go-libs/structmatcher"
     8  	"github.com/tuhaihe/gp-common-go-libs/testhelper"
     9  	"github.com/tuhaihe/gpbackup/backup"
    10  	"github.com/tuhaihe/gpbackup/testutils"
    11  
    12  	. "github.com/onsi/ginkgo/v2"
    13  	. "github.com/onsi/gomega"
    14  	. "github.com/onsi/gomega/gbytes"
    15  )
    16  
    17  var _ = Describe("backup integration create statement tests", func() {
    18  	BeforeEach(func() {
    19  		tocfile, backupfile = testutils.InitializeTestTOC(buffer, "predata")
    20  	})
    21  	Describe("PrintCreateDatabaseStatement", func() {
    22  		emptyDB := backup.Database{}
    23  		emptyMetadataMap := backup.MetadataMap{}
    24  		BeforeEach(func() {
    25  			connectionPool.DBName = "create_test_db"
    26  		})
    27  		AfterEach(func() {
    28  			connectionPool.DBName = "testdb"
    29  		})
    30  		It("creates a basic database", func() {
    31  			db := backup.Database{Oid: 1, Name: "create_test_db", Tablespace: "pg_default", Encoding: "UTF8"}
    32  			backup.PrintCreateDatabaseStatement(backupfile, tocfile, emptyDB, db, emptyMetadataMap)
    33  
    34  			testhelper.AssertQueryRuns(connectionPool, buffer.String())
    35  			defer testhelper.AssertQueryRuns(connectionPool, "DROP DATABASE create_test_db")
    36  
    37  			resultDB := backup.GetDatabaseInfo(connectionPool)
    38  			structmatcher.ExpectStructsToMatchExcluding(&db, &resultDB, "Oid", "Collate", "CType")
    39  		})
    40  		It("creates a database with properties the same as defaults", func() {
    41  			defaultDB := backup.GetDefaultDatabaseEncodingInfo(connectionPool)
    42  			var db backup.Database
    43  			db = backup.Database{Oid: 1, Name: "create_test_db", Tablespace: "pg_default", Encoding: "UTF8", Collate: defaultDB.Collate, CType: defaultDB.Collate}
    44  
    45  			backup.PrintCreateDatabaseStatement(backupfile, tocfile, defaultDB, db, emptyMetadataMap)
    46  
    47  			testhelper.AssertQueryRuns(connectionPool, buffer.String())
    48  			defer testhelper.AssertQueryRuns(connectionPool, "DROP DATABASE create_test_db")
    49  
    50  			resultDB := backup.GetDatabaseInfo(connectionPool)
    51  			structmatcher.ExpectStructsToMatchExcluding(&db, &resultDB, "Oid")
    52  		})
    53  		It("creates a database with all properties", func() {
    54  			var db backup.Database
    55  			if false {
    56  				db = backup.Database{Oid: 1, Name: "create_test_db", Tablespace: "pg_default", Encoding: "UTF8", Collate: "", CType: ""}
    57  			} else {
    58  				db = backup.Database{Oid: 1, Name: "create_test_db", Tablespace: "pg_default", Encoding: "UTF8", Collate: "en_US.utf-8", CType: "en_US.utf-8"}
    59  			}
    60  
    61  			backup.PrintCreateDatabaseStatement(backupfile, tocfile, emptyDB, db, emptyMetadataMap)
    62  
    63  			testhelper.AssertQueryRuns(connectionPool, buffer.String())
    64  			defer testhelper.AssertQueryRuns(connectionPool, "DROP DATABASE create_test_db")
    65  
    66  			resultDB := backup.GetDatabaseInfo(connectionPool)
    67  			structmatcher.ExpectStructsToMatchExcluding(&db, &resultDB, "Oid")
    68  		})
    69  	})
    70  	Describe("PrintDatabaseGUCs", func() {
    71  		It("creates database GUCs with correct quoting", func() {
    72  			enableNestLoopGUC := "SET enable_nestloop TO 'true'"
    73  			searchPathGUC := "SET search_path TO pg_catalog, public"
    74  			defaultStorageGUC := "SET gp_default_storage_options TO 'appendonly=true, compresslevel=6, orientation=row, compresstype=none'"
    75  			if true {
    76  				defaultStorageGUC = "SET gp_default_storage_options TO 'compresslevel=6, compresstype=none'"
    77  			}
    78  
    79  			gucs := []string{enableNestLoopGUC, searchPathGUC, defaultStorageGUC}
    80  
    81  			backup.PrintDatabaseGUCs(backupfile, tocfile, gucs, "testdb")
    82  			testhelper.AssertQueryRuns(connectionPool, buffer.String())
    83  			defer testhelper.AssertQueryRuns(connectionPool, "ALTER DATABASE testdb RESET enable_nestloop")
    84  			defer testhelper.AssertQueryRuns(connectionPool, "ALTER DATABASE testdb RESET search_path")
    85  			defer testhelper.AssertQueryRuns(connectionPool, "ALTER DATABASE testdb RESET gp_default_storage_options")
    86  			resultGUCs := backup.GetDatabaseGUCs(connectionPool)
    87  			Expect(resultGUCs).To(Equal(gucs))
    88  		})
    89  	})
    90  	Describe("PrintCreateResourceQueueStatements", func() {
    91  		It("creates a basic resource queue with a comment", func() {
    92  			basicQueue := backup.ResourceQueue{Oid: 1, Name: `"basicQueue"`, ActiveStatements: -1, MaxCost: "32.80", CostOvercommit: false, MinCost: "0.00", Priority: "medium", MemoryLimit: "-1"}
    93  			resQueueMetadataMap := testutils.DefaultMetadataMap("RESOURCE QUEUE", false, false, true, false)
    94  			resQueueMetadata := resQueueMetadataMap[basicQueue.GetUniqueID()]
    95  
    96  			backup.PrintCreateResourceQueueStatements(backupfile, tocfile, []backup.ResourceQueue{basicQueue}, resQueueMetadataMap)
    97  
    98  			// CREATE RESOURCE QUEUE statements can not be part of a multi-command statement, so
    99  			// feed the CREATE RESOURCE QUEUE and COMMENT ON statements separately.
   100  			hunks := regexp.MustCompile(";\n\n").Split(buffer.String(), 2)
   101  			testhelper.AssertQueryRuns(connectionPool, hunks[0])
   102  			defer testhelper.AssertQueryRuns(connectionPool, `DROP RESOURCE QUEUE "basicQueue"`)
   103  			testhelper.AssertQueryRuns(connectionPool, hunks[1])
   104  
   105  			resultResourceQueues := backup.GetResourceQueues(connectionPool)
   106  			resQueueUniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "basicQueue", backup.TYPE_RESOURCEQUEUE)
   107  			resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_RESOURCEQUEUE)
   108  			resultMetadata := resultMetadataMap[resQueueUniqueID]
   109  			structmatcher.ExpectStructsToMatch(&resultMetadata, &resQueueMetadata)
   110  
   111  			for _, resultQueue := range resultResourceQueues {
   112  				if resultQueue.Name == `"basicQueue"` {
   113  					structmatcher.ExpectStructsToMatchExcluding(&basicQueue, &resultQueue, "Oid")
   114  					return
   115  				}
   116  			}
   117  		})
   118  		It("creates a resource queue with all attributes", func() {
   119  			everythingQueue := backup.ResourceQueue{Oid: 1, Name: `"everythingQueue"`, ActiveStatements: 7, MaxCost: "32.80", CostOvercommit: true, MinCost: "22.80", Priority: "low", MemoryLimit: "2GB"}
   120  			emptyMetadataMap := map[backup.UniqueID]backup.ObjectMetadata{}
   121  
   122  			backup.PrintCreateResourceQueueStatements(backupfile, tocfile, []backup.ResourceQueue{everythingQueue}, emptyMetadataMap)
   123  
   124  			testhelper.AssertQueryRuns(connectionPool, buffer.String())
   125  			defer testhelper.AssertQueryRuns(connectionPool, `DROP RESOURCE QUEUE "everythingQueue"`)
   126  
   127  			resultResourceQueues := backup.GetResourceQueues(connectionPool)
   128  
   129  			for _, resultQueue := range resultResourceQueues {
   130  				if resultQueue.Name == `"everythingQueue"` {
   131  					structmatcher.ExpectStructsToMatchExcluding(&everythingQueue, &resultQueue, "Oid")
   132  					return
   133  				}
   134  			}
   135  			Fail("Could not find everythingQueue")
   136  		})
   137  	})
   138  	Describe("PrintCreateResourceGroupStatements", func() {
   139  		BeforeEach(func() {
   140  			testutils.SkipIfBefore5(connectionPool)
   141  		})
   142  		It("creates a basic resource group", func() {
   143  			someGroup := backup.ResourceGroup{Oid: 1, Name: "some_group", CPURateLimit: "10", MemoryLimit: "20", Concurrency: "15", MemorySharedQuota: "25", MemorySpillRatio: "30", MemoryAuditor: "0", Cpuset: "-1"}
   144  			emptyMetadataMap := map[backup.UniqueID]backup.ObjectMetadata{}
   145  
   146  			backup.PrintCreateResourceGroupStatements(backupfile, tocfile, []backup.ResourceGroup{someGroup}, emptyMetadataMap)
   147  
   148  			testhelper.AssertQueryRuns(connectionPool, buffer.String())
   149  			defer testhelper.AssertQueryRuns(connectionPool, `DROP RESOURCE GROUP some_group`)
   150  
   151  			resultResourceGroups := backup.GetResourceGroups(connectionPool)
   152  
   153  			for _, resultGroup := range resultResourceGroups {
   154  				if resultGroup.Name == "some_group" {
   155  					structmatcher.ExpectStructsToMatchExcluding(&someGroup, &resultGroup, "Oid")
   156  					return
   157  				}
   158  			}
   159  			Fail("Could not find some_group")
   160  		})
   161  		It("creates a resource group with defaults", func() {
   162  			expectedDefaults := backup.ResourceGroup{Oid: 1, Name: "some_group", CPURateLimit: "10", MemoryLimit: "20", Concurrency: concurrencyDefault, MemorySharedQuota: memSharedDefault, MemorySpillRatio: memSpillDefault, MemoryAuditor: memAuditDefault, Cpuset: cpuSetDefault}
   163  
   164  			testhelper.AssertQueryRuns(connectionPool, "CREATE RESOURCE GROUP some_group WITH (CPU_RATE_LIMIT=10, MEMORY_LIMIT=20);")
   165  			defer testhelper.AssertQueryRuns(connectionPool, `DROP RESOURCE GROUP some_group`)
   166  
   167  			resultResourceGroups := backup.GetResourceGroups(connectionPool)
   168  
   169  			for _, resultGroup := range resultResourceGroups {
   170  				if resultGroup.Name == "some_group" {
   171  					structmatcher.ExpectStructsToMatchExcluding(&expectedDefaults, &resultGroup, "Oid")
   172  					return
   173  				}
   174  			}
   175  			Fail("Could not find some_group")
   176  		})
   177  		It("creates a resource group using old format for MemorySpillRatio", func() {
   178  			// temporarily special case for 5x resource groups #temp5xResGroup
   179  			if false {
   180  				Skip("Test only applicable to GPDB 5.20 and above")
   181  			}
   182  			expectedDefaults := backup.ResourceGroup{Oid: 1, Name: "some_group", CPURateLimit: "10", MemoryLimit: "20", Concurrency: concurrencyDefault, MemorySharedQuota: memSharedDefault, MemorySpillRatio: "19", MemoryAuditor: memAuditDefault, Cpuset: cpuSetDefault}
   183  
   184  			testhelper.AssertQueryRuns(connectionPool, "CREATE RESOURCE GROUP some_group WITH (CPU_RATE_LIMIT=10, MEMORY_LIMIT=20, MEMORY_SPILL_RATIO=19);")
   185  			defer testhelper.AssertQueryRuns(connectionPool, `DROP RESOURCE GROUP some_group`)
   186  
   187  			resultResourceGroups := backup.GetResourceGroups(connectionPool)
   188  
   189  			for _, resultGroup := range resultResourceGroups {
   190  				if resultGroup.Name == "some_group" {
   191  					structmatcher.ExpectStructsToMatchExcluding(&expectedDefaults, &resultGroup, "Oid")
   192  					return
   193  				}
   194  			}
   195  			Fail("Could not find some_group")
   196  		})
   197  		It("alters a default resource group", func() {
   198  			defaultGroup := backup.ResourceGroup{Oid: 1, Name: "default_group", CPURateLimit: "10", MemoryLimit: "20", Concurrency: "15", MemorySharedQuota: "25", MemorySpillRatio: "30", MemoryAuditor: "0", Cpuset: "-1"}
   199  			emptyMetadataMap := map[backup.UniqueID]backup.ObjectMetadata{}
   200  
   201  			backup.PrintCreateResourceGroupStatements(backupfile, tocfile, []backup.ResourceGroup{defaultGroup}, emptyMetadataMap)
   202  
   203  			hunks := regexp.MustCompile(";\n\n").Split(buffer.String(), 5)
   204  			for i := 0; i < 5; i++ {
   205  				testhelper.AssertQueryRuns(connectionPool, hunks[i])
   206  			}
   207  			resultResourceGroups := backup.GetResourceGroups(connectionPool)
   208  
   209  			for _, resultGroup := range resultResourceGroups {
   210  				if resultGroup.Name == "default_group" {
   211  					structmatcher.ExpectStructsToMatchExcluding(&defaultGroup, &resultGroup, "Oid")
   212  					return
   213  				}
   214  			}
   215  			Fail("Could not find default_group")
   216  		})
   217  	})
   218  	Describe("PrintCreateRoleStatements", func() {
   219  		var role1 backup.Role
   220  		BeforeEach(func() {
   221  			role1 = backup.Role{
   222  				Oid:             1,
   223  				Name:            "role1",
   224  				Super:           true,
   225  				Inherit:         false,
   226  				CreateRole:      false,
   227  				CreateDB:        false,
   228  				CanLogin:        false,
   229  				ConnectionLimit: -1,
   230  				Password:        "",
   231  				ValidUntil:      "",
   232  				ResQueue:        "pg_default",
   233  				ResGroup:        "default_group",
   234  				Createrexthttp:  false,
   235  				Createrextgpfd:  false,
   236  				Createwextgpfd:  false,
   237  				Createrexthdfs:  false,
   238  				Createwexthdfs:  false,
   239  				TimeConstraints: nil,
   240  			}
   241  		})
   242  		emptyMetadataMap := backup.MetadataMap{}
   243  		It("creates a basic role", func() {
   244  			if false {
   245  				role1.ResGroup = ""
   246  			}
   247  
   248  			backup.PrintCreateRoleStatements(backupfile, tocfile, []backup.Role{role1}, emptyMetadataMap)
   249  
   250  			testhelper.AssertQueryRuns(connectionPool, buffer.String())
   251  			defer testhelper.AssertQueryRuns(connectionPool, `DROP ROLE "role1"`)
   252  			role1.Oid = testutils.OidFromObjectName(connectionPool, "", "role1", backup.TYPE_ROLE)
   253  
   254  			resultRoles := backup.GetRoles(connectionPool)
   255  			for _, role := range resultRoles {
   256  				if role.Name == "role1" {
   257  					structmatcher.ExpectStructsToMatch(&role1, role)
   258  					return
   259  				}
   260  			}
   261  			Fail("Role 'role1' was not found")
   262  		})
   263  		It("creates a role with all attributes", func() {
   264  			role1 := backup.Role{
   265  				Oid:             1,
   266  				Name:            "role1",
   267  				Super:           false,
   268  				Inherit:         true,
   269  				CreateRole:      true,
   270  				CreateDB:        true,
   271  				CanLogin:        true,
   272  				ConnectionLimit: 4,
   273  				Password:        "md5a8b2c77dfeba4705f29c094592eb3369",
   274  				ValidUntil:      "2099-01-01 08:00:00-00",
   275  				ResQueue:        "pg_default",
   276  				ResGroup:        "",
   277  				Createrexthttp:  true,
   278  				Createrextgpfd:  true,
   279  				Createwextgpfd:  true,
   280  				Createrexthdfs:  true,
   281  				Createwexthdfs:  true,
   282  				TimeConstraints: []backup.TimeConstraint{
   283  					{
   284  						Oid:       0,
   285  						StartDay:  0,
   286  						StartTime: "13:30:00",
   287  						EndDay:    3,
   288  						EndTime:   "14:30:00",
   289  					}, {
   290  						Oid:       0,
   291  						StartDay:  5,
   292  						StartTime: "00:00:00",
   293  						EndDay:    5,
   294  						EndTime:   "24:00:00",
   295  					},
   296  				},
   297  			}
   298  			if true {
   299  				role1.ResGroup = "default_group"
   300  			}
   301  			if true {
   302  				role1.Createrexthdfs = false
   303  				role1.Createwexthdfs = false
   304  			}
   305  			metadataMap := testutils.DefaultMetadataMap("ROLE", false, false, true, includeSecurityLabels)
   306  
   307  			backup.PrintCreateRoleStatements(backupfile, tocfile, []backup.Role{role1}, metadataMap)
   308  
   309  			testhelper.AssertQueryRuns(connectionPool, buffer.String())
   310  			defer testhelper.AssertQueryRuns(connectionPool, `DROP ROLE "role1"`)
   311  			role1.Oid = testutils.OidFromObjectName(connectionPool, "", "role1", backup.TYPE_ROLE)
   312  
   313  			resultRoles := backup.GetRoles(connectionPool)
   314  			for _, role := range resultRoles {
   315  				if role.Name == "role1" {
   316  					structmatcher.ExpectStructsToMatchExcluding(&role1, role, "TimeConstraints.Oid")
   317  					return
   318  				}
   319  			}
   320  			Fail("Role 'role1' was not found")
   321  		})
   322  		It("creates a role with replication", func() {
   323  			testutils.SkipIfBefore6(connectionPool)
   324  
   325  			role1.Replication = true
   326  			backup.PrintCreateRoleStatements(backupfile, tocfile, []backup.Role{role1}, emptyMetadataMap)
   327  
   328  			testhelper.AssertQueryRuns(connectionPool, buffer.String())
   329  			defer testhelper.AssertQueryRuns(connectionPool, `DROP ROLE "role1"`)
   330  			role1.Oid = testutils.OidFromObjectName(connectionPool, "", "role1", backup.TYPE_ROLE)
   331  
   332  			resultRoles := backup.GetRoles(connectionPool)
   333  			for _, role := range resultRoles {
   334  				if role.Name == "role1" {
   335  					structmatcher.ExpectStructsToMatch(&role1, role)
   336  					return
   337  				}
   338  			}
   339  			Fail("Role 'role1' was not found")
   340  		})
   341  	})
   342  	Describe("PrintRoleMembershipStatements", func() {
   343  		BeforeEach(func() {
   344  			testhelper.AssertQueryRuns(connectionPool, `CREATE ROLE usergroup`)
   345  			testhelper.AssertQueryRuns(connectionPool, `CREATE ROLE testuser`)
   346  		})
   347  		AfterEach(func() {
   348  			defer testhelper.AssertQueryRuns(connectionPool, `DROP ROLE usergroup`)
   349  			defer testhelper.AssertQueryRuns(connectionPool, `DROP ROLE testuser`)
   350  		})
   351  		It("grants a role without ADMIN OPTION", func() {
   352  			numRoleMembers := len(backup.GetRoleMembers(connectionPool))
   353  			expectedRoleMember := backup.RoleMember{Role: "usergroup", Member: "testuser", Grantor: "testrole", IsAdmin: false}
   354  			backup.PrintRoleMembershipStatements(backupfile, tocfile, []backup.RoleMember{expectedRoleMember})
   355  
   356  			testhelper.AssertQueryRuns(connectionPool, buffer.String())
   357  
   358  			resultRoleMembers := backup.GetRoleMembers(connectionPool)
   359  			Expect(resultRoleMembers).To(HaveLen(numRoleMembers + 1))
   360  			for _, roleMember := range resultRoleMembers {
   361  				if roleMember.Role == "usergroup" {
   362  					structmatcher.ExpectStructsToMatch(&expectedRoleMember, &roleMember)
   363  					return
   364  				}
   365  			}
   366  			Fail("Role 'testuser' is not a member of role 'usergroup'")
   367  		})
   368  		It("grants a role WITH ADMIN OPTION", func() {
   369  			numRoleMembers := len(backup.GetRoleMembers(connectionPool))
   370  			expectedRoleMember := backup.RoleMember{Role: "usergroup", Member: "testuser", Grantor: "testrole", IsAdmin: true}
   371  			backup.PrintRoleMembershipStatements(backupfile, tocfile, []backup.RoleMember{expectedRoleMember})
   372  
   373  			testhelper.AssertQueryRuns(connectionPool, buffer.String())
   374  
   375  			resultRoleMembers := backup.GetRoleMembers(connectionPool)
   376  			Expect(resultRoleMembers).To(HaveLen(numRoleMembers + 1))
   377  			for _, roleMember := range resultRoleMembers {
   378  				if roleMember.Role == "usergroup" {
   379  					structmatcher.ExpectStructsToMatch(&expectedRoleMember, &roleMember)
   380  					return
   381  				}
   382  			}
   383  			Fail("Role 'testuser' is not a member of role 'usergroup'")
   384  		})
   385  	})
   386  	Describe("PrintRoleGUCStatements", func() {
   387  		BeforeEach(func() {
   388  			testhelper.AssertQueryRuns(connectionPool, `CREATE ROLE testuser`)
   389  		})
   390  		AfterEach(func() {
   391  			testhelper.AssertQueryRuns(connectionPool, `DROP ROLE testuser`)
   392  		})
   393  		It("Sets GUCs for a particular role", func() {
   394  			defaultStorageOptionsString := "appendonly=true, compresslevel=6, orientation=row, compresstype=none"
   395  			if true {
   396  				defaultStorageOptionsString = "compresslevel=6, compresstype=none"
   397  			}
   398  
   399  			roleConfigMap := map[string][]backup.RoleGUC{
   400  				"testuser": {
   401  					{RoleName: "testuser", Config: fmt.Sprintf("SET gp_default_storage_options TO '%s'", defaultStorageOptionsString)},
   402  					{RoleName: "testuser", Config: "SET search_path TO public"}},
   403  			}
   404  
   405  			backup.PrintRoleGUCStatements(backupfile, tocfile, roleConfigMap)
   406  
   407  			testhelper.AssertQueryRuns(connectionPool, buffer.String())
   408  
   409  			resultGUCs := backup.GetRoleGUCs(connectionPool)
   410  			Expect(resultGUCs["testuser"]).To(ConsistOf(roleConfigMap["testuser"]))
   411  		})
   412  		It("Sets GUCs for a role in a particular database", func() {
   413  			testutils.SkipIfBefore6(connectionPool)
   414  
   415  			defaultStorageOptionsString := "appendonly=true, compresslevel=6, orientation=row, compresstype=none"
   416  			if true {
   417  				defaultStorageOptionsString = "compresslevel=6, compresstype=none"
   418  			}
   419  
   420  			roleConfigMap := map[string][]backup.RoleGUC{
   421  				"testuser": {
   422  					{RoleName: "testuser", DbName: "testdb", Config: fmt.Sprintf("SET gp_default_storage_options TO '%s'", defaultStorageOptionsString)},
   423  					{RoleName: "testuser", DbName: "testdb", Config: "SET search_path TO public"}},
   424  			}
   425  
   426  			backup.PrintRoleGUCStatements(backupfile, tocfile, roleConfigMap)
   427  
   428  			testhelper.AssertQueryRuns(connectionPool, buffer.String())
   429  
   430  			resultGUCs := backup.GetRoleGUCs(connectionPool)
   431  			Expect(resultGUCs["testuser"]).To(ConsistOf(roleConfigMap["testuser"]))
   432  		})
   433  	})
   434  	Describe("PrintCreateTablespaceStatements", func() {
   435  		var expectedTablespace backup.Tablespace
   436  		BeforeEach(func() {
   437  			if true {
   438  				expectedTablespace = backup.Tablespace{Oid: 1, Tablespace: "test_tablespace", FileLocation: "'/tmp/test_dir'", SegmentLocations: []string{}}
   439  			} else {
   440  				expectedTablespace = backup.Tablespace{Oid: 1, Tablespace: "test_tablespace", FileLocation: "test_dir"}
   441  			}
   442  		})
   443  		It("creates a basic tablespace", func() {
   444  			numTablespaces := len(backup.GetTablespaces(connectionPool))
   445  			emptyMetadataMap := backup.MetadataMap{}
   446  			backup.PrintCreateTablespaceStatements(backupfile, tocfile, []backup.Tablespace{expectedTablespace}, emptyMetadataMap)
   447  
   448  			testhelper.AssertQueryRuns(connectionPool, buffer.String())
   449  			defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLESPACE test_tablespace")
   450  
   451  			resultTablespaces := backup.GetTablespaces(connectionPool)
   452  			Expect(resultTablespaces).To(HaveLen(numTablespaces + 1))
   453  			for _, tablespace := range resultTablespaces {
   454  				if tablespace.Tablespace == "test_tablespace" {
   455  					structmatcher.ExpectStructsToMatchExcluding(&expectedTablespace, &tablespace, "Oid")
   456  					return
   457  				}
   458  			}
   459  			Fail("Tablespace 'test_tablespace' was not created")
   460  		})
   461  		It("creates a basic tablespace with different segment locations and options", func() {
   462  			testutils.SkipIfBefore6(connectionPool)
   463  
   464  			expectedTablespace = backup.Tablespace{
   465  				Oid: 1, Tablespace: "test_tablespace", FileLocation: "'/tmp/test_dir'",
   466  				SegmentLocations: []string{"content0='/tmp/test_dir1'", "content1='/tmp/test_dir2'"},
   467  				Options:          "seq_page_cost=123",
   468  			}
   469  			numTablespaces := len(backup.GetTablespaces(connectionPool))
   470  			emptyMetadataMap := backup.MetadataMap{}
   471  			backup.PrintCreateTablespaceStatements(backupfile, tocfile, []backup.Tablespace{expectedTablespace}, emptyMetadataMap)
   472  
   473  			gbuffer := BufferWithBytes([]byte(buffer.String()))
   474  			entries, _ := testutils.SliceBufferByEntries(tocfile.GlobalEntries, gbuffer)
   475  			create, setOptions := entries[0], entries[1]
   476  			testhelper.AssertQueryRuns(connectionPool, create)
   477  			defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLESPACE test_tablespace")
   478  			testhelper.AssertQueryRuns(connectionPool, setOptions)
   479  
   480  			resultTablespaces := backup.GetTablespaces(connectionPool)
   481  			Expect(resultTablespaces).To(HaveLen(numTablespaces + 1))
   482  			for _, tablespace := range resultTablespaces {
   483  				if tablespace.Tablespace == "test_tablespace" {
   484  					structmatcher.ExpectStructsToMatchExcluding(&expectedTablespace, &tablespace, "Oid")
   485  					return
   486  				}
   487  			}
   488  			Fail("Tablespace 'test_tablespace' was not created")
   489  		})
   490  		It("creates a tablespace with permissions, an owner, security label, and a comment", func() {
   491  			numTablespaces := len(backup.GetTablespaces(connectionPool))
   492  			tablespaceMetadataMap := testutils.DefaultMetadataMap("TABLESPACE", true, true, true, includeSecurityLabels)
   493  			tablespaceMetadata := tablespaceMetadataMap[expectedTablespace.GetUniqueID()]
   494  			backup.PrintCreateTablespaceStatements(backupfile, tocfile, []backup.Tablespace{expectedTablespace}, tablespaceMetadataMap)
   495  
   496  			if true {
   497  				/*
   498  				 * In GPDB 6 and later, a CREATE TABLESPACE statement can't be run in a multi-command string
   499  				 * with other statements, so we execute it separately from the metadata statements.
   500  				 */
   501  				gbuffer := BufferWithBytes([]byte(buffer.String()))
   502  				entries, _ := testutils.SliceBufferByEntries(tocfile.GlobalEntries, gbuffer)
   503  				for _, entry := range entries {
   504  					testhelper.AssertQueryRuns(connectionPool, entry)
   505  				}
   506  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLESPACE test_tablespace")
   507  			} else {
   508  				testhelper.AssertQueryRuns(connectionPool, buffer.String())
   509  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLESPACE test_tablespace")
   510  			}
   511  
   512  			resultTablespaces := backup.GetTablespaces(connectionPool)
   513  			resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_TABLESPACE)
   514  			Expect(resultTablespaces).To(HaveLen(numTablespaces + 1))
   515  			for _, tablespace := range resultTablespaces {
   516  				if tablespace.Tablespace == "test_tablespace" {
   517  					resultMetadata := resultMetadataMap[tablespace.GetUniqueID()]
   518  					structmatcher.ExpectStructsToMatchExcluding(&tablespaceMetadata, &resultMetadata, "Oid")
   519  					structmatcher.ExpectStructsToMatchExcluding(&expectedTablespace, &tablespace, "Oid")
   520  					return
   521  				}
   522  			}
   523  			Fail("Tablespace 'test_tablespace' was not created")
   524  		})
   525  	})
   526  })