Skip to content

Commit 92ab045

Browse files
committed
test the ClusterConnectionReconciler error cases
1 parent 2020658 commit 92ab045

4 files changed

Lines changed: 119 additions & 15 deletions

File tree

build.gradle.kts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ dependencies {
8787
* Testing
8888
*/
8989
testImplementation("io.quarkus:quarkus-junit5")
90+
testImplementation("io.quarkus:quarkus-junit5-mockito")
9091
testImplementation("org.awaitility:awaitility")
9192
testImplementation(libs.assertj)
9293
testImplementation(libs.datafaker)
@@ -128,6 +129,13 @@ tasks.withType<Test> {
128129
systemProperty("java.util.logging.manager", "org.jboss.logmanager.LogManager")
129130
jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED")
130131

132+
val mockitoAgent = configurations.testRuntimeClasspath.get().find {
133+
it.name.contains("mockito-core")
134+
}
135+
if (mockitoAgent != null) {
136+
jvmArgs("-javaagent:${mockitoAgent.absolutePath}")
137+
}
138+
131139
testLogging {
132140
exceptionFormat = TestExceptionFormat.FULL
133141

src/main/java/it/aboutbits/postgresql/core/BaseReconciler.java

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,19 +93,8 @@ public <E extends Exception> UpdateControl<CR> handleError(
9393
S status,
9494
E exception
9595
) {
96-
return handleError(
97-
resource,
98-
status,
99-
exception.getMessage()
100-
);
101-
}
102-
103-
public UpdateControl<CR> handleError(
104-
CR resource,
105-
S status,
106-
@Nullable String message
107-
) {
108-
status.setPhase(CRPhase.ERROR).setMessage(message);
96+
status.setPhase(CRPhase.ERROR)
97+
.setMessage(exception.getMessage());
10998

11099
return UpdateControl.patchStatus(resource)
111100
.rescheduleAfter(Duration.ofSeconds(30));

src/main/java/it/aboutbits/postgresql/crd/role/RoleUtil.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,14 +349,14 @@ public static void reconcileRoleMembership(
349349
}
350350
}
351351

352-
public static Query buildGrantRoleToMember(
352+
private static Query buildGrantRoleToMember(
353353
String role,
354354
String member
355355
) {
356356
return query("grant {0} to {1}", role(role), role(member));
357357
}
358358

359-
public static Query buildRevokeRoleFromMember(
359+
private static Query buildRevokeRoleFromMember(
360360
String role,
361361
String member
362362
) {
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package it.aboutbits.postgresql.crd.connection;
2+
3+
import io.fabric8.kubernetes.api.model.ObjectMeta;
4+
import io.javaoperatorsdk.operator.api.reconciler.Context;
5+
import io.quarkus.test.InjectMock;
6+
import io.quarkus.test.junit.QuarkusTest;
7+
import it.aboutbits.postgresql.core.PostgreSQLContextFactory;
8+
import jakarta.inject.Inject;
9+
import org.jooq.DSLContext;
10+
import org.jooq.exception.DataAccessException;
11+
import org.junit.jupiter.api.BeforeEach;
12+
import org.junit.jupiter.api.DisplayName;
13+
import org.junit.jupiter.api.Test;
14+
15+
import java.sql.SQLException;
16+
import java.util.Collections;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.mockito.ArgumentMatchers.anyString;
20+
import static org.mockito.Mockito.mock;
21+
import static org.mockito.Mockito.when;
22+
23+
@QuarkusTest
24+
class ClusterConnectionReconcilerErrorTest {
25+
@InjectMock
26+
PostgreSQLContextFactory contextFactory;
27+
28+
@Inject
29+
ClusterConnectionReconciler reconciler;
30+
31+
private ClusterConnection resource;
32+
private Context<ClusterConnection> context;
33+
34+
@BeforeEach
35+
void setUp() {
36+
resource = new ClusterConnection();
37+
38+
var metadata = new ObjectMeta();
39+
metadata.setGeneration(1L);
40+
41+
// We mock the spec to ensure getName() works safely without throwing NPE,
42+
// as the custom getName() implementation in ClusterConnection relies on spec fields.
43+
var spec = mock(ClusterConnectionSpec.class);
44+
45+
when(spec.getHost()).thenReturn("localhost");
46+
when(spec.getPort()).thenReturn(5432);
47+
when(spec.getMaintenanceDatabase()).thenReturn("postgres");
48+
when(spec.getParameters()).thenReturn(Collections.emptyMap());
49+
50+
resource.setSpec(spec);
51+
resource.setMetadata(metadata);
52+
53+
//noinspection unchecked
54+
context = mock(Context.class);
55+
}
56+
57+
@Test
58+
@DisplayName("Should handle SQLException during DSL context creation")
59+
void reconcile_whenDslCreationFails_shouldReturnErrorStatus() throws SQLException {
60+
// given
61+
var errorMessage = "Connection refused to database";
62+
63+
when(contextFactory.getDSLContext(resource)).thenThrow(
64+
new SQLException(errorMessage)
65+
);
66+
67+
// when
68+
var updateControl = reconciler.reconcile(resource, context);
69+
70+
// then
71+
assertThat(updateControl.getResource())
72+
.isPresent()
73+
.get()
74+
.extracting(ClusterConnection::getStatus)
75+
.satisfies(status -> {
76+
assertThat(status.getMessage()).contains(errorMessage);
77+
});
78+
}
79+
80+
@Test
81+
@DisplayName("Should handle DataAccessException during version check")
82+
void reconcile_whenVersionQueryFails_shouldReturnErrorStatus() throws SQLException {
83+
// given
84+
var errorMessage = "Query execution failed";
85+
var dslContext = mock(DSLContext.class);
86+
87+
when(contextFactory.getDSLContext(resource)).thenReturn(
88+
dslContext
89+
);
90+
91+
when(dslContext.fetchSingle(anyString())).thenThrow(
92+
new DataAccessException(errorMessage)
93+
);
94+
95+
// when
96+
var updateControl = reconciler.reconcile(resource, context);
97+
98+
// then
99+
assertThat(updateControl.getResource())
100+
.isPresent()
101+
.get()
102+
.extracting(ClusterConnection::getStatus)
103+
.satisfies(status -> {
104+
assertThat(status.getMessage()).contains(errorMessage);
105+
});
106+
}
107+
}

0 commit comments

Comments
 (0)