Skip to content

Commit

Permalink
test(database): add e2e case of declarative database with delete recl…
Browse files Browse the repository at this point in the history
…aim policy (cloudnative-pg#5774)

Closes cloudnative-pg#5680

Signed-off-by: Gabriele Quaresima <[email protected]>
Signed-off-by: Jaime Silvela <[email protected]>
Signed-off-by: Niccolò Fei <[email protected]>
Signed-off-by: Marco Nenciarini <[email protected]>
Co-authored-by: Jaime Silvela <[email protected]>
Co-authored-by: Niccolò Fei <[email protected]>
Co-authored-by: Marco Nenciarini <[email protected]>
  • Loading branch information
4 people authored Oct 22, 2024
1 parent e5ab643 commit cdc28e0
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 95 deletions.
1 change: 1 addition & 0 deletions contribute/e2e_testing_environment/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ exported, it will select all medium test cases from the feature type provided.
| `security` |
| `maintenance` |
| `tablespaces` |
| `declarative-databases` |

ex:
```shell
Expand Down
4 changes: 4 additions & 0 deletions docs/src/e2e.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,7 @@ and the following suite of E2E tests are performed on that cluster:
* Declarative creation of temporary tablespaces
* Backup / recovery from object storage
* Backup / recovery from volume snapshots

* **Declarative databases**
* Declarative creation of databases with default (retain) reclaim policy
* Declarative creation of databases with delete reclaim policy
192 changes: 113 additions & 79 deletions tests/e2e/declarative_database_management_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ import (
// - spinning up a cluster, apply a declarative database on it

// Set of tests in which we use the declarative database CRD to add new databases on an existing cluster
var _ = Describe("Declarative databases management test", Label(tests.LabelSmoke, tests.LabelBasic), func() {
var _ = Describe("Declarative database management", Label(tests.LabelSmoke, tests.LabelBasic,
tests.LabelDeclarativeDatabases), func() {
const (
clusterManifest = fixturesDir + "/declarative_databases/cluster.yaml.template"
databaseManifest = fixturesDir + "/declarative_databases/database.yaml.template"
level = tests.Medium
clusterManifest = fixturesDir + "/declarative_databases/cluster.yaml.template"
level = tests.Medium
)

BeforeEach(func() {
Expand All @@ -46,15 +46,14 @@ var _ = Describe("Declarative databases management test", Label(tests.LabelSmoke
}
})

Context("plain vanilla cluster", Ordered, func() {
Context("in a plain vanilla cluster", Ordered, func() {
const (
namespacePrefix = "declarative-db"
dbname = "declarative"
)
var (
clusterName, namespace, databaseObjectName string
database *apiv1.Database
err error
clusterName, namespace string
err error
)

BeforeAll(func() {
Expand All @@ -70,27 +69,9 @@ var _ = Describe("Declarative databases management test", Label(tests.LabelSmoke
})
})

assertDatabaseExists := func(namespace, primaryPod, dbname string, shouldContain bool) {
Eventually(func(g Gomega) {
stdout, _, err := env.ExecQueryInInstancePod(
utils.PodLocator{
Namespace: namespace,
PodName: primaryPod,
},
"postgres",
"\\l")
g.Expect(err).ToNot(HaveOccurred())
if shouldContain {
g.Expect(stdout).Should(ContainSubstring(dbname))
} else {
g.Expect(stdout).ShouldNot(ContainSubstring(dbname))
}
}, 300).Should(Succeed())
}

assertDatabaseHasExpectedFields := func(namespace, primaryPod string, db apiv1.Database) {
query := fmt.Sprintf("select count(*) from pg_database where datname = '%s' "+
"and encoding = %s and datctype = '%s' and datcollate = '%s'",
"and encoding = pg_char_to_encoding('%s') and datctype = '%s' and datcollate = '%s'",
db.Spec.Name, db.Spec.Encoding, db.Spec.LcCtype, db.Spec.LcCollate)
Eventually(func(g Gomega) {
stdout, _, err := env.ExecQueryInInstancePod(
Expand All @@ -101,65 +82,118 @@ var _ = Describe("Declarative databases management test", Label(tests.LabelSmoke
"postgres",
query)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(stdout).Should(ContainSubstring("1"))
g.Expect(stdout).Should(ContainSubstring("1"), "expected database not found")
}, 30).Should(Succeed())
}

When("Database CRD reclaim policy is set to retain (default) inside spec", func() {
It("can add a declarative database", func() {
By("applying Database CRD manifest", func() {
CreateResourceFromFile(namespace, databaseManifest)
databaseObjectName, err = env.GetResourceNameFromYAML(databaseManifest)
Expect(err).NotTo(HaveOccurred())
})
By("ensuring the Database CRD succeeded reconciliation", func() {
// get database object
database = &apiv1.Database{}
databaseNamespacedName := types.NamespacedName{
Namespace: namespace,
Name: databaseObjectName,
}

Eventually(func(g Gomega) {
err := env.Client.Get(env.Ctx, databaseNamespacedName, database)
Expect(err).ToNot(HaveOccurred())
g.Expect(database.Status.Ready).Should(BeTrue())
}, 300).WithPolling(10 * time.Second).Should(Succeed())
})

By("verifying new database has been created with the expected fields", func() {
primaryPodInfo, err := env.GetClusterPrimary(namespace, clusterName)
Expect(err).ToNot(HaveOccurred())

assertDatabaseExists(namespace, primaryPodInfo.Name, dbname, true)

// NOTE: the `pg_database` table in Postgres does not contain fields
// for the owner nor the template.
// Its fields are dependent on the version of Postgres, so we pick
// a subset that is available to check even on PG v12
expectedDatabaseFields := apiv1.Database{
Spec: apiv1.DatabaseSpec{
Name: "declarative",
LcCtype: "en_US.utf8",
LcCollate: "C", // this is the default value
Encoding: "0", // corresponds to SQL_ASCII
},
}
assertDatabaseHasExpectedFields(namespace, primaryPodInfo.Name, expectedDatabaseFields)
})
assertTestDeclarativeDatabase := func(
databaseManifest string,
retainOnDeletion bool,
) {
var (
database apiv1.Database
databaseObjectName string
)
By("applying Database CRD manifest", func() {
CreateResourceFromFile(namespace, databaseManifest)
databaseObjectName, err = env.GetResourceNameFromYAML(databaseManifest)
Expect(err).NotTo(HaveOccurred())
})
By("ensuring the Database CRD succeeded reconciliation", func() {
// get database object
database = apiv1.Database{}
databaseNamespacedName := types.NamespacedName{
Namespace: namespace,
Name: databaseObjectName,
}

Eventually(func(g Gomega) {
err := env.Client.Get(env.Ctx, databaseNamespacedName, &database)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(database.Status.Ready).Should(BeTrue())
}, 300).WithPolling(10 * time.Second).Should(Succeed())
})

By("verifying new database has been created with the expected fields", func() {
primaryPodInfo, err := env.GetClusterPrimary(namespace, clusterName)
Expect(err).ToNot(HaveOccurred())

AssertDatabaseExists(primaryPodInfo, dbname, true)

assertDatabaseHasExpectedFields(namespace, primaryPodInfo.Name, database)
})

It("keeps the db when Database CRD is removed", func() {
By("remove Database CRD", func() {
Expect(utils.DeleteObject(env, database)).To(Succeed())
})
By("removing the Database object", func() {
Expect(utils.DeleteObject(env, &database)).To(Succeed())
})

By("verifying database is still existing", func() {
primaryPodInfo, err := env.GetClusterPrimary(namespace, clusterName)
Expect(err).ToNot(HaveOccurred())
By("verifying the retention policy in the postgres database", func() {
primaryPodInfo, err := env.GetClusterPrimary(namespace, clusterName)
Expect(err).ToNot(HaveOccurred())

assertDatabaseExists(namespace, primaryPodInfo.Name, dbname, true)
})
AssertDatabaseExists(primaryPodInfo, dbname, retainOnDeletion)
})
}

When("Database CRD reclaim policy is set to delete", func() {
It("can manage a declarative database and delete it in Postgres", func() {
databaseManifest := fixturesDir +
"/declarative_databases/database-with-delete-reclaim-policy.yaml.template"
assertTestDeclarativeDatabase(databaseManifest,
false)
})
})

When("Database CRD reclaim policy is set to retain", func() {
It("can manage a declarative database and release it", func() {
databaseManifest := fixturesDir + "/declarative_databases/database.yaml.template"
assertTestDeclarativeDatabase(databaseManifest, true)
})
})
})

Context("in a Namespace to be deleted manually", func() {
const (
namespace = "declarative-db-finalizers"
)
var (
err error
clusterName string
databaseObjectName string
)
It("will not prevent the deletion of the namespace with lagging finalizers", func() {
By("setting up the new namespace and cluster", func() {
err = env.CreateNamespace(namespace)
Expect(err).ToNot(HaveOccurred())

clusterName, err = env.GetResourceNameFromYAML(clusterManifest)
Expect(err).ToNot(HaveOccurred())

AssertCreateCluster(namespace, clusterName, clusterManifest, env)
})
By("creating the database", func() {
databaseManifest := fixturesDir +
"/declarative_databases/database-with-delete-reclaim-policy.yaml.template"
databaseObjectName, err = env.GetResourceNameFromYAML(databaseManifest)
Expect(err).NotTo(HaveOccurred())
CreateResourceFromFile(namespace, databaseManifest)
})
By("ensuring the database is reconciled successfully", func() {
// get database object
dbObj := &apiv1.Database{}
databaseNamespacedName := types.NamespacedName{
Namespace: namespace,
Name: databaseObjectName,
}
Eventually(func(g Gomega) {
err := env.Client.Get(env.Ctx, databaseNamespacedName, dbObj)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(dbObj.Status.Ready).Should(BeTrue())
}, 300).WithPolling(10 * time.Second).Should(Succeed())
})
By("deleting the namespace and making sure it succeeds before timeout", func() {
err := env.DeleteNamespaceAndWait(namespace, 60)
Expect(err).ToNot(HaveOccurred())
})
})
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: postgresql.cnpg.io/v1
kind: Database
metadata:
name: db-declarative-delete
spec:
name: declarative
owner: app
lc_ctype: C
lc_collate: C
encoding: UTF8
databaseReclaimPolicy: delete
cluster:
name: cluster-with-declarative-databases
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ spec:
name: declarative
owner: app
lc_ctype: "en_US.utf8"
lc_collate: C
encoding: SQL_ASCII
template: template0
cluster:
Expand Down
35 changes: 19 additions & 16 deletions tests/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,28 @@ const (
// LabelBackupRestore is a label for only selecting backup and restore tests
LabelBackupRestore = "backup-restore"

// LabelBasic is a label for selecting basic test
// LabelBasic is a label for selecting basic tests
LabelBasic = "basic"

// LabelClusterMetadata is a label for selecting cluster-metadata test
// LabelClusterMetadata is a label for selecting cluster-metadata tests
LabelClusterMetadata = "cluster-metadata"

// LabelDeclarativeDatabases is a label for selecting the declarative databases test
LabelDeclarativeDatabases = "declarative-databases"

// LabelDisruptive is the string for labelling disruptive tests
LabelDisruptive = "disruptive"

// LabelImportingDatabases is a label for selecting importing-databases test
// LabelImportingDatabases is a label for selecting the importing-databases test
LabelImportingDatabases = "importing-databases"

// LabelMaintenance is a label for selecting maintenance test
// LabelMaintenance is a label for selecting maintenance tests
LabelMaintenance = "maintenance"

// LabelNoOpenshift is the string for labelling tests that don't run on Openshift
// LabelNoOpenshift is the string for selecting tests that don't run on Openshift
LabelNoOpenshift = "no-openshift"

// LabelObservability is a label for selecting observability test
// LabelObservability is a label for selecting observability tests
LabelObservability = "observability"

// LabelOperator is a label for only selecting operator tests
Expand All @@ -50,7 +53,7 @@ const (
// LabelPerformance is the string for labelling performance tests
LabelPerformance = "performance"

// LabelPlugin is a label for selecting plugin test
// LabelPlugin is a label for selecting plugin tests
LabelPlugin = "plugin"

// LabelPodScheduling is a label for selecting pod-scheduling test
Expand All @@ -59,33 +62,33 @@ const (
// LabelPostgresConfiguration is a label for selecting postgres-configuration test
LabelPostgresConfiguration = "postgres-configuration"

// LabelRecovery is a label for selecting recovery test
// LabelRecovery is a label for selecting recovery tests
LabelRecovery = "recovery"

// LabelReplication is a label for selecting replication test
// LabelReplication is a label for selecting replication tests
LabelReplication = "replication"

// LabelSecurity is a label for selecting security test
// LabelSecurity is a label for selecting security tests
LabelSecurity = "security"

// LabelSelfHealing is a label for selecting self-healing test
// LabelSelfHealing is a label for selecting self-healing tests
LabelSelfHealing = "self-healing"

// LabelServiceConnectivity is a label for selecting service connections test
// LabelServiceConnectivity is a label for selecting service connections tests
LabelServiceConnectivity = "service-connectivity"

// LabelSmoke is a label for selecting smoke test
// LabelSmoke is a label for selecting smoke tests
LabelSmoke = "smoke"

// LabelSnapshot is a label for selecting snapshot tests
LabelSnapshot = "snapshot"

// LabelStorage is a label for selecting storage test
// LabelStorage is a label for selecting storage tests
LabelStorage = "storage"

// LabelTablespaces is a lable for selectin the tablespaces tests
// LabelTablespaces is a label for selecting the tablespaces test
LabelTablespaces = "tablespaces"

// LabelUpgrade is the string for labelling upgrade tests
// LabelUpgrade is a label for upgrade tests
LabelUpgrade = "upgrade"
)

0 comments on commit cdc28e0

Please sign in to comment.