Skip to content

Commit 817f8ca

Browse files
authoredFeb 4, 2022
refactor: share more code (#910)
·
v5.1.1v2.1.1
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

Lines changed: 89 additions & 8 deletions
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

Lines changed: 13 additions & 78 deletions
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

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

Lines changed: 14 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,22 @@
66
import java.util.List;
77
import java.util.concurrent.TimeUnit;
88
import java.util.stream.Collectors;
9+
import java.util.stream.Stream;
910

10-
import org.awaitility.Awaitility;
1111
import org.junit.jupiter.api.extension.ExtensionContext;
1212
import org.slf4j.Logger;
1313
import org.slf4j.LoggerFactory;
1414

1515
import io.fabric8.kubernetes.api.model.HasMetadata;
16-
import io.fabric8.kubernetes.api.model.NamespaceBuilder;
1716
import io.javaoperatorsdk.operator.Operator;
18-
import io.javaoperatorsdk.operator.api.config.BaseConfigurationService;
1917
import io.javaoperatorsdk.operator.api.config.ConfigurationService;
20-
import io.javaoperatorsdk.operator.api.config.Version;
2118
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
2219
import io.javaoperatorsdk.operator.processing.Controller;
2320
import io.javaoperatorsdk.operator.processing.retry.Retry;
2421

2522
import static io.javaoperatorsdk.operator.api.config.ControllerConfigurationOverrider.override;
2623

24+
@SuppressWarnings("rawtypes")
2725
public class OperatorExtension extends AbstractOperatorExtension {
2826

2927
private static final Logger LOGGER = LoggerFactory.getLogger(OperatorExtension.class);
@@ -43,7 +41,7 @@ private OperatorExtension(
4341
preserveNamespaceOnError,
4442
waitForNamespaceDeletion);
4543
this.reconcilers = reconcilers;
46-
this.operator = new Operator(this.kubernetesClient, this.configurationService);
44+
this.operator = new Operator(getKubernetesClient(), this.configurationService);
4745
}
4846

4947
/**
@@ -55,23 +53,20 @@ public static Builder builder() {
5553
return new Builder();
5654
}
5755

58-
@SuppressWarnings({"rawtypes"})
56+
private Stream<Reconciler> reconcilers() {
57+
return operator.getControllers().stream().map(Controller::getReconciler);
58+
}
59+
5960
public List<Reconciler> getReconcilers() {
60-
return operator.getControllers().stream()
61-
.map(Controller::getReconciler)
62-
.collect(Collectors.toUnmodifiableList());
61+
return reconcilers().collect(Collectors.toUnmodifiableList());
6362
}
6463

6564
public Reconciler getFirstReconciler() {
66-
return operator.getControllers().stream()
67-
.map(Controller::getReconciler)
68-
.findFirst().orElseThrow();
65+
return reconcilers().findFirst().orElseThrow();
6966
}
7067

71-
@SuppressWarnings({"rawtypes"})
7268
public <T extends Reconciler> T getControllerOfType(Class<T> type) {
73-
return operator.getControllers().stream()
74-
.map(Controller::getReconciler)
69+
return reconcilers()
7570
.filter(type::isInstance)
7671
.map(type::cast)
7772
.findFirst()
@@ -81,18 +76,7 @@ public <T extends Reconciler> T getControllerOfType(Class<T> type) {
8176

8277
@SuppressWarnings("unchecked")
8378
protected void before(ExtensionContext context) {
84-
LOGGER.info("Initializing integration test in namespace {}", namespace);
85-
86-
kubernetesClient
87-
.namespaces()
88-
.create(new NamespaceBuilder().withNewMetadata().withName(namespace).endMetadata().build());
89-
90-
kubernetesClient
91-
.resourceList(infrastructure)
92-
.createOrReplace();
93-
kubernetesClient
94-
.resourceList(infrastructure)
95-
.waitUntilReady(infrastructureTimeout.toMillis(), TimeUnit.MILLISECONDS);
79+
super.before(context);
9680

9781
for (var ref : reconcilers) {
9882
final var config = configurationService.getConfigurationFor(ref.reconciler);
@@ -103,6 +87,7 @@ protected void before(ExtensionContext context) {
10387
oconfig.withRetry(ref.retry);
10488
}
10589

90+
final var kubernetesClient = getKubernetesClient();
10691
try (InputStream is = getClass().getResourceAsStream(path)) {
10792
final var crd = kubernetesClient.load(is);
10893
crd.createOrReplace();
@@ -116,7 +101,6 @@ protected void before(ExtensionContext context) {
116101
((KubernetesClientAware) ref.reconciler).setKubernetesClient(kubernetesClient);
117102
}
118103

119-
120104
this.operator.register(ref.reconciler, oconfig.build());
121105
}
122106

@@ -125,22 +109,7 @@ protected void before(ExtensionContext context) {
125109
}
126110

127111
protected void after(ExtensionContext context) {
128-
if (namespace != null) {
129-
if (preserveNamespaceOnError && context.getExecutionException().isPresent()) {
130-
LOGGER.info("Preserving namespace {}", namespace);
131-
} else {
132-
kubernetesClient.resourceList(infrastructure).delete();
133-
LOGGER.info("Deleting namespace {} and stopping operator", namespace);
134-
kubernetesClient.namespaces().withName(namespace).delete();
135-
if (waitForNamespaceDeletion) {
136-
LOGGER.info("Waiting for namespace {} to be deleted", namespace);
137-
Awaitility.await("namespace deleted")
138-
.pollInterval(50, TimeUnit.MILLISECONDS)
139-
.atMost(90, TimeUnit.SECONDS)
140-
.until(() -> kubernetesClient.namespaces().withName(namespace).get() == null);
141-
}
142-
}
143-
}
112+
super.after(context);
144113

145114
try {
146115
this.operator.stop();
@@ -150,53 +119,14 @@ protected void after(ExtensionContext context) {
150119
}
151120

152121
@SuppressWarnings("rawtypes")
153-
public static class Builder extends AbstractBuilder {
122+
public static class Builder extends AbstractBuilder<Builder> {
154123
private final List<ReconcilerSpec> reconcilers;
155-
private ConfigurationService configurationService;
156124

157125
protected Builder() {
158126
super();
159-
this.configurationService = new BaseConfigurationService(Version.UNKNOWN);
160127
this.reconcilers = new ArrayList<>();
161128
}
162129

163-
public Builder preserveNamespaceOnError(boolean value) {
164-
this.preserveNamespaceOnError = value;
165-
return this;
166-
}
167-
168-
public Builder waitForNamespaceDeletion(boolean value) {
169-
this.waitForNamespaceDeletion = value;
170-
return this;
171-
}
172-
173-
public Builder oneNamespacePerClass(boolean value) {
174-
this.oneNamespacePerClass = value;
175-
return this;
176-
}
177-
178-
public Builder withConfigurationService(ConfigurationService value) {
179-
configurationService = value;
180-
return this;
181-
}
182-
183-
public Builder withInfrastructureTimeout(Duration value) {
184-
infrastructureTimeout = value;
185-
return this;
186-
}
187-
188-
public Builder withInfrastructure(List<HasMetadata> hm) {
189-
infrastructure.addAll(hm);
190-
return this;
191-
}
192-
193-
public Builder withInfrastructure(HasMetadata... hms) {
194-
for (HasMetadata hm : hms) {
195-
infrastructure.add(hm);
196-
}
197-
return this;
198-
}
199-
200130
@SuppressWarnings("rawtypes")
201131
public Builder withReconciler(Reconciler value) {
202132
reconcilers.add(new ReconcilerSpec(value, null));

0 commit comments

Comments
 (0)
Please sign in to comment.