Skip to content
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

WebPage E2E Test #68

Merged
merged 4 commits into from
Apr 5, 2024
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
31 changes: 25 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_unit_and_integration_tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -38,4 +35,26 @@ jobs:
java-version: 21
cache: 'maven'
- name: Run integration tests
run: ./mvnw ${MAVEN_ARGS} clean install
run: ./mvnw clean install
run_e2e_tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Java and Maven
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
cache: 'maven'
- name: Setup minikube for E2E tests
uses: manusa/[email protected]
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
33 changes: 33 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
<excludes>
<exclude>**/*E2E.java</exclude>
</excludes>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
Expand Down Expand Up @@ -204,7 +210,34 @@
</java>
</configuration>
</plugin>

</plugins>
</build>

<profiles>
<profile>
<id>e2e-tests</id>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<includes>
<include>**/*E2E.java</include>
</includes>
<excludes>
<exclude>**/*Test.java</exclude>
</excludes>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>

</project>
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
99 changes: 84 additions & 15 deletions src/test/java/io/csviri/operator/resourceglue/TestUtils.java
Original file line number Diff line number Diff line change
@@ -1,9 +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 @@ -17,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 All @@ -39,40 +44,104 @@ public static GlueOperator loadResourceFlowOperator(String path) {
}
}

public static GenericKubernetesResource load(String path) {
public static <T extends HasMetadata> T load(String path, Class<T> clazz) {
try (InputStream is = TestUtils.class.getResourceAsStream(path)) {
return Serialization.unmarshal(is, GenericKubernetesResource.class);
return Serialization.unmarshal(is, clazz);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

public static GenericKubernetesResource load(String path) {
return load(path, GenericKubernetesResource.class);
}

public static GenericKubernetesResource createOrUpdate(KubernetesClient client, String path) {
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);
}

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);
}
@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, false));
}

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);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +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")
@Group("resourceglueoperator.sample")
@Singular("webpage")
@Plural("webpages")
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();
});
}

}
Loading
Loading