Skip to content

Commit

Permalink
test: new unit test verifying finalizer removal
Browse files Browse the repository at this point in the history
Signed-off-by: Jaime Silvela <[email protected]>
  • Loading branch information
jsilvela authored and NiccoloFei committed Oct 22, 2024
1 parent 8285528 commit f3def85
Showing 1 changed file with 85 additions and 5 deletions.
90 changes: 85 additions & 5 deletions internal/management/controller/database_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/DATA-DOG/go-sqlmock"
"github.com/jackc/pgx/v5"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
Expand Down Expand Up @@ -78,8 +79,9 @@ var _ = Describe("Managed Database status", func() {
ClusterRef: corev1.LocalObjectReference{
Name: cluster.Name,
},
Name: "db-one",
Owner: "app",
ReclaimPolicy: apiv1.DatabaseReclaimDelete,
Name: "db-one",
Owner: "app",
},
}

Expand Down Expand Up @@ -112,7 +114,8 @@ var _ = Describe("Managed Database status", func() {
Expect(dbMock.ExpectationsWereMet()).To(Succeed())
})

It("database object shows ready on success", func(ctx SpecContext) {
It("adds finalizer and sets status ready on success", func(ctx SpecContext) {
Expect(database.Finalizers).To(BeEmpty())
// Mocking DetectDB
expectedValue := sqlmock.NewRows([]string{""}).AddRow("0")
dbMock.ExpectQuery(`SELECT count(*)
Expand Down Expand Up @@ -141,6 +144,7 @@ var _ = Describe("Managed Database status", func() {

Expect(updatedDatabase.Status.Ready).Should(BeTrue())
Expect(updatedDatabase.Status.Error).Should(BeEmpty())
Expect(updatedDatabase.Finalizers).NotTo(BeEmpty())
})

It("database object inherits error after patching", func(ctx SpecContext) {
Expand Down Expand Up @@ -175,7 +179,83 @@ var _ = Describe("Managed Database status", func() {
Expect(updatedDatabase.Status.Error).Should(ContainSubstring(expectedError.Error()))
})

It("database object skips reconciliation if cluster isn't found (deleted cluster)", func(ctx SpecContext) {
It("on deleting it removes finalizers and drops DB", func(ctx SpecContext) {
Expect(database.Finalizers).To(BeEmpty())
// Mocking DetectDB
expectedValue := sqlmock.NewRows([]string{""}).AddRow("0")
dbMock.ExpectQuery(`SELECT count(*)
FROM pg_database
WHERE datname = $1`).WithArgs(database.Spec.Name).WillReturnRows(expectedValue)

expectedCreate := sqlmock.NewResult(0, 1)
expectedQuery := fmt.Sprintf(
"CREATE DATABASE %s OWNER %s",
pgx.Identifier{database.Spec.Name}.Sanitize(), pgx.Identifier{database.Spec.Owner}.Sanitize(),
)
dbMock.ExpectExec(expectedQuery).WillReturnResult(expectedCreate)

_, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: types.NamespacedName{
Namespace: database.Namespace,
Name: database.Name,
}})
Expect(err).ToNot(HaveOccurred())

var updatedDatabase apiv1.Database
err = fakeClient.Get(ctx, client.ObjectKey{
Namespace: database.Namespace,
Name: database.Name,
}, &updatedDatabase)
Expect(err).ToNot(HaveOccurred())

Expect(updatedDatabase.Status.Ready).Should(BeTrue())
Expect(updatedDatabase.Status.Error).Should(BeEmpty())

Expect(updatedDatabase.Finalizers).NotTo(BeEmpty())

// the next 3 lines are a hacky bit to make sure the next reconciler
// call doesn't skip on account of Generation == ObservedGeneration.
// See fake.Client known issues with `Generation`
// https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/client/[email protected]#NewClientBuilder
currentDatabase := updatedDatabase.DeepCopy()
updatedDatabase.Status.ObservedGeneration = 2
Expect(fakeClient.Status().Patch(ctx, &updatedDatabase, client.MergeFrom(currentDatabase))).To(Succeed())

// We now look at the behavior when we delete the Database object

Expect(fakeClient.Delete(ctx, database)).To(Succeed())
// the Database object is Deleted, but its finalizer prevents removal from
// the API
var fadingDatabase apiv1.Database
err = fakeClient.Get(ctx, client.ObjectKey{
Namespace: database.Namespace,
Name: database.Name,
}, &fadingDatabase)
Expect(err).ToNot(HaveOccurred())
Expect(fadingDatabase.DeletionTimestamp).NotTo(BeZero())
Expect(fadingDatabase.Finalizers).NotTo(BeEmpty())

// Mocking Drop Database
expectedDrop := fmt.Sprintf("DROP DATABASE IF EXISTS %s",
pgx.Identifier{database.Spec.Name}.Sanitize(),
)
dbMock.ExpectExec(expectedDrop).WillReturnResult(sqlmock.NewResult(0, 1))

_, err = r.Reconcile(ctx, ctrl.Request{NamespacedName: types.NamespacedName{
Namespace: database.Namespace,
Name: database.Name,
}})
Expect(err).ToNot(HaveOccurred())

var finalDatabase apiv1.Database
err = fakeClient.Get(ctx, client.ObjectKey{
Namespace: database.Namespace,
Name: database.Name,
}, &finalDatabase)
Expect(err).To(HaveOccurred())
Expect(apierrors.IsNotFound(err)).To(BeTrue())
})

It("skips reconciliation if cluster isn't found (deleted cluster)", func(ctx SpecContext) {
// since the fakeClient has the `cluster-example` cluster, let's reference
// another cluster `cluster-other` that is not found by the fakeClient
pgInstance := postgres.NewInstance().
Expand Down Expand Up @@ -214,7 +294,7 @@ var _ = Describe("Managed Database status", func() {
Expect(updatedDatabase.Status.Error).Should(BeEmpty())
})

It("database skips reconciliation if database isn't found (deleted database)", func(ctx SpecContext) {
It("skips reconciliation if database object isn't found (deleted database)", func(ctx SpecContext) {
// since the fakeClient has the `cluster-example` cluster, let's reference
// another cluster `cluster-other` that is not found by the fakeClient
otherDatabase := &apiv1.Database{
Expand Down

0 comments on commit f3def85

Please sign in to comment.