Skip to content

Commit

Permalink
e2e test impl
Browse files Browse the repository at this point in the history
Signed-off-by: Attila Mészáros <csviri@gmail.com>
  • Loading branch information
csviri committed Apr 5, 2024
1 parent d95c61a commit 2c38d29
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 50 deletions.
21 changes: 15 additions & 6 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
name: Verify Pull Request

env:
MAVEN_ARGS: -V -ntp -e

concurrency:
group: ${{ github.ref }}-${{ github.workflow }}
cancel-in-progress: true
Expand All @@ -25,9 +22,9 @@ jobs:
cache: 'maven'
- name: Check code format
run: |
./mvnw ${MAVEN_ARGS} spotless:check --file pom.xml
./mvnw spotless:check --file pom.xml
build_with_tests:
build_and_run_tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -38,4 +35,16 @@ jobs:
java-version: 21
cache: 'maven'
- name: Run integration tests
run: ./mvnw ${MAVEN_ARGS} clean install
run: ./mvnw clean install
- name: Setup minikube for E2E tests
uses: manusa/actions-setup-minikube@v2.10.0
with:
minikube version: v1.32.0
kubernetes version: v1.29.1
github token: ${{ secrets.GITHUB_TOKEN }}
driver: docker
- name: Run E2E tests
run: |
eval $(minikube -p minikube docker-env)
./mvnw clean install -DskipTests -Dquarkus.container-image.build=true -Dquarkus.kubernetes.namespace=default
./mvnw test -Pe2e-tests
2 changes: 1 addition & 1 deletion src/main/java/io/csviri/operator/resourceglue/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public static Map<String, GenericKubernetesResource> getRelatedResources(Glue gl
Context<?> context) {
var gvk =
new GroupVersionKind(relatedResourceSpec.getApiVersion(), relatedResourceSpec.getKind());
log.debug("Getting event source for gvk: {}", gvk);
log.trace("Getting event source for gvk: {}", gvk);
var es =
(InformerEventSource<GenericKubernetesResource, Glue>) context
.eventSourceRetriever()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ class GlueOperatorTest extends TestBase {

@BeforeEach
void applyCRD() {
TestUtils.applyCrd(TestCustomResource.class, client);
TestUtils.applyCrd(TestCustomResource2.class, client);
TestUtils.applyTestCrd(client, TestCustomResource.class, TestCustomResource2.class);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class GlueRelatedResourcesTest extends TestBase {

@BeforeEach
void applyCRD() {
TestUtils.applyCrd(ClusterScopeTestCustomResource.class, client);
TestUtils.applyTestCrd(client, ClusterScopeTestCustomResource.class);
}

@Test
Expand Down
87 changes: 73 additions & 14 deletions src/test/java/io/csviri/operator/resourceglue/TestUtils.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package io.csviri.operator.resourceglue;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -18,6 +20,8 @@
import io.fabric8.kubernetes.client.utils.Serialization;
import io.javaoperatorsdk.operator.ReconcilerUtils;

import static com.oracle.truffle.js.builtins.ObjectFunctionBuiltins.ObjectFunction.is;

public class TestUtils {

public static final int CRD_READY_WAIT = 1000;
Expand Down Expand Up @@ -56,33 +60,88 @@ public static GenericKubernetesResource createOrUpdate(KubernetesClient client,
return client.resource(load(path)).createOr(NonDeletingOperation::update);
}

public static void applyCrd(Class<? extends HasMetadata> resourceClass, KubernetesClient client) {
applyCrd(ReconcilerUtils.getResourceTypeName(resourceClass), client);
public static void applyCrd(Class<? extends HasMetadata> resourceClass, KubernetesClient client,
boolean test) {
applyCrd(ReconcilerUtils.getResourceTypeName(resourceClass), client, test);
}

@SafeVarargs
public static void applyTestCrd(KubernetesClient client,
Class<? extends HasMetadata>... resourceClasses) {
Arrays.stream(resourceClasses).forEach(c -> applyCrd(c, client, true));
}

@SafeVarargs
public static void applyCrd(KubernetesClient client,
Class<? extends HasMetadata>... resourceClasses) {
Arrays.stream(resourceClasses).forEach(c -> applyCrd(c, client));
Arrays.stream(resourceClasses).forEach(c -> applyCrd(c, client, false));
}

public static void applyCrd(String resourceTypeName, KubernetesClient client) {
String path = "/META-INF/fabric8/" + resourceTypeName + "-v1.yml";
try (InputStream is = TestUtils.class.getResourceAsStream(path)) {
if (is == null) {
throw new IllegalStateException("Cannot find CRD at " + path);
}
public static void applyCrd(String resourceTypeName, KubernetesClient client, boolean test) {

try (InputStream is = createInputStream(resourceTypeName, test)) {

var crdString = new String(is.readAllBytes(), StandardCharsets.UTF_8);
log.debug("Applying CRD: {}", crdString);
final var crd = client.load(new ByteArrayInputStream(crdString.getBytes()));
crd.createOrReplace();
Thread.sleep(CRD_READY_WAIT); // readiness is not applicable for CRD, just wait a little
log.debug("Applied CRD with path: {}", path);
log.debug("Applied CRD for resource: {}", resourceTypeName);
} catch (InterruptedException ex) {
log.error("Interrupted.", ex);
Thread.currentThread().interrupt();
} catch (Exception ex) {
throw new IllegalStateException("Cannot apply CRD yaml: " + path, ex);
throw new IllegalStateException("Cannot apply CRD for: " + resourceTypeName, ex);
}
}

private static InputStream createInputStream(String resourceTypeName, boolean test)
throws FileNotFoundException {
if (test) {
String path = "/META-INF/fabric8/" + resourceTypeName + "-v1.yml";
return TestUtils.class.getResourceAsStream(path);
} else {
String path = "target/kubernetes/" + resourceTypeName + "-v1.yml";
File file = new File(path);

var res = new FileInputStream(path);
if (!file.exists()) {
throw new IllegalStateException("Cannot find CRD at " + file.getAbsolutePath());
}
return res;
}
}

public static void applyAndWait(KubernetesClient client, String path) {
applyAndWait(client, path, null);
}

public static void applyAndWait(KubernetesClient client, String path,
UnaryOperator<HasMetadata> transform) {
try (FileInputStream fileInputStream = new FileInputStream(path)) {
applyAndWait(client, fileInputStream, transform);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}

public static void applyAndWait(KubernetesClient client, InputStream is) {
applyAndWait(client, is, null);
}

public static void applyAndWait(KubernetesClient client, List<HasMetadata> resources,
UnaryOperator<HasMetadata> transformer) {
if (transformer != null) {
resources = resources.stream().map(transformer).collect(Collectors.toList());
}
client.resourceList(resources).createOrReplace();
client.resourceList(resources).waitUntilReady(3, TimeUnit.MINUTES);
}

public static void applyAndWait(KubernetesClient client, InputStream is,
UnaryOperator<HasMetadata> transformer) {
var resources = client.load(is).items();
applyAndWait(client, resources, transformer);
}

}
21 changes: 0 additions & 21 deletions src/test/java/io/csviri/operator/resourceglue/WebPageE2E.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package io.csviri.operator.resourceglue.sample.webpage;

import io.fabric8.kubernetes.api.model.Namespaced;
import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.model.annotation.Group;
import io.fabric8.kubernetes.model.annotation.Plural;
import io.fabric8.kubernetes.model.annotation.Singular;
import io.fabric8.kubernetes.model.annotation.Version;

@Version(value = "v1", storage = true, served = true)
@Version(value = "v1")
@Group("resourceglueoperator.sample")
@Singular("webpage")
@Plural("webpages")
@javax.annotation.processing.Generated("io.fabric8.java.generator.CRGeneratorRunner")
public class WebPage extends io.fabric8.kubernetes.client.CustomResource<WebPageSpec, WebPageStatus>
implements io.fabric8.kubernetes.api.model.Namespaced {
public class WebPage extends CustomResource<WebPageSpec, WebPageStatus>
implements Namespaced {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package io.csviri.operator.resourceglue;


import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import io.csviri.operator.resourceglue.customresource.glue.Glue;
import io.csviri.operator.resourceglue.customresource.operator.GlueOperator;
import io.csviri.operator.resourceglue.sample.webpage.WebPage;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
import io.fabric8.kubernetes.client.dsl.NonDeletingOperation;

import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

public class WebPageE2E {

private KubernetesClient client = new KubernetesClientBuilder().build();

@BeforeEach
void applyCRDs() {
TestUtils.applyCrd(client, Glue.class, GlueOperator.class);
TestUtils.applyTestCrd(client, WebPage.class);
TestUtils.applyAndWait(client, "target/kubernetes/kubernetes.yml");
}

@Test
void testDeployment() {
client.resource(TestUtils.load("/sample/webpage/webpage.operator.yaml"))
.createOr(NonDeletingOperation::update);
var webPage = TestUtils.load("/sample/webpage/webpage.sample.yaml", WebPage.class);
var createdWebPage = client.resource(webPage).createOr(NonDeletingOperation::update);

await().untilAsserted(() -> {
var deployment =
client.resources(Deployment.class).withName(webPage.getMetadata().getName()).get();
var configMap =
client.resources(ConfigMap.class).withName(webPage.getMetadata().getName()).get();
var service = client.resources(Service.class).withName(webPage.getMetadata().getName()).get();
var ingress = client.resources(Ingress.class).withName(webPage.getMetadata().getName()).get();

assertThat(deployment).isNotNull();
assertThat(configMap).isNotNull();
assertThat(service).isNotNull();
assertThat(ingress).isNull();
});

createdWebPage.getMetadata().setResourceVersion(null);
createdWebPage.getSpec().setExposed(true);
createdWebPage = client.resource(createdWebPage).update();

await().untilAsserted(() -> {
var ingress = client.resources(Ingress.class).withName(webPage.getMetadata().getName()).get();
assertThat(ingress).isNotNull();
});

client.resource(createdWebPage).delete();

await().untilAsserted(() -> {
var deployment =
client.resources(Deployment.class).withName(webPage.getMetadata().getName()).get();
var configMap =
client.resources(ConfigMap.class).withName(webPage.getMetadata().getName()).get();
var service = client.resources(Service.class).withName(webPage.getMetadata().getName()).get();
var ingress = client.resources(Ingress.class).withName(webPage.getMetadata().getName()).get();

assertThat(deployment).isNull();
assertThat(configMap).isNull();
assertThat(service).isNull();
assertThat(ingress).isNull();
});
}

}
2 changes: 1 addition & 1 deletion src/test/resources/sample/webpage/webpage.sample.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apiVersion: "resourceglueoperator.sample/v1"
kind: WebPage
metadata:
name: hellows
name: webpage1
spec:
exposed: false
html: |
Expand Down

0 comments on commit 2c38d29

Please sign in to comment.