Skip to content

refactor: share more code #910

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@

import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import org.awaitility.Awaitility;
import org.junit.jupiter.api.extension.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.KubernetesResourceList;
import io.fabric8.kubernetes.api.model.NamespaceBuilder;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
Expand All @@ -26,7 +32,9 @@ public abstract class AbstractOperatorExtension implements HasKubernetesClient,
AfterAllCallback,
AfterEachCallback {

protected final KubernetesClient kubernetesClient;
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractOperatorExtension.class);

private final KubernetesClient kubernetesClient;
protected final ConfigurationService configurationService;
protected final List<HasMetadata> infrastructure;
protected Duration infrastructureTimeout;
Expand Down Expand Up @@ -55,22 +63,22 @@ protected AbstractOperatorExtension(


@Override
public void beforeAll(ExtensionContext context) throws Exception {
public void beforeAll(ExtensionContext context) {
beforeAllImpl(context);
}

@Override
public void beforeEach(ExtensionContext context) throws Exception {
public void beforeEach(ExtensionContext context) {
beforeEachImpl(context);
}

@Override
public void afterAll(ExtensionContext context) throws Exception {
public void afterAll(ExtensionContext context) {
afterAllImpl(context);
}

@Override
public void afterEach(ExtensionContext context) throws Exception {
public void afterEach(ExtensionContext context) {
afterEachImpl(context);
}

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

@SuppressWarnings("unchecked")
public <T extends HasMetadata> boolean delete(Class<T> type, T resource) {
return kubernetesClient.resources(type).inNamespace(namespace).delete(resource);
}
Expand Down Expand Up @@ -130,7 +139,20 @@ protected void beforeEachImpl(ExtensionContext context) {
}
}

protected abstract void before(ExtensionContext context);
protected void before(ExtensionContext context) {
LOGGER.info("Initializing integration test in namespace {}", namespace);

kubernetesClient
.namespaces()
.create(new NamespaceBuilder().withNewMetadata().withName(namespace).endMetadata().build());

kubernetesClient
.resourceList(infrastructure)
.createOrReplace();
kubernetesClient
.resourceList(infrastructure)
.waitUntilReady(infrastructureTimeout.toMillis(), TimeUnit.MILLISECONDS);
}

protected void afterAllImpl(ExtensionContext context) {
if (oneNamespacePerClass) {
Expand All @@ -144,9 +166,32 @@ protected void afterEachImpl(ExtensionContext context) {
}
}

protected abstract void after(ExtensionContext context);
protected void after(ExtensionContext context) {
if (namespace != null) {
if (preserveNamespaceOnError && context.getExecutionException().isPresent()) {
LOGGER.info("Preserving namespace {}", namespace);
} else {
kubernetesClient.resourceList(infrastructure).delete();
deleteOperator();
LOGGER.info("Deleting namespace {} and stopping operator", namespace);
kubernetesClient.namespaces().withName(namespace).delete();
if (waitForNamespaceDeletion) {
LOGGER.info("Waiting for namespace {} to be deleted", namespace);
Awaitility.await("namespace deleted")
.pollInterval(50, TimeUnit.MILLISECONDS)
.atMost(90, TimeUnit.SECONDS)
.until(() -> kubernetesClient.namespaces().withName(namespace).get() == null);
}
}
}
}

protected void deleteOperator() {
// nothing to do by default: only needed if the operator is deployed to the cluster
}

public static abstract class AbstractBuilder {
@SuppressWarnings("unchecked")
public static abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
protected ConfigurationService configurationService;
protected final List<HasMetadata> infrastructure;
protected Duration infrastructureTimeout;
Expand All @@ -172,5 +217,41 @@ protected AbstractBuilder() {
"josdk.it.oneNamespacePerClass",
false);
}

public T preserveNamespaceOnError(boolean value) {
this.preserveNamespaceOnError = value;
return (T) this;
}

public T waitForNamespaceDeletion(boolean value) {
this.waitForNamespaceDeletion = value;
return (T) this;
}

public T oneNamespacePerClass(boolean value) {
this.oneNamespacePerClass = value;
return (T) this;
}

public T withConfigurationService(ConfigurationService value) {
configurationService = value;
return (T) this;
}

public T withInfrastructureTimeout(Duration value) {
infrastructureTimeout = value;
return (T) this;
}

public T withInfrastructure(List<HasMetadata> hm) {
infrastructure.addAll(hm);
return (T) this;
}

public T withInfrastructure(HasMetadata... hms) {
infrastructure.addAll(Arrays.asList(hms));
return (T) this;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
import java.io.InputStream;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import org.awaitility.Awaitility;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.NamespaceBuilder;
import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
import io.javaoperatorsdk.operator.api.config.ConfigurationService;

Expand Down Expand Up @@ -51,25 +51,15 @@ public static Builder builder() {
return new Builder();
}

@SuppressWarnings("unchecked")
protected void before(ExtensionContext context) {
LOGGER.info("Initializing integration test in namespace {}", namespace);

kubernetesClient
.namespaces()
.create(new NamespaceBuilder().withNewMetadata().withName(namespace).endMetadata().build());

kubernetesClient
.resourceList(infrastructure)
.createOrReplace();
kubernetesClient
.resourceList(infrastructure)
.waitUntilReady(infrastructureTimeout.toMillis(), TimeUnit.MILLISECONDS);
super.before(context);

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

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

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

protected void after(ExtensionContext context) {
if (namespace != null) {
if (preserveNamespaceOnError && context.getExecutionException().isPresent()) {
LOGGER.info("Preserving namespace {}", namespace);
} else {
kubernetesClient.resourceList(infrastructure).delete();
kubernetesClient.resourceList(operatorDeployment).inNamespace(namespace).delete();
LOGGER.info("Deleting namespace {} and stopping operator", namespace);
kubernetesClient.namespaces().withName(namespace).delete();
if (waitForNamespaceDeletion) {
LOGGER.info("Waiting for namespace {} to be deleted", namespace);
Awaitility.await("namespace deleted")
.pollInterval(50, TimeUnit.MILLISECONDS)
.atMost(90, TimeUnit.SECONDS)
.until(() -> kubernetesClient.namespaces().withName(namespace).get() == null);
}
}
}
@Override
protected void deleteOperator() {
getKubernetesClient().resourceList(operatorDeployment).inNamespace(namespace).delete();
}

@SuppressWarnings("rawtypes")
public static class Builder extends AbstractBuilder {
public static class Builder extends AbstractBuilder<Builder> {
private final List<HasMetadata> operatorDeployment;
private Duration deploymentTimeout;

protected Builder() {
super();;
super();
this.operatorDeployment = new ArrayList<>();
this.deploymentTimeout = Duration.ofMinutes(1);
}

public Builder preserveNamespaceOnError(boolean value) {
this.preserveNamespaceOnError = value;
return this;
}

public Builder waitForNamespaceDeletion(boolean value) {
this.waitForNamespaceDeletion = value;
return this;
}

public Builder oneNamespacePerClass(boolean value) {
this.oneNamespacePerClass = value;
return this;
}

public Builder withConfigurationService(ConfigurationService value) {
configurationService = value;
return this;
}

public Builder withDeploymentTimeout(Duration value) {
deploymentTimeout = value;
return this;
}

public Builder withInfrastructureTimeout(Duration value) {
infrastructureTimeout = value;
return this;
}

public Builder withInfrastructure(List<HasMetadata> hm) {
infrastructure.addAll(hm);
return this;
}

public Builder withInfrastructure(HasMetadata... hms) {
for (HasMetadata hm : hms) {
infrastructure.add(hm);
}
return this;
}

public Builder withOperatorDeployment(List<HasMetadata> hm) {
operatorDeployment.addAll(hm);
return this;
}

public Builder withOperatorDeployment(HasMetadata... hms) {
for (HasMetadata hm : hms) {
operatorDeployment.add(hm);
}
operatorDeployment.addAll(Arrays.asList(hms));
return this;
}

Expand Down
Loading