Skip to content

Commit 817f8ca

Browse files
authored
refactor: share more code (#910)
1 parent ff1a44d commit 817f8ca

File tree

3 files changed

+116
-170
lines changed

3 files changed

+116
-170
lines changed

operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/AbstractOperatorExtension.java

+89-8
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,20 @@
22

33
import java.time.Duration;
44
import java.util.ArrayList;
5+
import java.util.Arrays;
56
import java.util.List;
67
import java.util.Locale;
78
import java.util.UUID;
9+
import java.util.concurrent.TimeUnit;
810

11+
import org.awaitility.Awaitility;
912
import org.junit.jupiter.api.extension.*;
13+
import org.slf4j.Logger;
14+
import org.slf4j.LoggerFactory;
1015

1116
import io.fabric8.kubernetes.api.model.HasMetadata;
1217
import io.fabric8.kubernetes.api.model.KubernetesResourceList;
18+
import io.fabric8.kubernetes.api.model.NamespaceBuilder;
1319
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
1420
import io.fabric8.kubernetes.client.KubernetesClient;
1521
import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
@@ -26,7 +32,9 @@ public abstract class AbstractOperatorExtension implements HasKubernetesClient,
2632
AfterAllCallback,
2733
AfterEachCallback {
2834

29-
protected final KubernetesClient kubernetesClient;
35+
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractOperatorExtension.class);
36+
37+
private final KubernetesClient kubernetesClient;
3038
protected final ConfigurationService configurationService;
3139
protected final List<HasMetadata> infrastructure;
3240
protected Duration infrastructureTimeout;
@@ -55,22 +63,22 @@ protected AbstractOperatorExtension(
5563

5664

5765
@Override
58-
public void beforeAll(ExtensionContext context) throws Exception {
66+
public void beforeAll(ExtensionContext context) {
5967
beforeAllImpl(context);
6068
}
6169

6270
@Override
63-
public void beforeEach(ExtensionContext context) throws Exception {
71+
public void beforeEach(ExtensionContext context) {
6472
beforeEachImpl(context);
6573
}
6674

6775
@Override
68-
public void afterAll(ExtensionContext context) throws Exception {
76+
public void afterAll(ExtensionContext context) {
6977
afterAllImpl(context);
7078
}
7179

7280
@Override
73-
public void afterEach(ExtensionContext context) throws Exception {
81+
public void afterEach(ExtensionContext context) {
7482
afterEachImpl(context);
7583
}
7684

@@ -100,6 +108,7 @@ public <T extends HasMetadata> T replace(Class<T> type, T resource) {
100108
return kubernetesClient.resources(type).inNamespace(namespace).replace(resource);
101109
}
102110

111+
@SuppressWarnings("unchecked")
103112
public <T extends HasMetadata> boolean delete(Class<T> type, T resource) {
104113
return kubernetesClient.resources(type).inNamespace(namespace).delete(resource);
105114
}
@@ -130,7 +139,20 @@ protected void beforeEachImpl(ExtensionContext context) {
130139
}
131140
}
132141

133-
protected abstract void before(ExtensionContext context);
142+
protected void before(ExtensionContext context) {
143+
LOGGER.info("Initializing integration test in namespace {}", namespace);
144+
145+
kubernetesClient
146+
.namespaces()
147+
.create(new NamespaceBuilder().withNewMetadata().withName(namespace).endMetadata().build());
148+
149+
kubernetesClient
150+
.resourceList(infrastructure)
151+
.createOrReplace();
152+
kubernetesClient
153+
.resourceList(infrastructure)
154+
.waitUntilReady(infrastructureTimeout.toMillis(), TimeUnit.MILLISECONDS);
155+
}
134156

135157
protected void afterAllImpl(ExtensionContext context) {
136158
if (oneNamespacePerClass) {
@@ -144,9 +166,32 @@ protected void afterEachImpl(ExtensionContext context) {
144166
}
145167
}
146168

147-
protected abstract void after(ExtensionContext context);
169+
protected void after(ExtensionContext context) {
170+
if (namespace != null) {
171+
if (preserveNamespaceOnError && context.getExecutionException().isPresent()) {
172+
LOGGER.info("Preserving namespace {}", namespace);
173+
} else {
174+
kubernetesClient.resourceList(infrastructure).delete();
175+
deleteOperator();
176+
LOGGER.info("Deleting namespace {} and stopping operator", namespace);
177+
kubernetesClient.namespaces().withName(namespace).delete();
178+
if (waitForNamespaceDeletion) {
179+
LOGGER.info("Waiting for namespace {} to be deleted", namespace);
180+
Awaitility.await("namespace deleted")
181+
.pollInterval(50, TimeUnit.MILLISECONDS)
182+
.atMost(90, TimeUnit.SECONDS)
183+
.until(() -> kubernetesClient.namespaces().withName(namespace).get() == null);
184+
}
185+
}
186+
}
187+
}
188+
189+
protected void deleteOperator() {
190+
// nothing to do by default: only needed if the operator is deployed to the cluster
191+
}
148192

149-
public static abstract class AbstractBuilder {
193+
@SuppressWarnings("unchecked")
194+
public static abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
150195
protected ConfigurationService configurationService;
151196
protected final List<HasMetadata> infrastructure;
152197
protected Duration infrastructureTimeout;
@@ -172,5 +217,41 @@ protected AbstractBuilder() {
172217
"josdk.it.oneNamespacePerClass",
173218
false);
174219
}
220+
221+
public T preserveNamespaceOnError(boolean value) {
222+
this.preserveNamespaceOnError = value;
223+
return (T) this;
224+
}
225+
226+
public T waitForNamespaceDeletion(boolean value) {
227+
this.waitForNamespaceDeletion = value;
228+
return (T) this;
229+
}
230+
231+
public T oneNamespacePerClass(boolean value) {
232+
this.oneNamespacePerClass = value;
233+
return (T) this;
234+
}
235+
236+
public T withConfigurationService(ConfigurationService value) {
237+
configurationService = value;
238+
return (T) this;
239+
}
240+
241+
public T withInfrastructureTimeout(Duration value) {
242+
infrastructureTimeout = value;
243+
return (T) this;
244+
}
245+
246+
public T withInfrastructure(List<HasMetadata> hm) {
247+
infrastructure.addAll(hm);
248+
return (T) this;
249+
}
250+
251+
public T withInfrastructure(HasMetadata... hms) {
252+
infrastructure.addAll(Arrays.asList(hms));
253+
return (T) this;
254+
}
255+
175256
}
176257
}

operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/E2EOperatorExtension.java

+13-78
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@
55
import java.io.InputStream;
66
import java.time.Duration;
77
import java.util.ArrayList;
8+
import java.util.Arrays;
89
import java.util.List;
910
import java.util.Locale;
11+
import java.util.Objects;
1012
import java.util.concurrent.TimeUnit;
1113

12-
import org.awaitility.Awaitility;
1314
import org.junit.jupiter.api.extension.ExtensionContext;
1415
import org.slf4j.Logger;
1516
import org.slf4j.LoggerFactory;
1617

1718
import io.fabric8.kubernetes.api.model.HasMetadata;
18-
import io.fabric8.kubernetes.api.model.NamespaceBuilder;
1919
import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
2020
import io.javaoperatorsdk.operator.api.config.ConfigurationService;
2121

@@ -51,25 +51,15 @@ public static Builder builder() {
5151
return new Builder();
5252
}
5353

54-
@SuppressWarnings("unchecked")
5554
protected void before(ExtensionContext context) {
56-
LOGGER.info("Initializing integration test in namespace {}", namespace);
57-
58-
kubernetesClient
59-
.namespaces()
60-
.create(new NamespaceBuilder().withNewMetadata().withName(namespace).endMetadata().build());
61-
62-
kubernetesClient
63-
.resourceList(infrastructure)
64-
.createOrReplace();
65-
kubernetesClient
66-
.resourceList(infrastructure)
67-
.waitUntilReady(infrastructureTimeout.toMillis(), TimeUnit.MILLISECONDS);
55+
super.before(context);
6856

6957
final var crdPath = "./target/classes/META-INF/fabric8/";
7058
final var crdSuffix = "-v1.yml";
7159

72-
for (var crdFile : new File(crdPath).listFiles((ignored, name) -> name.endsWith(crdSuffix))) {
60+
final var kubernetesClient = getKubernetesClient();
61+
for (var crdFile : Objects
62+
.requireNonNull(new File(crdPath).listFiles((ignored, name) -> name.endsWith(crdSuffix)))) {
7363
try (InputStream is = new FileInputStream(crdFile)) {
7464
final var crd = kubernetesClient.load(is);
7565
crd.createOrReplace();
@@ -81,7 +71,7 @@ protected void before(ExtensionContext context) {
8171
}
8272

8373
LOGGER.debug("Deploying the operator into Kubernetes");
84-
operatorDeployment.stream().forEach(hm -> {
74+
operatorDeployment.forEach(hm -> {
8575
hm.getMetadata().setNamespace(namespace);
8676
if (hm.getKind().toLowerCase(Locale.ROOT).equals("clusterrolebinding")) {
8777
var crb = (ClusterRoleBinding) hm;
@@ -100,88 +90,33 @@ protected void before(ExtensionContext context) {
10090
.waitUntilReady(operatorDeploymentTimeout.toMillis(), TimeUnit.MILLISECONDS);
10191
}
10292

103-
protected void after(ExtensionContext context) {
104-
if (namespace != null) {
105-
if (preserveNamespaceOnError && context.getExecutionException().isPresent()) {
106-
LOGGER.info("Preserving namespace {}", namespace);
107-
} else {
108-
kubernetesClient.resourceList(infrastructure).delete();
109-
kubernetesClient.resourceList(operatorDeployment).inNamespace(namespace).delete();
110-
LOGGER.info("Deleting namespace {} and stopping operator", namespace);
111-
kubernetesClient.namespaces().withName(namespace).delete();
112-
if (waitForNamespaceDeletion) {
113-
LOGGER.info("Waiting for namespace {} to be deleted", namespace);
114-
Awaitility.await("namespace deleted")
115-
.pollInterval(50, TimeUnit.MILLISECONDS)
116-
.atMost(90, TimeUnit.SECONDS)
117-
.until(() -> kubernetesClient.namespaces().withName(namespace).get() == null);
118-
}
119-
}
120-
}
93+
@Override
94+
protected void deleteOperator() {
95+
getKubernetesClient().resourceList(operatorDeployment).inNamespace(namespace).delete();
12196
}
12297

123-
@SuppressWarnings("rawtypes")
124-
public static class Builder extends AbstractBuilder {
98+
public static class Builder extends AbstractBuilder<Builder> {
12599
private final List<HasMetadata> operatorDeployment;
126100
private Duration deploymentTimeout;
127101

128102
protected Builder() {
129-
super();;
103+
super();
130104
this.operatorDeployment = new ArrayList<>();
131105
this.deploymentTimeout = Duration.ofMinutes(1);
132106
}
133107

134-
public Builder preserveNamespaceOnError(boolean value) {
135-
this.preserveNamespaceOnError = value;
136-
return this;
137-
}
138-
139-
public Builder waitForNamespaceDeletion(boolean value) {
140-
this.waitForNamespaceDeletion = value;
141-
return this;
142-
}
143-
144-
public Builder oneNamespacePerClass(boolean value) {
145-
this.oneNamespacePerClass = value;
146-
return this;
147-
}
148-
149-
public Builder withConfigurationService(ConfigurationService value) {
150-
configurationService = value;
151-
return this;
152-
}
153-
154108
public Builder withDeploymentTimeout(Duration value) {
155109
deploymentTimeout = value;
156110
return this;
157111
}
158112

159-
public Builder withInfrastructureTimeout(Duration value) {
160-
infrastructureTimeout = value;
161-
return this;
162-
}
163-
164-
public Builder withInfrastructure(List<HasMetadata> hm) {
165-
infrastructure.addAll(hm);
166-
return this;
167-
}
168-
169-
public Builder withInfrastructure(HasMetadata... hms) {
170-
for (HasMetadata hm : hms) {
171-
infrastructure.add(hm);
172-
}
173-
return this;
174-
}
175-
176113
public Builder withOperatorDeployment(List<HasMetadata> hm) {
177114
operatorDeployment.addAll(hm);
178115
return this;
179116
}
180117

181118
public Builder withOperatorDeployment(HasMetadata... hms) {
182-
for (HasMetadata hm : hms) {
183-
operatorDeployment.add(hm);
184-
}
119+
operatorDeployment.addAll(Arrays.asList(hms));
185120
return this;
186121
}
187122

0 commit comments

Comments
 (0)