diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8eaa3f7..f9afe66 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: build-and-release: needs: test runs-on: ubuntu-24.04 - timeout-minutes: 15 + timeout-minutes: 5 steps: - uses: actions/checkout@v6 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 475903f..1c995fb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,7 +7,7 @@ jobs: test: name: Tests (PostgreSQL ${{ matrix.postgres-version }}) runs-on: ubuntu-24.04 - timeout-minutes: 5 + timeout-minutes: 10 strategy: fail-fast: false matrix: diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 143080a..c18543b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,7 @@ checkstyle = "13.0.0" datafaker = "2.5.3" errorProne = "2.46.0" errorPronePlugin = "4.4.0" -nullAway = "0.13.0" +nullAway = "0.13.1" [plugins] # https://github.com/allegro/axion-release-plugin diff --git a/operator/src/main/java/it/aboutbits/postgresql/core/ClusterReference.java b/operator/src/main/java/it/aboutbits/postgresql/core/ClusterReference.java index 9e2cc6a..b1b9a7d 100644 --- a/operator/src/main/java/it/aboutbits/postgresql/core/ClusterReference.java +++ b/operator/src/main/java/it/aboutbits/postgresql/core/ClusterReference.java @@ -13,7 +13,7 @@ public class ClusterReference { @Required @ValidationRule( - value = "self.size() > 0", + value = "self.trim().size() > 0", message = "The ClusterReference name must not be empty." ) private String name = ""; diff --git a/operator/src/main/java/it/aboutbits/postgresql/core/SecretRef.java b/operator/src/main/java/it/aboutbits/postgresql/core/SecretRef.java index 3267b1b..9e4b57a 100644 --- a/operator/src/main/java/it/aboutbits/postgresql/core/SecretRef.java +++ b/operator/src/main/java/it/aboutbits/postgresql/core/SecretRef.java @@ -13,7 +13,7 @@ public class SecretRef { @Required @ValidationRule( - value = "self.size() > 0", + value = "self.trim().size() > 0", message = "The SecretRef name must not be empty." ) private String name = ""; diff --git a/operator/src/main/java/it/aboutbits/postgresql/crd/clusterconnection/ClusterConnectionReconciler.java b/operator/src/main/java/it/aboutbits/postgresql/crd/clusterconnection/ClusterConnectionReconciler.java index 1afc816..56430f0 100644 --- a/operator/src/main/java/it/aboutbits/postgresql/crd/clusterconnection/ClusterConnectionReconciler.java +++ b/operator/src/main/java/it/aboutbits/postgresql/crd/clusterconnection/ClusterConnectionReconciler.java @@ -26,6 +26,16 @@ public UpdateControl reconcile( ) { var status = initializeStatus(resource); + var name = resource.getMetadata().getName(); + var namespace = resource.getMetadata().getNamespace(); + + log.info( + "Reconciling ClusterConnection [resource={}/{}, status.phase={}]", + namespace, + name, + status.getPhase() + ); + try (var dsl = contextFactory.getDSLContext(resource)) { var version = dsl.fetchSingle("select version()").into(String.class); diff --git a/operator/src/main/java/it/aboutbits/postgresql/crd/clusterconnection/ClusterConnectionSpec.java b/operator/src/main/java/it/aboutbits/postgresql/crd/clusterconnection/ClusterConnectionSpec.java index 32316ff..65b4ec8 100644 --- a/operator/src/main/java/it/aboutbits/postgresql/crd/clusterconnection/ClusterConnectionSpec.java +++ b/operator/src/main/java/it/aboutbits/postgresql/crd/clusterconnection/ClusterConnectionSpec.java @@ -18,7 +18,7 @@ public class ClusterConnectionSpec { @Required @ValidationRule( - value = "self.size() > 0", + value = "self.trim().size() > 0", message = "The ClusterConnection host must not be empty." ) private String host = ""; @@ -30,7 +30,7 @@ public class ClusterConnectionSpec { @Required @ValidationRule( - value = "self.size() > 0", + value = "self.trim().size() > 0", message = "The ClusterConnection database must not be empty." ) private String database = "postgres"; diff --git a/operator/src/main/java/it/aboutbits/postgresql/crd/database/DatabaseReconciler.java b/operator/src/main/java/it/aboutbits/postgresql/crd/database/DatabaseReconciler.java index 86c5645..8e96de0 100644 --- a/operator/src/main/java/it/aboutbits/postgresql/crd/database/DatabaseReconciler.java +++ b/operator/src/main/java/it/aboutbits/postgresql/crd/database/DatabaseReconciler.java @@ -119,7 +119,7 @@ public DeleteControl cleanup( context.getClient().resource(resource).patchStatus(); return DeleteControl.noFinalizerRemoval() - .rescheduleAfter(1, TimeUnit.SECONDS); + .rescheduleAfter(100, TimeUnit.MILLISECONDS); } // We do not actually delete the database if the reclaimPolicy is set to RETAIN, we only delete the CR instance diff --git a/operator/src/main/java/it/aboutbits/postgresql/crd/database/DatabaseSpec.java b/operator/src/main/java/it/aboutbits/postgresql/crd/database/DatabaseSpec.java index 53fc170..0eadc44 100644 --- a/operator/src/main/java/it/aboutbits/postgresql/crd/database/DatabaseSpec.java +++ b/operator/src/main/java/it/aboutbits/postgresql/crd/database/DatabaseSpec.java @@ -22,7 +22,7 @@ public class DatabaseSpec { message = "The Database name is immutable. Allowing to rename the Database name using 'alter database rename to ' would add unwanted side-effects to the Operator." ) @ValidationRule( - value = "self.size() > 0", + value = "self.trim().size() > 0", message = "The Database name must not be empty." ) private String name = ""; diff --git a/operator/src/main/java/it/aboutbits/postgresql/crd/defaultprivilege/DefaultPrivilegeReconciler.java b/operator/src/main/java/it/aboutbits/postgresql/crd/defaultprivilege/DefaultPrivilegeReconciler.java index 11a2698..6b2c315 100644 --- a/operator/src/main/java/it/aboutbits/postgresql/crd/defaultprivilege/DefaultPrivilegeReconciler.java +++ b/operator/src/main/java/it/aboutbits/postgresql/crd/defaultprivilege/DefaultPrivilegeReconciler.java @@ -141,7 +141,7 @@ public DeleteControl cleanup( context.getClient().resource(resource).patchStatus(); return DeleteControl.noFinalizerRemoval() - .rescheduleAfter(1, TimeUnit.SECONDS); + .rescheduleAfter(100, TimeUnit.MILLISECONDS); } var clusterRef = spec.getClusterRef(); @@ -164,9 +164,10 @@ public DeleteControl cleanup( .rescheduleAfter(60, TimeUnit.SECONDS); } + var database = spec.getDatabase(); var clusterConnection = clusterConnectionOptional.get(); - try (var dsl = contextFactory.getDSLContext(clusterConnection)) { + try (var dsl = contextFactory.getDSLContext(clusterConnection, database)) { dsl.transaction(cfg -> { var tx = cfg.dsl(); diff --git a/operator/src/main/java/it/aboutbits/postgresql/crd/defaultprivilege/DefaultPrivilegeService.java b/operator/src/main/java/it/aboutbits/postgresql/crd/defaultprivilege/DefaultPrivilegeService.java index c509a24..990dc87 100644 --- a/operator/src/main/java/it/aboutbits/postgresql/crd/defaultprivilege/DefaultPrivilegeService.java +++ b/operator/src/main/java/it/aboutbits/postgresql/crd/defaultprivilege/DefaultPrivilegeService.java @@ -41,6 +41,7 @@ public Set determineCurrentDefaultPrivileges( DSLContext tx, DefaultPrivilegeSpec spec ) { + var owner = spec.getOwner(); var role = spec.getRole(); var schema = spec.getSchema(); @@ -65,6 +66,11 @@ public Set determineCurrentDefaultPrivileges( .from(PG_DEFAULT_ACL) .crossJoin(Routines.aclexplode(PG_DEFAULT_ACL.DEFACLACL)) .where( + PG_DEFAULT_ACL.DEFACLROLE.eq(field( + ROLE_OID_SQL, + OID_DATA_TYPE, + val(owner) + )), PG_DEFAULT_ACL.DEFACLOBJTYPE.eq(objectType.objectTypeChar()), objectType == SCHEMA ? noCondition() diff --git a/operator/src/main/java/it/aboutbits/postgresql/crd/grant/GrantReconciler.java b/operator/src/main/java/it/aboutbits/postgresql/crd/grant/GrantReconciler.java index d5adb51..2c2da1d 100644 --- a/operator/src/main/java/it/aboutbits/postgresql/crd/grant/GrantReconciler.java +++ b/operator/src/main/java/it/aboutbits/postgresql/crd/grant/GrantReconciler.java @@ -146,7 +146,7 @@ public DeleteControl cleanup( context.getClient().resource(resource).patchStatus(); return DeleteControl.noFinalizerRemoval() - .rescheduleAfter(1, TimeUnit.SECONDS); + .rescheduleAfter(100, TimeUnit.MILLISECONDS); } var clusterRef = spec.getClusterRef(); @@ -213,7 +213,7 @@ protected CRStatus newStatus() { return new CRStatus(); } - @SuppressWarnings("java:S3776") + @SuppressWarnings({"checkstyle:MethodLength", "java:S3776"}) private UpdateControl reconcileInTransaction( DSLContext tx, Grant resource, diff --git a/operator/src/main/java/it/aboutbits/postgresql/crd/role/RoleReconciler.java b/operator/src/main/java/it/aboutbits/postgresql/crd/role/RoleReconciler.java index 2926467..9850008 100644 --- a/operator/src/main/java/it/aboutbits/postgresql/crd/role/RoleReconciler.java +++ b/operator/src/main/java/it/aboutbits/postgresql/crd/role/RoleReconciler.java @@ -149,7 +149,7 @@ public DeleteControl cleanup( context.getClient().resource(resource).patchStatus(); return DeleteControl.noFinalizerRemoval() - .rescheduleAfter(1, TimeUnit.SECONDS); + .rescheduleAfter(100, TimeUnit.MILLISECONDS); } var clusterRef = spec.getClusterRef(); diff --git a/operator/src/main/java/it/aboutbits/postgresql/crd/role/RoleSpec.java b/operator/src/main/java/it/aboutbits/postgresql/crd/role/RoleSpec.java index 777a89d..1207cfe 100644 --- a/operator/src/main/java/it/aboutbits/postgresql/crd/role/RoleSpec.java +++ b/operator/src/main/java/it/aboutbits/postgresql/crd/role/RoleSpec.java @@ -27,7 +27,7 @@ public class RoleSpec { message = "The Role name is immutable. Allowing to rename the Role name using 'alter role rename to ' would add unwanted side-effects to the Operator." ) @ValidationRule( - value = "self.size() > 0", + value = "self.trim().size() > 0", message = "The Role name must not be empty." ) private String name = ""; diff --git a/operator/src/main/java/it/aboutbits/postgresql/crd/schema/SchemaReconciler.java b/operator/src/main/java/it/aboutbits/postgresql/crd/schema/SchemaReconciler.java index a4e6c6d..54acc4d 100644 --- a/operator/src/main/java/it/aboutbits/postgresql/crd/schema/SchemaReconciler.java +++ b/operator/src/main/java/it/aboutbits/postgresql/crd/schema/SchemaReconciler.java @@ -121,7 +121,7 @@ public DeleteControl cleanup( context.getClient().resource(resource).patchStatus(); return DeleteControl.noFinalizerRemoval() - .rescheduleAfter(1, TimeUnit.SECONDS); + .rescheduleAfter(100, TimeUnit.MILLISECONDS); } // We do not actually delete the schema if the reclaimPolicy is set to RETAIN, we only delete the CR instance diff --git a/operator/src/main/java/it/aboutbits/postgresql/crd/schema/SchemaSpec.java b/operator/src/main/java/it/aboutbits/postgresql/crd/schema/SchemaSpec.java index 5a9a4b6..2038ca3 100644 --- a/operator/src/main/java/it/aboutbits/postgresql/crd/schema/SchemaSpec.java +++ b/operator/src/main/java/it/aboutbits/postgresql/crd/schema/SchemaSpec.java @@ -22,7 +22,7 @@ public class SchemaSpec { message = "The Schema name is immutable. Allowing to rename the Schema name using 'alter schema rename to ' would add unwanted side-effects to the Operator." ) @ValidationRule( - value = "self.size() > 0", + value = "self.trim().size() > 0", message = "The Schema name must not be empty." ) private String name = ""; diff --git a/operator/src/test/java/it/aboutbits/postgresql/PostgreSQLInstanceReadinessCheckTest.java b/operator/src/test/java/it/aboutbits/postgresql/PostgreSQLInstanceReadinessCheckTest.java index dd04b70..548a2e0 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/PostgreSQLInstanceReadinessCheckTest.java +++ b/operator/src/test/java/it/aboutbits/postgresql/PostgreSQLInstanceReadinessCheckTest.java @@ -2,8 +2,8 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.quarkus.test.junit.QuarkusTest; +import it.aboutbits.postgresql._support.testdata.base.TestUtil; import it.aboutbits.postgresql._support.testdata.persisted.Given; -import it.aboutbits.postgresql.crd.clusterconnection.ClusterConnection; import jakarta.inject.Inject; import org.eclipse.microprofile.health.HealthCheckResponse; import org.eclipse.microprofile.health.Readiness; @@ -12,7 +12,6 @@ import org.junit.jupiter.api.Test; import java.util.Objects; -import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; @@ -30,10 +29,8 @@ class PostgreSQLInstanceReadinessCheckTest { KubernetesClient kubernetesClient; @BeforeEach - void cleanUp() { - kubernetesClient.resources(ClusterConnection.class) - .withTimeout(5, TimeUnit.SECONDS) - .delete(); + void resetEnvironment() { + TestUtil.resetEnvironment(kubernetesClient); } @Test diff --git a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/base/TestDataCreator.java b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/base/TestDataCreator.java index e7e871b..956b87a 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/base/TestDataCreator.java +++ b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/base/TestDataCreator.java @@ -62,7 +62,8 @@ public static String randomKubernetesNameSuffix(String name) { } var separator = "-"; - var suffixLength = maxLength - name.length() - separator.length(); + var availableSpace = maxLength - name.length() - separator.length(); + var suffixLength = Math.min(7, availableSpace); return name + separator + FAKER.regexify("[a-z0-9]{%d}".formatted(suffixLength)); } diff --git a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/base/TestUtil.java b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/base/TestUtil.java new file mode 100644 index 0000000..178698a --- /dev/null +++ b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/base/TestUtil.java @@ -0,0 +1,44 @@ +package it.aboutbits.postgresql._support.testdata.base; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.client.KubernetesClient; +import it.aboutbits.postgresql.crd.clusterconnection.ClusterConnection; +import it.aboutbits.postgresql.crd.database.Database; +import it.aboutbits.postgresql.crd.defaultprivilege.DefaultPrivilege; +import it.aboutbits.postgresql.crd.grant.Grant; +import it.aboutbits.postgresql.crd.role.Role; +import it.aboutbits.postgresql.crd.schema.Schema; +import org.jspecify.annotations.NullMarked; + +import java.util.concurrent.TimeUnit; + +import static org.awaitility.Awaitility.await; + +@NullMarked +public final class TestUtil { + public static void resetEnvironment(KubernetesClient kubernetesClient) { + // Reverse Dependency Deletion + deleteResource(kubernetesClient, DefaultPrivilege.class); + deleteResource(kubernetesClient, Grant.class); + deleteResource(kubernetesClient, Schema.class); + deleteResource(kubernetesClient, Role.class); + deleteResource(kubernetesClient, Database.class); + deleteResource(kubernetesClient, ClusterConnection.class); + } + + public static void deleteResource( + KubernetesClient kubernetesClient, + Class resourceClass + ) { + // Async call to the Kubernetes API Server that triggers the Operator Controllers + kubernetesClient.resources(resourceClass).delete(); + + // Wait for the Operator Controller to finish the CR cleanup + await().atMost(5, TimeUnit.SECONDS) + .pollInterval(100, TimeUnit.MILLISECONDS) + .until(() -> kubernetesClient.resources(resourceClass).list().getItems().isEmpty()); + } + + private TestUtil() { + } +} diff --git a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/Given.java b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/Given.java index 422df54..3f3ab98 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/Given.java +++ b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/Given.java @@ -99,6 +99,7 @@ public RoleCreate role() { public DatabaseCreate database() { return new DatabaseCreate( numberOfItems, + given, kubernetesClient ); } @@ -106,6 +107,7 @@ public DatabaseCreate database() { public SchemaCreate schema() { return new SchemaCreate( numberOfItems, + given, kubernetesClient ); } diff --git a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/ClusterConnectionCreate.java b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/ClusterConnectionCreate.java index 11185df..0c27ae5 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/ClusterConnectionCreate.java +++ b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/ClusterConnectionCreate.java @@ -100,7 +100,7 @@ protected ClusterConnection create(int index) { .inNamespace(namespace) .withName(name) .waitUntilCondition( - clusterConnection -> clusterConnection.getStatus() != null, + clusterConnection -> clusterConnection != null && clusterConnection.getStatus() != null, 5, TimeUnit.SECONDS ); @@ -116,7 +116,9 @@ private String getNamespace() { return withNamespace; } - return kubernetesClient.getNamespace(); + withNamespace = kubernetesClient.getNamespace(); + + return withNamespace; } private String getName() { @@ -124,7 +126,9 @@ private String getName() { return withName; } - return randomKubernetesNameSuffix("test-cluster-connection"); + withName = randomKubernetesNameSuffix("test-cluster-connection"); + + return withName; } private String getHost() { @@ -132,7 +136,9 @@ private String getHost() { return withHost; } - return "localhost"; + withHost = "localhost"; + + return withHost; } private int getPort() { @@ -140,14 +146,18 @@ private int getPort() { return withPort; } - return dbConnectionDetails.port(); + withPort = dbConnectionDetails.port(); + + return withPort; } private String getDatabase() { - return Objects.requireNonNullElse( + withDatabase = Objects.requireNonNullElse( withDatabase, "postgres" ); + + return withDatabase; } private SecretRef getAdminSecretRef() { diff --git a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/DatabaseCreate.java b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/DatabaseCreate.java index 7b4260c..1b0071c 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/DatabaseCreate.java +++ b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/DatabaseCreate.java @@ -3,6 +3,7 @@ import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.client.KubernetesClient; import it.aboutbits.postgresql._support.testdata.base.TestDataCreator; +import it.aboutbits.postgresql._support.testdata.persisted.Given; import it.aboutbits.postgresql.core.ClusterReference; import it.aboutbits.postgresql.core.ReclaimPolicy; import it.aboutbits.postgresql.crd.database.Database; @@ -13,13 +14,14 @@ import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; -import java.util.Objects; import java.util.concurrent.TimeUnit; @NullMarked @Setter @Accessors(fluent = true, chain = true) public class DatabaseCreate extends TestDataCreator { + private final Given given; + private final KubernetesClient kubernetesClient; @Nullable @@ -43,9 +45,11 @@ public class DatabaseCreate extends TestDataCreator { public DatabaseCreate( int numberOfItems, + Given given, KubernetesClient kubernetesClient ) { super(numberOfItems); + this.given = given; this.kubernetesClient = kubernetesClient; } @@ -90,7 +94,7 @@ protected Database create(int index) { .inNamespace(namespace) .withName(name) .waitUntilCondition( - db -> db.getStatus() != null, + db -> db != null && db.getStatus() != null, 5, TimeUnit.SECONDS ); @@ -106,7 +110,9 @@ private String getNamespace() { return withNamespace; } - return kubernetesClient.getNamespace(); + withNamespace = kubernetesClient.getNamespace(); + + return withNamespace; } private String getName() { @@ -114,13 +120,23 @@ private String getName() { return withName; } - return randomKubernetesNameSuffix("test-database"); + withName = randomKubernetesNameSuffix("test-database"); + + return withName; } private String getClusterConnectionName() { - return Objects.requireNonNullElse( - withClusterConnectionName, - "test-cluster-connection" - ); + if (withClusterConnectionName != null) { + return withClusterConnectionName; + } + + var clusterConnection = given.one() + .clusterConnection() + .withName("%s-conn".formatted(getName())) + .returnFirst(); + + withClusterConnectionNamespace = clusterConnection.getMetadata().getNamespace(); + + return clusterConnection.getMetadata().getName(); } } diff --git a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/DefaultPrivilegeCreate.java b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/DefaultPrivilegeCreate.java index c4aa865..8982c99 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/DefaultPrivilegeCreate.java +++ b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/DefaultPrivilegeCreate.java @@ -17,9 +17,10 @@ import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.concurrent.TimeUnit; +import static it.aboutbits.postgresql.core.ReclaimPolicy.DELETE; + @NullMarked @Setter @Accessors(fluent = true, chain = true) @@ -133,7 +134,7 @@ protected DefaultPrivilege create(int index) { .inNamespace(namespace) .withName(name) .waitUntilCondition( - defaultPrivilege -> defaultPrivilege.getStatus() != null, + defaultPrivilege -> defaultPrivilege != null && defaultPrivilege.getStatus() != null, 5, TimeUnit.SECONDS ); @@ -149,7 +150,9 @@ private String getNamespace() { return withNamespace; } - return kubernetesClient.getNamespace(); + withNamespace = kubernetesClient.getNamespace(); + + return withNamespace; } private String getName() { @@ -157,14 +160,24 @@ private String getName() { return withName; } - return randomKubernetesNameSuffix("test-default-privilege"); + withName = randomKubernetesNameSuffix("test-default-privilege"); + + return withName; } private String getClusterConnectionName() { - return Objects.requireNonNullElse( - withClusterConnectionName, - "test-cluster-connection" - ); + if (withClusterConnectionName != null) { + return withClusterConnectionName; + } + + var clusterConnection = given.one() + .clusterConnection() + .withName("%s-conn".formatted(getName())) + .returnFirst(); + + withClusterConnectionNamespace = clusterConnection.getMetadata().getNamespace(); + + return clusterConnection.getMetadata().getName(); } private String getDatabase() { @@ -172,11 +185,16 @@ private String getDatabase() { return withDatabase; } - return given.one() + var item = given.one() .database() - .returnFirst() - .getSpec() - .getName(); + .withClusterConnectionName(getClusterConnectionName()) + .withClusterConnectionNamespace(withClusterConnectionNamespace) + .withReclaimPolicy(DELETE) + .returnFirst(); + + withDatabase = item.getSpec().getName(); + + return withDatabase; } private String getRole() { @@ -184,11 +202,15 @@ private String getRole() { return withRole; } - return given.one() + var item = given.one() .role() - .returnFirst() - .getSpec() - .getName(); + .withClusterConnectionName(getClusterConnectionName()) + .withClusterConnectionNamespace(withClusterConnectionNamespace) + .returnFirst(); + + withRole = item.getSpec().getName(); + + return withRole; } private String getOwner() { @@ -196,11 +218,15 @@ private String getOwner() { return withOwner; } - return given.one() + var item = given.one() .role() - .returnFirst() - .getSpec() - .getName(); + .withClusterConnectionName(getClusterConnectionName()) + .withClusterConnectionNamespace(withClusterConnectionNamespace) + .returnFirst(); + + withOwner = item.getSpec().getName(); + + return withOwner; } private String getSchema() { @@ -208,10 +234,34 @@ private String getSchema() { return withSchema; } - return given.one() + var databaseName = getDatabase(); + if (databaseName.isBlank()) { + databaseName = given.one() + .database() + .withClusterConnectionName(getClusterConnectionName()) + .withClusterConnectionNamespace(withClusterConnectionNamespace) + .withReclaimPolicy(DELETE) + .returnFirst() + .getSpec() + .getName(); + } + + var clusterConnectionDb = given.one() + .clusterConnection() + .withName(getClusterConnectionName() + "-db") + .withNamespace(withClusterConnectionNamespace) + .withDatabase(databaseName) + .returnFirst(); + + var item = given.one() .schema() - .returnFirst() - .getSpec() - .getName(); + .withClusterConnectionName(clusterConnectionDb.getMetadata().getName()) + .withClusterConnectionNamespace(clusterConnectionDb.getMetadata().getNamespace()) + .withReclaimPolicy(DELETE) + .returnFirst(); + + withSchema = item.getSpec().getName(); + + return withSchema; } } diff --git a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/GrantCreate.java b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/GrantCreate.java index 750060e..2cbc55d 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/GrantCreate.java +++ b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/GrantCreate.java @@ -17,9 +17,10 @@ import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.concurrent.TimeUnit; +import static it.aboutbits.postgresql.core.ReclaimPolicy.DELETE; + @NullMarked @Setter @Accessors(fluent = true, chain = true) @@ -151,7 +152,7 @@ protected Grant create(int index) { .inNamespace(namespace) .withName(name) .waitUntilCondition( - grant -> grant.getStatus() != null, + grant -> grant != null && grant.getStatus() != null, 5, TimeUnit.SECONDS ); @@ -167,7 +168,9 @@ private String getNamespace() { return withNamespace; } - return kubernetesClient.getNamespace(); + withNamespace = kubernetesClient.getNamespace(); + + return withNamespace; } private String getName() { @@ -175,14 +178,24 @@ private String getName() { return withName; } - return randomKubernetesNameSuffix("test-grant"); + withName = randomKubernetesNameSuffix("test-grant"); + + return withName; } private String getClusterConnectionName() { - return Objects.requireNonNullElse( - withClusterConnectionName, - "test-cluster-connection" - ); + if (withClusterConnectionName != null) { + return withClusterConnectionName; + } + + var clusterConnection = given.one() + .clusterConnection() + .withName("%s-conn".formatted(getName())) + .returnFirst(); + + withClusterConnectionNamespace = clusterConnection.getMetadata().getNamespace(); + + return clusterConnection.getMetadata().getName(); } private String getDatabase() { @@ -190,11 +203,16 @@ private String getDatabase() { return withDatabase; } - return given.one() + var item = given.one() .database() - .returnFirst() - .getSpec() - .getName(); + .withClusterConnectionName(getClusterConnectionName()) + .withClusterConnectionNamespace(withClusterConnectionNamespace) + .withReclaimPolicy(DELETE) + .returnFirst(); + + withDatabase = item.getSpec().getName(); + + return withDatabase; } private String getRole() { @@ -202,11 +220,15 @@ private String getRole() { return withRole; } - return given.one() + var item = given.one() .role() - .returnFirst() - .getSpec() - .getName(); + .withClusterConnectionName(getClusterConnectionName()) + .withClusterConnectionNamespace(withClusterConnectionNamespace) + .returnFirst(); + + withRole = item.getSpec().getName(); + + return withRole; } private String getSchema() { @@ -214,10 +236,34 @@ private String getSchema() { return withSchema; } - return given.one() + var databaseName = getDatabase(); + if (databaseName.isBlank()) { + databaseName = given.one() + .database() + .withClusterConnectionName(getClusterConnectionName()) + .withClusterConnectionNamespace(withClusterConnectionNamespace) + .withReclaimPolicy(DELETE) + .returnFirst() + .getSpec() + .getName(); + } + + var clusterConnectionDb = given.one() + .clusterConnection() + .withName(getClusterConnectionName() + "-db") + .withNamespace(withClusterConnectionNamespace) + .withDatabase(databaseName) + .returnFirst(); + + var item = given.one() .schema() - .returnFirst() - .getSpec() - .getName(); + .withClusterConnectionName(clusterConnectionDb.getMetadata().getName()) + .withClusterConnectionNamespace(clusterConnectionDb.getMetadata().getNamespace()) + .withReclaimPolicy(DELETE) + .returnFirst(); + + withSchema = item.getSpec().getName(); + + return withSchema; } } diff --git a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/RoleCreate.java b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/RoleCreate.java index c1436a6..8547140 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/RoleCreate.java +++ b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/RoleCreate.java @@ -14,7 +14,6 @@ import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; -import java.util.Objects; import java.util.concurrent.TimeUnit; @NullMarked @@ -121,7 +120,7 @@ protected Role create(int index) { .inNamespace(namespace) .withName(name) .waitUntilCondition( - role -> role.getStatus() != null, + role -> role != null && role.getStatus() != null, 5, TimeUnit.SECONDS ); @@ -137,7 +136,9 @@ private String getNamespace() { return withNamespace; } - return kubernetesClient.getNamespace(); + withNamespace = kubernetesClient.getNamespace(); + + return withNamespace; } private String getName() { @@ -145,13 +146,23 @@ private String getName() { return withName; } - return randomKubernetesNameSuffix("test-role"); + withName = randomKubernetesNameSuffix("test-role"); + + return withName; } private String getClusterConnectionName() { - return Objects.requireNonNullElse( - withClusterConnectionName, - "test-cluster-connection" - ); + if (withClusterConnectionName != null) { + return withClusterConnectionName; + } + + var clusterConnection = given.one() + .clusterConnection() + .withName("%s-conn".formatted(getName())) + .returnFirst(); + + withClusterConnectionNamespace = clusterConnection.getMetadata().getNamespace(); + + return clusterConnection.getMetadata().getName(); } } diff --git a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/SchemaCreate.java b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/SchemaCreate.java index a869783..91ef69c 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/SchemaCreate.java +++ b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/SchemaCreate.java @@ -3,6 +3,7 @@ import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.client.KubernetesClient; import it.aboutbits.postgresql._support.testdata.base.TestDataCreator; +import it.aboutbits.postgresql._support.testdata.persisted.Given; import it.aboutbits.postgresql.core.ClusterReference; import it.aboutbits.postgresql.core.ReclaimPolicy; import it.aboutbits.postgresql.crd.schema.Schema; @@ -13,13 +14,14 @@ import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; -import java.util.Objects; import java.util.concurrent.TimeUnit; @NullMarked @Setter @Accessors(fluent = true, chain = true) public class SchemaCreate extends TestDataCreator { + private final Given given; + private final KubernetesClient kubernetesClient; @Nullable @@ -43,9 +45,11 @@ public class SchemaCreate extends TestDataCreator { public SchemaCreate( int numberOfItems, + Given given, KubernetesClient kubernetesClient ) { super(numberOfItems); + this.given = given; this.kubernetesClient = kubernetesClient; } @@ -90,7 +94,7 @@ protected Schema create(int index) { .inNamespace(namespace) .withName(name) .waitUntilCondition( - db -> db.getStatus() != null, + db -> db != null && db.getStatus() != null, 5, TimeUnit.SECONDS ); @@ -106,7 +110,9 @@ private String getNamespace() { return withNamespace; } - return kubernetesClient.getNamespace(); + withNamespace = kubernetesClient.getNamespace(); + + return withNamespace; } private String getName() { @@ -114,13 +120,23 @@ private String getName() { return withName; } - return randomKubernetesNameSuffix("test-schema"); + withName = randomKubernetesNameSuffix("test-schema"); + + return withName; } private String getClusterConnectionName() { - return Objects.requireNonNullElse( - withClusterConnectionName, - "test-cluster-connection" - ); + if (withClusterConnectionName != null) { + return withClusterConnectionName; + } + + var clusterConnection = given.one() + .clusterConnection() + .withName("%s-conn".formatted(getName())) + .returnFirst(); + + withClusterConnectionNamespace = clusterConnection.getMetadata().getNamespace(); + + return clusterConnection.getMetadata().getName(); } } diff --git a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/SecretRefCreate.java b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/SecretRefCreate.java index 7033537..11ccb49 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/SecretRefCreate.java +++ b/operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/SecretRefCreate.java @@ -101,7 +101,9 @@ private String getNamespace() { return withNamespace; } - return kubernetesClient.getNamespace(); + withNamespace = kubernetesClient.getNamespace(); + + return withNamespace; } private String getName() { @@ -109,7 +111,9 @@ private String getName() { return withName; } - return randomKubernetesNameSuffix("test-secret"); + withName = randomKubernetesNameSuffix("test-secret"); + + return withName; } @Nullable @@ -122,7 +126,9 @@ private String getUsername() { return withUsername; } - return FAKER.credentials().username(); + withUsername = FAKER.credentials().username(); + + return withUsername; } @Nullable @@ -135,6 +141,8 @@ private String getPassword() { return withPassword; } - return FAKER.credentials().username(); + withPassword = FAKER.credentials().password(8, 16, true, true); + + return withPassword; } } diff --git a/operator/src/test/java/it/aboutbits/postgresql/crd/clusterconnection/ClusterConnectionReconcilerTest.java b/operator/src/test/java/it/aboutbits/postgresql/crd/clusterconnection/ClusterConnectionReconcilerTest.java index 1e34a4a..4b7ba1f 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/crd/clusterconnection/ClusterConnectionReconcilerTest.java +++ b/operator/src/test/java/it/aboutbits/postgresql/crd/clusterconnection/ClusterConnectionReconcilerTest.java @@ -2,6 +2,7 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.quarkus.test.junit.QuarkusTest; +import it.aboutbits.postgresql._support.testdata.base.TestUtil; import it.aboutbits.postgresql._support.testdata.persisted.Given; import it.aboutbits.postgresql.core.CRPhase; import it.aboutbits.postgresql.core.CRStatus; @@ -18,7 +19,6 @@ import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; import java.util.Objects; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import static org.assertj.core.api.Assertions.assertThat; @@ -32,13 +32,12 @@ class ClusterConnectionReconcilerTest { private final Given given; private final PostgreSQLContextFactory postgreSQLContextFactory; + private final KubernetesClient kubernetesClient; @BeforeEach - void cleanUp() { - kubernetesClient.resources(ClusterConnection.class) - .withTimeout(5, TimeUnit.SECONDS) - .delete(); + void resetEnvironment() { + TestUtil.resetEnvironment(kubernetesClient); } @Test diff --git a/operator/src/test/java/it/aboutbits/postgresql/crd/database/DatabaseReconcilerTest.java b/operator/src/test/java/it/aboutbits/postgresql/crd/database/DatabaseReconcilerTest.java index 5ec6e4a..ff9f09c 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/crd/database/DatabaseReconcilerTest.java +++ b/operator/src/test/java/it/aboutbits/postgresql/crd/database/DatabaseReconcilerTest.java @@ -2,11 +2,11 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.quarkus.test.junit.QuarkusTest; +import it.aboutbits.postgresql._support.testdata.base.TestUtil; import it.aboutbits.postgresql._support.testdata.persisted.Given; import it.aboutbits.postgresql.core.CRPhase; import it.aboutbits.postgresql.core.CRStatus; import it.aboutbits.postgresql.core.PostgreSQLContextFactory; -import it.aboutbits.postgresql.crd.clusterconnection.ClusterConnection; import lombok.RequiredArgsConstructor; import org.jspecify.annotations.NullMarked; import org.junit.jupiter.api.BeforeEach; @@ -15,8 +15,8 @@ import java.time.OffsetDateTime; import java.time.ZoneOffset; -import java.util.concurrent.TimeUnit; +import static it.aboutbits.postgresql.core.ReclaimPolicy.DELETE; import static org.assertj.core.api.Assertions.assertThat; @NullMarked @@ -31,14 +31,8 @@ class DatabaseReconcilerTest { private final KubernetesClient kubernetesClient; @BeforeEach - void cleanUp() { - kubernetesClient.resources(Database.class) - .withTimeout(5, TimeUnit.SECONDS) - .delete(); - - kubernetesClient.resources(ClusterConnection.class) - .withTimeout(5, TimeUnit.SECONDS) - .delete(); + void resetEnvironment() { + TestUtil.resetEnvironment(kubernetesClient); } @Test @@ -58,6 +52,7 @@ void createDatabase_andStatusReady() { .database() .withName(dbName) .withClusterConnectionName(clusterConnection.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); // then diff --git a/operator/src/test/java/it/aboutbits/postgresql/crd/defaultprivilege/DefaultPrivilegeReconcilerTest.java b/operator/src/test/java/it/aboutbits/postgresql/crd/defaultprivilege/DefaultPrivilegeReconcilerTest.java index e7079d7..039233e 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/crd/defaultprivilege/DefaultPrivilegeReconcilerTest.java +++ b/operator/src/test/java/it/aboutbits/postgresql/crd/defaultprivilege/DefaultPrivilegeReconcilerTest.java @@ -1,9 +1,9 @@ package it.aboutbits.postgresql.crd.defaultprivilege; -import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientException; import io.quarkus.test.junit.QuarkusTest; +import it.aboutbits.postgresql._support.testdata.base.TestUtil; import it.aboutbits.postgresql._support.testdata.persisted.Given; import it.aboutbits.postgresql._support.valuesource.BlankSource; import it.aboutbits.postgresql.core.CRPhase; @@ -11,9 +11,6 @@ import it.aboutbits.postgresql.core.PostgreSQLContextFactory; import it.aboutbits.postgresql.core.Privilege; import it.aboutbits.postgresql.crd.clusterconnection.ClusterConnection; -import it.aboutbits.postgresql.crd.database.Database; -import it.aboutbits.postgresql.crd.role.Role; -import it.aboutbits.postgresql.crd.schema.Schema; import lombok.RequiredArgsConstructor; import org.jspecify.annotations.NullMarked; import org.junit.jupiter.api.BeforeEach; @@ -37,11 +34,12 @@ import static it.aboutbits.postgresql.core.Privilege.MAINTAIN; import static it.aboutbits.postgresql.core.Privilege.SELECT; import static it.aboutbits.postgresql.core.Privilege.USAGE; +import static it.aboutbits.postgresql.core.ReclaimPolicy.DELETE; import static it.aboutbits.postgresql.crd.defaultprivilege.DefaultPrivilegeObjectType.SCHEMA; import static it.aboutbits.postgresql.crd.defaultprivilege.DefaultPrivilegeObjectType.SEQUENCE; import static it.aboutbits.postgresql.crd.defaultprivilege.DefaultPrivilegeObjectType.TABLE; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @NullMarked @QuarkusTest @@ -56,22 +54,7 @@ class DefaultPrivilegeReconcilerTest { @BeforeEach void resetEnvironment() { - deleteResources(DefaultPrivilege.class); - deleteResources(Schema.class); - deleteResources(Database.class); - deleteResources(Role.class); - deleteResources(ClusterConnection.class); - - // Create the default connection "test-cluster-connection" used by DefaultPrivilegeCreate defaults - given.one().clusterConnection() - .withName("test-cluster-connection") - .returnFirst(); - } - - private void deleteResources(Class resourceClass) { - kubernetesClient.resources(resourceClass) - .withTimeout(5, TimeUnit.SECONDS) - .delete(); + TestUtil.resetEnvironment(kubernetesClient); } @Nested @@ -85,7 +68,7 @@ void failWhenDatabaseIsBlankOrEmptyString( String blankOrEmptyString ) { // then - assertThatThrownBy(() -> + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> // given / when given.one() .defaultPrivilege() @@ -93,8 +76,7 @@ void failWhenDatabaseIsBlankOrEmptyString( .withObjectType(SCHEMA) .withPrivileges(USAGE) .apply() - ).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The DefaultPrivilege database must not be empty."); + ).withMessageContaining("The DefaultPrivilege database must not be empty."); } @ParameterizedTest @@ -104,7 +86,7 @@ void failWhenRoleIsBlankOrEmptyString( String blankOrEmptyString ) { // then - assertThatThrownBy(() -> + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> // given / when given.one() .defaultPrivilege() @@ -112,8 +94,7 @@ void failWhenRoleIsBlankOrEmptyString( .withObjectType(SCHEMA) .withPrivileges(USAGE) .apply() - ).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The DefaultPrivilege role must not be empty."); + ).withMessageContaining("The DefaultPrivilege role must not be empty."); } @ParameterizedTest @@ -123,7 +104,7 @@ void failWhenOwnerIsBlankOrEmptyString( String blankOrEmptyString ) { // then - assertThatThrownBy(() -> + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> // given / when given.one() .defaultPrivilege() @@ -131,8 +112,7 @@ void failWhenOwnerIsBlankOrEmptyString( .withObjectType(SCHEMA) .withPrivileges(USAGE) .apply() - ).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The DefaultPrivilege owner must not be empty."); + ).withMessageContaining("The DefaultPrivilege owner must not be empty."); } @ParameterizedTest @@ -142,7 +122,7 @@ void failWhenSchemaIsBlankOrEmptyString( String blankOrEmptyString ) { // then - assertThatThrownBy(() -> + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> // given / when given.one() .defaultPrivilege() @@ -150,24 +130,21 @@ void failWhenSchemaIsBlankOrEmptyString( .withObjectType(SCHEMA) .withPrivileges(USAGE) .apply() - ).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The DefaultPrivilege schema must not be empty."); + ).withMessageContaining("The DefaultPrivilege schema must not be empty."); } @Test @DisplayName("Should fail when the privileges are an empty List (CEL rule)") - void failWhenPrivilegesAreAnEmptyList( - ) { + void failWhenPrivilegesAreAnEmptyList() { // then - assertThatThrownBy(() -> + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> // given / when given.one() .defaultPrivilege() .withObjectType(SCHEMA) .withPrivileges(List.of()) .apply() - ).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The DefaultPrivilege privileges must not be empty."); + ).withMessageContaining("The DefaultPrivilege privileges must not be empty."); } } @@ -184,7 +161,7 @@ void failWhenDatabaseChanges() { .returnFirst(); // then - assertThatThrownBy(() -> { + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> { // when item.getSpec().setDatabase("new-database"); @@ -192,8 +169,7 @@ void failWhenDatabaseChanges() { .inNamespace(item.getMetadata().getNamespace()) .withName(item.getMetadata().getName()) .patch(item); - }).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The DefaultPrivilege database is immutable."); + }).withMessageContaining("The DefaultPrivilege database is immutable."); } @Test @@ -207,7 +183,7 @@ void failWhenRoleChanges() { .returnFirst(); // then - assertThatThrownBy(() -> { + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> { // when item.getSpec().setRole("new-role"); @@ -215,8 +191,7 @@ void failWhenRoleChanges() { .inNamespace(item.getMetadata().getNamespace()) .withName(item.getMetadata().getName()) .patch(item); - }).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The DefaultPrivilege role is immutable."); + }).withMessageContaining("The DefaultPrivilege role is immutable."); } @Test @@ -230,7 +205,7 @@ void failWhenOwnerChanges() { .returnFirst(); // then - assertThatThrownBy(() -> { + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> { // when item.getSpec().setOwner("new-owner"); @@ -238,8 +213,7 @@ void failWhenOwnerChanges() { .inNamespace(item.getMetadata().getNamespace()) .withName(item.getMetadata().getName()) .patch(item); - }).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The DefaultPrivilege owner is immutable."); + }).withMessageContaining("The DefaultPrivilege owner is immutable."); } @Test @@ -253,7 +227,7 @@ void failWhenSchemaChanges() { .returnFirst(); // then - assertThatThrownBy(() -> { + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> { // when item.getSpec().setSchema("new-schema"); @@ -261,8 +235,7 @@ void failWhenSchemaChanges() { .inNamespace(item.getMetadata().getNamespace()) .withName(item.getMetadata().getName()) .patch(item); - }).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The DefaultPrivilege schema is immutable."); + }).withMessageContaining("The DefaultPrivilege schema is immutable."); } @Test @@ -276,7 +249,7 @@ void failWhenObjectTypeChanges() { .returnFirst(); // then - assertThatThrownBy(() -> { + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> { // when item.getSpec().setObjectType(SEQUENCE); @@ -284,8 +257,7 @@ void failWhenObjectTypeChanges() { .inNamespace(item.getMetadata().getNamespace()) .withName(item.getMetadata().getName()) .patch(item); - }).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The DefaultPrivilege objectType is immutable."); + }).withMessageContaining("The DefaultPrivilege objectType is immutable."); } } @@ -295,7 +267,7 @@ class RelatedFields { @DisplayName("Should fail when objectType is SCHEMA but schema is set (CEL rule)") void failWhenDatabaseHasSchema() { // then - assertThatThrownBy(() -> + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> // given / when given.one() .defaultPrivilege() @@ -303,8 +275,7 @@ void failWhenDatabaseHasSchema() { .withObjectType(SCHEMA) .withPrivileges(USAGE) .returnFirst() - ).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The DefaultPrivilege schema must be not set if objectType is 'schema'"); + ).withMessageContaining("The DefaultPrivilege schema must be not set if objectType is 'schema'"); } @Test @@ -346,6 +317,7 @@ void errorWhenUnsupportedMaintainTablePrivilege() { var database = given.one() .database() .withClusterConnectionName(clusterConnectionMain.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var clusterConnectionDb = given.one() @@ -356,6 +328,7 @@ void errorWhenUnsupportedMaintainTablePrivilege() { var schema = given.one() .schema() .withClusterConnectionName(clusterConnectionDb.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var role = given.one() @@ -403,6 +376,7 @@ void defaultPrivilegeOnSchema() { var database = given.one() .database() .withClusterConnectionName(clusterConnectionMain.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); // To create a Schema in the new database, we need a ClusterConnection pointing to it @@ -512,6 +486,7 @@ void defaultPrivilegeOnTable( var database = given.one() .database() .withClusterConnectionName(clusterConnectionMain.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var clusterConnectionDb = given.one() @@ -522,6 +497,7 @@ void defaultPrivilegeOnTable( var schema = given.one() .schema() .withClusterConnectionName(clusterConnectionDb.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var role = given.one() @@ -636,6 +612,7 @@ void defaultPrivilegeOnSequence() { var database = given.one() .database() .withClusterConnectionName(clusterConnectionMain.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var clusterConnectionDb = given.one() @@ -646,6 +623,7 @@ void defaultPrivilegeOnSequence() { var schema = given.one() .schema() .withClusterConnectionName(clusterConnectionDb.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var role = given.one() diff --git a/operator/src/test/java/it/aboutbits/postgresql/crd/grant/GrantReconcilerTest.java b/operator/src/test/java/it/aboutbits/postgresql/crd/grant/GrantReconcilerTest.java index 45b9bef..4fc98f0 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/crd/grant/GrantReconcilerTest.java +++ b/operator/src/test/java/it/aboutbits/postgresql/crd/grant/GrantReconcilerTest.java @@ -1,9 +1,9 @@ package it.aboutbits.postgresql.crd.grant; -import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientException; import io.quarkus.test.junit.QuarkusTest; +import it.aboutbits.postgresql._support.testdata.base.TestUtil; import it.aboutbits.postgresql._support.testdata.persisted.Given; import it.aboutbits.postgresql._support.valuesource.BlankSource; import it.aboutbits.postgresql.core.CRPhase; @@ -11,9 +11,6 @@ import it.aboutbits.postgresql.core.PostgreSQLContextFactory; import it.aboutbits.postgresql.core.Privilege; import it.aboutbits.postgresql.crd.clusterconnection.ClusterConnection; -import it.aboutbits.postgresql.crd.database.Database; -import it.aboutbits.postgresql.crd.role.Role; -import it.aboutbits.postgresql.crd.schema.Schema; import lombok.RequiredArgsConstructor; import org.jooq.impl.SQLDataType; import org.jspecify.annotations.NullMarked; @@ -40,12 +37,13 @@ import static it.aboutbits.postgresql.core.Privilege.MAINTAIN; import static it.aboutbits.postgresql.core.Privilege.SELECT; import static it.aboutbits.postgresql.core.Privilege.USAGE; +import static it.aboutbits.postgresql.core.ReclaimPolicy.DELETE; import static it.aboutbits.postgresql.crd.grant.GrantObjectType.DATABASE; import static it.aboutbits.postgresql.crd.grant.GrantObjectType.SCHEMA; import static it.aboutbits.postgresql.crd.grant.GrantObjectType.SEQUENCE; import static it.aboutbits.postgresql.crd.grant.GrantObjectType.TABLE; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.jooq.impl.DSL.quotedName; @NullMarked @@ -61,22 +59,7 @@ class GrantReconcilerTest { @BeforeEach void resetEnvironment() { - deleteResources(Grant.class); - deleteResources(Schema.class); - deleteResources(Database.class); - deleteResources(Role.class); - deleteResources(ClusterConnection.class); - - // Create the default connection "test-cluster-connection" used by GrantCreate defaults - given.one().clusterConnection() - .withName("test-cluster-connection") - .returnFirst(); - } - - private void deleteResources(Class resourceClass) { - kubernetesClient.resources(resourceClass) - .withTimeout(5, TimeUnit.SECONDS) - .delete(); + TestUtil.resetEnvironment(kubernetesClient); } @Nested @@ -90,7 +73,7 @@ void failWhenDatabaseIsBlankOrEmptyString( String blankOrEmptyString ) { // then - assertThatThrownBy(() -> + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> // given / when given.one() .grant() @@ -98,8 +81,7 @@ void failWhenDatabaseIsBlankOrEmptyString( .withObjectType(SCHEMA) .withPrivileges(USAGE) .apply() - ).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The Grant database must not be empty."); + ).withMessageContaining("The Grant database must not be empty."); } @ParameterizedTest @@ -109,7 +91,7 @@ void failWhenRoleIsBlankOrEmptyString( String blankOrEmptyString ) { // then - assertThatThrownBy(() -> + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> // given / when given.one() .grant() @@ -117,8 +99,7 @@ void failWhenRoleIsBlankOrEmptyString( .withObjectType(SCHEMA) .withPrivileges(USAGE) .apply() - ).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The Grant role must not be empty."); + ).withMessageContaining("The Grant role must not be empty."); } @ParameterizedTest @@ -128,7 +109,7 @@ void failWhenSchemaIsBlankOrEmptyString( String blankOrEmptyString ) { // then - assertThatThrownBy(() -> + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> // given / when given.one() .grant() @@ -136,24 +117,21 @@ void failWhenSchemaIsBlankOrEmptyString( .withObjectType(SCHEMA) .withPrivileges(USAGE) .apply() - ).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The Grant schema must not be empty."); + ).withMessageContaining("The Grant schema must not be empty."); } @Test @DisplayName("Should fail when the privileges are an empty List (CEL rule)") - void failWhenPrivilegesAreAnEmptyList( - ) { + void failWhenPrivilegesAreAnEmptyList() { // then - assertThatThrownBy(() -> + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> // given / when given.one() .grant() .withObjectType(SCHEMA) .withPrivileges(List.of()) .apply() - ).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The Grant privileges must not be empty."); + ).withMessageContaining("The Grant privileges must not be empty."); } } @@ -170,7 +148,7 @@ void failWhenDatabaseChanges() { .returnFirst(); // then - assertThatThrownBy(() -> { + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> { // when item.getSpec().setDatabase("new-database"); @@ -178,8 +156,7 @@ void failWhenDatabaseChanges() { .inNamespace(item.getMetadata().getNamespace()) .withName(item.getMetadata().getName()) .patch(item); - }).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The Grant database is immutable."); + }).withMessageContaining("The Grant database is immutable."); } @Test @@ -193,7 +170,7 @@ void failWhenRoleChanges() { .returnFirst(); // then - assertThatThrownBy(() -> { + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> { // when item.getSpec().setRole("new-role"); @@ -201,8 +178,7 @@ void failWhenRoleChanges() { .inNamespace(item.getMetadata().getNamespace()) .withName(item.getMetadata().getName()) .patch(item); - }).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The Grant role is immutable."); + }).withMessageContaining("The Grant role is immutable."); } @Test @@ -216,7 +192,7 @@ void failWhenSchemaChanges() { .returnFirst(); // then - assertThatThrownBy(() -> { + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> { // when item.getSpec().setSchema("new-schema"); @@ -224,8 +200,7 @@ void failWhenSchemaChanges() { .inNamespace(item.getMetadata().getNamespace()) .withName(item.getMetadata().getName()) .patch(item); - }).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The Grant schema is immutable."); + }).withMessageContaining("The Grant schema is immutable."); } @Test @@ -239,7 +214,7 @@ void failWhenObjectTypeChanges() { .returnFirst(); // then - assertThatThrownBy(() -> { + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> { // when item.getSpec().setObjectType(SEQUENCE); @@ -247,8 +222,7 @@ void failWhenObjectTypeChanges() { .inNamespace(item.getMetadata().getNamespace()) .withName(item.getMetadata().getName()) .patch(item); - }).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The Grant objectType is immutable."); + }).withMessageContaining("The Grant objectType is immutable."); } } @@ -258,7 +232,7 @@ class RelatedFields { @DisplayName("Should fail when objectType is DATABASE but schema is set (CEL rule)") void failWhenDatabaseHasSchema() { // then - assertThatThrownBy(() -> + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> // given / when given.one() .grant() @@ -266,15 +240,14 @@ void failWhenDatabaseHasSchema() { .withObjectType(DATABASE) .withPrivileges(CONNECT) .returnFirst() - ).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The Grant schema must be not set if objectType is 'database'"); + ).withMessageContaining("The Grant schema must be not set if objectType is 'database'"); } @Test @DisplayName("Should fail when objectType is DATABASE but objects has items (CEL rule)") void failWhenDatabaseHasObjects() { // then - assertThatThrownBy(() -> + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> // given / when given.one() .grant() @@ -282,15 +255,14 @@ void failWhenDatabaseHasObjects() { .withObjects("some_object", "other_object") .withPrivileges(CONNECT) .returnFirst() - ).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The Grant objects must be not set if objectType is 'database' or 'schema', for all other objectType's a list is required."); + ).withMessageContaining("The Grant objects must be not set if objectType is 'database' or 'schema', for all other objectType's a list is required."); } @Test @DisplayName("Should fail when objectType is SCHEMA but objects has items (CEL rule)") void failWhenSchemaHasObjects() { // then - assertThatThrownBy(() -> + assertThatExceptionOfType(KubernetesClientException.class).isThrownBy(() -> // given / when given.one() .grant() @@ -298,8 +270,7 @@ void failWhenSchemaHasObjects() { .withObjects("some_object", "other_object") .withPrivileges(USAGE) .returnFirst() - ).isInstanceOf(KubernetesClientException.class) - .hasMessageContaining("The Grant objects must be not set if objectType is 'database' or 'schema', for all other objectType's a list is required."); + ).withMessageContaining("The Grant objects must be not set if objectType is 'database' or 'schema', for all other objectType's a list is required."); } @Test @@ -341,6 +312,7 @@ void errorWhenUnsupportedMaintainTablePrivilege() { var database = given.one() .database() .withClusterConnectionName(clusterConnectionMain.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var clusterConnectionDb = given.one() @@ -351,6 +323,7 @@ void errorWhenUnsupportedMaintainTablePrivilege() { var schema = given.one() .schema() .withClusterConnectionName(clusterConnectionDb.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var role = given.one() @@ -388,6 +361,14 @@ void errorWhenUnsupportedMaintainTablePrivilege() { .startsWith("The following privileges require a newer PostgreSQL version (current:") .contains("{MAINTAIN=17}"); }); + + // cleanup + deleteTable( + clusterConnectionDb, + database.getSpec().getName(), + schema.getSpec().getName(), + tableName + ); } } } @@ -412,6 +393,7 @@ void grantOnDatabase() { var database = given.one() .database() .withClusterConnectionName(clusterConnection.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); // when @@ -511,6 +493,7 @@ void grantOnSchema() { var database = given.one() .database() .withClusterConnectionName(clusterConnectionMain.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); // To create a Schema in the new database, we need a ClusterConnection pointing to it @@ -522,6 +505,7 @@ void grantOnSchema() { var schema = given.one() .schema() .withClusterConnectionName(clusterConnectionDb.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var role = given.one() @@ -632,6 +616,7 @@ void grantOnTable( var database = given.one() .database() .withClusterConnectionName(clusterConnectionMain.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var clusterConnectionDb = given.one() @@ -642,6 +627,7 @@ void grantOnTable( var schema = given.one() .schema() .withClusterConnectionName(clusterConnectionDb.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var role = given.one() @@ -738,8 +724,17 @@ void grantOnTable( grant, tableName ); + + // cleanup + deleteTable( + clusterConnectionDb, + database.getSpec().getName(), + schema.getSpec().getName(), + tableName + ); } + @SuppressWarnings("checkstyle:MethodLength") @ParameterizedTest @MethodSource("provideAllSupportedPrivileges") @DisplayName("Should grant and revoke privileges on all tables") @@ -756,6 +751,7 @@ void grantOnAllTables( var database = given.one() .database() .withClusterConnectionName(clusterConnectionMain.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var clusterConnectionDb = given.one() @@ -766,6 +762,7 @@ void grantOnAllTables( var schema = given.one() .schema() .withClusterConnectionName(clusterConnectionDb.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var role = given.one() @@ -892,6 +889,20 @@ void grantOnAllTables( grant, tableName2 ); + + // cleanup + deleteTable( + clusterConnectionDb, + database.getSpec().getName(), + schema.getSpec().getName(), + tableName1 + ); + deleteTable( + clusterConnectionDb, + database.getSpec().getName(), + schema.getSpec().getName(), + tableName2 + ); } static Stream> provideAllSupportedPrivileges() { @@ -923,6 +934,7 @@ void grantOnSequence() { var database = given.one() .database() .withClusterConnectionName(clusterConnectionMain.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var clusterConnectionDb = given.one() @@ -933,6 +945,7 @@ void grantOnSequence() { var schema = given.one() .schema() .withClusterConnectionName(clusterConnectionDb.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var role = given.one() @@ -1030,8 +1043,17 @@ void grantOnSequence() { grant, sequenceName ); + + // cleanup + deleteTable( + clusterConnectionDb, + database.getSpec().getName(), + schema.getSpec().getName(), + tableName + ); } + @SuppressWarnings("checkstyle:MethodLength") @Test @DisplayName("Should grant and revoke privileges on all sequences") void grantOnAllSequences() { @@ -1045,6 +1067,7 @@ void grantOnAllSequences() { var database = given.one() .database() .withClusterConnectionName(clusterConnectionMain.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var clusterConnectionDb = given.one() @@ -1055,6 +1078,7 @@ void grantOnAllSequences() { var schema = given.one() .schema() .withClusterConnectionName(clusterConnectionDb.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); var role = given.one() @@ -1183,6 +1207,20 @@ void grantOnAllSequences() { grant, sequenceName2 ); + + // cleanup + deleteTable( + clusterConnectionDb, + database.getSpec().getName(), + schema.getSpec().getName(), + tableName1 + ); + deleteTable( + clusterConnectionDb, + database.getSpec().getName(), + schema.getSpec().getName(), + tableName2 + ); } } @@ -1257,6 +1295,17 @@ private void createTableWithSerial( } } + private void deleteTable( + ClusterConnection clusterConnection, + String databaseName, + String schemaName, + String tableName + ) { + try (var dsl = postgreSQLContextFactory.getDSLContext(clusterConnection, databaseName)) { + dsl.dropTable(quotedName(schemaName, tableName)).execute(); + } + } + private void assertThatPrivileges( ClusterConnection clusterConnection, Grant grant, diff --git a/operator/src/test/java/it/aboutbits/postgresql/crd/role/RoleReconcilerTest.java b/operator/src/test/java/it/aboutbits/postgresql/crd/role/RoleReconcilerTest.java index 6c82008..41df236 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/crd/role/RoleReconcilerTest.java +++ b/operator/src/test/java/it/aboutbits/postgresql/crd/role/RoleReconcilerTest.java @@ -3,13 +3,13 @@ import io.fabric8.kubernetes.api.model.SecretBuilder; import io.fabric8.kubernetes.client.KubernetesClient; import io.quarkus.test.junit.QuarkusTest; +import it.aboutbits.postgresql._support.testdata.base.TestUtil; import it.aboutbits.postgresql._support.testdata.persisted.Given; import it.aboutbits.postgresql.core.CRPhase; import it.aboutbits.postgresql.core.CRStatus; import it.aboutbits.postgresql.core.PostgreSQLAuthenticationService; import it.aboutbits.postgresql.core.PostgreSQLContextFactory; import it.aboutbits.postgresql.core.SecretRef; -import it.aboutbits.postgresql.crd.clusterconnection.ClusterConnection; import lombok.RequiredArgsConstructor; import org.jooq.DSLContext; import org.jooq.Field; @@ -50,14 +50,8 @@ class RoleReconcilerTest { private final KubernetesClient kubernetesClient; @BeforeEach - void cleanUp() { - kubernetesClient.resources(Role.class) - .withTimeout(5, TimeUnit.SECONDS) - .delete(); - - kubernetesClient.resources(ClusterConnection.class) - .withTimeout(5, TimeUnit.SECONDS) - .delete(); + void resetEnvironment() { + TestUtil.resetEnvironment(kubernetesClient); } @Test @@ -233,6 +227,12 @@ void createRole_withMissingClusterConnection_setsPending() { now ); assertThat(role.getStatus().getLastPhaseTransitionTime()).isNull(); + + // We have to manually clean up this as the RoleController#cleanup will always fail as the ClusterConnection does not exist + kubernetesClient.resource(role).delete(); + role.getMetadata().setFinalizers(null); + role.getMetadata().setResourceVersion(null); + kubernetesClient.resource(role).patch(); } @Test @@ -274,7 +274,7 @@ void secretChange_triggersReconciliation() { // then: password should match the initial one // Wait for password to match because reconciliation might take a bit await().atMost(5, TimeUnit.SECONDS) - .pollInterval(500, TimeUnit.MILLISECONDS) + .pollInterval(100, TimeUnit.MILLISECONDS) .until(() -> postgreSQLAuthenticationService.passwordMatches( dsl, role.getSpec(), @@ -294,7 +294,7 @@ void secretChange_triggersReconciliation() { // then: password should eventually match the new one await().atMost(5, TimeUnit.SECONDS) - .pollInterval(500, TimeUnit.MILLISECONDS) + .pollInterval(100, TimeUnit.MILLISECONDS) .until(() -> postgreSQLAuthenticationService.passwordMatches( dsl, role.getSpec(), @@ -342,7 +342,7 @@ void secretRefChange_triggersReconciliation() { // then: password should match the initial one await().atMost(5, TimeUnit.SECONDS) - .pollInterval(500, TimeUnit.MILLISECONDS) + .pollInterval(100, TimeUnit.MILLISECONDS) .until(() -> postgreSQLAuthenticationService.passwordMatches( dsl, role.getSpec(), @@ -356,7 +356,7 @@ void secretRefChange_triggersReconciliation() { // then: password should eventually match the new one await().atMost(5, TimeUnit.SECONDS) - .pollInterval(500, TimeUnit.MILLISECONDS) + .pollInterval(100, TimeUnit.MILLISECONDS) .until(() -> postgreSQLAuthenticationService.passwordMatches( dsl, updatedRole.getSpec(), @@ -864,7 +864,7 @@ void deleteRole_removesFromDatabase() { // then await().atMost(5, TimeUnit.SECONDS) - .pollInterval(500, TimeUnit.MILLISECONDS) + .pollInterval(100, TimeUnit.MILLISECONDS) .until(() -> !roleService.roleExists(dsl, role.getSpec())); } diff --git a/operator/src/test/java/it/aboutbits/postgresql/crd/schema/SchemaReconcilerTest.java b/operator/src/test/java/it/aboutbits/postgresql/crd/schema/SchemaReconcilerTest.java index 01c89cb..f0a87e1 100644 --- a/operator/src/test/java/it/aboutbits/postgresql/crd/schema/SchemaReconcilerTest.java +++ b/operator/src/test/java/it/aboutbits/postgresql/crd/schema/SchemaReconcilerTest.java @@ -2,11 +2,11 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.quarkus.test.junit.QuarkusTest; +import it.aboutbits.postgresql._support.testdata.base.TestUtil; import it.aboutbits.postgresql._support.testdata.persisted.Given; import it.aboutbits.postgresql.core.CRPhase; import it.aboutbits.postgresql.core.CRStatus; import it.aboutbits.postgresql.core.PostgreSQLContextFactory; -import it.aboutbits.postgresql.crd.clusterconnection.ClusterConnection; import lombok.RequiredArgsConstructor; import org.jspecify.annotations.NullMarked; import org.junit.jupiter.api.BeforeEach; @@ -15,8 +15,8 @@ import java.time.OffsetDateTime; import java.time.ZoneOffset; -import java.util.concurrent.TimeUnit; +import static it.aboutbits.postgresql.core.ReclaimPolicy.DELETE; import static org.assertj.core.api.Assertions.assertThat; @NullMarked @@ -31,14 +31,8 @@ class SchemaReconcilerTest { private final KubernetesClient kubernetesClient; @BeforeEach - void cleanUp() { - kubernetesClient.resources(Schema.class) - .withTimeout(5, TimeUnit.SECONDS) - .delete(); - - kubernetesClient.resources(ClusterConnection.class) - .withTimeout(5, TimeUnit.SECONDS) - .delete(); + void resetEnvironment() { + TestUtil.resetEnvironment(kubernetesClient); } @Test @@ -58,6 +52,7 @@ void createSchema_andStatusReady() { .schema() .withName(schemaName) .withClusterConnectionName(clusterConnection.getMetadata().getName()) + .withReclaimPolicy(DELETE) .returnFirst(); // then