Skip to content

Commit 96ac02e

Browse files
committed
add a DatabaseReconcilerTest with testdata creator and so some cleanup
1 parent 80ee56d commit 96ac02e

7 files changed

Lines changed: 303 additions & 39 deletions

File tree

operator/src/main/java/it/aboutbits/postgresql/crd/database/DatabaseReconciler.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,11 @@ public UpdateControl<Database> reconcile(Database resource, Context<Database> co
6969
UpdateControl<Database> updateControl;
7070

7171
try (var dsl = contextFactory.getDSLContext(clusterConnection)) {
72-
// Run everything in a single transaction
73-
updateControl = dsl.transactionResult(
74-
cfg -> reconcileInTransaction(
75-
cfg.dsl(),
76-
resource,
77-
status
78-
)
72+
// PostgreSQL doesn't allow running `create database` in a transaction
73+
updateControl = reconcile(
74+
dsl,
75+
resource,
76+
status
7977
);
8078
} catch (Exception e) {
8179
return handleError(
@@ -166,8 +164,8 @@ protected CRStatus newStatus() {
166164
return new CRStatus();
167165
}
168166

169-
private UpdateControl<Database> reconcileInTransaction(
170-
DSLContext tx,
167+
private UpdateControl<Database> reconcile(
168+
DSLContext dsl,
171169
Database resource,
172170
CRStatus status
173171
) {
@@ -177,15 +175,15 @@ private UpdateControl<Database> reconcileInTransaction(
177175
var spec = resource.getSpec();
178176

179177
// Create and return the role if it doesn't exist yet
180-
if (!databaseService.databaseExists(tx, spec)) {
178+
if (!databaseService.databaseExists(dsl, spec)) {
181179
log.info(
182180
"Creating Database [resource={}/{}]",
183181
namespace,
184182
name
185183
);
186184

187185
databaseService.createDatabase(
188-
tx,
186+
dsl,
189187
spec
190188
);
191189

@@ -195,7 +193,7 @@ private UpdateControl<Database> reconcileInTransaction(
195193
return UpdateControl.patchStatus(resource);
196194
}
197195

198-
var currentOwner = databaseService.fetchDatabaseOwner(tx, spec);
196+
var currentOwner = databaseService.fetchDatabaseOwner(dsl, spec);
199197
var expectedOwner = spec.getOwner();
200198

201199
if (Objects.equals(currentOwner, expectedOwner)) {
@@ -214,7 +212,7 @@ private UpdateControl<Database> reconcileInTransaction(
214212
name
215213
);
216214

217-
databaseService.changeDatabaseOwner(tx, spec);
215+
databaseService.changeDatabaseOwner(dsl, spec);
218216

219217
status.setPhase(CRPhase.READY)
220218
.setMessage("Database owner changed [previousOwner=%s, newOwner=%s]".formatted(

operator/src/main/java/it/aboutbits/postgresql/crd/database/DatabaseService.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import it.aboutbits.postgresql.core.infrastructure.persistence.Routines;
44
import jakarta.inject.Singleton;
5-
import org.jooq.CloseableDSLContext;
65
import org.jooq.DSLContext;
76
import org.jspecify.annotations.NullMarked;
87

@@ -16,33 +15,33 @@
1615
@Singleton
1716
public class DatabaseService {
1817
public boolean databaseExists(
19-
DSLContext tx,
18+
DSLContext dsl,
2019
DatabaseSpec spec
2120
) {
22-
return tx.fetchExists(selectOne()
21+
return dsl.fetchExists(selectOne()
2322
.from(PG_DATABASE)
2423
.where(PG_DATABASE.DATNAME.eq(spec.getName()))
2524
);
2625
}
2726

2827
public void createDatabase(
29-
DSLContext tx,
28+
DSLContext dsl,
3029
DatabaseSpec spec
3130
) {
3231
var name = quotedName(spec.getName());
3332

34-
tx.createDatabase(name).execute();
33+
dsl.createDatabase(name).execute();
3534

3635
if (spec.getOwner() != null) {
37-
changeDatabaseOwner(tx, spec);
36+
changeDatabaseOwner(dsl, spec);
3837
}
3938
}
4039

4140
public String fetchDatabaseOwner(
42-
DSLContext tx,
41+
DSLContext dsl,
4342
DatabaseSpec spec
4443
) {
45-
return tx
44+
return dsl
4645
.select(Routines.pgGetUserbyid(
4746
PG_DATABASE.DATDBA
4847
))
@@ -52,12 +51,12 @@ public String fetchDatabaseOwner(
5251
}
5352

5453
public void changeDatabaseOwner(
55-
DSLContext tx,
54+
DSLContext dsl,
5655
DatabaseSpec spec
5756
) {
5857
var name = quotedName(spec.getName());
5958

60-
tx.execute(query(
59+
dsl.execute(query(
6160
"alter database {0} owner to {1}",
6261
name,
6362
role(spec.getOwner())

operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/Given.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.fabric8.kubernetes.client.KubernetesClient;
44
import it.aboutbits.postgresql._support.testdata.persisted.creator.ClusterConnectionCreate;
5+
import it.aboutbits.postgresql._support.testdata.persisted.creator.DatabaseCreate;
56
import it.aboutbits.postgresql._support.testdata.persisted.creator.RoleCreate;
67
import it.aboutbits.postgresql._support.testdata.persisted.creator.SecretRefCreate;
78
import jakarta.enterprise.context.ApplicationScoped;
@@ -91,6 +92,13 @@ public RoleCreate role() {
9192
kubernetesClient
9293
);
9394
}
95+
96+
public DatabaseCreate database() {
97+
return new DatabaseCreate(
98+
numberOfItems,
99+
kubernetesClient
100+
);
101+
}
94102
}
95103

96104
public record DBConnectionDetails(

operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/ClusterConnectionCreate.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,24 @@ public class ClusterConnectionCreate extends TestDataCreator<ClusterConnection>
4848
@Nullable
4949
private String withApplicationName;
5050

51-
public ClusterConnectionCreate withoutNamespace() {
52-
this.withoutNamespace = true;
53-
return this;
54-
}
55-
5651
public ClusterConnectionCreate(
5752
int numberOfItems,
58-
Given given, KubernetesClient kubernetesClient, Given.DBConnectionDetails dbConnectionDetails
53+
Given given,
54+
KubernetesClient kubernetesClient,
55+
Given.DBConnectionDetails dbConnectionDetails
5956
) {
6057
super(numberOfItems);
6158
this.given = given;
6259
this.kubernetesClient = kubernetesClient;
6360
this.dbConnectionDetails = dbConnectionDetails;
6461
}
6562

63+
@SuppressWarnings("unused")
64+
public ClusterConnectionCreate withoutNamespace() {
65+
this.withoutNamespace = true;
66+
return this;
67+
}
68+
6669
@Override
6770
protected ClusterConnection create(int index) {
6871
// given
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package it.aboutbits.postgresql._support.testdata.persisted.creator;
2+
3+
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
4+
import io.fabric8.kubernetes.client.KubernetesClient;
5+
import it.aboutbits.postgresql._support.testdata.base.TestDataCreator;
6+
import it.aboutbits.postgresql.core.ClusterReference;
7+
import it.aboutbits.postgresql.core.ReclaimPolicy;
8+
import it.aboutbits.postgresql.crd.database.Database;
9+
import it.aboutbits.postgresql.crd.database.DatabaseSpec;
10+
import lombok.AccessLevel;
11+
import lombok.Setter;
12+
import lombok.experimental.Accessors;
13+
import org.jspecify.annotations.NullMarked;
14+
import org.jspecify.annotations.Nullable;
15+
16+
import java.util.Objects;
17+
import java.util.concurrent.TimeUnit;
18+
19+
@NullMarked
20+
@Setter
21+
@Accessors(fluent = true, chain = true)
22+
public class DatabaseCreate extends TestDataCreator<Database> {
23+
private final KubernetesClient kubernetesClient;
24+
25+
@Nullable
26+
private String withNamespace;
27+
@Setter(AccessLevel.NONE)
28+
private boolean withoutNamespace = false;
29+
30+
@Nullable
31+
private String withName;
32+
33+
@Nullable
34+
private String withClusterConnectionName;
35+
36+
@Nullable
37+
private String withClusterConnectionNamespace;
38+
39+
private ReclaimPolicy withReclaimPolicy = ReclaimPolicy.RETAIN;
40+
41+
@Nullable
42+
private String withOwner;
43+
44+
public DatabaseCreate(
45+
int numberOfItems,
46+
KubernetesClient kubernetesClient
47+
) {
48+
super(numberOfItems);
49+
this.kubernetesClient = kubernetesClient;
50+
}
51+
52+
@SuppressWarnings("unused")
53+
public DatabaseCreate withoutNamespace() {
54+
withoutNamespace = true;
55+
return this;
56+
}
57+
58+
@Override
59+
protected Database create(int index) {
60+
var namespace = getNamespace();
61+
var name = getName();
62+
63+
var item = new Database();
64+
65+
item.setMetadata(new ObjectMetaBuilder()
66+
.withName(name)
67+
.withNamespace(namespace)
68+
.build()
69+
);
70+
71+
var spec = new DatabaseSpec();
72+
spec.setName(name);
73+
spec.setReclaimPolicy(withReclaimPolicy);
74+
spec.setOwner(withOwner);
75+
76+
var clusterRef = new ClusterReference();
77+
clusterRef.setName(getClusterConnectionName());
78+
clusterRef.setNamespace(withClusterConnectionNamespace);
79+
spec.setClusterRef(clusterRef);
80+
81+
item.setSpec(spec);
82+
83+
kubernetesClient.resources(Database.class)
84+
.inNamespace(namespace)
85+
.resource(item)
86+
.serverSideApply();
87+
88+
//noinspection ConstantConditions
89+
return kubernetesClient.resources(Database.class)
90+
.inNamespace(namespace)
91+
.withName(name)
92+
.waitUntilCondition(
93+
db -> db.getStatus() != null,
94+
10,
95+
TimeUnit.SECONDS
96+
);
97+
}
98+
99+
@Nullable
100+
private String getNamespace() {
101+
if (withoutNamespace) {
102+
return null;
103+
}
104+
105+
if (withNamespace != null) {
106+
return withNamespace;
107+
}
108+
109+
return kubernetesClient.getNamespace();
110+
}
111+
112+
private String getName() {
113+
if (withName != null) {
114+
return withName;
115+
}
116+
117+
return randomKubernetesNameSuffix("test-database");
118+
}
119+
120+
private String getClusterConnectionName() {
121+
return Objects.requireNonNullElse(
122+
withClusterConnectionName,
123+
"test-cluster-connection"
124+
);
125+
}
126+
}

operator/src/test/java/it/aboutbits/postgresql/_support/testdata/persisted/creator/RoleCreate.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,17 @@ public class RoleCreate extends TestDataCreator<Role> {
4747

4848
private RoleSpec.@Nullable Flags withFlags;
4949

50+
public RoleCreate(
51+
int numberOfItems,
52+
Given given,
53+
KubernetesClient kubernetesClient
54+
) {
55+
super(numberOfItems);
56+
this.given = given;
57+
this.kubernetesClient = kubernetesClient;
58+
}
59+
60+
@SuppressWarnings("unused")
5061
public RoleCreate withLogin(boolean login) {
5162
if (!login) {
5263
withPasswordSecretRef = null;
@@ -64,21 +75,12 @@ public RoleCreate withLogin(boolean login) {
6475
return this;
6576
}
6677

78+
@SuppressWarnings("unused")
6779
public RoleCreate withoutNamespace() {
6880
withoutNamespace = true;
6981
return this;
7082
}
7183

72-
public RoleCreate(
73-
int numberOfItems,
74-
Given given,
75-
KubernetesClient kubernetesClient
76-
) {
77-
super(numberOfItems);
78-
this.given = given;
79-
this.kubernetesClient = kubernetesClient;
80-
}
81-
8284
@Override
8385
protected Role create(int index) {
8486
var namespace = getNamespace();

0 commit comments

Comments
 (0)