diff --git a/connectors/citrus-knative/pom.xml b/connectors/citrus-knative/pom.xml new file mode 100644 index 0000000000..9220def1ed --- /dev/null +++ b/connectors/citrus-knative/pom.xml @@ -0,0 +1,96 @@ + + 4.0.0 + + + org.citrusframework + citrus-connectors + 4.4.0-SNAPSHOT + ../pom.xml + + + citrus-knative + Citrus :: Connectors :: Knative + + + + org.citrusframework + citrus-base + ${project.version} + + + org.citrusframework + citrus-http + ${project.version} + + + org.citrusframework + citrus-kubernetes + ${project.version} + + + + jakarta.xml.bind + jakarta.xml.bind-api + + + + io.fabric8 + kubernetes-client + + + io.fabric8 + knative-client + + + + com.squareup.okhttp3 + okhttp + + + + + org.citrusframework + citrus-test-support + ${project.version} + test + + + org.citrusframework + citrus-testng + ${project.version} + test + + + org.citrusframework + citrus-spring + ${project.version} + test + + + org.citrusframework + citrus-xml + ${project.version} + test + + + org.citrusframework + citrus-yaml + ${project.version} + test + + + + io.fabric8 + kubernetes-server-mock + test + + + com.squareup.okhttp3 + mockwebserver + test + + + + diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/KnativeSettings.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/KnativeSettings.java new file mode 100644 index 0000000000..7f9a960a43 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/KnativeSettings.java @@ -0,0 +1,253 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative; + +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.citrusframework.kubernetes.KubernetesSettings; +import org.citrusframework.util.StringUtils; + +public class KnativeSettings { + + private static final String KNATIVE_PROPERTY_PREFIX = "citrus.knative."; + private static final String KNATIVE_ENV_PREFIX = "CITRUS_KNATIVE_"; + + private static final String EVENT_PRODUCER_TIMEOUT_PROPERTY = KNATIVE_PROPERTY_PREFIX + "event.producer.timeout"; + private static final String EVENT_PRODUCER_TIMEOUT_ENV = KNATIVE_ENV_PREFIX + "EVENT_PRODUCER_TIMEOUT"; + private static final String EVENT_PRODUCER_TIMEOUT_DEFAULT = "2000"; + + private static final String EVENT_CONSUMER_TIMEOUT_PROPERTY = KNATIVE_PROPERTY_PREFIX + "event.consumer.timeout"; + private static final String EVENT_CONSUMER_TIMEOUT_ENV = KNATIVE_ENV_PREFIX + "EVENT_CONSUMER_TIMEOUT"; + private static final String EVENT_CONSUMER_TIMEOUT_DEFAULT = "2000"; + + private static final String NAMESPACE_PROPERTY = KNATIVE_PROPERTY_PREFIX + "namespace"; + private static final String NAMESPACE_ENV = KNATIVE_ENV_PREFIX + "NAMESPACE"; + + private static final String API_VERSION_PROPERTY = KNATIVE_PROPERTY_PREFIX + "api.version"; + private static final String API_VERSION_ENV = KNATIVE_ENV_PREFIX + "API_VERSION"; + private static final String API_VERSION_DEFAULT = "v1"; + + private static final String BROKER_HOST_PROPERTY = KNATIVE_PROPERTY_PREFIX + "broker.host"; + private static final String BROKER_HOST_ENV = KNATIVE_ENV_PREFIX + "BROKER_HOST"; + private static final String BROKER_HOST_DEFAULT = String.format("broker-ingress.knative-eventing.%s", KubernetesSettings.DEFAULT_DOMAIN_SUFFIX); + + private static final String BROKER_NAME_PROPERTY = KNATIVE_PROPERTY_PREFIX + "broker.name"; + private static final String BROKER_NAME_ENV = KNATIVE_ENV_PREFIX + "BROKER_NAME"; + private static final String BROKER_NAME_DEFAULT = "default"; + + private static final String BROKER_PORT_PROPERTY = KNATIVE_PROPERTY_PREFIX + "broker.port"; + private static final String BROKER_PORT_ENV = KNATIVE_ENV_PREFIX + "BROKER_PORT"; + private static final String BROKER_PORT_DEFAULT = "8080"; + + private static final String BROKER_URL_PROPERTY = KNATIVE_PROPERTY_PREFIX + "broker.url"; + private static final String BROKER_URL_ENV = KNATIVE_ENV_PREFIX + "BROKER_URL"; + + private static final String SERVICE_NAME_PROPERTY = KNATIVE_PROPERTY_PREFIX + "service.name"; + private static final String SERVICE_NAME_ENV = KNATIVE_ENV_PREFIX + "SERVICE_NAME"; + private static final String SERVICE_NAME_DEFAULT = "citrus-knative-service"; + + private static final String SERVICE_PORT_PROPERTY = KNATIVE_PROPERTY_PREFIX + "service.port"; + private static final String SERVICE_PORT_ENV = KNATIVE_ENV_PREFIX + "SERVICE_PORT"; + + private static final String AUTO_REMOVE_RESOURCES_PROPERTY = KNATIVE_PROPERTY_PREFIX + "auto.remove.resources"; + private static final String AUTO_REMOVE_RESOURCES_ENV = KNATIVE_ENV_PREFIX + "AUTO_REMOVE_RESOURCES"; + private static final String AUTO_REMOVE_RESOURCES_DEFAULT = "true"; + + private static final String VERIFY_BROKER_RESPONSE_PROPERTY = KNATIVE_PROPERTY_PREFIX + "verify.broker.resources"; + private static final String VERIFY_BROKER_RESPONSE_ENV = KNATIVE_ENV_PREFIX + "VERIFY_BROKER_RESPONSE"; + private static final String VERIFY_BROKER_RESPONSE_DEFAULT = "true"; + + private static final String BROKER_RESPONSE_STATUS_PROPERTY = KNATIVE_PROPERTY_PREFIX + "broker.response"; + private static final String BROKER_RESPONSE_STATUS_ENV = KNATIVE_ENV_PREFIX + "BROKER_RESPONSE_STATUS"; + + private static final String DEFAULT_LABELS_PROPERTY = KNATIVE_PROPERTY_PREFIX + "default.labels"; + private static final String DEFAULT_LABELS_ENV = KNATIVE_ENV_PREFIX + "DEFAULT_LABELS"; + private static final String DEFAULT_LABELS_DEFAULT = "app=citrus"; + + private KnativeSettings() { + // prevent instantiation of utility class + } + + /** + * Request timeout when sending cloud events. + * @return + */ + public static long getEventProducerTimeout() { + return Long.parseLong(System.getProperty(EVENT_PRODUCER_TIMEOUT_PROPERTY, + System.getenv(EVENT_PRODUCER_TIMEOUT_ENV) != null ? System.getenv(EVENT_PRODUCER_TIMEOUT_ENV) : EVENT_PRODUCER_TIMEOUT_DEFAULT)); + } + + /** + * Request timeout when receiving cloud events. + * @return + */ + public static long getEventConsumerTimeout() { + return Long.parseLong(System.getProperty(EVENT_CONSUMER_TIMEOUT_PROPERTY, + System.getenv(EVENT_CONSUMER_TIMEOUT_ENV) != null ? System.getenv(EVENT_CONSUMER_TIMEOUT_ENV) : EVENT_CONSUMER_TIMEOUT_DEFAULT)); + } + + /** + * Namespace to work on when performing Knative client operations such as creating triggers, services and so on. + * @return + */ + public static String getNamespace() { + String systemNamespace = System.getProperty(NAMESPACE_PROPERTY, System.getenv(NAMESPACE_ENV)); + + if (systemNamespace != null) { + return systemNamespace; + } + + return KubernetesSettings.getNamespace(); + } + + /** + * Api version for current Knative installation. + * @return + */ + public static String getApiVersion() { + return System.getProperty(API_VERSION_PROPERTY, + System.getenv(API_VERSION_ENV) != null ? System.getenv(API_VERSION_ENV) : API_VERSION_DEFAULT); + } + + /** + * Broker host used as Http header when creating cloud events. + * @return + */ + public static String getBrokerHost() { + String brokerHostDefault; + + if (KubernetesSettings.isKubernetesCluster() || KubernetesSettings.isOpenshiftCluster()) { + brokerHostDefault = BROKER_HOST_DEFAULT; + } else { + brokerHostDefault = "localhost"; + } + + return System.getProperty(BROKER_HOST_PROPERTY, + System.getenv(BROKER_HOST_ENV) != null ? System.getenv(BROKER_HOST_ENV) : brokerHostDefault); + } + + /** + * Broker to use when producing/consuming cloud events. + * @return + */ + public static String getBrokerName() { + return System.getProperty(BROKER_NAME_PROPERTY, + System.getenv(BROKER_NAME_ENV) != null ? System.getenv(BROKER_NAME_ENV) : BROKER_NAME_DEFAULT); + } + + /** + * Broker port to use when producing/consuming cloud events in local environment. + * @return + */ + public static String getBrokerPort() { + return System.getProperty(BROKER_PORT_PROPERTY, + System.getenv(BROKER_PORT_ENV) != null ? System.getenv(BROKER_PORT_ENV) : BROKER_PORT_DEFAULT); + } + + /** + * Broker URL to use when producing/consuming cloud events. + * @return + */ + public static String getBrokerUrl() { + String brokerUrlDefault; + if (KubernetesSettings.isKubernetesCluster() || KubernetesSettings.isOpenshiftCluster()) { + brokerUrlDefault = String.format("http://%s/%s/${%s}", getBrokerHost(), getNamespace(), KnativeVariableNames.BROKER_NAME.value()); + } else if (KubernetesSettings.isLocal()) { + brokerUrlDefault = String.format("http://%s%s", getBrokerHost(), StringUtils.hasText(getBrokerPort()) ? ":" + getBrokerPort() : ""); + } else { + brokerUrlDefault = String.format("http://%s", getBrokerHost()); + } + + return System.getProperty(BROKER_URL_PROPERTY, + System.getenv(BROKER_URL_ENV) != null ? System.getenv(BROKER_URL_ENV) : brokerUrlDefault); + } + + /** + * Service name to use when creating a new service for cloud event subscriptions. + * @return + */ + public static String getServiceName() { + return System.getProperty(SERVICE_NAME_PROPERTY, + System.getenv(SERVICE_NAME_ENV) != null ? System.getenv(SERVICE_NAME_ENV) : SERVICE_NAME_DEFAULT); + } + + /** + * Service port used when consuming cloud events via Http. + * @return + */ + public static int getServicePort() { + return Optional.ofNullable(System.getProperty(SERVICE_PORT_PROPERTY, System.getenv(SERVICE_PORT_ENV))) + .map(Integer::parseInt) + .orElseGet(KubernetesSettings::getServicePort); + } + + /** + * Read labels for K8s resources created by the test. The environment setting should be a + * comma delimited list of key-value pairs. + * @return + */ + public static Map getDefaultLabels() { + String labelsConfig = System.getProperty(DEFAULT_LABELS_PROPERTY, System.getenv(DEFAULT_LABELS_ENV)); + + if (labelsConfig == null) { + return KubernetesSettings.getDefaultLabels(); + } + + return Stream.of(labelsConfig.split(",")) + .map(item -> item.split("=", 2)) + .filter(keyValue -> keyValue.length == 2) + .collect(Collectors.toMap(item -> item[0], item -> item[1])); + } + + /** + * When set to true Knative resources (triggers, subscriptions, brokers, etc.) created during the test are + * automatically removed after the test. + * @return + */ + public static boolean isAutoRemoveResources() { + return Boolean.parseBoolean(System.getProperty(AUTO_REMOVE_RESOURCES_PROPERTY, + System.getenv(AUTO_REMOVE_RESOURCES_ENV) != null ? System.getenv(AUTO_REMOVE_RESOURCES_ENV) : AUTO_REMOVE_RESOURCES_DEFAULT)); + } + + public static boolean isVerifyBrokerResponse() { + return Boolean.parseBoolean(System.getProperty(VERIFY_BROKER_RESPONSE_PROPERTY, + System.getenv(VERIFY_BROKER_RESPONSE_ENV) != null ? System.getenv(VERIFY_BROKER_RESPONSE_ENV) : VERIFY_BROKER_RESPONSE_DEFAULT)); + } + + public static int getBrokerResponseStatus() { + String defaultResponseStatus; + if (KubernetesSettings.isLocal()) { + defaultResponseStatus = "204"; // NO_CONTENT + } else { + defaultResponseStatus = "202"; // ACCEPTED + } + + return Integer.parseInt(System.getProperty(BROKER_RESPONSE_STATUS_PROPERTY, + System.getenv(BROKER_RESPONSE_STATUS_ENV) != null ? System.getenv(BROKER_RESPONSE_STATUS_ENV) : defaultResponseStatus)); + } + + public static String getKnativeMessagingGroup() { + return "messaging.knative.dev"; + } + + public static String getKnativeEventingGroup() { + return "eventing.knative.dev"; + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/KnativeSupport.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/KnativeSupport.java new file mode 100644 index 0000000000..7f8f50b6c6 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/KnativeSupport.java @@ -0,0 +1,128 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative; + +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import javax.net.ssl.SSLContext; + +import io.fabric8.knative.client.DefaultKnativeClient; +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.TrustAllStrategy; +import org.apache.hc.core5.ssl.SSLContexts; +import org.citrusframework.Citrus; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.kubernetes.KubernetesVariableNames; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; + +public final class KnativeSupport { + + private KnativeSupport() { + // prevent instantiation of utility class + } + + public static KnativeClient getKnativeClient(Citrus citrus) { + if (citrus.getCitrusContext().getReferenceResolver().resolveAll(KnativeClient.class).size() == 1L) { + return citrus.getCitrusContext().getReferenceResolver().resolve(KnativeClient.class); + } else { + return new DefaultKnativeClient(); + } + } + + public static CustomResourceDefinitionContext knativeCRDContext(String knativeComponent, String kind, String version) { + return new CustomResourceDefinitionContext.Builder() + .withName(String.format("%s.%s.knative.dev", kind, knativeComponent)) + .withGroup(String.format("%s.knative.dev", knativeComponent)) + .withVersion(version) + .withPlural(kind) + .withScope("Namespaced") + .build(); + } + + public static String knativeApiVersion() { + return KnativeSettings.getApiVersion(); + } + + public static String knativeMessagingGroup() { + return KnativeSettings.getKnativeMessagingGroup(); + } + + public static String knativeEventingGroup() { + return KnativeSettings.getKnativeEventingGroup(); + } + + /** + * Retrieve current namespace set as test variable. + * In case no suitable test variable is available use namespace loaded from Kubernetes settings via environment settings. + * @param context potentially holding the namespace variable. + * @return + */ + public static String getNamespace(TestContext context) { + if (context.getVariables().containsKey(KnativeVariableNames.NAMESPACE.value())) { + return context.getVariable(KnativeVariableNames.NAMESPACE.value()); + } + + if (context.getVariables().containsKey(KubernetesVariableNames.NAMESPACE.value())) { + return context.getVariable(KubernetesVariableNames.NAMESPACE.value()); + } + + return KnativeSettings.getNamespace(); + } + + /** + * Get secure request factory. + * @return + */ + public static HttpComponentsClientHttpRequestFactory sslRequestFactory() { + return new HttpComponentsClientHttpRequestFactory(sslClient()); + } + + /** + * Get secure http client implementation with trust all strategy and noop host name verifier. + * @return + */ + private static HttpClient sslClient() { + try { + SSLContext sslcontext = SSLContexts + .custom() + .loadTrustMaterial(TrustAllStrategy.INSTANCE) + .build(); + + SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory( + sslcontext, NoopHostnameVerifier.INSTANCE); + + PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() + .setSSLSocketFactory(sslSocketFactory) + .build(); + + return HttpClients.custom() + .setConnectionManager(connectionManager) + .build(); + } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) { + throw new CitrusRuntimeException("Failed to create http client for ssl connection", e); + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/KnativeVariableNames.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/KnativeVariableNames.java new file mode 100644 index 0000000000..e64f477f7c --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/KnativeVariableNames.java @@ -0,0 +1,43 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative; + +/** + * Variable names used by Knative component. + */ +public enum KnativeVariableNames { + + CLUSTER_TYPE("CITRUS_CLUSTER_TYPE"), + BROKER_NAME("KNATIVE_BROKER"), + BROKER_PORT("KNATIVE_BROKER_PORT"), + NAMESPACE("KNATIVE_NAMESPACE"); + + private final String variableName; + + KnativeVariableNames(String variableName) { + this.variableName = variableName; + } + + public String value() { + return variableName; + } + + @Override + public String toString() { + return variableName; + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/AbstractKnativeAction.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/AbstractKnativeAction.java new file mode 100644 index 0000000000..32be6661d9 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/AbstractKnativeAction.java @@ -0,0 +1,146 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.actions; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.AbstractTestActionBuilder; +import org.citrusframework.actions.AbstractTestAction; +import org.citrusframework.context.TestContext; +import org.citrusframework.kubernetes.ClusterType; +import org.citrusframework.spi.ReferenceResolver; +import org.citrusframework.spi.ReferenceResolverAware; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractKnativeAction extends AbstractTestAction implements KnativeAction { + + /** Logger */ + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + private final KnativeClient knativeClient; + private final KubernetesClient kubernetesClient; + + private final ClusterType clusterType; + private final String namespace; + + public AbstractKnativeAction(String name, Builder builder) { + super("knative:" + name, builder); + + this.knativeClient = builder.knativeClient; + this.kubernetesClient = builder.kubernetesClient; + this.namespace = builder.namespace; + this.clusterType = builder.clusterType; + } + + @Override + public KubernetesClient getKubernetesClient() { + return kubernetesClient; + } + + @Override + public KnativeClient getKnativeClient() { + return knativeClient; + } + + @Override + public ClusterType clusterType(TestContext context) { + if (clusterType != null) { + return clusterType; + } + + return KnativeAction.super.clusterType(context); + } + + @Override + public String getNamespace() { + return namespace; + } + + /** + * Action builder. + */ + public static abstract class Builder> extends AbstractTestActionBuilder implements ReferenceResolverAware { + + private KnativeClient knativeClient; + private KubernetesClient kubernetesClient; + + private ClusterType clusterType; + private String namespace; + + protected ReferenceResolver referenceResolver; + + /** + * Use a custom Kubernetes client. + */ + public B client(KubernetesClient kubernetesClient) { + this.kubernetesClient = kubernetesClient; + return self; + } + + /** + * Use a custom Knative client. + */ + public B client(KnativeClient knativeClient) { + this.knativeClient = knativeClient; + return self; + } + + /** + * Use an explicit namespace. + */ + public B inNamespace(String namespace) { + this.namespace = namespace; + return self; + } + + /** + * Explicitly set cluster type for this action. + */ + public B clusterType(ClusterType clusterType) { + this.clusterType = clusterType; + return self; + } + + public B withReferenceResolver(ReferenceResolver referenceResolver) { + this.referenceResolver = referenceResolver; + return self; + } + + @Override + public T build() { + if (referenceResolver != null) { + if (kubernetesClient == null && referenceResolver.isResolvable(KubernetesClient.class)) { + kubernetesClient = referenceResolver.resolve(KubernetesClient.class); + } + + if (knativeClient == null && referenceResolver.isResolvable(KnativeClient.class)) { + knativeClient = referenceResolver.resolve(KnativeClient.class); + } + } + + return doBuild(); + } + + protected abstract T doBuild(); + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.referenceResolver = referenceResolver; + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/DeleteKnativeResourceAction.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/DeleteKnativeResourceAction.java new file mode 100644 index 0000000000..ff5813279e --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/DeleteKnativeResourceAction.java @@ -0,0 +1,72 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.actions; + +import org.citrusframework.context.TestContext; +import org.citrusframework.knative.KnativeSupport; +import org.citrusframework.kubernetes.KubernetesSupport; + +public class DeleteKnativeResourceAction extends AbstractKnativeAction { + + private final String component; + private final String kind; + private final String resourceName; + + public DeleteKnativeResourceAction(Builder builder) { + super("delete-" + builder.kind, builder); + + this.component = builder.component; + this.kind = builder.kind; + this.resourceName = builder.resourceName; + } + + @Override + public void doExecute(TestContext context) { + KubernetesSupport.deleteResource(getKubernetesClient(), namespace(context), + KnativeSupport.knativeCRDContext(component, kind, KnativeSupport.knativeApiVersion()), resourceName); + } + + /** + * Action builder. + */ + public static class Builder extends AbstractKnativeAction.Builder { + + private String component = "eventing"; + private String kind; + private String resourceName; + + public Builder component(String component) { + this.component = component; + return this; + } + + public Builder kind(String kind) { + this.kind = kind; + return this; + } + + public Builder resource(String resourceName) { + this.resourceName = resourceName; + return this; + } + + @Override + public DeleteKnativeResourceAction doBuild() { + return new DeleteKnativeResourceAction(this); + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/KnativeAction.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/KnativeAction.java new file mode 100644 index 0000000000..17ec75fa35 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/KnativeAction.java @@ -0,0 +1,110 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.actions; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestAction; +import org.citrusframework.context.TestContext; +import org.citrusframework.knative.KnativeSettings; +import org.citrusframework.knative.KnativeSupport; +import org.citrusframework.knative.KnativeVariableNames; +import org.citrusframework.kubernetes.ClusterType; +import org.citrusframework.kubernetes.KubernetesSettings; + +/** + * Base action provides access to Knative properties such as broker name. These properties are read from + * environment settings or explicitly set as part of the test case and get stored as test variables in the current context. + * This base class gives convenient access to the test variables and provides a fallback if no variable is set. + */ +public interface KnativeAction extends TestAction { + + /** + * Gets the Kubernetes client. + * @return + */ + KubernetesClient getKubernetesClient(); + + /** + * Gets the Knative client. + * @return + */ + KnativeClient getKnativeClient(); + + + /** + * Gets the current namespace. + */ + String getNamespace(); + + /** + * Resolves namespace name from given test context using the stored test variable. + * Fallback to the namespace given in Knative environment settings when no test variable is present. + * + * @param context + * @return + */ + default String namespace(TestContext context) { + if (getNamespace() != null) { + return getNamespace(); + } + + return KnativeSupport.getNamespace(context); + } + + /** + * Resolves the current broker name that has been set in the test context as test variable. + * Fallback to the broker given in Knative environment settings when no test variable is present. + * + * @param brokerName + * @param context + * @return + */ + default String brokerName(String brokerName, TestContext context) { + if (brokerName != null) { + return brokerName; + } + + if (context.getVariables().containsKey(KnativeVariableNames.BROKER_NAME.value())) { + context.getVariable(KnativeVariableNames.BROKER_NAME.value()); + } + + return KnativeSettings.getBrokerName(); + } + + /** + * Resolves cluster type from given test context using the stored test variable. + * Fallback to retrieving the cluster type from environment settings when no test variable is present. + * + * @param context + * @return + */ + default ClusterType clusterType(TestContext context) { + if (context.getVariables().containsKey(KnativeVariableNames.CLUSTER_TYPE.value())) { + Object clusterType = context.getVariableObject(KnativeVariableNames.CLUSTER_TYPE.value()); + + if (clusterType instanceof ClusterType) { + return (ClusterType) clusterType; + } else { + return ClusterType.valueOf(clusterType.toString()); + } + } + + return KubernetesSettings.getClusterType(); + } +} + diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/KnativeActionBuilder.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/KnativeActionBuilder.java new file mode 100644 index 0000000000..fb7c35d40d --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/KnativeActionBuilder.java @@ -0,0 +1,275 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.actions; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestActionBuilder; +import org.citrusframework.knative.actions.eventing.CreateBrokerAction; +import org.citrusframework.knative.actions.eventing.CreateTriggerAction; +import org.citrusframework.knative.actions.eventing.DeleteBrokerAction; +import org.citrusframework.knative.actions.eventing.DeleteTriggerAction; +import org.citrusframework.knative.actions.eventing.ReceiveEventAction; +import org.citrusframework.knative.actions.eventing.SendEventAction; +import org.citrusframework.knative.actions.eventing.VerifyBrokerAction; +import org.citrusframework.knative.actions.messaging.CreateChannelAction; +import org.citrusframework.knative.actions.messaging.CreateSubscriptionAction; +import org.springframework.util.Assert; + +public class KnativeActionBuilder implements TestActionBuilder.DelegatingTestActionBuilder { + + /** Kubernetes client */ + private KubernetesClient kubernetesClient; + private KnativeClient knativeClient; + + private AbstractKnativeAction.Builder delegate; + + /** + * Fluent API action building entry method used in Java DSL. + * @return + */ + public static KnativeActionBuilder knative() { + return new KnativeActionBuilder(); + } + + /** + * Use a custom Kubernetes client. + * @param kubernetesClient + */ + public KnativeActionBuilder client(KubernetesClient kubernetesClient) { + this.kubernetesClient = kubernetesClient; + return this; + } + + /** + * Use a custom Knative client. + * @param knativeClient + */ + public KnativeActionBuilder client(KnativeClient knativeClient) { + this.knativeClient = knativeClient; + return this; + } + + /** + * Produce and consume events for the Knative broker. + * @return + */ + public EventsActionBuilder event() { + return new EventsActionBuilder(); + } + + /** + * Performs action on Knative channels. + * @return + */ + public ChannelActionBuilder channels() { + return new ChannelActionBuilder(); + } + + /** + * Performs action on Knative subscriptions. + * @return + */ + public SubscriptionActionBuilder subscriptions() { + return new SubscriptionActionBuilder(); + } + + /** + * Performs action on Knative trigger. + * @return + */ + public TriggerActionBuilder trigger() { + return new TriggerActionBuilder(); + } + + /** + * Performs action on Knative brokers. + * @return + */ + public BrokerActionBuilder brokers() { + return new BrokerActionBuilder(); + } + + @Override + public KnativeAction build() { + Assert.notNull(delegate, "Missing delegate action to build"); + if (kubernetesClient != null) { + delegate.client(kubernetesClient); + } + + if (knativeClient != null) { + delegate.client(knativeClient); + } + return delegate.build(); + } + + @Override + public TestActionBuilder getDelegate() { + return delegate; + } + + public class EventsActionBuilder { + /** + * Produce event for the Knative broker. + * @return + */ + public SendEventAction.Builder send() { + SendEventAction.Builder builder = new SendEventAction.Builder(); + delegate = builder; + return builder; + } + + /** + * Receive event from the Knative broker. + * @return + */ + public ReceiveEventAction.Builder receive() { + ReceiveEventAction.Builder builder = new ReceiveEventAction.Builder(); + delegate = builder; + return builder; + } + } + + public class ChannelActionBuilder { + /** + * Create channel instance. + * @param channelName the name of the Knative channel. + */ + public CreateChannelAction.Builder create(String channelName) { + CreateChannelAction.Builder builder = new CreateChannelAction.Builder() + .client(kubernetesClient) + .client(knativeClient) + .channel(channelName); + delegate = builder; + return builder; + } + + /** + * Delete channel instance. + * @param channelName the name of the Knative channel. + */ + public DeleteKnativeResourceAction.Builder delete(String channelName) { + DeleteKnativeResourceAction.Builder builder = new DeleteKnativeResourceAction.Builder() + .client(kubernetesClient) + .client(knativeClient) + .component("messaging") + .kind("channels") + .resource(channelName); + delegate = builder; + return builder; + } + } + + public class SubscriptionActionBuilder { + /** + * Create subscription instance. + * @param subscriptionName the name of the Knative subscription. + */ + public CreateSubscriptionAction.Builder create(String subscriptionName) { + CreateSubscriptionAction.Builder builder = new CreateSubscriptionAction.Builder() + .client(kubernetesClient) + .client(knativeClient) + .subscription(subscriptionName); + delegate = builder; + return builder; + } + + /** + * Delete subscription instance. + * @param subscriptionName the name of the Knative subscription. + */ + public DeleteKnativeResourceAction.Builder delete(String subscriptionName) { + DeleteKnativeResourceAction.Builder builder = new DeleteKnativeResourceAction.Builder() + .client(kubernetesClient) + .client(knativeClient) + .component("messaging") + .kind("subscriptions") + .resource(subscriptionName); + delegate = builder; + return builder; + } + } + + public class TriggerActionBuilder { + /** + * Create trigger instance. + * @param triggerName the name of the Knative trigger. + */ + public CreateTriggerAction.Builder create(String triggerName) { + CreateTriggerAction.Builder builder = new CreateTriggerAction.Builder() + .client(kubernetesClient) + .client(knativeClient) + .trigger(triggerName); + delegate = builder; + return builder; + } + + /** + * Delete trigger instance. + * @param triggerName the name of the Knative trigger. + */ + public DeleteTriggerAction.Builder delete(String triggerName) { + DeleteTriggerAction.Builder builder = new DeleteTriggerAction.Builder() + .client(kubernetesClient) + .client(knativeClient) + .trigger(triggerName); + delegate = builder; + return builder; + } + } + + public class BrokerActionBuilder { + /** + * Create broker instance. + * @param brokerName the name of the Knative broker. + */ + public CreateBrokerAction.Builder create(String brokerName) { + CreateBrokerAction.Builder builder = new CreateBrokerAction.Builder() + .client(kubernetesClient) + .client(knativeClient) + .broker(brokerName); + delegate = builder; + return builder; + } + + /** + * Delete broker instance. + * @param brokerName the name of the Knative broker. + */ + public DeleteBrokerAction.Builder delete(String brokerName) { + DeleteBrokerAction.Builder builder = new DeleteBrokerAction.Builder() + .client(kubernetesClient) + .client(knativeClient) + .broker(brokerName); + delegate = builder; + return builder; + } + + /** + * Verify given broker instance is running. + * @param brokerName the name of the Knative broker. + */ + public VerifyBrokerAction.Builder verify(String brokerName) { + VerifyBrokerAction.Builder builder = new VerifyBrokerAction.Builder() + .client(kubernetesClient) + .client(knativeClient) + .broker(brokerName); + delegate = builder; + return builder; + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/CreateBrokerAction.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/CreateBrokerAction.java new file mode 100644 index 0000000000..f9daa84672 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/CreateBrokerAction.java @@ -0,0 +1,123 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.actions.eventing; + +import io.fabric8.knative.eventing.v1.Broker; +import io.fabric8.knative.eventing.v1.BrokerBuilder; +import io.fabric8.kubernetes.client.dsl.Updatable; +import org.citrusframework.context.TestContext; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.http.server.HttpServerBuilder; +import org.citrusframework.knative.KnativeSettings; +import org.citrusframework.knative.KnativeSupport; +import org.citrusframework.knative.KnativeVariableNames; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.kubernetes.KubernetesSettings; + +public class CreateBrokerAction extends AbstractKnativeAction { + + private final String brokerName; + + public CreateBrokerAction(Builder builder) { + super("create-broker", builder); + + this.brokerName = builder.brokerName; + } + + @Override + public void doExecute(TestContext context) { + if (KubernetesSettings.isLocal(clusterType(context))) { + createLocalBroker(context); + } else { + createBroker(context); + } + } + + /** + * Creates Http server as a local Knative broker. + * @param context + */ + private void createLocalBroker(TestContext context) { + String resolvedBrokerName = context.replaceDynamicContentInString(brokerName); + + logger.info(String.format("Creating local Knative broker: %s", resolvedBrokerName)); + + HttpServer brokerServer; + if (!context.getReferenceResolver().isResolvable(resolvedBrokerName, HttpServer.class)) { + brokerServer = new HttpServerBuilder() + .autoStart(true) + .port(KnativeSettings.getServicePort()) + .referenceResolver(context.getReferenceResolver()) + .build(); + + brokerServer.initialize(); + context.getReferenceResolver() + .bind(resolvedBrokerName, brokerServer); + } else { + brokerServer = context.getReferenceResolver().resolve(resolvedBrokerName, HttpServer.class); + } + + context.setVariable(KnativeVariableNames.BROKER_PORT.value(), brokerServer.getPort()); + + logger.info(String.format("Successfully created Knative broker: %s", resolvedBrokerName)); + } + + /** + * Creates Knative broker on current namespace. + * @param context + */ + private void createBroker(TestContext context) { + String resolvedBrokerName = context.replaceDynamicContentInString(brokerName); + String brokerNamespace = namespace(context); + + logger.info(String.format("Creating Knative broker '%s' in namespace %s", resolvedBrokerName, brokerNamespace)); + + Broker broker = new BrokerBuilder() + .withApiVersion(String.format("%s/%s", KnativeSupport.knativeEventingGroup(), KnativeSupport.knativeApiVersion())) + .withNewMetadata() + .withNamespace(brokerNamespace) + .withName(resolvedBrokerName) + .withLabels(KnativeSettings.getDefaultLabels()) + .endMetadata() + .build(); + + getKnativeClient().brokers() + .inNamespace(brokerNamespace) + .resource(broker) + .createOr(Updatable::update); + + logger.info(String.format("Successfully created Knative broker '%s' in namespace %s", resolvedBrokerName, brokerNamespace)); + } + + /** + * Action builder. + */ + public static class Builder extends AbstractKnativeAction.Builder { + + private String brokerName; + + public Builder broker(String brokerName) { + this.brokerName = brokerName; + return this; + } + + @Override + public CreateBrokerAction doBuild() { + return new CreateBrokerAction(this); + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/CreateTriggerAction.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/CreateTriggerAction.java new file mode 100644 index 0000000000..5c7ddcfaae --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/CreateTriggerAction.java @@ -0,0 +1,160 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.actions.eventing; + +import java.util.HashMap; +import java.util.Map; + +import io.fabric8.knative.eventing.v1.Trigger; +import io.fabric8.knative.eventing.v1.TriggerBuilder; +import io.fabric8.knative.eventing.v1.TriggerSpecBuilder; +import io.fabric8.kubernetes.client.dsl.Updatable; +import org.citrusframework.context.TestContext; +import org.citrusframework.knative.KnativeSettings; +import org.citrusframework.knative.KnativeSupport; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.kubernetes.KubernetesSettings; + +public class CreateTriggerAction extends AbstractKnativeAction { + + private final String triggerName; + private final String serviceName; + private final String brokerName; + private final String channelName; + + private final Map filterOnAttributes; + + public CreateTriggerAction(Builder builder) { + super("create-trigger", builder); + + this.triggerName = builder.triggerName; + this.serviceName = builder.serviceName; + this.brokerName = builder.brokerName; + this.channelName = builder.channelName; + this.filterOnAttributes = builder.filterOnAttributes; + } + + @Override + public void doExecute(TestContext context) { + TriggerSpecBuilder triggerSpec = new TriggerSpecBuilder() + .withBroker(brokerName(brokerName, context)); + + addServiceSubscriber(triggerSpec, context); + addChannelSubscriber(triggerSpec, context); + addFilterOnAttributes(triggerSpec, context); + + Trigger trigger = new TriggerBuilder() + .withApiVersion(String.format("%s/%s", KnativeSupport.knativeEventingGroup(), KnativeSupport.knativeApiVersion())) + .withNewMetadata() + .withNamespace(namespace(context)) + .withName(context.replaceDynamicContentInString(triggerName)) + .withLabels(KnativeSettings.getDefaultLabels()) + .endMetadata() + .withSpec(triggerSpec.build()) + .build(); + + getKnativeClient().triggers() + .inNamespace(namespace(context)) + .resource(trigger) + .createOr(Updatable::update); + } + + private void addFilterOnAttributes(TriggerSpecBuilder triggerSpec, TestContext context) { + if (!filterOnAttributes.isEmpty()) { + triggerSpec.withNewFilter() + .withAttributes(context.resolveDynamicValuesInMap(filterOnAttributes)) + .endFilter(); + } + } + + private void addChannelSubscriber(TriggerSpecBuilder triggerSpec, TestContext context) { + if (channelName != null) { + triggerSpec.withNewSubscriber() + .withNewRef() + .withApiVersion(String.format("%s/%s", KnativeSupport.knativeMessagingGroup(), KnativeSupport.knativeApiVersion())) + .withKind("InMemoryChannel") + .withName(context.replaceDynamicContentInString(channelName)) + .endRef() + .endSubscriber(); + } + } + + private void addServiceSubscriber(TriggerSpecBuilder triggerSpec, TestContext context) { + if (serviceName != null) { + triggerSpec.withNewSubscriber() + .withNewRef() + .withApiVersion("v1") + .withKind("Service") + .withName(context.replaceDynamicContentInString(serviceName)) + .endRef() + .endSubscriber(); + } + } + + @Override + public boolean isDisabled(TestContext context) { + return KubernetesSettings.isLocal(clusterType(context)); + } + + /** + * Action builder. + */ + public static class Builder extends AbstractKnativeAction.Builder { + + private String triggerName; + private String serviceName; + private String brokerName; + private String channelName; + + private final Map filterOnAttributes = new HashMap<>(); + + public Builder trigger(String triggerName) { + this.triggerName = triggerName; + return this; + } + + public Builder broker(String brokerName) { + this.brokerName = brokerName; + return this; + } + + public Builder channel(String channelName) { + this.channelName = channelName; + return this; + } + + public Builder service(String serviceName) { + this.serviceName = serviceName; + return this; + } + + public Builder filter(Map filter) { + this.filterOnAttributes.putAll(filter); + return this; + } + + public Builder filter(String attributeName, String value) { + this.filterOnAttributes.put(attributeName, value); + return this; + } + + @Override + public CreateTriggerAction doBuild() { + return new CreateTriggerAction(this); + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/DeleteBrokerAction.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/DeleteBrokerAction.java new file mode 100644 index 0000000000..579e7e9e48 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/DeleteBrokerAction.java @@ -0,0 +1,83 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.actions.eventing; + +import org.citrusframework.context.TestContext; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.kubernetes.KubernetesSettings; + +public class DeleteBrokerAction extends AbstractKnativeAction { + + private final String brokerName; + + public DeleteBrokerAction(Builder builder) { + super("delete-broker", builder); + + this.brokerName = builder.brokerName; + } + + @Override + public void doExecute(TestContext context) { + if (KubernetesSettings.isLocal(clusterType(context))) { + deleteLocalBroker(context); + } else { + deleteBroker(context); + } + } + + /** + * Removes Http server acting as local Knative broker. + * @param context + */ + private void deleteLocalBroker(TestContext context) { + String resolvedBrokerName = context.replaceDynamicContentInString(brokerName); + if (context.getReferenceResolver().isResolvable(resolvedBrokerName, HttpServer.class)) { + HttpServer brokerServer = context.getReferenceResolver().resolve(resolvedBrokerName, HttpServer.class); + brokerServer.stop(); + } + } + + /** + * Removes Knative broker from current namespace. + * @param context + */ + private void deleteBroker(TestContext context) { + getKnativeClient().brokers() + .inNamespace(namespace(context)) + .withName(context.replaceDynamicContentInString(brokerName)) + .delete(); + } + + /** + * Action builder. + */ + public static class Builder extends AbstractKnativeAction.Builder { + + private String brokerName; + + public Builder broker(String brokerName) { + this.brokerName = brokerName; + return this; + } + + @Override + public DeleteBrokerAction doBuild() { + return new DeleteBrokerAction(this); + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/DeleteTriggerAction.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/DeleteTriggerAction.java new file mode 100644 index 0000000000..d1e5fe2e89 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/DeleteTriggerAction.java @@ -0,0 +1,63 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.actions.eventing; + +import org.citrusframework.context.TestContext; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.kubernetes.KubernetesSettings; + +public class DeleteTriggerAction extends AbstractKnativeAction { + + private final String triggerName; + + public DeleteTriggerAction(Builder builder) { + super("delete-trigger", builder); + + this.triggerName = builder.triggerName; + } + + @Override + public void doExecute(TestContext context) { + getKnativeClient().triggers() + .inNamespace(namespace(context)) + .withName(context.replaceDynamicContentInString(triggerName)) + .delete(); + } + + @Override + public boolean isDisabled(TestContext context) { + return KubernetesSettings.isLocal(clusterType(context)); + } + + /** + * Action builder. + */ + public static class Builder extends AbstractKnativeAction.Builder { + + private String triggerName; + + public Builder trigger(String triggerName) { + this.triggerName = triggerName; + return this; + } + + @Override + public DeleteTriggerAction doBuild() { + return new DeleteTriggerAction(this); + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/ReceiveEventAction.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/ReceiveEventAction.java new file mode 100644 index 0000000000..90376d1c8c --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/ReceiveEventAction.java @@ -0,0 +1,191 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.actions.eventing; + +import java.util.HashMap; +import java.util.Map; + +import org.citrusframework.context.TestContext; +import org.citrusframework.http.actions.HttpServerActionBuilder; +import org.citrusframework.http.actions.HttpServerRequestActionBuilder; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.http.server.HttpServerBuilder; +import org.citrusframework.knative.KnativeSettings; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.ce.CloudEvent; +import org.citrusframework.knative.ce.CloudEventMessage; +import org.citrusframework.knative.ce.CloudEventSupport; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.RequestMethod; + +import static org.citrusframework.http.actions.HttpActionBuilder.http; + +/** + * Receives CloudEvent event from Knative message broker. + * Uses Knative trigger and service binding to receive the CloudEvent data. + */ +public class ReceiveEventAction extends AbstractKnativeAction { + + private final CloudEventMessage message; + private final HttpServer httpServer; + + public ReceiveEventAction(Builder builder) { + super("receive-event", builder); + + this.message = builder.message; + this.httpServer = builder.httpServer; + } + + @Override + public void doExecute(TestContext context) { + receiveEvent(message, context); + } + + /** + * Receives event from given service. + * @param request + */ + public void receiveEvent(HttpMessage request, TestContext context) { + if (!httpServer.isRunning()) { + httpServer.start(); + } + + HttpServerActionBuilder.HttpServerReceiveActionBuilder receiveBuilder = http().server(httpServer).receive(); + HttpServerRequestActionBuilder.HttpMessageBuilderSupport requestBuilder; + + if (request.getRequestMethod() == null || request.getRequestMethod().equals(RequestMethod.POST)) { + requestBuilder = receiveBuilder.post().message(request); + } else if (request.getRequestMethod().equals(RequestMethod.GET)) { + requestBuilder = receiveBuilder.get().message(request); + } else if (request.getRequestMethod().equals(RequestMethod.PUT)) { + requestBuilder = receiveBuilder.put().message(request); + } else if (request.getRequestMethod().equals(RequestMethod.DELETE)) { + requestBuilder = receiveBuilder.delete().message(request); + } else if (request.getRequestMethod().equals(RequestMethod.HEAD)) { + requestBuilder = receiveBuilder.head().message(request); + } else if (request.getRequestMethod().equals(RequestMethod.TRACE)) { + requestBuilder = receiveBuilder.trace().message(request); + } else if (request.getRequestMethod().equals(RequestMethod.PATCH)) { + requestBuilder = receiveBuilder.patch().message(request); + } else if (request.getRequestMethod().equals(RequestMethod.OPTIONS)) { + requestBuilder = receiveBuilder.options().message(request); + } else { + requestBuilder = receiveBuilder.post().message(request); + } + + requestBuilder.headerNameIgnoreCase(true); + requestBuilder.type(message.getType()); + requestBuilder.build().execute(context); + + http().server(httpServer) + .send() + .response(HttpStatus.ACCEPTED); + } + + /** + * Action builder. + */ + public static class Builder extends AbstractKnativeAction.Builder { + + private String serviceName = KnativeSettings.getServiceName(); + private int servicePort = KnativeSettings.getServicePort(); + private HttpServer httpServer; + private CloudEventMessage message; + private String eventData; + private final Map ceAttributes = new HashMap<>(); + private long timeout = KnativeSettings.getEventProducerTimeout(); + + public Builder service(String serviceName, int servicePort) { + this.serviceName = serviceName; + this.servicePort = servicePort; + return this; + } + + public Builder serviceName(String serviceName) { + this.serviceName = serviceName; + return this; + } + + public Builder servicePort(int servicePort) { + this.servicePort = servicePort; + return this; + } + + public Builder timeout(long timeout) { + this.timeout = timeout; + return this; + } + + public Builder event(CloudEventMessage message) { + this.message = message; + return this; + } + + public Builder event(CloudEvent event) { + return event(CloudEventMessage.fromEvent(event)); + } + + public Builder eventData(String eventData) { + this.eventData = eventData; + return this; + } + + public Builder attributes(Map ceAttributes) { + this.ceAttributes.putAll(ceAttributes); + return this; + } + + public Builder attribute(String name, String value) { + this.ceAttributes.put(name, value); + return this; + } + + public Builder server(HttpServer httpServer) { + this.httpServer = httpServer; + return this; + } + + @Override + public ReceiveEventAction doBuild() { + if (message == null) { + message = CloudEventSupport.createEventMessage(eventData, ceAttributes); + } + + if (httpServer == null) { + if (referenceResolver != null && referenceResolver.isResolvable(serviceName, HttpServer.class)) { + httpServer = referenceResolver.resolve(serviceName, HttpServer.class); + } else { + httpServer = new HttpServerBuilder() + .autoStart(true) + .timeout(timeout) + .port(servicePort) + .name(serviceName) + .build(); + + httpServer.initialize(); + } + } + + if (referenceResolver != null && !referenceResolver.isResolvable(serviceName, HttpServer.class)) { + referenceResolver.bind(serviceName, httpServer); + } + + return new ReceiveEventAction(this); + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/SendEventAction.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/SendEventAction.java new file mode 100644 index 0000000000..e32ec024f3 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/SendEventAction.java @@ -0,0 +1,207 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.actions.eventing; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +import org.citrusframework.context.TestContext; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.http.client.HttpClientBuilder; +import org.citrusframework.knative.KnativeSettings; +import org.citrusframework.knative.KnativeSupport; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.ce.CloudEvent; +import org.citrusframework.knative.ce.CloudEventMessage; +import org.citrusframework.knative.ce.CloudEventSupport; +import org.citrusframework.spi.ReferenceResolverAware; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.util.StringUtils; + +import static org.citrusframework.http.actions.HttpActionBuilder.http; + +/** + * Send CloudEvent event to Knative message broker. Uses the Http transport to send the CloudEvent data. + */ +public class SendEventAction extends AbstractKnativeAction { + + private final String brokerUrl; + private final HttpClient httpClient; + private final long timeout; + private final CloudEventMessage message; + private final boolean forkMode; + + public SendEventAction(Builder builder) { + super("send-event", builder); + + this.brokerUrl = builder.brokerUrl; + this.httpClient = builder.httpClient; + this.message = builder.message; + this.timeout = builder.timeout; + this.forkMode = builder.forkMode; + } + + @Override + public void doExecute(TestContext context) { + sendEvent(message, context); + } + + /** + * Sends event request as Http request and verify accepted response. + * @param request + * @param context + */ + private void sendEvent(CloudEventMessage request, TestContext context) { + if (Objects.isNull(request.getContentType())) { + request.contentType(MediaType.APPLICATION_JSON_VALUE); + } + + if (request.getEventId() == null) { + request.eventId(UUID.randomUUID().toString()); + } + + if (request.getEventType() == null) { + request.eventType("org.citrusframework.event.test"); + } + + if (request.getSource() == null) { + request.source("citrus-test"); + } + + request.setHeader("Host", KnativeSettings.getBrokerHost()); + + HttpClientRequestActionBuilder.HttpMessageBuilderSupport requestBuilder = http().client(httpClient) + .send() + .post() + .message(request); + + requestBuilder.fork(forkMode); + + if (StringUtils.hasText(brokerUrl)) { + requestBuilder.uri(brokerUrl); + } + + requestBuilder.build().execute(context); + + if (KnativeSettings.isVerifyBrokerResponse()) { + http().client(httpClient) + .receive() + .response(HttpStatus.valueOf(KnativeSettings.getBrokerResponseStatus())) + .timeout(timeout) + .build().execute(context); + } + } + + /** + * Action builder. + */ + public static class Builder extends AbstractKnativeAction.Builder implements ReferenceResolverAware { + + private String brokerUrl = KnativeSettings.getBrokerUrl(); + private String brokerName; + private HttpClient httpClient; + private CloudEventMessage message; + private String eventData; + private final Map ceAttributes = new HashMap<>(); + private long timeout = KnativeSettings.getEventProducerTimeout(); + private boolean forkMode; + + public Builder broker(String brokerName) { + this.brokerName = brokerName; + return this; + } + + public Builder brokerUrl(String brokerUrl) { + this.brokerUrl = brokerUrl; + return this; + } + + public Builder timeout(long timeout) { + this.timeout = timeout; + return this; + } + + public Builder fork(boolean enabled) { + this.forkMode = enabled; + return this; + } + + public Builder event(CloudEventMessage message) { + this.message = message; + return this; + } + + public Builder event(CloudEvent event) { + return event(CloudEventMessage.fromEvent(event)); + } + + public Builder eventData(String eventData) { + this.eventData = eventData; + return this; + } + + public Builder attributes(Map ceAttributes) { + this.ceAttributes.putAll(ceAttributes); + return this; + } + + public Builder attribute(String name, String value) { + this.ceAttributes.put(name, value); + return this; + } + + public Builder client(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + @Override + public SendEventAction doBuild() { + if (message == null) { + message = CloudEventSupport.createEventMessage(eventData, ceAttributes); + } + + if (httpClient == null) { + if (referenceResolver != null && brokerName != null && + referenceResolver.isResolvable(brokerName, HttpClient.class)) { + httpClient = referenceResolver.resolve(brokerName, HttpClient.class); + brokerUrl = httpClient.getEndpointConfiguration().getRequestUrl(); + } else { + httpClient = new HttpClientBuilder() + .timeout(timeout) + .requestUrl(brokerUrl) + .build(); + + if (brokerUrl.startsWith("https")) { + httpClient.getEndpointConfiguration().setRequestFactory(KnativeSupport.sslRequestFactory()); + } + } + } + + if (referenceResolver != null && brokerName != null && + !referenceResolver.isResolvable(brokerName, HttpClient.class)) { + referenceResolver.bind(brokerName, httpClient); + } + + return new SendEventAction(this); + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/VerifyBrokerAction.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/VerifyBrokerAction.java new file mode 100644 index 0000000000..4479d2deac --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/eventing/VerifyBrokerAction.java @@ -0,0 +1,100 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.actions.eventing; + +import io.fabric8.knative.eventing.v1.Broker; +import io.fabric8.kubernetes.client.KubernetesClientException; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.ValidationException; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.kubernetes.KubernetesSettings; + +public class VerifyBrokerAction extends AbstractKnativeAction { + + private final String brokerName; + + public VerifyBrokerAction(Builder builder) { + super("verify-broker", builder); + + this.brokerName = builder.brokerName; + } + + @Override + public void doExecute(TestContext context) { + if (KubernetesSettings.isLocal(clusterType(context))) { + verifyLocalBroker(context); + } else { + verifyBroker(context); + } + } + + private void verifyLocalBroker(TestContext context) { + String resolvedBrokerName = context.replaceDynamicContentInString(brokerName); + + if (!context.getReferenceResolver().isResolvable(resolvedBrokerName, HttpServer.class)) { + throw new ValidationException(String.format("Knative broker '%s' not found", brokerName)); + } + + HttpServer brokerServer = context.getReferenceResolver().resolve(resolvedBrokerName, HttpServer.class); + if (!brokerServer.isRunning()) { + throw new ValidationException(String.format("Knative broker '%s' is not ready", brokerName)); + } + + logger.info(String.format("Knative broker %s is ready", brokerName)); + } + + private void verifyBroker(TestContext context) { + try { + Broker broker = getKnativeClient().brokers() + .inNamespace(namespace(context)) + .withName(brokerName) + .get(); + + if (broker.getStatus() != null && + broker.getStatus().getConditions() != null && + broker.getStatus().getConditions().stream() + .anyMatch(condition -> condition.getType().equals("Ready") && + condition.getStatus().equalsIgnoreCase("True"))) { + logger.info(String.format("Knative broker %s is ready", brokerName)); + } else { + throw new ValidationException(String.format("Knative broker '%s' is not ready", brokerName)); + } + } catch (KubernetesClientException e) { + throw new ValidationException(String.format("Failed to validate Knative broker '%s' - " + + "not found in namespace '%s'", brokerName, namespace(context)), e); + } + } + + /** + * Action builder. + */ + public static class Builder extends AbstractKnativeAction.Builder { + + private String brokerName; + + public Builder broker(String brokerName) { + this.brokerName = brokerName; + return this; + } + + @Override + public VerifyBrokerAction doBuild() { + return new VerifyBrokerAction(this); + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/messaging/CreateChannelAction.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/messaging/CreateChannelAction.java new file mode 100644 index 0000000000..a6d07c82c6 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/messaging/CreateChannelAction.java @@ -0,0 +1,77 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.actions.messaging; + +import io.fabric8.knative.messaging.v1.Channel; +import io.fabric8.knative.messaging.v1.ChannelBuilder; +import io.fabric8.kubernetes.client.dsl.Updatable; +import org.citrusframework.context.TestContext; +import org.citrusframework.knative.KnativeSettings; +import org.citrusframework.knative.KnativeSupport; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.kubernetes.KubernetesSettings; + +public class CreateChannelAction extends AbstractKnativeAction { + + private final String channelName; + + public CreateChannelAction(Builder builder) { + super("create-channel", builder); + + this.channelName = builder.channelName; + } + + @Override + public void doExecute(TestContext context) { + Channel channel = new ChannelBuilder() + .withApiVersion(String.format("%s/%s", KnativeSupport.knativeMessagingGroup(), KnativeSupport.knativeApiVersion())) + .withNewMetadata() + .withNamespace(namespace(context)) + .withName(context.replaceDynamicContentInString(channelName)) + .withLabels(KnativeSettings.getDefaultLabels()) + .endMetadata() + .build(); + + getKnativeClient().channels() + .inNamespace(namespace(context)) + .resource(channel) + .createOr(Updatable::update); + } + + @Override + public boolean isDisabled(TestContext context) { + return KubernetesSettings.isLocal(clusterType(context)); + } + + /** + * Action builder. + */ + public static class Builder extends AbstractKnativeAction.Builder { + + private String channelName; + + public Builder channel(String channelName) { + this.channelName = channelName; + return this; + } + + @Override + public CreateChannelAction doBuild() { + return new CreateChannelAction(this); + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/messaging/CreateSubscriptionAction.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/messaging/CreateSubscriptionAction.java new file mode 100644 index 0000000000..feb7d08be2 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/actions/messaging/CreateSubscriptionAction.java @@ -0,0 +1,112 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.actions.messaging; + +import io.fabric8.knative.internal.pkg.apis.duck.v1.KReferenceBuilder; +import io.fabric8.knative.messaging.v1.Subscription; +import io.fabric8.knative.messaging.v1.SubscriptionBuilder; +import io.fabric8.kubernetes.client.dsl.Updatable; +import org.citrusframework.context.TestContext; +import org.citrusframework.knative.KnativeSettings; +import org.citrusframework.knative.KnativeSupport; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.kubernetes.KubernetesSettings; + +public class CreateSubscriptionAction extends AbstractKnativeAction { + + private final String subscriptionName; + private final String channelName; + private final String serviceName; + + public CreateSubscriptionAction(Builder builder) { + super("create-subscription", builder); + + this.subscriptionName = builder.subscriptionName; + this.channelName = builder.channelName; + this.serviceName = builder.serviceName; + } + + @Override + public void doExecute(TestContext context) { + Subscription subscription = new SubscriptionBuilder() + .withApiVersion(String.format("%s/%s", KnativeSupport.knativeMessagingGroup(), KnativeSupport.knativeApiVersion())) + .withNewMetadata() + .withNamespace(namespace(context)) + .withName(context.replaceDynamicContentInString(subscriptionName)) + .withLabels(KnativeSettings.getDefaultLabels()) + .endMetadata() + .withNewSpec() + .withChannel(new KReferenceBuilder() + .withApiVersion(String.format("%s/%s", KnativeSupport.knativeMessagingGroup(), KnativeSupport.knativeApiVersion())) + .withKind("InMemoryChannel") + .withName(context.replaceDynamicContentInString(channelName)) + .build()) + .withNewSubscriber() + .withNewRef() + .withApiVersion("v1") + .withKind("Service") + .withName(context.replaceDynamicContentInString(serviceName)) + .endRef() + .endSubscriber() + .endSpec() + .build(); + + getKnativeClient().subscriptions() + .inNamespace(namespace(context)) + .resource(subscription) + .createOr(Updatable::update); + } + + @Override + public boolean isDisabled(TestContext context) { + return KubernetesSettings.isLocal(clusterType(context)); + } + + /** + * Action builder. + */ + public static class Builder extends AbstractKnativeAction.Builder { + + private String subscriptionName; + private String channelName; + private String serviceName; + + public Builder subscription(String subscriptionName) { + this.subscriptionName = subscriptionName; + return this; + } + + public Builder channel(String channelName) { + this.channelName = channelName; + return this; + } + + public Builder service(String serviceName) { + this.serviceName = serviceName; + return this; + } + + @Override + public CreateSubscriptionAction doBuild() { + if (subscriptionName == null) { + subscriptionName = serviceName + "subscription"; + } + + return new CreateSubscriptionAction(this); + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/ce/CloudEvent.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/ce/CloudEvent.java new file mode 100644 index 0000000000..fb8d23ae65 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/ce/CloudEvent.java @@ -0,0 +1,119 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.ce; + +import java.util.Arrays; +import java.util.List; + +public class CloudEvent { + + private final String version; + private final List attributes; + + private CloudEvent(String version, List attributes) { + this.version = version; + this.attributes = attributes; + } + + public String version() { + return version; + } + + public List attributes() { + return attributes; + } + + /** + * Create new cloud event for version 1.0 + * https://github.com/cloudevents/spec/blob/v1.0/spec.md + * @return + */ + public static CloudEvent v1_0() { + return new CloudEvent( + "1.0", + Arrays.asList( + Attribute.ID, + Attribute.SOURCE, + Attribute.SPEC_VERSION, + Attribute.TYPE, + Attribute.SUBJECT, + Attribute.DATA_SCHEMA, + Attribute.TIME, + Attribute.CONTENT_TYPE + ) + ); + } + + /** + * Cloud event attribute with Http header name and Json field name representation. Optional default value + * can be specified. + */ + public enum Attribute { + + ID("Ce-Id", "id"), + SOURCE("Ce-Source", "source"), + SPEC_VERSION("Ce-Specversion", "specversion", "1.0"), + TYPE("Ce-Type", "type"), + SUBJECT("Ce-Subject", "subject"), + DATA_SCHEMA("Ce-Dataschema", "dataschema"), + TIME("Ce-Time", "time"), + CONTENT_TYPE("Content-Type", "datacontenttype"); + + private final String http; + private final String json; + private final String defaultValue; + + /** + * The name of the http header. + */ + public String http() { + return this.http; + } + + /** + * The name of the json field. + */ + public String json() { + return this.json; + } + + /** + * Default value if any. + */ + public String defaultValue() { + return this.defaultValue; + } + + /** + * Checks if this attribute provides a default value. + * @return + */ + public boolean hasDefaultValue() { + return defaultValue != null; + } + + Attribute(String http, String json) { + this(http, json, null); + } + + Attribute(String http, String json, String defaultValue) { + this.http = http; + this.json = json; + this.defaultValue = defaultValue; + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/ce/CloudEventMessage.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/ce/CloudEventMessage.java new file mode 100644 index 0000000000..1020d68735 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/ce/CloudEventMessage.java @@ -0,0 +1,103 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.ce; + +import java.util.HashMap; +import java.util.Map; + +import org.citrusframework.http.message.HttpMessage; + +public class CloudEventMessage extends HttpMessage { + + private final Map attributes = new HashMap<>(); + + public CloudEventMessage eventId(String id) { + return setAttribute(CloudEvent.Attribute.ID, id); + } + + public Object getEventId() { + return getAttribute(CloudEvent.Attribute.ID); + } + + public CloudEventMessage eventType(String type) { + return setAttribute(CloudEvent.Attribute.TYPE, type); + } + + public Object getEventType() { + return getAttribute(CloudEvent.Attribute.TYPE); + } + + public CloudEventMessage specVersion(String version) { + return setAttribute(CloudEvent.Attribute.SPEC_VERSION, version); + } + + public Object getSpecVersion() { + return getAttribute(CloudEvent.Attribute.SPEC_VERSION); + } + + public CloudEventMessage source(String source) { + return setAttribute(CloudEvent.Attribute.SOURCE, source); + } + + public Object getSource() { + return getAttribute(CloudEvent.Attribute.SOURCE); + } + + public CloudEventMessage subject(String subject) { + return setAttribute(CloudEvent.Attribute.SUBJECT, subject); + } + + public Object getSubject() { + return getAttribute(CloudEvent.Attribute.SUBJECT); + } + + public CloudEventMessage time(String time) { + return setAttribute(CloudEvent.Attribute.TIME, time); + } + + public Object getTime() { + return getAttribute(CloudEvent.Attribute.TIME); + } + + public CloudEventMessage dataSchema(String schema) { + return setAttribute(CloudEvent.Attribute.DATA_SCHEMA, schema); + } + + public Object getDataSchema() { + return getAttribute(CloudEvent.Attribute.DATA_SCHEMA); + } + + public Object getAttribute(CloudEvent.Attribute attribute) { + return attributes.get(attribute); + } + + public CloudEventMessage setAttribute(CloudEvent.Attribute attribute, Object value) { + attributes.put(attribute, value); + header(attribute.http(), value); + return this; + } + + public static CloudEventMessage fromEvent(CloudEvent event) { + CloudEventMessage message = new CloudEventMessage(); + + event.attributes().stream() + .filter(CloudEvent.Attribute::hasDefaultValue) + .forEach(a -> message.setAttribute(a, a.defaultValue())); + + return message; + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/ce/CloudEventSupport.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/ce/CloudEventSupport.java new file mode 100644 index 0000000000..13fd08ed8d --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/ce/CloudEventSupport.java @@ -0,0 +1,99 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.ce; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.message.MessageType; +import org.springframework.http.HttpMethod; +import org.springframework.util.StringUtils; + +public final class CloudEventSupport { + + /** + * Prevent instantiation + */ + private CloudEventSupport() { + //utility class + } + + /** + * Prepare request message with given event data as body and CloudEvent attributes set as Http headers. + * @param eventData + * @param attributes + * @return + */ + public static CloudEventMessage createEventMessage(String eventData, Map attributes) { + CloudEventMessage request = CloudEventMessage.fromEvent(CloudEvent.v1_0()); + request.setType(MessageType.JSON); + request.method(HttpMethod.POST); + + if (attributes.containsKey("data")) { + request.setPayload(attributes.get("data")); + } else if (StringUtils.hasText(eventData)) { + request.setPayload(eventData); + } + + attributes.entrySet() + .stream() + .filter(entry -> !entry.getKey().equals("data")) + .forEach(entry -> { + Optional attribute = CloudEvent.v1_0().attributes() + .stream() + .filter(a -> a.http().equalsIgnoreCase(entry.getKey()) || a.json().equals(entry.getKey())) + .findFirst(); + + if (attribute.isPresent()) { + request.setAttribute(attribute.get(), entry.getValue()); + } else { + request.header(entry.getKey(), entry.getValue()); + } + }); + + return request; + } + + /** + * Reads given json string and extracts CloudEvent attributes. + * @param json + * @return + */ + public static Map attributesFromJson(String json) { + Map attributes = new HashMap<>(); + try { + JsonNode event = new ObjectMapper().reader().readTree(json); + for (CloudEvent.Attribute attribute : CloudEvent.v1_0().attributes()) { + Optional.ofNullable(event.findValue(attribute.json())) + .ifPresent(e -> attributes.put(attribute.json(), e.textValue())); + } + + if (event.findValue("data") != null) { + attributes.put("data", event.get("data").textValue()); + } + } catch (JsonProcessingException e) { + throw new CitrusRuntimeException("Failed to read cloud event json", e); + } + + return attributes; + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/CreateBroker.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/CreateBroker.java new file mode 100644 index 0000000000..11cc8f2a86 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/CreateBroker.java @@ -0,0 +1,82 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlRootElement; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.eventing.CreateBrokerAction; +import org.citrusframework.spi.ReferenceResolver; + +@XmlRootElement(name = "create-broker") +public class CreateBroker extends AbstractKnativeAction.Builder { + + private final CreateBrokerAction.Builder delegate = new CreateBrokerAction.Builder(); + + @XmlAttribute(required = true) + public void setName(String name) { + this.delegate.broker(name); + } + + @Override + public CreateBroker description(String description) { + delegate.description(description); + return this; + } + + @Override + public CreateBroker actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public CreateBroker client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateBroker client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateBroker inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public CreateBrokerAction build() { + return delegate.build(); + } + + @Override + protected CreateBrokerAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/CreateChannel.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/CreateChannel.java new file mode 100644 index 0000000000..6d9fe4ad51 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/CreateChannel.java @@ -0,0 +1,82 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlRootElement; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.messaging.CreateChannelAction; +import org.citrusframework.spi.ReferenceResolver; + +@XmlRootElement(name = "create-channel") +public class CreateChannel extends AbstractKnativeAction.Builder { + + private final CreateChannelAction.Builder delegate = new CreateChannelAction.Builder(); + + @XmlAttribute(required = true) + public void setName(String name) { + this.delegate.channel(name); + } + + @Override + public CreateChannel description(String description) { + delegate.description(description); + return this; + } + + @Override + public CreateChannel actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public CreateChannel client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateChannel client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateChannel inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public CreateChannelAction build() { + return delegate.build(); + } + + @Override + protected CreateChannelAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/CreateSubscription.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/CreateSubscription.java new file mode 100644 index 0000000000..84fccea149 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/CreateSubscription.java @@ -0,0 +1,92 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlRootElement; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.messaging.CreateSubscriptionAction; +import org.citrusframework.spi.ReferenceResolver; + +@XmlRootElement(name = "create-subscription") +public class CreateSubscription extends AbstractKnativeAction.Builder { + + private final CreateSubscriptionAction.Builder delegate = new CreateSubscriptionAction.Builder(); + + @XmlAttribute(required = true) + public void setName(String name) { + this.delegate.subscription(name); + } + + @XmlAttribute(required = true) + public void setChannel(String name) { + this.delegate.channel(name); + } + + @XmlAttribute(required = true) + public void setService(String name) { + this.delegate.service(name); + } + + @Override + public CreateSubscription description(String description) { + delegate.description(description); + return this; + } + + @Override + public CreateSubscription actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public CreateSubscription client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateSubscription client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateSubscription inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public CreateSubscriptionAction build() { + return delegate.build(); + } + + @Override + protected CreateSubscriptionAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/CreateTrigger.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/CreateTrigger.java new file mode 100644 index 0000000000..ecd73bf708 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/CreateTrigger.java @@ -0,0 +1,153 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import java.util.ArrayList; +import java.util.List; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import jakarta.xml.bind.annotation.XmlAccessType; +import jakarta.xml.bind.annotation.XmlAccessorType; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlType; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.eventing.CreateTriggerAction; +import org.citrusframework.spi.ReferenceResolver; + +@XmlRootElement(name = "create-trigger") +public class CreateTrigger extends AbstractKnativeAction.Builder { + + private final CreateTriggerAction.Builder delegate = new CreateTriggerAction.Builder(); + + @XmlAttribute(required = true) + public void setName(String name) { + this.delegate.trigger(name); + } + + @XmlAttribute + public void setBroker(String name) { + this.delegate.broker(name); + } + + @XmlAttribute + public void setChannel(String name) { + this.delegate.channel(name); + } + + @XmlAttribute + public void setService(String name) { + this.delegate.service(name); + } + + @XmlElement + public void setFilter(Filter filter) { + filter.getAttributes().forEach(attr -> this.delegate.filter(attr.getName(), attr.getValue())); + } + + @Override + public CreateTrigger description(String description) { + delegate.description(description); + return this; + } + + @Override + public CreateTrigger actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public CreateTrigger client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateTrigger client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateTrigger inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public CreateTriggerAction build() { + return delegate.build(); + } + + @Override + protected CreateTriggerAction doBuild() { + return this.delegate.doBuild(); + } + + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "attributes", + }) + public static class Filter { + + @XmlElement(name = "attribute") + protected List attributes; + + public List getAttributes() { + if (attributes == null) { + attributes = new ArrayList<>(); + } + return this.attributes; + } + + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "") + public static class Attribute { + + @XmlAttribute(name = "name", required = true) + protected String name; + @XmlAttribute(name = "value") + protected String value; + + public String getName() { + return name; + } + + public void setName(String value) { + this.name = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + } + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteBroker.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteBroker.java new file mode 100644 index 0000000000..d10208967e --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteBroker.java @@ -0,0 +1,82 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlRootElement; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.eventing.DeleteBrokerAction; +import org.citrusframework.spi.ReferenceResolver; + +@XmlRootElement(name = "delete-broker") +public class DeleteBroker extends AbstractKnativeAction.Builder { + + private final DeleteBrokerAction.Builder delegate = new DeleteBrokerAction.Builder(); + + @XmlAttribute(required = true) + public void setName(String name) { + this.delegate.broker(name); + } + + @Override + public DeleteBroker description(String description) { + delegate.description(description); + return this; + } + + @Override + public DeleteBroker actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public DeleteBroker client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteBroker client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteBroker inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public DeleteBrokerAction build() { + return delegate.build(); + } + + @Override + protected DeleteBrokerAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteChannel.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteChannel.java new file mode 100644 index 0000000000..c674a9316a --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteChannel.java @@ -0,0 +1,85 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlRootElement; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.DeleteKnativeResourceAction; +import org.citrusframework.spi.ReferenceResolver; + +@XmlRootElement(name = "delete-channel") +public class DeleteChannel extends AbstractKnativeAction.Builder { + + private final DeleteKnativeResourceAction.Builder delegate = new DeleteKnativeResourceAction.Builder(); + + @XmlAttribute(required = true) + public void setName(String name) { + this.delegate.resource(name); + } + + @Override + public DeleteChannel description(String description) { + delegate.description(description); + return this; + } + + @Override + public DeleteChannel actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public DeleteChannel client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteChannel client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteChannel inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public DeleteKnativeResourceAction build() { + this.delegate.component("messaging"); + this.delegate.kind("inmemorychannels"); + + return delegate.build(); + } + + @Override + protected DeleteKnativeResourceAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteResource.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteResource.java new file mode 100644 index 0000000000..a69bbe8f56 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteResource.java @@ -0,0 +1,92 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlRootElement; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.DeleteKnativeResourceAction; +import org.citrusframework.spi.ReferenceResolver; + +@XmlRootElement(name = "delete-resource") +public class DeleteResource extends AbstractKnativeAction.Builder { + + private final DeleteKnativeResourceAction.Builder delegate = new DeleteKnativeResourceAction.Builder(); + + @XmlAttribute(required = true) + public void setName(String name) { + this.delegate.resource(name); + } + + @XmlAttribute + public void setKind(String kind) { + this.delegate.kind(kind); + } + + @XmlAttribute + public void setComponent(String component) { + this.delegate.component(component); + } + + @Override + public DeleteResource description(String description) { + delegate.description(description); + return this; + } + + @Override + public DeleteResource actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public DeleteResource client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteResource client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteResource inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public DeleteKnativeResourceAction build() { + return delegate.build(); + } + + @Override + protected DeleteKnativeResourceAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteSubscription.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteSubscription.java new file mode 100644 index 0000000000..c413f1f01e --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteSubscription.java @@ -0,0 +1,85 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlRootElement; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.DeleteKnativeResourceAction; +import org.citrusframework.spi.ReferenceResolver; + +@XmlRootElement(name = "delete-subscription") +public class DeleteSubscription extends AbstractKnativeAction.Builder { + + private final DeleteKnativeResourceAction.Builder delegate = new DeleteKnativeResourceAction.Builder(); + + @XmlAttribute(required = true) + public void setName(String name) { + this.delegate.resource(name); + } + + @Override + public DeleteSubscription description(String description) { + delegate.description(description); + return this; + } + + @Override + public DeleteSubscription actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public DeleteSubscription client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteSubscription client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteSubscription inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public DeleteKnativeResourceAction build() { + this.delegate.component("messaging"); + this.delegate.kind("subscriptions"); + + return delegate.build(); + } + + @Override + protected DeleteKnativeResourceAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteTrigger.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteTrigger.java new file mode 100644 index 0000000000..858e4165b4 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/DeleteTrigger.java @@ -0,0 +1,82 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlRootElement; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.eventing.DeleteTriggerAction; +import org.citrusframework.spi.ReferenceResolver; + +@XmlRootElement(name = "delete-trigger") +public class DeleteTrigger extends AbstractKnativeAction.Builder { + + private final DeleteTriggerAction.Builder delegate = new DeleteTriggerAction.Builder(); + + @XmlAttribute(required = true) + public void setName(String name) { + this.delegate.trigger(name); + } + + @Override + public DeleteTrigger description(String description) { + delegate.description(description); + return this; + } + + @Override + public DeleteTrigger actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public DeleteTrigger client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteTrigger client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteTrigger inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public DeleteTriggerAction build() { + return delegate.build(); + } + + @Override + protected DeleteTriggerAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/Knative.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/Knative.java new file mode 100644 index 0000000000..cfb278d2a7 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/Knative.java @@ -0,0 +1,175 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import org.citrusframework.TestActionBuilder; +import org.citrusframework.TestActionContainerBuilder; +import org.citrusframework.TestActor; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.KnativeAction; +import org.citrusframework.spi.ReferenceResolver; +import org.citrusframework.spi.ReferenceResolverAware; + +@XmlRootElement(name = "knative") +public class Knative implements TestActionBuilder, ReferenceResolverAware { + + private AbstractKnativeAction.Builder builder; + + private String description; + private String actor; + + private String k8sClient; + private String knativeClient; + private String namespace; + + private ReferenceResolver referenceResolver; + + @XmlElement + public Knative setDescription(String value) { + this.description = description; + return this; + } + + @XmlAttribute + public Knative setActor(String actor) { + this.actor = actor; + return this; + } + + @XmlAttribute + public Knative setNamespace(String namespace) { + this.namespace = namespace; + return this; + } + + @XmlAttribute(name = "kubernetes-client") + public Knative setKubernetesClient(String client) { + this.k8sClient = client; + return this; + } + + @XmlAttribute + public Knative setClient(String client) { + this.knativeClient = client; + return this; + } + + @XmlElement(name = "create-broker") + public void setCreateBroker(CreateBroker builder) { + this.builder = builder; + } + + @XmlElement(name = "delete-broker") + public void setDeleteBroker(DeleteBroker builder) { + this.builder = builder; + } + + @XmlElement(name = "verify-broker") + public void setVerifyBroker(VerifyBroker builder) { + this.builder = builder; + } + + @XmlElement(name = "create-trigger") + public void setCreateTrigger(CreateTrigger builder) { + this.builder = builder; + } + + @XmlElement(name = "delete-trigger") + public void setDeleteTrigger(DeleteTrigger builder) { + this.builder = builder; + } + + @XmlElement(name = "create-channel") + public void setCreateChannel(CreateChannel builder) { + this.builder = builder; + } + + @XmlElement(name = "delete-channel") + public void setDeleteChannel(DeleteChannel builder) { + this.builder = builder; + } + + @XmlElement(name = "create-subscription") + public void setCreateSubscription(CreateSubscription builder) { + this.builder = builder; + } + + @XmlElement(name = "delete-subscription") + public void setDeleteSubscription(DeleteSubscription builder) { + this.builder = builder; + } + + @XmlElement(name = "send-event") + public void setSendEvent(SendEvent builder) { + this.builder = builder; + } + + @XmlElement(name = "receive-event") + public void setReceiveEvent(ReceiveEvent builder) { + this.builder = builder; + } + + @XmlElement(name = "delete-resource") + public void setDeleteResource(DeleteResource builder) { + this.builder = builder; + } + + @Override + public KnativeAction build() { + if (builder == null) { + throw new CitrusRuntimeException("Missing Knative action - please provide proper action details"); + } + + if (builder instanceof TestActionContainerBuilder) { + ((TestActionContainerBuilder) builder).getActions().stream() + .filter(action -> action instanceof ReferenceResolverAware) + .forEach(action -> ((ReferenceResolverAware) action).setReferenceResolver(referenceResolver)); + } + + builder.setReferenceResolver(referenceResolver); + + builder.description(description); + builder.inNamespace(namespace); + + if (referenceResolver != null) { + if (k8sClient != null) { + builder.client(referenceResolver.resolve(k8sClient, KubernetesClient.class)); + } + + if (knativeClient != null) { + builder.client(referenceResolver.resolve(knativeClient, KnativeClient.class)); + } + + if (actor != null) { + builder.actor(referenceResolver.resolve(actor, TestActor.class)); + } + } + + return builder.build(); + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.referenceResolver = referenceResolver; + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/ObjectFactory.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/ObjectFactory.java new file mode 100644 index 0000000000..9abef64e6f --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/ObjectFactory.java @@ -0,0 +1,53 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import jakarta.xml.bind.annotation.XmlRegistry; +import org.citrusframework.kubernetes.xml.Kubernetes; + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the org.citrusframework.ftp.model package. + *

An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.citrusframework.xml.actions + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link Knative } + * + */ + public Knative createKnative() { + return new Knative(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/ReceiveEvent.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/ReceiveEvent.java new file mode 100644 index 0000000000..b6febca06f --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/ReceiveEvent.java @@ -0,0 +1,177 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import java.util.ArrayList; +import java.util.List; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import jakarta.xml.bind.annotation.XmlAccessType; +import jakarta.xml.bind.annotation.XmlAccessorType; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlType; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.eventing.ReceiveEventAction; +import org.citrusframework.spi.ReferenceResolver; +import org.citrusframework.spi.ReferenceResolverAware; + +@XmlRootElement(name = "receive-event") +public class ReceiveEvent extends AbstractKnativeAction.Builder implements ReferenceResolverAware { + + private final ReceiveEventAction.Builder delegate = new ReceiveEventAction.Builder(); + + @XmlAttribute(required = true) + public void setService(String name) { + this.delegate.serviceName(name); + } + + @XmlAttribute + public void setPort(int port) { + this.delegate.servicePort(port); + } + + @XmlAttribute + public void setTimeout(long timeout) { + this.delegate.timeout(timeout); + } + + @XmlElement(name = "event", required = true) + public void setEvent(Event event) { + event.getAttributes().getAttributes().forEach( + attr -> this.delegate.attribute(attr.getName(), attr.getValue()) + ); + this.delegate.eventData(event.getData()); + } + + @Override + public ReceiveEvent description(String description) { + delegate.description(description); + return this; + } + + @Override + public ReceiveEvent actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public ReceiveEvent client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public ReceiveEvent client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public ReceiveEvent inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public ReceiveEventAction build() { + return delegate.build(); + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "attributes", + "data" + }) + public static class Event { + + @XmlElement + protected String data; + + @XmlElement(name = "ce-attributes") + protected Attributes attributes; + + public Attributes getAttributes() { + if (attributes == null) { + attributes = new Attributes(); + } + return this.attributes; + } + + public String getData() { + return data; + } + + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "attributes", + }) + public static class Attributes { + + @XmlElement(name = "ce-attribute") + protected List attributes; + + public List getAttributes() { + if (attributes == null) { + attributes = new ArrayList<>(); + } + return this.attributes; + } + + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "") + public static class Attribute { + + @XmlAttribute(name = "name", required = true) + protected String name; + @XmlAttribute(name = "value") + protected String value; + + public String getName() { + return name; + } + + public void setName(String value) { + this.name = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + } + } + } + + @Override + protected ReceiveEventAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/SendEvent.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/SendEvent.java new file mode 100644 index 0000000000..a08b8275f5 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/SendEvent.java @@ -0,0 +1,181 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import java.util.ArrayList; +import java.util.List; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import jakarta.xml.bind.annotation.XmlAccessType; +import jakarta.xml.bind.annotation.XmlAccessorType; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlType; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.eventing.SendEventAction; +import org.citrusframework.spi.ReferenceResolver; +import org.citrusframework.spi.ReferenceResolverAware; + +@XmlRootElement(name = "send-event") +public class SendEvent extends AbstractKnativeAction.Builder implements ReferenceResolverAware { + + private final SendEventAction.Builder delegate = new SendEventAction.Builder(); + + @XmlAttribute(required = true) + public void setBroker(String urlOrName) { + if (urlOrName.startsWith("http://") || urlOrName.startsWith("https://")) { + this.delegate.brokerUrl(urlOrName); + } else { + this.delegate.broker(urlOrName); + } + } + + @XmlAttribute(name = "fork") + public void setFork(Boolean value) { + this.delegate.fork(value); + } + + @XmlAttribute + public void setTimeout(long timeout) { + this.delegate.timeout(timeout); + } + + @XmlElement(name = "event", required = true) + public void setEvent(Event event) { + event.getAttributes().getAttributes().forEach( + attr -> this.delegate.attribute(attr.getName(), attr.getValue()) + ); + this.delegate.eventData(event.getData()); + } + + @Override + public SendEvent description(String description) { + delegate.description(description); + return this; + } + + @Override + public SendEvent actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public SendEvent client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public SendEvent client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public SendEvent inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public SendEventAction build() { + return delegate.build(); + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "attributes", + "data" + }) + public static class Event { + + @XmlElement + protected String data; + + @XmlElement(name = "ce-attributes") + protected Attributes attributes; + + public Attributes getAttributes() { + if (attributes == null) { + attributes = new Attributes(); + } + return this.attributes; + } + + public String getData() { + return data; + } + + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "attributes", + }) + public static class Attributes { + + @XmlElement(name = "ce-attribute") + protected List attributes; + + public List getAttributes() { + if (attributes == null) { + attributes = new ArrayList<>(); + } + return this.attributes; + } + + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "") + public static class Attribute { + + @XmlAttribute(name = "name", required = true) + protected String name; + @XmlAttribute(name = "value") + protected String value; + + public String getName() { + return name; + } + + public void setName(String value) { + this.name = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + } + } + } + + @Override + protected SendEventAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/VerifyBroker.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/VerifyBroker.java new file mode 100644 index 0000000000..e52e73c3fb --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/VerifyBroker.java @@ -0,0 +1,82 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlRootElement; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.eventing.VerifyBrokerAction; +import org.citrusframework.spi.ReferenceResolver; + +@XmlRootElement(name = "verify-broker") +public class VerifyBroker extends AbstractKnativeAction.Builder { + + private final VerifyBrokerAction.Builder delegate = new VerifyBrokerAction.Builder(); + + @XmlAttribute(required = true) + public void setName(String name) { + this.delegate.broker(name); + } + + @Override + public VerifyBroker description(String description) { + delegate.description(description); + return this; + } + + @Override + public VerifyBroker actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public VerifyBroker client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public VerifyBroker client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public VerifyBroker inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public VerifyBrokerAction build() { + return delegate.build(); + } + + @Override + protected VerifyBrokerAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/package-info.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/package-info.java new file mode 100644 index 0000000000..0a1737081e --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/xml/package-info.java @@ -0,0 +1,18 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@jakarta.xml.bind.annotation.XmlSchema(namespace = "http://citrusframework.org/schema/xml/testcase", elementFormDefault = jakarta.xml.bind.annotation.XmlNsForm.QUALIFIED) +package org.citrusframework.knative.xml; diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/CreateBroker.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/CreateBroker.java new file mode 100644 index 0000000000..5e7d850070 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/CreateBroker.java @@ -0,0 +1,78 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.eventing.CreateBrokerAction; +import org.citrusframework.spi.ReferenceResolver; + +public class CreateBroker extends AbstractKnativeAction.Builder { + + private final CreateBrokerAction.Builder delegate = new CreateBrokerAction.Builder(); + + public void setName(String name) { + this.delegate.broker(name); + } + + @Override + public CreateBroker description(String description) { + delegate.description(description); + return this; + } + + @Override + public CreateBroker actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public CreateBroker client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateBroker client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateBroker inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public CreateBrokerAction build() { + return delegate.build(); + } + + @Override + protected CreateBrokerAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/CreateChannel.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/CreateChannel.java new file mode 100644 index 0000000000..3cc53bf03a --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/CreateChannel.java @@ -0,0 +1,78 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.messaging.CreateChannelAction; +import org.citrusframework.spi.ReferenceResolver; + +public class CreateChannel extends AbstractKnativeAction.Builder { + + private final CreateChannelAction.Builder delegate = new CreateChannelAction.Builder(); + + public void setName(String name) { + this.delegate.channel(name); + } + + @Override + public CreateChannel description(String description) { + delegate.description(description); + return this; + } + + @Override + public CreateChannel actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public CreateChannel client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateChannel client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateChannel inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public CreateChannelAction build() { + return delegate.build(); + } + + @Override + protected CreateChannelAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/CreateSubscription.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/CreateSubscription.java new file mode 100644 index 0000000000..38f416ff03 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/CreateSubscription.java @@ -0,0 +1,86 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.messaging.CreateSubscriptionAction; +import org.citrusframework.spi.ReferenceResolver; + +public class CreateSubscription extends AbstractKnativeAction.Builder { + + private final CreateSubscriptionAction.Builder delegate = new CreateSubscriptionAction.Builder(); + + public void setName(String name) { + this.delegate.subscription(name); + } + + public void setChannel(String name) { + this.delegate.channel(name); + } + + public void setService(String name) { + this.delegate.service(name); + } + + @Override + public CreateSubscription description(String description) { + delegate.description(description); + return this; + } + + @Override + public CreateSubscription actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public CreateSubscription client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateSubscription client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateSubscription inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public CreateSubscriptionAction build() { + return delegate.build(); + } + + @Override + protected CreateSubscriptionAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/CreateTrigger.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/CreateTrigger.java new file mode 100644 index 0000000000..0e60f49019 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/CreateTrigger.java @@ -0,0 +1,136 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import java.util.ArrayList; +import java.util.List; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.eventing.CreateTriggerAction; +import org.citrusframework.spi.ReferenceResolver; + +public class CreateTrigger extends AbstractKnativeAction.Builder { + + private final CreateTriggerAction.Builder delegate = new CreateTriggerAction.Builder(); + + public void setName(String name) { + this.delegate.trigger(name); + } + + public void setBroker(String name) { + this.delegate.broker(name); + } + + public void setChannel(String name) { + this.delegate.channel(name); + } + + public void setService(String name) { + this.delegate.service(name); + } + + public void setFilter(Filter filter) { + filter.getAttributes().forEach(attr -> this.delegate.filter(attr.getName(), attr.getValue())); + } + + @Override + public CreateTrigger description(String description) { + delegate.description(description); + return this; + } + + @Override + public CreateTrigger actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public CreateTrigger client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateTrigger client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public CreateTrigger inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public CreateTriggerAction build() { + return delegate.build(); + } + + public static class Filter { + + protected List attributes; + + public void setAttributes(List attributes) { + this.attributes = attributes; + } + + public List getAttributes() { + if (attributes == null) { + attributes = new ArrayList<>(); + } + return this.attributes; + } + + public static class Attribute { + + protected String name; + protected String value; + + public String getName() { + return name; + } + + public void setName(String value) { + this.name = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + } + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + protected CreateTriggerAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteBroker.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteBroker.java new file mode 100644 index 0000000000..31a303c88a --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteBroker.java @@ -0,0 +1,78 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.eventing.DeleteBrokerAction; +import org.citrusframework.spi.ReferenceResolver; + +public class DeleteBroker extends AbstractKnativeAction.Builder { + + private final DeleteBrokerAction.Builder delegate = new DeleteBrokerAction.Builder(); + + public void setName(String name) { + this.delegate.broker(name); + } + + @Override + public DeleteBroker description(String description) { + delegate.description(description); + return this; + } + + @Override + public DeleteBroker actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public DeleteBroker client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteBroker client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteBroker inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public DeleteBrokerAction build() { + return delegate.build(); + } + + @Override + protected DeleteBrokerAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteChannel.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteChannel.java new file mode 100644 index 0000000000..bffcaeb82b --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteChannel.java @@ -0,0 +1,81 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.DeleteKnativeResourceAction; +import org.citrusframework.spi.ReferenceResolver; + +public class DeleteChannel extends AbstractKnativeAction.Builder { + + private final DeleteKnativeResourceAction.Builder delegate = new DeleteKnativeResourceAction.Builder(); + + public void setName(String name) { + this.delegate.resource(name); + } + + @Override + public DeleteChannel description(String description) { + delegate.description(description); + return this; + } + + @Override + public DeleteChannel actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public DeleteChannel client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteChannel client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteChannel inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public DeleteKnativeResourceAction build() { + this.delegate.component("messaging"); + this.delegate.kind("inmemorychannels"); + + return delegate.build(); + } + + @Override + protected DeleteKnativeResourceAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteResource.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteResource.java new file mode 100644 index 0000000000..7471118c55 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteResource.java @@ -0,0 +1,86 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.DeleteKnativeResourceAction; +import org.citrusframework.spi.ReferenceResolver; + +public class DeleteResource extends AbstractKnativeAction.Builder { + + private final DeleteKnativeResourceAction.Builder delegate = new DeleteKnativeResourceAction.Builder(); + + public void setName(String name) { + this.delegate.resource(name); + } + + public void setKind(String kind) { + this.delegate.kind(kind); + } + + public void setComponent(String component) { + this.delegate.component(component); + } + + @Override + public DeleteResource description(String description) { + delegate.description(description); + return this; + } + + @Override + public DeleteResource actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public DeleteResource client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteResource client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteResource inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public DeleteKnativeResourceAction build() { + return delegate.build(); + } + + @Override + protected DeleteKnativeResourceAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteSubscription.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteSubscription.java new file mode 100644 index 0000000000..67c4ccfcc1 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteSubscription.java @@ -0,0 +1,81 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.DeleteKnativeResourceAction; +import org.citrusframework.spi.ReferenceResolver; + +public class DeleteSubscription extends AbstractKnativeAction.Builder { + + private final DeleteKnativeResourceAction.Builder delegate = new DeleteKnativeResourceAction.Builder(); + + public void setName(String name) { + this.delegate.resource(name); + } + + @Override + public DeleteSubscription description(String description) { + delegate.description(description); + return this; + } + + @Override + public DeleteSubscription actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public DeleteSubscription client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteSubscription client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteSubscription inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public DeleteKnativeResourceAction build() { + this.delegate.component("messaging"); + this.delegate.kind("subscriptions"); + + return delegate.build(); + } + + @Override + protected DeleteKnativeResourceAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteTrigger.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteTrigger.java new file mode 100644 index 0000000000..610eeb544d --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/DeleteTrigger.java @@ -0,0 +1,78 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.eventing.DeleteTriggerAction; +import org.citrusframework.spi.ReferenceResolver; + +public class DeleteTrigger extends AbstractKnativeAction.Builder { + + private final DeleteTriggerAction.Builder delegate = new DeleteTriggerAction.Builder(); + + public void setName(String name) { + this.delegate.trigger(name); + } + + @Override + public DeleteTrigger description(String description) { + delegate.description(description); + return this; + } + + @Override + public DeleteTrigger actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public DeleteTrigger client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteTrigger client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public DeleteTrigger inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public DeleteTriggerAction build() { + return delegate.build(); + } + + @Override + protected DeleteTriggerAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/Knative.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/Knative.java new file mode 100644 index 0000000000..d346287bb8 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/Knative.java @@ -0,0 +1,149 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestActionBuilder; +import org.citrusframework.TestActionContainerBuilder; +import org.citrusframework.TestActor; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.KnativeAction; +import org.citrusframework.spi.ReferenceResolver; +import org.citrusframework.spi.ReferenceResolverAware; + +public class Knative implements TestActionBuilder, ReferenceResolverAware { + + private AbstractKnativeAction.Builder builder; + + private String description; + private String actor; + + private String k8sClient; + private String knativeClient; + private String namespace; + + private ReferenceResolver referenceResolver; + + public void setDescription(String value) { + this.description = description; + } + + public void setActor(String actor) { + this.actor = actor; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public void setKubernetesClient(String client) { + this.k8sClient = client; + } + + public void setClient(String client) { + this.knativeClient = client; + } + + public void setCreateBroker(CreateBroker builder) { + this.builder = builder; + } + + public void setDeleteBroker(DeleteBroker builder) { + this.builder = builder; + } + + public void setVerifyBroker(VerifyBroker builder) { + this.builder = builder; + } + + public void setCreateTrigger(CreateTrigger builder) { + this.builder = builder; + } + + public void setDeleteTrigger(DeleteTrigger builder) { + this.builder = builder; + } + + public void setCreateChannel(CreateChannel builder) { + this.builder = builder; + } + + public void setDeleteChannel(DeleteChannel builder) { + this.builder = builder; + } + + public void setCreateSubscription(CreateSubscription builder) { + this.builder = builder; + } + + public void setDeleteSubscription(DeleteSubscription builder) { + this.builder = builder; + } + + public void setSendEvent(SendEvent builder) { + this.builder = builder; + } + + public void setReceiveEvent(ReceiveEvent builder) { + this.builder = builder; + } + + public void setDeleteResource(DeleteResource builder) { + this.builder = builder; + } + + @Override + public KnativeAction build() { + if (builder == null) { + throw new CitrusRuntimeException("Missing Knative action - please provide proper action details"); + } + + if (builder instanceof TestActionContainerBuilder) { + ((TestActionContainerBuilder) builder).getActions().stream() + .filter(action -> action instanceof ReferenceResolverAware) + .forEach(action -> ((ReferenceResolverAware) action).setReferenceResolver(referenceResolver)); + } + + builder.setReferenceResolver(referenceResolver); + + builder.description(description); + builder.inNamespace(namespace); + + if (referenceResolver != null) { + if (k8sClient != null) { + builder.client(referenceResolver.resolve(k8sClient, KubernetesClient.class)); + } + + if (knativeClient != null) { + builder.client(referenceResolver.resolve(knativeClient, KnativeClient.class)); + } + + if (actor != null) { + builder.actor(referenceResolver.resolve(actor, TestActor.class)); + } + } + + return builder.build(); + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.referenceResolver = referenceResolver; + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/ReceiveEvent.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/ReceiveEvent.java new file mode 100644 index 0000000000..8a4e2be95b --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/ReceiveEvent.java @@ -0,0 +1,146 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import java.util.ArrayList; +import java.util.List; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.eventing.ReceiveEventAction; +import org.citrusframework.spi.ReferenceResolver; +import org.citrusframework.spi.ReferenceResolverAware; + +public class ReceiveEvent extends AbstractKnativeAction.Builder implements ReferenceResolverAware { + + private final ReceiveEventAction.Builder delegate = new ReceiveEventAction.Builder(); + + public void setService(String name) { + this.delegate.serviceName(name); + } + + public void setPort(int port) { + this.delegate.servicePort(port); + } + + public void setTimeout(long timeout) { + this.delegate.timeout(timeout); + } + + public void setEvent(Event event) { + event.getAttributes().forEach( + attr -> this.delegate.attribute(attr.getName(), attr.getValue()) + ); + this.delegate.eventData(event.getData()); + } + + @Override + public ReceiveEvent description(String description) { + delegate.description(description); + return this; + } + + @Override + public ReceiveEvent actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public ReceiveEvent client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public ReceiveEvent client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public ReceiveEvent inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public ReceiveEventAction build() { + return delegate.build(); + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + public static class Event { + + protected String data; + + protected List attributes; + + public void setAttributes(List attributes) { + this.attributes = attributes; + } + + public List getAttributes() { + if (attributes == null) { + attributes = new ArrayList<>(); + } + return this.attributes; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public static class Attribute { + + protected String name; + protected String value; + + public String getName() { + return name; + } + + public void setName(String value) { + this.name = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + } + } + + @Override + protected ReceiveEventAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/SendEvent.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/SendEvent.java new file mode 100644 index 0000000000..7de2cabbc3 --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/SendEvent.java @@ -0,0 +1,149 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import java.util.ArrayList; +import java.util.List; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.eventing.SendEventAction; +import org.citrusframework.spi.ReferenceResolver; +import org.citrusframework.spi.ReferenceResolverAware; + +public class SendEvent extends AbstractKnativeAction.Builder implements ReferenceResolverAware { + + private final SendEventAction.Builder delegate = new SendEventAction.Builder(); + + public void setBroker(String urlOrName) { + if (urlOrName.startsWith("http://") || urlOrName.startsWith("https://")) { + this.delegate.brokerUrl(urlOrName); + } else { + this.delegate.broker(urlOrName); + } + } + + public void setFork(Boolean value) { + this.delegate.fork(value); + } + + public void setTimeout(long timeout) { + this.delegate.timeout(timeout); + } + + public void setEvent(Event event) { + event.getAttributes().forEach( + attr -> this.delegate.attribute(attr.getName(), attr.getValue()) + ); + this.delegate.eventData(event.getData()); + } + + @Override + public SendEvent description(String description) { + delegate.description(description); + return this; + } + + @Override + public SendEvent actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public SendEvent client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public SendEvent client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public SendEvent inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public SendEventAction build() { + return delegate.build(); + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + public static class Event { + + protected List attributes; + protected String data; + + public void setAttributes(List attributes) { + this.attributes = attributes; + } + + public List getAttributes() { + if (attributes == null) { + attributes = new ArrayList<>(); + } + return this.attributes; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public static class Attribute { + + protected String name; + protected String value; + + public String getName() { + return name; + } + + public void setName(String value) { + this.name = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + } + } + + @Override + protected SendEventAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/VerifyBroker.java b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/VerifyBroker.java new file mode 100644 index 0000000000..fb3c898f6f --- /dev/null +++ b/connectors/citrus-knative/src/main/java/org/citrusframework/knative/yaml/VerifyBroker.java @@ -0,0 +1,78 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.TestActor; +import org.citrusframework.knative.actions.AbstractKnativeAction; +import org.citrusframework.knative.actions.eventing.VerifyBrokerAction; +import org.citrusframework.spi.ReferenceResolver; + +public class VerifyBroker extends AbstractKnativeAction.Builder { + + private final VerifyBrokerAction.Builder delegate = new VerifyBrokerAction.Builder(); + + public void setName(String name) { + this.delegate.broker(name); + } + + @Override + public VerifyBroker description(String description) { + delegate.description(description); + return this; + } + + @Override + public VerifyBroker actor(TestActor actor) { + delegate.actor(actor); + return this; + } + + @Override + public VerifyBroker client(KubernetesClient client) { + delegate.client(client); + return this; + } + + @Override + public VerifyBroker client(KnativeClient client) { + delegate.client(client); + return this; + } + + @Override + public VerifyBroker inNamespace(String namespace) { + this.delegate.inNamespace(namespace); + return this; + } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + + @Override + public VerifyBrokerAction build() { + return delegate.build(); + } + + @Override + protected VerifyBrokerAction doBuild() { + return this.delegate.doBuild(); + } +} diff --git a/connectors/citrus-knative/src/main/resources/META-INF/LICENSE.txt b/connectors/citrus-knative/src/main/resources/META-INF/LICENSE.txt new file mode 100644 index 0000000000..0234973237 --- /dev/null +++ b/connectors/citrus-knative/src/main/resources/META-INF/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright the original author or authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/connectors/citrus-knative/src/main/resources/META-INF/NOTICE.txt b/connectors/citrus-knative/src/main/resources/META-INF/NOTICE.txt new file mode 100644 index 0000000000..ad3886b5ab --- /dev/null +++ b/connectors/citrus-knative/src/main/resources/META-INF/NOTICE.txt @@ -0,0 +1,32 @@ + ======================================================================== + == NOTICE file corresponding to section 4 d of the Apache License, == + == Version 2.0, in this case for the Citrus distribution. == + ======================================================================== + + This product includes software developed by the Citrus + project (https://citrusframework.org). + + The end-user documentation included with a redistribution, if any, + must include the following acknowledgement: + + "This product includes software developed by the Citrus + Project (https://citrusframework.org)." + + Alternatively, this acknowledgement may appear in the software itself, + if and wherever such third-party acknowledgements normally appear. + + The names "Citrus" and "Citrus Framework" must not be used to endorse or + promote products derived from this software without prior written permission. + For written permission, please contact user@citrusframework.org. + + Copyright (C) 2006-2023 the original author or authors. + + Citrus is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. + + You should have received a copy of the Apache License Version 2.0 + along with Citrus. If not, see . + + dev@citrusframework.org + https://citrusframework.org diff --git a/connectors/citrus-knative/src/main/resources/META-INF/citrus/xml/builder/knative b/connectors/citrus-knative/src/main/resources/META-INF/citrus/xml/builder/knative new file mode 100644 index 0000000000..6d959adff1 --- /dev/null +++ b/connectors/citrus-knative/src/main/resources/META-INF/citrus/xml/builder/knative @@ -0,0 +1,2 @@ +type=org.citrusframework.knative.xml.Knative +ns=http://citrusframework.org/schema/xml/testcase diff --git a/connectors/citrus-knative/src/main/resources/META-INF/citrus/yaml/builder/knative b/connectors/citrus-knative/src/main/resources/META-INF/citrus/yaml/builder/knative new file mode 100644 index 0000000000..10982c4bbf --- /dev/null +++ b/connectors/citrus-knative/src/main/resources/META-INF/citrus/yaml/builder/knative @@ -0,0 +1 @@ +type=org.citrusframework.knative.yaml.Knative diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/AbstractKnativeIT.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/AbstractKnativeIT.java new file mode 100644 index 0000000000..af8fcf9c2c --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/AbstractKnativeIT.java @@ -0,0 +1,24 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.integration; + +import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; +import org.springframework.test.context.ContextConfiguration; + +@ContextConfiguration(classes = KnativeServiceConfiguration.class) +public class AbstractKnativeIT extends TestNGCitrusSpringSupport { +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/CreateKnativeBrokerIT.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/CreateKnativeBrokerIT.java new file mode 100644 index 0000000000..abef6647be --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/CreateKnativeBrokerIT.java @@ -0,0 +1,60 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.integration; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.knative.eventing.v1.Broker; +import org.citrusframework.annotations.CitrusTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.testng.Assert; +import org.testng.annotations.Test; + +import static org.citrusframework.container.FinallySequence.Builder.doFinally; +import static org.citrusframework.knative.actions.KnativeActionBuilder.knative; + +public class CreateKnativeBrokerIT extends AbstractKnativeIT { + + @Autowired + private KnativeClient knativeClient; + + private final String namespace = "test"; + + @Test + @CitrusTest + public void shouldCreateBroker() { + given(doFinally().actions(context -> knativeClient.brokers() + .inNamespace(namespace) + .withName("my-broker") + .delete())); + + when(knative() + .client(knativeClient) + .brokers() + .create("my-broker") + .inNamespace(namespace)); + + then(context -> { + Broker broker = knativeClient.brokers() + .inNamespace(namespace) + .withName("my-broker") + .get(); + + Assert.assertNotNull(broker); + }); + } + +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/CreateKnativeTriggerIT.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/CreateKnativeTriggerIT.java new file mode 100644 index 0000000000..26af75b93a --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/CreateKnativeTriggerIT.java @@ -0,0 +1,61 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.integration; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.knative.eventing.v1.Trigger; +import org.citrusframework.annotations.CitrusTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.testng.Assert; +import org.testng.annotations.Test; + +import static org.citrusframework.container.FinallySequence.Builder.doFinally; +import static org.citrusframework.knative.actions.KnativeActionBuilder.knative; + +public class CreateKnativeTriggerIT extends AbstractKnativeIT { + + @Autowired + private KnativeClient knativeClient; + + private final String namespace = "test"; + + @Test + @CitrusTest + public void shouldCreateTrigger() { + given(doFinally().actions(context -> knativeClient.triggers() + .inNamespace(namespace) + .withName("my-trigger") + .delete())); + + when(knative() + .client(knativeClient) + .trigger() + .create("my-trigger") + .service("my-service") + .inNamespace(namespace)); + + then(context -> { + Trigger trigger = knativeClient.triggers() + .inNamespace(namespace) + .withName("my-trigger") + .get(); + + Assert.assertNotNull(trigger); + }); + } + +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/DeleteKnativeBrokerIT.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/DeleteKnativeBrokerIT.java new file mode 100644 index 0000000000..e299167ca3 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/DeleteKnativeBrokerIT.java @@ -0,0 +1,69 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.integration; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.knative.eventing.v1.Broker; +import io.fabric8.knative.eventing.v1.BrokerBuilder; +import org.citrusframework.annotations.CitrusTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.testng.Assert; +import org.testng.annotations.Test; + +import static org.citrusframework.knative.actions.KnativeActionBuilder.knative; + +public class DeleteKnativeBrokerIT extends AbstractKnativeIT { + + @Autowired + private KnativeClient knativeClient; + + private final String namespace = "test"; + + @Test + @CitrusTest + public void shouldDeleteBroker() { + given(context -> { + Broker broker = new BrokerBuilder() + .withNewMetadata() + .withName("my-broker") + .withNamespace(namespace) + .endMetadata() + .build(); + + knativeClient.brokers() + .inNamespace(namespace) + .resource(broker) + .create(); + }); + + when(knative() + .client(knativeClient) + .brokers() + .delete("my-broker") + .inNamespace(namespace)); + + then(context -> { + Broker broker = knativeClient.brokers() + .inNamespace(namespace) + .withName("my-broker") + .get(); + + Assert.assertNull(broker); + }); + } + +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/DeleteKnativeResourceIT.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/DeleteKnativeResourceIT.java new file mode 100644 index 0000000000..fe27562a16 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/DeleteKnativeResourceIT.java @@ -0,0 +1,90 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.integration; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.knative.internal.pkg.apis.duck.v1.DestinationBuilder; +import io.fabric8.knative.internal.pkg.apis.duck.v1.KReferenceBuilder; +import io.fabric8.knative.messaging.v1.Subscription; +import io.fabric8.knative.messaging.v1.SubscriptionBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.citrusframework.annotations.CitrusTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.testng.Assert; +import org.testng.annotations.Test; + +import static org.citrusframework.knative.actions.KnativeActionBuilder.knative; + +public class DeleteKnativeResourceIT extends AbstractKnativeIT { + + @Autowired + private KubernetesClient k8sClient; + + @Autowired + private KnativeClient knativeClient; + + private final String namespace = "test"; + + @Test + @CitrusTest + public void shouldDeleteResource() { + given(context -> { + Subscription subscription = new SubscriptionBuilder() + .withNewMetadata() + .withName("my-subscription") + .withNamespace(namespace) + .endMetadata() + .withNewSpec() + .withChannel(new KReferenceBuilder() + .withApiVersion("messaging/v1") + .withKind("InMemoryChannel") + .withName("my-channel") + .build()) + .withSubscriber(new DestinationBuilder() + .withNewRef() + .withApiVersion("v1") + .withKind("Service") + .withName("my-service") + .endRef() + .build()) + .endSpec() + .build(); + + knativeClient.subscriptions() + .inNamespace(namespace) + .resource(subscription) + .create(); + }); + + when(knative() + .client(k8sClient) + .client(knativeClient) + .subscriptions() + .delete("my-subscription") + .inNamespace(namespace)); + + then(context -> { + Subscription subscription = knativeClient.subscriptions() + .inNamespace(namespace) + .withName("my-subscription") + .get(); + + Assert.assertNull(subscription); + }); + } + +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/DeleteKnativeTriggerIT.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/DeleteKnativeTriggerIT.java new file mode 100644 index 0000000000..15de5d8662 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/DeleteKnativeTriggerIT.java @@ -0,0 +1,69 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.integration; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.knative.eventing.v1.Trigger; +import io.fabric8.knative.eventing.v1.TriggerBuilder; +import org.citrusframework.annotations.CitrusTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.testng.Assert; +import org.testng.annotations.Test; + +import static org.citrusframework.knative.actions.KnativeActionBuilder.knative; + +public class DeleteKnativeTriggerIT extends AbstractKnativeIT { + + @Autowired + private KnativeClient knativeClient; + + private final String namespace = "test"; + + @Test + @CitrusTest + public void shouldDeleteTrigger() { + given(context -> { + Trigger trigger = new TriggerBuilder() + .withNewMetadata() + .withName("my-trigger") + .withNamespace(namespace) + .endMetadata() + .build(); + + knativeClient.triggers() + .inNamespace(namespace) + .resource(trigger) + .create(); + }); + + when(knative() + .client(knativeClient) + .trigger() + .delete("my-trigger") + .inNamespace(namespace)); + + then(context -> { + Trigger trigger = knativeClient.triggers() + .inNamespace(namespace) + .withName("my-trigger") + .get(); + + Assert.assertNull(trigger); + }); + } + +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/KnativeServiceConfiguration.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/KnativeServiceConfiguration.java new file mode 100644 index 0000000000..927e3f76cc --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/KnativeServiceConfiguration.java @@ -0,0 +1,91 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.integration; + +import java.util.HashMap; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.server.mock.KubernetesCrudDispatcher; +import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; +import io.fabric8.mockwebserver.Context; +import okhttp3.mockwebserver.MockWebServer; +import org.citrusframework.endpoint.EndpointAdapter; +import org.citrusframework.endpoint.adapter.StaticEndpointAdapter; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.http.server.HttpServerBuilder; +import org.citrusframework.message.Message; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.testng.Assert; + +@Configuration +public class KnativeServiceConfiguration { + + private static final int HTTP_PORT = 8080; + + private final KubernetesMockServer kubernetesServer = new KubernetesMockServer(new Context(), new MockWebServer(), + new HashMap<>(), new KubernetesCrudDispatcher(), false); + + @Bean(initMethod = "init", destroyMethod = "destroy") + public KubernetesMockServer kubernetesMockServer() { + return kubernetesServer; + } + + @Bean(destroyMethod = "close") + @DependsOn("kubernetesMockServer") + public KnativeClient knativeClient() { + return kubernetesClient().adapt(KnativeClient.class); + } + + @Bean(destroyMethod = "close") + @DependsOn("kubernetesMockServer") + public KubernetesClient kubernetesClient() { + return kubernetesServer.createClient(); + } + + @Bean + public HttpServer httpServer() { + return new HttpServerBuilder() + .port(HTTP_PORT) + .autoStart(true) + .endpointAdapter(handleCloudEventAdapter()) + .build(); + } + + @Bean + public EndpointAdapter handleCloudEventAdapter() { + return new StaticEndpointAdapter() { + @Override + protected Message handleMessageInternal(Message message) { + Assert.assertEquals(message.getHeader("Ce-Id"), "say-hello"); + Assert.assertEquals(message.getHeader("Ce-Specversion"), "1.0"); + Assert.assertEquals(message.getHeader("Ce-Subject"), "hello"); + Assert.assertEquals(message.getHeader("Ce-Type"), "greeting"); + Assert.assertEquals(message.getHeader("Ce-Source"), "https://github.com/citrusframework/yaks"); + Assert.assertEquals(message.getHeader("Content-Type").toString(), MediaType.APPLICATION_JSON_UTF8_VALUE); + Assert.assertEquals(message.getPayload(String.class), "{\"msg\": \"Hello Knative!\"}"); + + return new HttpMessage().status(HttpStatus.ACCEPTED); + } + }; + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/ReceiveEventIT.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/ReceiveEventIT.java new file mode 100644 index 0000000000..7f5d643a2f --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/ReceiveEventIT.java @@ -0,0 +1,71 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.integration; + +import org.citrusframework.annotations.CitrusTest; +import org.citrusframework.http.endpoint.builder.HttpEndpoints; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.spi.BindToRegistry; +import org.citrusframework.util.SocketUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; + +import static org.citrusframework.knative.actions.KnativeActionBuilder.knative; + +public class ReceiveEventIT extends AbstractKnativeIT { + + private final int port = SocketUtils.findAvailableTcpPort(8081); + + @BindToRegistry + public HttpServer knativeBroker = HttpEndpoints.http() + .server() + .port(port) + .defaultStatus(HttpStatus.ACCEPTED) + .autoStart(true) + .build(); + + @AfterClass(alwaysRun = true) + public void shutdown() { + knativeBroker.stop(); + } + + @Test + @CitrusTest + public void shouldReceiveEvents() { + given(knative() + .event() + .send() + .fork(true) + .brokerUrl("http://localhost:%d".formatted(port)) + .eventData("Hello Knative broker")); + + then( + knative() + .event() + .receive() + .server(knativeBroker) + .eventData("Hello Knative broker") + .attribute("ce-id", "@notNull()@") + .attribute("ce-type", "org.citrusframework.event.test") + .attribute("ce-source", "citrus-test") + .attribute("Content-Type", MediaType.APPLICATION_JSON_UTF8_VALUE) + ); + } + +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/SendEventIT.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/SendEventIT.java new file mode 100644 index 0000000000..6c7a0134e4 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/SendEventIT.java @@ -0,0 +1,78 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.integration; + +import org.citrusframework.annotations.CitrusTest; +import org.citrusframework.http.endpoint.builder.HttpEndpoints; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.spi.BindToRegistry; +import org.citrusframework.util.SocketUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; + +import static org.citrusframework.http.actions.HttpActionBuilder.http; +import static org.citrusframework.knative.actions.KnativeActionBuilder.knative; + +public class SendEventIT extends AbstractKnativeIT { + + private final int port = SocketUtils.findAvailableTcpPort(8081); + + @BindToRegistry + public HttpServer knativeBroker = HttpEndpoints.http() + .server() + .port(port) + .defaultStatus(HttpStatus.ACCEPTED) + .autoStart(true) + .build(); + + @AfterClass(alwaysRun = true) + public void shutdown() { + knativeBroker.stop(); + } + + @Test + @CitrusTest + public void shouldSendEvents() { + when(knative() + .event() + .send() + .fork(true) + .brokerUrl("http://localhost:%d".formatted(port)) + .eventData("Hello Knative broker")); + + then( + http().server(knativeBroker) + .receive() + .post() + .message() + .body("Hello Knative broker") + .header("ce-id", "@notNull()@") + .header("ce-type", "org.citrusframework.event.test") + .header("ce-source", "citrus-test") + .header("Content-Type", MediaType.APPLICATION_JSON_UTF8_VALUE) + ); + + then( + http().server(knativeBroker) + .send() + .response(HttpStatus.ACCEPTED) + ); + } + +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/VerifyKnativeBrokerIT.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/VerifyKnativeBrokerIT.java new file mode 100644 index 0000000000..660fbe98ba --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/integration/VerifyKnativeBrokerIT.java @@ -0,0 +1,110 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.integration; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.knative.eventing.v1.Broker; +import io.fabric8.knative.eventing.v1.BrokerBuilder; +import io.fabric8.knative.internal.pkg.apis.ConditionBuilder; +import org.citrusframework.annotations.CitrusTest; +import org.citrusframework.exceptions.ValidationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.testng.annotations.Test; + +import static org.citrusframework.container.Assert.Builder.assertException; +import static org.citrusframework.container.FinallySequence.Builder.doFinally; +import static org.citrusframework.knative.actions.KnativeActionBuilder.knative; + +public class VerifyKnativeBrokerIT extends AbstractKnativeIT { + + @Autowired + private KnativeClient knativeClient; + + private final String namespace = "test"; + + @Test + @CitrusTest + public void shouldVerifyBroker() { + given(doFinally().actions(context -> knativeClient.brokers() + .inNamespace(namespace) + .withName("my-broker") + .delete())); + + given(context -> { + Broker broker = new BrokerBuilder() + .withNewMetadata() + .withName("my-broker") + .withNamespace(namespace) + .endMetadata() + .withNewStatus() + .withConditions(new ConditionBuilder() + .withType("Ready") + .withStatus("true") + .build()) + .endStatus() + .build(); + + knativeClient.brokers() + .inNamespace(namespace) + .resource(broker) + .create(); + }); + + then(knative() + .client(knativeClient) + .brokers() + .verify("my-broker") + .inNamespace(namespace)); + } + + @Test + @CitrusTest + public void shouldVerifyBrokerReadyState() { + given(doFinally().actions(context -> knativeClient.brokers() + .inNamespace(namespace) + .withName("my-broker") + .delete())); + + given(context -> { + Broker broker = new BrokerBuilder() + .withNewMetadata() + .withName("my-broker") + .withNamespace(namespace) + .endMetadata() + .withNewStatus() + .withConditions(new ConditionBuilder() + .withType("Ready") + .withStatus("false") + .build()) + .endStatus() + .build(); + + knativeClient.brokers() + .inNamespace(namespace) + .resource(broker) + .create(); + }); + + then(assertException().exception(ValidationException.class) + .when(knative() + .client(knativeClient) + .brokers() + .verify("my-broker") + .inNamespace(namespace))); + } + +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/AbstractXmlActionTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/AbstractXmlActionTest.java new file mode 100644 index 0000000000..5ed4dd191a --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/AbstractXmlActionTest.java @@ -0,0 +1,105 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import java.util.HashMap; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.server.mock.KubernetesCrudDispatcher; +import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; +import io.fabric8.mockwebserver.Context; +import okhttp3.mockwebserver.MockWebServer; +import org.citrusframework.Citrus; +import org.citrusframework.CitrusContext; +import org.citrusframework.CitrusInstanceManager; +import org.citrusframework.DefaultTestCaseRunner; +import org.citrusframework.annotations.CitrusAnnotations; +import org.citrusframework.context.StaticTestContextFactory; +import org.citrusframework.context.TestContext; +import org.citrusframework.testng.AbstractTestNGUnitTest; +import org.citrusframework.xml.XmlTestLoader; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; + +public class AbstractXmlActionTest extends AbstractTestNGUnitTest { + + protected Citrus citrus; + + @Mock + protected CitrusContext citrusContext; + + private final KubernetesMockServer k8sServer = new KubernetesMockServer(new Context(), new MockWebServer(), + new HashMap<>(), new KubernetesCrudDispatcher(), false); + + protected KubernetesClient k8sClient; + + protected KnativeClient knativeClient; + + @BeforeClass + public void setupMocks() { + MockitoAnnotations.openMocks(this); + citrus = CitrusInstanceManager.newInstance(() -> citrusContext); + + k8sServer.init(); + k8sClient = k8sServer.createClient(); + knativeClient = k8sClient.adapt(KnativeClient.class); + } + + @AfterClass(alwaysRun = true) + public void stop() { + k8sServer.destroy(); + } + + @Override + protected TestContext createTestContext() { + TestContext context = super.createTestContext(); + when(citrusContext.getReferenceResolver()).thenReturn(context.getReferenceResolver()); + when(citrusContext.getMessageValidatorRegistry()).thenReturn(context.getMessageValidatorRegistry()); + when(citrusContext.getTestContextFactory()).thenReturn(new StaticTestContextFactory(context)); + doAnswer(invocationOnMock -> { + CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); + return null; + }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); + CitrusAnnotations.injectAll(this, citrus, context); + + context.getReferenceResolver().bind("k8sClient", k8sClient); + context.getReferenceResolver().bind("knativeClient", knativeClient); + + return context; + } + + protected XmlTestLoader createTestLoader(String sourcePath) { + XmlTestLoader testLoader = new XmlTestLoader(this.getClass(), "Test", this.getClass().getPackageName()); + CitrusAnnotations.injectAll(testLoader, citrus, context); + CitrusAnnotations.injectTestRunner(testLoader, new DefaultTestCaseRunner(context)); + testLoader.setSource(sourcePath); + + return testLoader; + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/CreateBrokerTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/CreateBrokerTest.java new file mode 100644 index 0000000000..33bbe4b873 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/CreateBrokerTest.java @@ -0,0 +1,48 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.eventing.v1.Broker; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.eventing.CreateBrokerAction; +import org.citrusframework.xml.XmlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class CreateBrokerTest extends AbstractXmlActionTest { + + @Test + public void shouldLoadKnativeActions() { + XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/xml/create-broker-test.xml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "CreateBrokerTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), CreateBrokerAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + String namespace = "test"; + Broker broker = knativeClient.brokers().inNamespace(namespace).withName("my-broker").get(); + Assert.assertNotNull(broker); + Assert.assertEquals(broker.getMetadata().getLabels().size(), 1); + Assert.assertEquals(broker.getMetadata().getLabels().get("app"), "citrus"); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/CreateChannelTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/CreateChannelTest.java new file mode 100644 index 0000000000..a3fbdb4f00 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/CreateChannelTest.java @@ -0,0 +1,48 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.messaging.v1.Channel; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.messaging.CreateChannelAction; +import org.citrusframework.xml.XmlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class CreateChannelTest extends AbstractXmlActionTest { + + @Test + public void shouldLoadKnativeActions() { + XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/xml/create-channel-test.xml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "CreateChannelTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), CreateChannelAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + String namespace = "test"; + Channel channel = knativeClient.channels().inNamespace(namespace).withName("my-channel").get(); + Assert.assertNotNull(channel); + Assert.assertEquals(channel.getMetadata().getLabels().size(), 1); + Assert.assertEquals(channel.getMetadata().getLabels().get("app"), "citrus"); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/CreateSubscriptionTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/CreateSubscriptionTest.java new file mode 100644 index 0000000000..5b7dfd1216 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/CreateSubscriptionTest.java @@ -0,0 +1,51 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.messaging.v1.Subscription; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.messaging.CreateSubscriptionAction; +import org.citrusframework.xml.XmlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class CreateSubscriptionTest extends AbstractXmlActionTest { + + @Test + public void shouldLoadKnativeActions() { + XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/xml/create-subscription-test.xml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "CreateSubscriptionTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), CreateSubscriptionAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + String namespace = "test"; + Subscription subscription = knativeClient.subscriptions().inNamespace(namespace).withName("my-subscription").get(); + Assert.assertNotNull(subscription); + Assert.assertEquals(subscription.getMetadata().getLabels().size(), 1); + Assert.assertEquals(subscription.getMetadata().getLabels().get("app"), "citrus"); + Assert.assertEquals(subscription.getSpec().getChannel().getName(), "my-channel"); + Assert.assertEquals(subscription.getSpec().getChannel().getKind(), "InMemoryChannel"); + Assert.assertEquals(subscription.getSpec().getSubscriber().getRef().getName(), "my-service"); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/CreateTriggerTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/CreateTriggerTest.java new file mode 100644 index 0000000000..0b29d7e028 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/CreateTriggerTest.java @@ -0,0 +1,61 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.eventing.v1.Trigger; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.eventing.CreateTriggerAction; +import org.citrusframework.xml.XmlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class CreateTriggerTest extends AbstractXmlActionTest { + + @Test + public void shouldLoadKnativeActions() { + XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/xml/create-trigger-test.xml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "CreateTriggerTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 2L); + Assert.assertEquals(result.getTestAction(0).getClass(), CreateTriggerAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + String namespace = "test"; + Trigger trigger = knativeClient.triggers().inNamespace(namespace).withName("my-trigger-1").get(); + Assert.assertNotNull(trigger); + Assert.assertEquals(trigger.getMetadata().getLabels().size(), 1); + Assert.assertEquals(trigger.getMetadata().getLabels().get("app"), "citrus"); + Assert.assertEquals(trigger.getSpec().getBroker(), "my-broker"); + Assert.assertEquals(trigger.getSpec().getSubscriber().getRef().getKind(), "Service"); + Assert.assertEquals(trigger.getSpec().getSubscriber().getRef().getName(), "my-service"); + + trigger = knativeClient.triggers().inNamespace(namespace).withName("my-trigger-2").get(); + Assert.assertNotNull(trigger); + Assert.assertEquals(trigger.getMetadata().getLabels().size(), 1); + Assert.assertEquals(trigger.getMetadata().getLabels().get("app"), "citrus"); + Assert.assertEquals(trigger.getSpec().getBroker(), "my-broker"); + Assert.assertEquals(trigger.getSpec().getSubscriber().getRef().getKind(), "Service"); + Assert.assertEquals(trigger.getSpec().getSubscriber().getRef().getName(), "my-service"); + Assert.assertEquals(trigger.getSpec().getFilter().getAttributes().size(), 1L); + Assert.assertEquals(trigger.getSpec().getFilter().getAttributes().get("foo"), "bar"); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteBrokerTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteBrokerTest.java new file mode 100644 index 0000000000..e5212c0f16 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteBrokerTest.java @@ -0,0 +1,59 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.eventing.v1.Broker; +import io.fabric8.knative.eventing.v1.BrokerBuilder; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.eventing.DeleteBrokerAction; +import org.citrusframework.xml.XmlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class DeleteBrokerTest extends AbstractXmlActionTest { + + @Test + public void shouldLoadKnativeActions() { + String namespace = "test"; + Broker broker = new BrokerBuilder() + .withNewMetadata() + .withName("my-broker") + .withNamespace(namespace) + .endMetadata() + .build(); + + knativeClient.brokers() + .inNamespace(namespace) + .resource(broker) + .create(); + + XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/xml/delete-broker-test.xml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "DeleteBrokerTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), DeleteBrokerAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + broker = knativeClient.brokers().inNamespace(namespace).withName("my-broker").get(); + Assert.assertNull(broker); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteChannelTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteChannelTest.java new file mode 100644 index 0000000000..0257ef420b --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteChannelTest.java @@ -0,0 +1,59 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.messaging.v1.InMemoryChannel; +import io.fabric8.knative.messaging.v1.InMemoryChannelBuilder; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.DeleteKnativeResourceAction; +import org.citrusframework.xml.XmlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class DeleteChannelTest extends AbstractXmlActionTest { + + @Test + public void shouldLoadKnativeActions() { + String namespace = "test"; + InMemoryChannel channel = new InMemoryChannelBuilder() + .withNewMetadata() + .withName("my-channel") + .withNamespace(namespace) + .endMetadata() + .build(); + + knativeClient.inMemoryChannels() + .inNamespace(namespace) + .resource(channel) + .create(); + + XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/xml/delete-channel-test.xml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "DeleteChannelTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), DeleteKnativeResourceAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + channel = knativeClient.inMemoryChannels().inNamespace(namespace).withName("my-channel").get(); + Assert.assertNull(channel); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteResourceTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteResourceTest.java new file mode 100644 index 0000000000..94a24b7c64 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteResourceTest.java @@ -0,0 +1,75 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.internal.pkg.apis.duck.v1.DestinationBuilder; +import io.fabric8.knative.internal.pkg.apis.duck.v1.KReferenceBuilder; +import io.fabric8.knative.messaging.v1.Subscription; +import io.fabric8.knative.messaging.v1.SubscriptionBuilder; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.DeleteKnativeResourceAction; +import org.citrusframework.xml.XmlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class DeleteResourceTest extends AbstractXmlActionTest { + + @Test + public void shouldLoadKnativeActions() { + String namespace = "test"; + Subscription subscription = new SubscriptionBuilder() + .withNewMetadata() + .withName("my-subscription") + .withNamespace(namespace) + .endMetadata() + .withNewSpec() + .withChannel(new KReferenceBuilder() + .withApiVersion("messaging/v1") + .withKind("InMemoryChannel") + .withName("my-channel") + .build()) + .withSubscriber(new DestinationBuilder() + .withNewRef() + .withApiVersion("v1") + .withKind("Service") + .withName("my-service") + .endRef() + .build()) + .endSpec() + .build(); + + knativeClient.subscriptions() + .inNamespace(namespace) + .resource(subscription) + .create(); + + XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/xml/delete-resource-test.xml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "DeleteResourceTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), DeleteKnativeResourceAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + subscription = knativeClient.subscriptions().inNamespace(namespace).withName("my-subscription").get(); + Assert.assertNull(subscription); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteSubscriptionTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteSubscriptionTest.java new file mode 100644 index 0000000000..99d860d12f --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteSubscriptionTest.java @@ -0,0 +1,75 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.internal.pkg.apis.duck.v1.DestinationBuilder; +import io.fabric8.knative.internal.pkg.apis.duck.v1.KReferenceBuilder; +import io.fabric8.knative.messaging.v1.Subscription; +import io.fabric8.knative.messaging.v1.SubscriptionBuilder; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.DeleteKnativeResourceAction; +import org.citrusframework.xml.XmlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class DeleteSubscriptionTest extends AbstractXmlActionTest { + + @Test + public void shouldLoadKnativeActions() { + String namespace = "test"; + Subscription subscription = new SubscriptionBuilder() + .withNewMetadata() + .withName("my-subscription") + .withNamespace(namespace) + .endMetadata() + .withNewSpec() + .withChannel(new KReferenceBuilder() + .withApiVersion("messaging/v1") + .withKind("InMemoryChannel") + .withName("my-channel") + .build()) + .withSubscriber(new DestinationBuilder() + .withNewRef() + .withApiVersion("v1") + .withKind("Service") + .withName("my-service") + .endRef() + .build()) + .endSpec() + .build(); + + knativeClient.subscriptions() + .inNamespace(namespace) + .resource(subscription) + .create(); + + XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/xml/delete-subscription-test.xml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "DeleteSubscriptionTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), DeleteKnativeResourceAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + subscription = knativeClient.subscriptions().inNamespace(namespace).withName("my-subscription").get(); + Assert.assertNull(subscription); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteTriggerTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteTriggerTest.java new file mode 100644 index 0000000000..151e858ae1 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/DeleteTriggerTest.java @@ -0,0 +1,59 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.eventing.v1.Trigger; +import io.fabric8.knative.eventing.v1.TriggerBuilder; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.eventing.DeleteTriggerAction; +import org.citrusframework.xml.XmlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class DeleteTriggerTest extends AbstractXmlActionTest { + + @Test + public void shouldLoadKnativeActions() { + String namespace = "test"; + Trigger trigger = new TriggerBuilder() + .withNewMetadata() + .withName("my-trigger") + .withNamespace(namespace) + .endMetadata() + .build(); + + knativeClient.triggers() + .inNamespace(namespace) + .resource(trigger) + .create(); + + XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/xml/delete-trigger-test.xml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "DeleteTriggerTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), DeleteTriggerAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + trigger = knativeClient.triggers().inNamespace(namespace).withName("my-trigger").get(); + Assert.assertNull(trigger); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/KnativeTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/KnativeTest.java new file mode 100644 index 0000000000..b750ba4006 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/KnativeTest.java @@ -0,0 +1,30 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import org.citrusframework.xml.actions.XmlTestActionBuilder; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class KnativeTest { + + @Test + public void shouldLookupTestActionBuilder() { + Assert.assertTrue(XmlTestActionBuilder.lookup("knative").isPresent()); + Assert.assertEquals(XmlTestActionBuilder.lookup("knative").get().getClass(), Knative.class); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/SendReceiveEventTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/SendReceiveEventTest.java new file mode 100644 index 0000000000..4a14462619 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/SendReceiveEventTest.java @@ -0,0 +1,84 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.annotations.CitrusAnnotations; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.http.client.HttpClientBuilder; +import org.citrusframework.http.endpoint.builder.HttpEndpoints; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.knative.actions.eventing.ReceiveEventAction; +import org.citrusframework.knative.actions.eventing.SendEventAction; +import org.citrusframework.spi.BindToRegistry; +import org.citrusframework.util.SocketUtils; +import org.citrusframework.xml.XmlTestLoader; +import org.springframework.http.HttpStatus; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class SendReceiveEventTest extends AbstractXmlActionTest { + + private final int port = SocketUtils.findAvailableTcpPort(8081); + + @BindToRegistry + private final HttpClient knativeClient = new HttpClientBuilder() + .requestUrl("http://localhost:%d".formatted(port)) + .build(); + + @BindToRegistry + public HttpServer knativeBroker = HttpEndpoints.http() + .server() + .port(port) + .timeout(100) + .defaultStatus(HttpStatus.ACCEPTED) + .autoStart(true) + .build(); + + @BeforeClass + @Override + public void setupMocks() { + super.setupMocks(); + CitrusAnnotations.injectAll(this); + } + + @AfterClass(alwaysRun = true) + public void shutdown() { + knativeBroker.stop(); + } + + @Test + public void shouldLoadKnativeActions() { + context.getReferenceResolver().bind("my-broker", knativeClient); + context.getReferenceResolver().bind("my-service", knativeBroker); + + XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/xml/send-receive-event-test.xml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "SendReceiveEventTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 2L); + Assert.assertEquals(result.getTestAction(0).getClass(), SendEventAction.class); + Assert.assertEquals(result.getTestAction(1).getClass(), ReceiveEventAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/VerifyBrokerTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/VerifyBrokerTest.java new file mode 100644 index 0000000000..c4a9bba024 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/xml/VerifyBrokerTest.java @@ -0,0 +1,63 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.xml; + +import io.fabric8.knative.eventing.v1.Broker; +import io.fabric8.knative.eventing.v1.BrokerBuilder; +import io.fabric8.knative.internal.pkg.apis.ConditionBuilder; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.eventing.VerifyBrokerAction; +import org.citrusframework.xml.XmlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class VerifyBrokerTest extends AbstractXmlActionTest { + + @Test + public void shouldLoadKnativeActions() { + String namespace = "test"; + Broker broker = new BrokerBuilder() + .withNewMetadata() + .withName("my-broker") + .withNamespace(namespace) + .endMetadata() + .withNewStatus() + .withConditions(new ConditionBuilder() + .withType("Ready") + .withStatus("true") + .build()) + .endStatus() + .build(); + + knativeClient.brokers() + .inNamespace(namespace) + .resource(broker) + .create(); + + XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/xml/verify-broker-test.xml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "VerifyBrokerTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), VerifyBrokerAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/AbstractYamlActionTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/AbstractYamlActionTest.java new file mode 100644 index 0000000000..ab36315b5b --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/AbstractYamlActionTest.java @@ -0,0 +1,118 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import java.util.HashMap; + +import io.fabric8.knative.client.KnativeClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.server.mock.KubernetesCrudDispatcher; +import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; +import io.fabric8.mockwebserver.Context; +import okhttp3.mockwebserver.MockWebServer; +import org.citrusframework.Citrus; +import org.citrusframework.CitrusContext; +import org.citrusframework.CitrusInstanceManager; +import org.citrusframework.DefaultTestCaseRunner; +import org.citrusframework.TestAction; +import org.citrusframework.TestActionBuilder; +import org.citrusframework.annotations.CitrusAnnotations; +import org.citrusframework.context.StaticTestContextFactory; +import org.citrusframework.context.TestContext; +import org.citrusframework.testng.AbstractTestNGUnitTest; +import org.citrusframework.yaml.YamlTestLoader; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; + +public class AbstractYamlActionTest extends AbstractTestNGUnitTest { + + protected Citrus citrus; + + @Mock + protected CitrusContext citrusContext; + + private final KubernetesMockServer k8sServer = new KubernetesMockServer(new Context(), new MockWebServer(), + new HashMap<>(), new KubernetesCrudDispatcher(), false); + + protected KubernetesClient k8sClient; + + protected KnativeClient knativeClient; + + @BeforeClass + public void setupMocks() { + MockitoAnnotations.openMocks(this); + citrus = CitrusInstanceManager.newInstance(() -> citrusContext); + + k8sServer.init(); + k8sClient = k8sServer.createClient(); + knativeClient = k8sClient.adapt(KnativeClient.class); + } + + @AfterClass(alwaysRun = true) + public void stop() { + k8sServer.destroy(); + } + + @Override + protected TestContext createTestContext() { + TestContext context = super.createTestContext(); + when(citrusContext.getReferenceResolver()).thenReturn(context.getReferenceResolver()); + when(citrusContext.getMessageValidatorRegistry()).thenReturn(context.getMessageValidatorRegistry()); + when(citrusContext.getTestContextFactory()).thenReturn(new StaticTestContextFactory(context)); + doAnswer(invocationOnMock -> { + CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); + return null; + }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); + CitrusAnnotations.injectAll(this, citrus, context); + + context.getReferenceResolver().bind("k8sClient", k8sClient); + context.getReferenceResolver().bind("knativeClient", knativeClient); + + return context; + } + + protected YamlTestLoader createTestLoader(String sourcePath) { + YamlTestLoader testLoader = new YamlTestLoader(this.getClass(), "Test", this.getClass().getPackageName()); + CitrusAnnotations.injectAll(testLoader, citrus, context); + CitrusAnnotations.injectTestRunner(testLoader, new NoopTestCaseRunner(context)); + testLoader.setSource(sourcePath); + + return testLoader; + } + + protected static class NoopTestCaseRunner extends DefaultTestCaseRunner { + public NoopTestCaseRunner(TestContext context) { + super(context); + } + + @Override + public T run(TestActionBuilder builder) { + return builder.build(); + } + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/CreateBrokerTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/CreateBrokerTest.java new file mode 100644 index 0000000000..97c8f2f351 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/CreateBrokerTest.java @@ -0,0 +1,48 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.eventing.v1.Broker; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.eventing.CreateBrokerAction; +import org.citrusframework.yaml.YamlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class CreateBrokerTest extends AbstractYamlActionTest { + + @Test + public void shouldLoadKnativeActions() { + YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/yaml/create-broker-test.yaml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "CreateBrokerTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), CreateBrokerAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + String namespace = "test"; + Broker broker = knativeClient.brokers().inNamespace(namespace).withName("my-broker").get(); + Assert.assertNotNull(broker); + Assert.assertEquals(broker.getMetadata().getLabels().size(), 1); + Assert.assertEquals(broker.getMetadata().getLabels().get("app"), "citrus"); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/CreateChannelTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/CreateChannelTest.java new file mode 100644 index 0000000000..7d30c84d62 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/CreateChannelTest.java @@ -0,0 +1,48 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.messaging.v1.Channel; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.messaging.CreateChannelAction; +import org.citrusframework.yaml.YamlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class CreateChannelTest extends AbstractYamlActionTest { + + @Test + public void shouldLoadKnativeActions() { + YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/yaml/create-channel-test.yaml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "CreateChannelTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), CreateChannelAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + String namespace = "test"; + Channel channel = knativeClient.channels().inNamespace(namespace).withName("my-channel").get(); + Assert.assertNotNull(channel); + Assert.assertEquals(channel.getMetadata().getLabels().size(), 1); + Assert.assertEquals(channel.getMetadata().getLabels().get("app"), "citrus"); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/CreateSubscriptionTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/CreateSubscriptionTest.java new file mode 100644 index 0000000000..cacd360a36 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/CreateSubscriptionTest.java @@ -0,0 +1,51 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.messaging.v1.Subscription; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.messaging.CreateSubscriptionAction; +import org.citrusframework.yaml.YamlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class CreateSubscriptionTest extends AbstractYamlActionTest { + + @Test + public void shouldLoadKnativeActions() { + YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/yaml/create-subscription-test.yaml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "CreateSubscriptionTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), CreateSubscriptionAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + String namespace = "test"; + Subscription subscription = knativeClient.subscriptions().inNamespace(namespace).withName("my-subscription").get(); + Assert.assertNotNull(subscription); + Assert.assertEquals(subscription.getMetadata().getLabels().size(), 1); + Assert.assertEquals(subscription.getMetadata().getLabels().get("app"), "citrus"); + Assert.assertEquals(subscription.getSpec().getChannel().getName(), "my-channel"); + Assert.assertEquals(subscription.getSpec().getChannel().getKind(), "InMemoryChannel"); + Assert.assertEquals(subscription.getSpec().getSubscriber().getRef().getName(), "my-service"); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/CreateTriggerTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/CreateTriggerTest.java new file mode 100644 index 0000000000..1ed3701568 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/CreateTriggerTest.java @@ -0,0 +1,61 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.eventing.v1.Trigger; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.eventing.CreateTriggerAction; +import org.citrusframework.yaml.YamlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class CreateTriggerTest extends AbstractYamlActionTest { + + @Test + public void shouldLoadKnativeActions() { + YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/yaml/create-trigger-test.yaml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "CreateTriggerTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 2L); + Assert.assertEquals(result.getTestAction(0).getClass(), CreateTriggerAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + String namespace = "test"; + Trigger trigger = knativeClient.triggers().inNamespace(namespace).withName("my-trigger-1").get(); + Assert.assertNotNull(trigger); + Assert.assertEquals(trigger.getMetadata().getLabels().size(), 1); + Assert.assertEquals(trigger.getMetadata().getLabels().get("app"), "citrus"); + Assert.assertEquals(trigger.getSpec().getBroker(), "my-broker"); + Assert.assertEquals(trigger.getSpec().getSubscriber().getRef().getKind(), "Service"); + Assert.assertEquals(trigger.getSpec().getSubscriber().getRef().getName(), "my-service"); + + trigger = knativeClient.triggers().inNamespace(namespace).withName("my-trigger-2").get(); + Assert.assertNotNull(trigger); + Assert.assertEquals(trigger.getMetadata().getLabels().size(), 1); + Assert.assertEquals(trigger.getMetadata().getLabels().get("app"), "citrus"); + Assert.assertEquals(trigger.getSpec().getBroker(), "my-broker"); + Assert.assertEquals(trigger.getSpec().getSubscriber().getRef().getKind(), "Service"); + Assert.assertEquals(trigger.getSpec().getSubscriber().getRef().getName(), "my-service"); + Assert.assertEquals(trigger.getSpec().getFilter().getAttributes().size(), 1L); + Assert.assertEquals(trigger.getSpec().getFilter().getAttributes().get("foo"), "bar"); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteBrokerTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteBrokerTest.java new file mode 100644 index 0000000000..90c0a5bc5f --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteBrokerTest.java @@ -0,0 +1,59 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.eventing.v1.Broker; +import io.fabric8.knative.eventing.v1.BrokerBuilder; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.eventing.DeleteBrokerAction; +import org.citrusframework.yaml.YamlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class DeleteBrokerTest extends AbstractYamlActionTest { + + @Test + public void shouldLoadKnativeActions() { + String namespace = "test"; + Broker broker = new BrokerBuilder() + .withNewMetadata() + .withName("my-broker") + .withNamespace(namespace) + .endMetadata() + .build(); + + knativeClient.brokers() + .inNamespace(namespace) + .resource(broker) + .create(); + + YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/yaml/delete-broker-test.yaml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "DeleteBrokerTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), DeleteBrokerAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + broker = knativeClient.brokers().inNamespace(namespace).withName("my-broker").get(); + Assert.assertNull(broker); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteChannelTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteChannelTest.java new file mode 100644 index 0000000000..2dad07a719 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteChannelTest.java @@ -0,0 +1,59 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.messaging.v1.InMemoryChannel; +import io.fabric8.knative.messaging.v1.InMemoryChannelBuilder; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.DeleteKnativeResourceAction; +import org.citrusframework.yaml.YamlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class DeleteChannelTest extends AbstractYamlActionTest { + + @Test + public void shouldLoadKnativeActions() { + String namespace = "test"; + InMemoryChannel channel = new InMemoryChannelBuilder() + .withNewMetadata() + .withName("my-channel") + .withNamespace(namespace) + .endMetadata() + .build(); + + knativeClient.inMemoryChannels() + .inNamespace(namespace) + .resource(channel) + .create(); + + YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/yaml/delete-channel-test.yaml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "DeleteChannelTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), DeleteKnativeResourceAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + channel = knativeClient.inMemoryChannels().inNamespace(namespace).withName("my-channel").get(); + Assert.assertNull(channel); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteResourceTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteResourceTest.java new file mode 100644 index 0000000000..eecb2f67fb --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteResourceTest.java @@ -0,0 +1,75 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.internal.pkg.apis.duck.v1.DestinationBuilder; +import io.fabric8.knative.internal.pkg.apis.duck.v1.KReferenceBuilder; +import io.fabric8.knative.messaging.v1.Subscription; +import io.fabric8.knative.messaging.v1.SubscriptionBuilder; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.DeleteKnativeResourceAction; +import org.citrusframework.yaml.YamlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class DeleteResourceTest extends AbstractYamlActionTest { + + @Test + public void shouldLoadKnativeActions() { + String namespace = "test"; + Subscription subscription = new SubscriptionBuilder() + .withNewMetadata() + .withName("my-subscription") + .withNamespace(namespace) + .endMetadata() + .withNewSpec() + .withChannel(new KReferenceBuilder() + .withApiVersion("messaging/v1") + .withKind("InMemoryChannel") + .withName("my-channel") + .build()) + .withSubscriber(new DestinationBuilder() + .withNewRef() + .withApiVersion("v1") + .withKind("Service") + .withName("my-service") + .endRef() + .build()) + .endSpec() + .build(); + + knativeClient.subscriptions() + .inNamespace(namespace) + .resource(subscription) + .create(); + + YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/yaml/delete-resource-test.yaml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "DeleteResourceTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), DeleteKnativeResourceAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + subscription = knativeClient.subscriptions().inNamespace(namespace).withName("my-subscription").get(); + Assert.assertNull(subscription); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteSubscriptionTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteSubscriptionTest.java new file mode 100644 index 0000000000..d3377b1089 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteSubscriptionTest.java @@ -0,0 +1,75 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.internal.pkg.apis.duck.v1.DestinationBuilder; +import io.fabric8.knative.internal.pkg.apis.duck.v1.KReferenceBuilder; +import io.fabric8.knative.messaging.v1.Subscription; +import io.fabric8.knative.messaging.v1.SubscriptionBuilder; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.DeleteKnativeResourceAction; +import org.citrusframework.yaml.YamlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class DeleteSubscriptionTest extends AbstractYamlActionTest { + + @Test + public void shouldLoadKnativeActions() { + String namespace = "test"; + Subscription subscription = new SubscriptionBuilder() + .withNewMetadata() + .withName("my-subscription") + .withNamespace(namespace) + .endMetadata() + .withNewSpec() + .withChannel(new KReferenceBuilder() + .withApiVersion("messaging/v1") + .withKind("InMemoryChannel") + .withName("my-channel") + .build()) + .withSubscriber(new DestinationBuilder() + .withNewRef() + .withApiVersion("v1") + .withKind("Service") + .withName("my-service") + .endRef() + .build()) + .endSpec() + .build(); + + knativeClient.subscriptions() + .inNamespace(namespace) + .resource(subscription) + .create(); + + YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/yaml/delete-subscription-test.yaml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "DeleteSubscriptionTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), DeleteKnativeResourceAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + subscription = knativeClient.subscriptions().inNamespace(namespace).withName("my-subscription").get(); + Assert.assertNull(subscription); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteTriggerTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteTriggerTest.java new file mode 100644 index 0000000000..b85cdab275 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/DeleteTriggerTest.java @@ -0,0 +1,59 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.eventing.v1.Trigger; +import io.fabric8.knative.eventing.v1.TriggerBuilder; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.eventing.DeleteTriggerAction; +import org.citrusframework.yaml.YamlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class DeleteTriggerTest extends AbstractYamlActionTest { + + @Test + public void shouldLoadKnativeActions() { + String namespace = "test"; + Trigger trigger = new TriggerBuilder() + .withNewMetadata() + .withName("my-trigger") + .withNamespace(namespace) + .endMetadata() + .build(); + + knativeClient.triggers() + .inNamespace(namespace) + .resource(trigger) + .create(); + + YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/yaml/delete-trigger-test.yaml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "DeleteTriggerTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), DeleteTriggerAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + + trigger = knativeClient.triggers().inNamespace(namespace).withName("my-trigger").get(); + Assert.assertNull(trigger); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/KnativeTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/KnativeTest.java new file mode 100644 index 0000000000..d7409701ec --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/KnativeTest.java @@ -0,0 +1,30 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import org.citrusframework.yaml.actions.YamlTestActionBuilder; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class KnativeTest { + + @Test + public void shouldLookupTestActionBuilder() { + Assert.assertTrue(YamlTestActionBuilder.lookup("knative").isPresent()); + Assert.assertEquals(YamlTestActionBuilder.lookup("knative").get().getClass(), Knative.class); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/SendReceiveEventTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/SendReceiveEventTest.java new file mode 100644 index 0000000000..b70cae1308 --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/SendReceiveEventTest.java @@ -0,0 +1,84 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.annotations.CitrusAnnotations; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.http.client.HttpClientBuilder; +import org.citrusframework.http.endpoint.builder.HttpEndpoints; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.knative.actions.eventing.ReceiveEventAction; +import org.citrusframework.knative.actions.eventing.SendEventAction; +import org.citrusframework.spi.BindToRegistry; +import org.citrusframework.util.SocketUtils; +import org.citrusframework.yaml.YamlTestLoader; +import org.springframework.http.HttpStatus; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class SendReceiveEventTest extends AbstractYamlActionTest { + + private final int port = SocketUtils.findAvailableTcpPort(8081); + + @BindToRegistry + private final HttpClient knativeClient = new HttpClientBuilder() + .requestUrl("http://localhost:%d".formatted(port)) + .build(); + + @BindToRegistry + public HttpServer knativeBroker = HttpEndpoints.http() + .server() + .port(port) + .timeout(100) + .defaultStatus(HttpStatus.ACCEPTED) + .autoStart(true) + .build(); + + @BeforeClass + @Override + public void setupMocks() { + super.setupMocks(); + CitrusAnnotations.injectAll(this); + } + + @AfterClass(alwaysRun = true) + public void shutdown() { + knativeBroker.stop(); + } + + @Test + public void shouldLoadKnativeActions() { + context.getReferenceResolver().bind("my-broker", knativeClient); + context.getReferenceResolver().bind("my-service", knativeBroker); + + YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/yaml/send-receive-event-test.yaml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "SendReceiveEventTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 2L); + Assert.assertEquals(result.getTestAction(0).getClass(), SendEventAction.class); + Assert.assertEquals(result.getTestAction(1).getClass(), ReceiveEventAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + } +} diff --git a/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/VerifyBrokerTest.java b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/VerifyBrokerTest.java new file mode 100644 index 0000000000..36b8b36f5f --- /dev/null +++ b/connectors/citrus-knative/src/test/java/org/citrusframework/knative/yaml/VerifyBrokerTest.java @@ -0,0 +1,63 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.knative.yaml; + +import io.fabric8.knative.eventing.v1.Broker; +import io.fabric8.knative.eventing.v1.BrokerBuilder; +import io.fabric8.knative.internal.pkg.apis.ConditionBuilder; +import org.citrusframework.TestCase; +import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.knative.actions.eventing.VerifyBrokerAction; +import org.citrusframework.yaml.YamlTestLoader; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class VerifyBrokerTest extends AbstractYamlActionTest { + + @Test + public void shouldLoadKnativeActions() { + String namespace = "test"; + Broker broker = new BrokerBuilder() + .withNewMetadata() + .withName("my-broker") + .withNamespace(namespace) + .endMetadata() + .withNewStatus() + .withConditions(new ConditionBuilder() + .withType("Ready") + .withStatus("true") + .build()) + .endStatus() + .build(); + + knativeClient.brokers() + .inNamespace(namespace) + .resource(broker) + .create(); + + YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/knative/yaml/verify-broker-test.yaml"); + + testLoader.load(); + TestCase result = testLoader.getTestCase(); + Assert.assertEquals(result.getName(), "VerifyBrokerTest"); + Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + Assert.assertEquals(result.getActionCount(), 1L); + Assert.assertEquals(result.getTestAction(0).getClass(), VerifyBrokerAction.class); + Assert.assertTrue(result.getTestResult().isSuccess()); + } +} diff --git a/connectors/citrus-knative/src/test/resources/citrus-context.xml b/connectors/citrus-knative/src/test/resources/citrus-context.xml new file mode 100644 index 0000000000..39d8914a89 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/citrus-context.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + diff --git a/connectors/citrus-knative/src/test/resources/citrus.properties b/connectors/citrus-knative/src/test/resources/citrus.properties new file mode 100644 index 0000000000..3ead21126c --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/citrus.properties @@ -0,0 +1 @@ +default.timeout=5000 diff --git a/connectors/citrus-knative/src/test/resources/log4j2-test.xml b/connectors/citrus-knative/src/test/resources/log4j2-test.xml new file mode 100644 index 0000000000..73d4fb3953 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/log4j2-test.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/context/citrus-unit-context.xml b/connectors/citrus-knative/src/test/resources/org/citrusframework/context/citrus-unit-context.xml new file mode 100644 index 0000000000..6ebc3ce93d --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/context/citrus-unit-context.xml @@ -0,0 +1,7 @@ + + + + diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/create-broker-test.xml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/create-broker-test.xml new file mode 100644 index 0000000000..a7a92ea2b3 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/create-broker-test.xml @@ -0,0 +1,26 @@ + + + + Sample test in XML + + + + + + diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/create-channel-test.xml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/create-channel-test.xml new file mode 100644 index 0000000000..56084d6828 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/create-channel-test.xml @@ -0,0 +1,26 @@ + + + + Sample test in XML + + + + + + diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/create-subscription-test.xml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/create-subscription-test.xml new file mode 100644 index 0000000000..393d421fd9 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/create-subscription-test.xml @@ -0,0 +1,26 @@ + + + + Sample test in XML + + + + + + diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/create-trigger-test.xml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/create-trigger-test.xml new file mode 100644 index 0000000000..21f00308f2 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/create-trigger-test.xml @@ -0,0 +1,34 @@ + + + + Sample test in XML + + + + + + + + + + + + + + diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-broker-test.xml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-broker-test.xml new file mode 100644 index 0000000000..24df6fdd05 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-broker-test.xml @@ -0,0 +1,26 @@ + + + + Sample test in XML + + + + + + diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-channel-test.xml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-channel-test.xml new file mode 100644 index 0000000000..4a633cce06 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-channel-test.xml @@ -0,0 +1,26 @@ + + + + Sample test in XML + + + + + + diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-resource-test.xml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-resource-test.xml new file mode 100644 index 0000000000..ad1f28d112 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-resource-test.xml @@ -0,0 +1,26 @@ + + + + Sample test in XML + + + + + + diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-subscription-test.xml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-subscription-test.xml new file mode 100644 index 0000000000..7f0d460793 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-subscription-test.xml @@ -0,0 +1,26 @@ + + + + Sample test in XML + + + + + + diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-trigger-test.xml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-trigger-test.xml new file mode 100644 index 0000000000..626347bb57 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/delete-trigger-test.xml @@ -0,0 +1,26 @@ + + + + Sample test in XML + + + + + + diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/send-receive-event-test.xml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/send-receive-event-test.xml new file mode 100644 index 0000000000..67001ab712 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/send-receive-event-test.xml @@ -0,0 +1,44 @@ + + + + Sample test in XML + + + + + + + + Hello Knative broker + + + + + + + + + + + Hello Knative broker + + + + + diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/verify-broker-test.xml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/verify-broker-test.xml new file mode 100644 index 0000000000..e5530b2257 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/xml/verify-broker-test.xml @@ -0,0 +1,26 @@ + + + + Sample test in XML + + + + + + diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/create-broker-test.yaml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/create-broker-test.yaml new file mode 100644 index 0000000000..e5503574ac --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/create-broker-test.yaml @@ -0,0 +1,10 @@ +name: "CreateBrokerTest" +author: "Christoph" +status: "FINAL" +description: Sample test in XML +actions: + - knative: + client: "knativeClient" + namespace: "test" + createBroker: + name: "my-broker" diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/create-channel-test.yaml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/create-channel-test.yaml new file mode 100644 index 0000000000..f135e7d18d --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/create-channel-test.yaml @@ -0,0 +1,10 @@ +name: "CreateChannelTest" +author: "Christoph" +status: "FINAL" +description: Sample test in XML +actions: + - knative: + client: "knativeClient" + namespace: "test" + createChannel: + name: "my-channel" diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/create-subscription-test.yaml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/create-subscription-test.yaml new file mode 100644 index 0000000000..3425306dde --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/create-subscription-test.yaml @@ -0,0 +1,12 @@ +name: "CreateSubscriptionTest" +author: "Christoph" +status: "FINAL" +description: Sample test in XML +actions: + - knative: + client: "knativeClient" + namespace: "test" + createSubscription: + name: "my-subscription" + channel: "my-channel" + service: "my-service" diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/create-trigger-test.yaml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/create-trigger-test.yaml new file mode 100644 index 0000000000..8c23f4119b --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/create-trigger-test.yaml @@ -0,0 +1,23 @@ +name: "CreateTriggerTest" +author: "Christoph" +status: "FINAL" +description: Sample test in XML +actions: + - knative: + client: "knativeClient" + namespace: "test" + createTrigger: + name: "my-trigger-1" + broker: "my-broker" + service: "my-service" + - knative: + client: "knativeClient" + namespace: "test" + createTrigger: + name: "my-trigger-2" + broker: "my-broker" + service: "my-service" + filter: + attributes: + - name: foo + value: bar diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-broker-test.yaml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-broker-test.yaml new file mode 100644 index 0000000000..4a68cd040f --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-broker-test.yaml @@ -0,0 +1,10 @@ +name: "DeleteBrokerTest" +author: "Christoph" +status: "FINAL" +description: Sample test in XML +actions: + - knative: + client: "knativeClient" + namespace: "test" + deleteBroker: + name: "my-broker" diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-channel-test.yaml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-channel-test.yaml new file mode 100644 index 0000000000..f0c15c72a3 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-channel-test.yaml @@ -0,0 +1,10 @@ +name: "DeleteChannelTest" +author: "Christoph" +status: "FINAL" +description: Sample test in XML +actions: + - knative: + client: "knativeClient" + namespace: "test" + deleteChannel: + name: "my-channel" diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-resource-test.yaml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-resource-test.yaml new file mode 100644 index 0000000000..0acbb2e64d --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-resource-test.yaml @@ -0,0 +1,12 @@ +name: "DeleteResourceTest" +author: "Christoph" +status: "FINAL" +description: Sample test in XML +actions: + - knative: + client: "knativeClient" + namespace: "test" + deleteResource: + component: "messaging" + kind: "subscriptions" + name: "my-subscription" diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-subscription-test.yaml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-subscription-test.yaml new file mode 100644 index 0000000000..2cb8236728 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-subscription-test.yaml @@ -0,0 +1,10 @@ +name: "DeleteSubscriptionTest" +author: "Christoph" +status: "FINAL" +description: Sample test in XML +actions: + - knative: + client: "knativeClient" + namespace: "test" + deleteSubscription: + name: "my-subscription" diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-trigger-test.yaml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-trigger-test.yaml new file mode 100644 index 0000000000..d20cd7acfe --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/delete-trigger-test.yaml @@ -0,0 +1,10 @@ +name: "DeleteTriggerTest" +author: "Christoph" +status: "FINAL" +description: Sample test in XML +actions: + - knative: + client: "knativeClient" + namespace: "test" + deleteTrigger: + name: "my-trigger" diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/send-receive-event-test.yaml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/send-receive-event-test.yaml new file mode 100644 index 0000000000..145f6b6385 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/send-receive-event-test.yaml @@ -0,0 +1,26 @@ +name: "SendReceiveEventTest" +author: "Christoph" +status: "FINAL" +description: Sample test in XML +actions: + - knative: + client: "knativeClient" + namespace: "test" + sendEvent: + broker: "my-broker" + fork: true + event: + data: Hello Knative broker + attributes: + - name: ce-type + value: "org.citrusframework.knative.event" + - knative: + client: "knativeClient" + namespace: "test" + receiveEvent: + service: "my-service" + event: + data: + attributes: + - name: ce-type + value: "org.citrusframework.knative.event" diff --git a/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/verify-broker-test.yaml b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/verify-broker-test.yaml new file mode 100644 index 0000000000..7de85febf4 --- /dev/null +++ b/connectors/citrus-knative/src/test/resources/org/citrusframework/knative/yaml/verify-broker-test.yaml @@ -0,0 +1,10 @@ +name: "VerifyBrokerTest" +author: "Christoph" +status: "FINAL" +description: Sample test in XML +actions: + - knative: + client: "knativeClient" + namespace: "test" + verifyBroker: + name: "my-broker" diff --git a/connectors/citrus-kubernetes/pom.xml b/connectors/citrus-kubernetes/pom.xml index bf3850aa71..163cccfdf5 100644 --- a/connectors/citrus-kubernetes/pom.xml +++ b/connectors/citrus-kubernetes/pom.xml @@ -60,6 +60,11 @@ citrus-base ${project.version} + + org.citrusframework + citrus-http + ${project.version} + org.citrusframework citrus-spring @@ -124,12 +129,6 @@ ${project.version} test - - org.citrusframework - citrus-http - ${project.version} - test - org.citrusframework citrus-validation-json diff --git a/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/ClusterType.java b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/ClusterType.java new file mode 100644 index 0000000000..360b4eab7a --- /dev/null +++ b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/ClusterType.java @@ -0,0 +1,37 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.kubernetes; + +/** + * Cluster types with different operator namespaces. + */ +public enum ClusterType { + + LOCAL(""), + KUBERNETES("citrus-system"), + OPENSHIFT("openshift-operators"); + + private final String operatorNamespace; + + ClusterType(String operatorNamespace) { + this.operatorNamespace = operatorNamespace; + } + + public String operatorNamespace() { + return operatorNamespace; + } +} diff --git a/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/KubernetesSettings.java b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/KubernetesSettings.java index c85fa83b8c..c6b39b0bb3 100644 --- a/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/KubernetesSettings.java +++ b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/KubernetesSettings.java @@ -19,13 +19,13 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; public class KubernetesSettings { @@ -43,6 +43,18 @@ public class KubernetesSettings { private static final String ENABLED_ENV = KUBERNETES_ENV_PREFIX + "ENABLED"; private static final String ENABLED_DEFAULT = "true"; + private static final String AUTO_CREATE_SERVER_BINDING_PROPERTY = KUBERNETES_PROPERTY_PREFIX + "auto.create.server.binding"; + private static final String AUTO_CREATE_SERVER_BINDING_ENV = KUBERNETES_ENV_PREFIX + "AUTO_CREATE_SERVER_BINDING"; + private static final String AUTO_CREATE_SERVER_BINDING_DEFAULT = "true"; + + private static final String CLUSTER_TYPE_PROPERTY = KUBERNETES_PROPERTY_PREFIX + "cluster.type"; + private static final String CLUSTER_TYPE_ENV = KUBERNETES_ENV_PREFIX + "CLUSTER_TYPE"; + private static final String CLUSTER_TYPE_DEFAULT = ClusterType.KUBERNETES.name(); + + private static final String CLUSTER_WILDCARD_DOMAIN_PROPERTY = KUBERNETES_PROPERTY_PREFIX + "cluster.wildcard.domain"; + private static final String CLUSTER_WILDCARD_DOMAIN_ENV = KUBERNETES_ENV_PREFIX + "CLUSTER_WILDCARD_DOMAIN"; + public static final String DEFAULT_DOMAIN_SUFFIX = "svc.cluster.local"; + private static final String SERVICE_TIMEOUT_PROPERTY = KUBERNETES_PROPERTY_PREFIX + "service.timeout"; private static final String SERVICE_TIMEOUT_ENV = KUBERNETES_ENV_PREFIX + "SERVICE_TIMEOUT"; private static final String SERVICE_TIMEOUT_DEFAULT = "2000"; @@ -55,6 +67,10 @@ public class KubernetesSettings { private static final String NAMESPACE_ENV = KUBERNETES_ENV_PREFIX + "NAMESPACE"; private static final String NAMESPACE_DEFAULT = "default"; + private static final String TEST_ID_LABEL_PROPERTY = KUBERNETES_PROPERTY_PREFIX + "test.id.label"; + private static final String TEST_ID_LABEL_ENV = KUBERNETES_ENV_PREFIX + "TEST_ID_LABEL"; + private static final String TEST_ID_LABEL_DEFAULT = "citrusframework.org/test-id"; + private static final String API_VERSION_PROPERTY = KUBERNETES_PROPERTY_PREFIX + "api.version"; private static final String API_VERSION_ENV = KUBERNETES_ENV_PREFIX + "API_VERSION"; private static final String API_VERSION_DEFAULT = "v1"; @@ -132,6 +148,24 @@ public static String getNamespace() { return NAMESPACE_DEFAULT; } + /** + * Cluster wildcard domain or default if non is set. + * @return + */ + public static String getClusterWildcardDomain() { + return System.getProperty(CLUSTER_WILDCARD_DOMAIN_PROPERTY, + System.getenv(CLUSTER_WILDCARD_DOMAIN_ENV) != null ? System.getenv(CLUSTER_WILDCARD_DOMAIN_ENV) : getNamespace() + "." + DEFAULT_DOMAIN_SUFFIX); + } + + /** + * Cluster type that YAKS is running on. + * @return + */ + public static ClusterType getClusterType() { + return ClusterType.valueOf(System.getProperty(CLUSTER_TYPE_PROPERTY, + System.getenv(CLUSTER_TYPE_ENV) != null ? System.getenv(CLUSTER_TYPE_ENV) : CLUSTER_TYPE_DEFAULT).toUpperCase(Locale.US)); + } + /** * Api version for current Kubernetes installation. * @return @@ -154,9 +188,9 @@ public static String getServiceName() { * Service port used when consuming cloud events via Http. * @return */ - public static String getServicePort() { - return System.getProperty(SERVICE_PORT_PROPERTY, - System.getenv(SERVICE_PORT_ENV) != null ? System.getenv(SERVICE_PORT_ENV) : SERVICE_PORT_DEFAULT); + public static int getServicePort() { + return Integer.parseInt(System.getProperty(SERVICE_PORT_PROPERTY, + System.getenv(SERVICE_PORT_ENV) != null ? System.getenv(SERVICE_PORT_ENV) : SERVICE_PORT_DEFAULT)); } /** @@ -168,10 +202,20 @@ public static Map getDefaultLabels() { String labelsConfig = System.getProperty(DEFAULT_LABELS_PROPERTY, System.getenv(DEFAULT_LABELS_ENV) != null ? System.getenv(DEFAULT_LABELS_ENV) : DEFAULT_LABELS_DEFAULT); - return Stream.of(StringUtils.commaDelimitedListToStringArray(labelsConfig)) - .map(item -> StringUtils.delimitedListToStringArray(item, "=")) - .filter(keyValue -> keyValue.length == 2) - .collect(Collectors.toMap(item -> item[0], item -> item[1])); + return Stream.of(labelsConfig.split(",")) + .map(item -> item.split("=", 2)) + .filter(keyValue -> keyValue.length == 2) + .collect(Collectors.toMap(item -> item[0], item -> item[1])); + } + + /** + * Should bind each Kubernetes service created to a local Http server instance. + * @return + */ + public static boolean isAutoCreateServerBinding() { + return Boolean.parseBoolean(System.getProperty(AUTO_CREATE_SERVER_BINDING_PROPERTY, + System.getenv(AUTO_CREATE_SERVER_BINDING_ENV) != null ? System.getenv(AUTO_CREATE_SERVER_BINDING_ENV) : + AUTO_CREATE_SERVER_BINDING_DEFAULT)); } /** @@ -228,4 +272,41 @@ public static long getWatchLogsTimeout() { return Long.parseLong(System.getProperty(WATCH_LOGS_TIMEOUT_PROPERTY, System.getenv(WATCH_LOGS_TIMEOUT_ENV) != null ? System.getenv(WATCH_LOGS_TIMEOUT_ENV) : WATCH_LOGS_TIMEOUT_DEFAULT)); } + + /** + * True when running on localhost. + * @return + */ + public static boolean isLocal() { + return isLocal(getClusterType()); + } + + /** + * True when running on localhost. + * @return + */ + public static boolean isLocal(ClusterType clusterType) { + return ClusterType.LOCAL.equals(clusterType); + } + + /** + * True when running on Openshift. + * @return + */ + public static boolean isOpenshiftCluster() { + return ClusterType.OPENSHIFT.equals(getClusterType()); + } + + /** + * True when running on Kubernetes. + * @return + */ + public static boolean isKubernetesCluster() { + return ClusterType.KUBERNETES.equals(getClusterType()); + } + + public static String getTestIdLabel() { + return System.getProperty(TEST_ID_LABEL_PROPERTY, + System.getenv(TEST_ID_LABEL_ENV) != null ? System.getenv(TEST_ID_LABEL_ENV) : TEST_ID_LABEL_DEFAULT); + } } diff --git a/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/KubernetesSupport.java b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/KubernetesSupport.java index 84a5c19e83..5c5f7fcf08 100644 --- a/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/KubernetesSupport.java +++ b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/KubernetesSupport.java @@ -226,4 +226,22 @@ public static Optional getServiceClusterIp(Citrus citrus, String service return Optional.empty(); } + + /** + * Create K8s conform name using lowercase RFC 1123 rules. + * @param name + * @return + */ + public static String sanitize(String name) { + String sanitized; + + if (name.contains(".")) { + sanitized = name.substring(0, name.indexOf(".")); + } else { + sanitized = name; + } + + sanitized = sanitized.replaceAll("([a-z])([A-Z]+)", "$1-$2").toLowerCase(); + return sanitized.replaceAll("[^a-z0-9-]", ""); + } } diff --git a/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/actions/ClusterConnectAction.java b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/actions/ClusterConnectAction.java new file mode 100644 index 0000000000..53856be404 --- /dev/null +++ b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/actions/ClusterConnectAction.java @@ -0,0 +1,121 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.kubernetes.actions; + +import java.util.HashMap; +import java.util.Map; + +import io.fabric8.kubernetes.api.model.ContainerBuilder; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; +import io.fabric8.kubernetes.client.dsl.Updatable; +import org.citrusframework.CitrusSettings; +import org.citrusframework.context.TestContext; +import org.citrusframework.kubernetes.KubernetesSettings; +import org.citrusframework.kubernetes.KubernetesSupport; + +/** + * Connects to a Kubernetes cluster. + * The action starts an agent Pod that is responsible for connecting to services on the cluster. + */ +public class ClusterConnectAction extends AbstractKubernetesAction implements KubernetesAction { + + private final String containerImage; + private final Map annotations; + private final Map labels; + + public ClusterConnectAction(Builder builder) { + super("kubernetes-connect", builder); + + this.containerImage = builder.containerImage; + this.labels = builder.labels; + this.annotations = builder.annotations; + } + + @Override + public void doExecute(TestContext context) { + Map resolvedAnnotations = context.resolveDynamicValuesInMap(annotations); + Map resolvedLabels = context.resolveDynamicValuesInMap(labels); + + if (!labels.containsKey(KubernetesSettings.getTestIdLabel())) { + labels.put(KubernetesSettings.getTestIdLabel(), context.getVariable(CitrusSettings.TEST_NAME_VARIABLE)); + } + + String testName = KubernetesSupport.sanitize("citrus-test-" + context.getVariable(CitrusSettings.TEST_NAME_VARIABLE)); + Deployment deployment = new DeploymentBuilder() + .withNewMetadata() + .withName(testName) + .addToAnnotations(resolvedAnnotations) + .addToLabels(resolvedLabels) + .endMetadata() + .withNewSpec() + .withNewTemplate() + .withNewSpec() + .addToContainers(new ContainerBuilder() + .withImage(containerImage) + .build()) + .endSpec() + .endTemplate() + .endSpec() + .build(); + + getKubernetesClient().apps().deployments() + .inNamespace(namespace(context)) + .resource(deployment) + .createOr(Updatable::update); + } + + /** + * Action builder. + */ + public static class Builder extends AbstractKubernetesAction.Builder { + + private String containerImage; + private final Map annotations = new HashMap<>(); + private final Map labels = new HashMap<>(); + + public Builder image(String containerImage) { + this.containerImage = containerImage; + return this; + } + + public Builder annotations(Mapannotations) { + this.annotations.putAll(annotations); + return this; + } + + public Builder annotation(String annotation, String value) { + this.annotations.put(annotation, value); + return this; + } + + public Builder labels(Maplabels) { + this.labels.putAll(labels); + return this; + } + + public Builder label(String label, String value) { + this.labels.put(label, value); + return this; + } + + @Override + public ClusterConnectAction doBuild() { + return new ClusterConnectAction(this); + } + } +} diff --git a/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/actions/CreateServiceAction.java b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/actions/CreateServiceAction.java index 349e926055..24eff71863 100644 --- a/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/actions/CreateServiceAction.java +++ b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/actions/CreateServiceAction.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.Service; @@ -30,8 +31,12 @@ import io.fabric8.kubernetes.client.dsl.Updatable; import org.citrusframework.CitrusSettings; import org.citrusframework.context.TestContext; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.http.server.HttpServerBuilder; import org.citrusframework.kubernetes.KubernetesSettings; import org.citrusframework.kubernetes.KubernetesVariableNames; +import org.citrusframework.spi.ReferenceResolver; +import org.citrusframework.spi.ReferenceResolverAware; public class CreateServiceAction extends AbstractKubernetesAction { @@ -95,13 +100,17 @@ public void doExecute(TestContext context) { /** * Action builder. */ - public static class Builder extends AbstractKubernetesAction.Builder { + public static class Builder extends AbstractKubernetesAction.Builder implements ReferenceResolverAware { - private String serviceName; + private String serviceName = KubernetesSettings.getServiceName(); private final List ports = new ArrayList<>(); private final List targetPorts = new ArrayList<>(); private String protocol = "TCP"; private final Map podSelector = new HashMap<>(); + private HttpServer httpServer; + private String httpServerName; + private boolean autoCreateServerBinding = KubernetesSettings.isAutoCreateServerBinding(); + private ReferenceResolver referenceResolver; public Builder service(String serviceName) { this.serviceName = serviceName; @@ -180,23 +189,71 @@ public Builder withPodSelector(Map selector) { return this; } + public Builder server(HttpServer httpServer) { + this.httpServer = httpServer; + return this; + } + + public Builder server(String httpServerName) { + this.httpServerName = httpServerName; + return this; + } + + public Builder autoCreateServerBinding(boolean enabled) { + this.autoCreateServerBinding = enabled; + return this; + } + + public Builder withReferenceResolver(ReferenceResolver referenceResolver) { + this.referenceResolver = referenceResolver; + return this; + } + @Override public CreateServiceAction doBuild() { + if (podSelector.isEmpty()) { + // Add default selector to the very specific Pod that is running the test right now. + // This way the service will route all traffic to the currently running test + podSelector.put("citrusframework.org/test-id", "${%s}".formatted(CitrusSettings.TEST_NAME_VARIABLE)); + } + + String serverName = Optional.ofNullable(httpServerName).orElse(serviceName); + if (httpServer == null) { + if (referenceResolver != null && referenceResolver.isResolvable(serverName, HttpServer.class)) { + httpServer = referenceResolver.resolve(serverName, HttpServer.class); + } else if (autoCreateServerBinding) { + httpServer = new HttpServerBuilder() + .autoStart(true) + .port(KubernetesSettings.getServicePort()) + .name(serverName) + .build(); + + httpServer.initialize(); + } + } + if (ports.isEmpty()) { ports.add("80"); } if (targetPorts.isEmpty()) { - targetPorts.add("8080"); + if (httpServer != null) { + targetPorts.add(String.valueOf(httpServer.getPort())); + } else { + targetPorts.add(String.valueOf(KubernetesSettings.getServicePort())); + } } - if (podSelector.isEmpty()) { - // Add default selector to the very specific Pod that is running the test right now. - // This way the service will route all traffic to the currently running test - podSelector.put("citrusframework.org/test-id", "${%s}".formatted(CitrusSettings.TEST_NAME_VARIABLE)); + if (referenceResolver != null && !referenceResolver.isResolvable(serverName, HttpServer.class)) { + referenceResolver.bind(serverName, httpServer); } return new CreateServiceAction(this); } + + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.referenceResolver = referenceResolver; + } } } diff --git a/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/xml/CreateService.java b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/xml/CreateService.java index b463e61f13..282f2ed173 100644 --- a/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/xml/CreateService.java +++ b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/xml/CreateService.java @@ -29,9 +29,11 @@ import org.citrusframework.TestActor; import org.citrusframework.kubernetes.actions.AbstractKubernetesAction; import org.citrusframework.kubernetes.actions.CreateServiceAction; +import org.citrusframework.spi.ReferenceResolver; +import org.citrusframework.spi.ReferenceResolverAware; @XmlRootElement(name = "create-service") -public class CreateService extends AbstractKubernetesAction.Builder { +public class CreateService extends AbstractKubernetesAction.Builder implements ReferenceResolverAware { private final CreateServiceAction.Builder delegate = new CreateServiceAction.Builder(); @@ -40,6 +42,16 @@ public void setName(String name) { this.delegate.service(name); } + @XmlAttribute + public void setServer(String serverName) { + this.delegate.server(serverName); + } + + @XmlAttribute(name = "auto-create-server-binding") + public void setAutoCreateServerBinding(boolean enabled) { + this.delegate.autoCreateServerBinding(enabled); + } + @XmlElement public void setPorts(PortMappings portMappings) { portMappings.getPorts().forEach( @@ -82,6 +94,11 @@ public CreateService inNamespace(String namespace) { return this; } + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + @Override public CreateServiceAction doBuild() { return delegate.build(); diff --git a/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/yaml/CreateService.java b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/yaml/CreateService.java index 11068524fc..a2d83474d6 100644 --- a/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/yaml/CreateService.java +++ b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/yaml/CreateService.java @@ -23,8 +23,10 @@ import org.citrusframework.TestActor; import org.citrusframework.kubernetes.actions.AbstractKubernetesAction; import org.citrusframework.kubernetes.actions.CreateServiceAction; +import org.citrusframework.spi.ReferenceResolver; +import org.citrusframework.spi.ReferenceResolverAware; -public class CreateService extends AbstractKubernetesAction.Builder { +public class CreateService extends AbstractKubernetesAction.Builder implements ReferenceResolverAware { private final CreateServiceAction.Builder delegate = new CreateServiceAction.Builder(); @@ -32,6 +34,14 @@ public void setName(String name) { this.delegate.service(name); } + public void setServer(String serverName) { + this.delegate.server(serverName); + } + + public void setAutoCreateServerBinding(boolean enabled) { + this.delegate.autoCreateServerBinding(enabled); + } + public void setPorts(List portMappings) { portMappings.forEach( mapping -> this.delegate.portMapping(mapping.getPort(), mapping.getTargetPort())); @@ -47,6 +57,11 @@ public void setSelector(PodSelector selector) { } + @Override + public void setReferenceResolver(ReferenceResolver referenceResolver) { + this.delegate.setReferenceResolver(referenceResolver); + } + @Override public CreateService description(String description) { delegate.description(description); diff --git a/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/integration/KubernetesCreateServiceIT.java b/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/integration/KubernetesCreateServiceIT.java index bf06539390..7b5314c450 100644 --- a/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/integration/KubernetesCreateServiceIT.java +++ b/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/integration/KubernetesCreateServiceIT.java @@ -20,7 +20,9 @@ import io.fabric8.kubernetes.api.model.Service; import org.citrusframework.annotations.CitrusTest; +import org.citrusframework.http.server.HttpServer; import org.citrusframework.kubernetes.client.KubernetesClient; +import org.mockito.Mock; import org.springframework.beans.factory.annotation.Autowired; import org.testng.Assert; import org.testng.annotations.Test; @@ -32,6 +34,9 @@ public class KubernetesCreateServiceIT extends AbstractKubernetesIT { @Autowired private KubernetesClient k8sClient; + @Mock + private HttpServer service; + private final String namespace = "test"; @Test @@ -41,6 +46,7 @@ public void shouldCreateService() { .client(k8sClient.getClient()) .services() .create("my-service") + .server(service) .inNamespace(namespace)); then(context -> { @@ -67,6 +73,7 @@ public void shouldCreateServiceWithCustomPortMapping() { .client(k8sClient.getClient()) .services() .create("my-service") + .server(service) .portMapping(80, 8888) .withPodSelector(Collections.singletonMap("test", "citrus")) .inNamespace(namespace)); diff --git a/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/xml/CreateServiceTest.java b/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/xml/CreateServiceTest.java index 4d30cce4cc..47609d2c21 100644 --- a/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/xml/CreateServiceTest.java +++ b/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/xml/CreateServiceTest.java @@ -19,8 +19,10 @@ import io.fabric8.kubernetes.api.model.Service; import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.http.server.HttpServer; import org.citrusframework.kubernetes.actions.CreateServiceAction; import org.citrusframework.xml.XmlTestLoader; +import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.Test; @@ -28,6 +30,8 @@ public class CreateServiceTest extends AbstractXmlActionTest { @Test public void shouldLoadKubernetesActions() { + context.getReferenceResolver().bind("myServer", Mockito.mock(HttpServer.class)); + XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/kubernetes/xml/create-service-test.xml"); testLoader.load(); diff --git a/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/yaml/CreateServiceTest.java b/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/yaml/CreateServiceTest.java index 1263215637..8617ad2093 100644 --- a/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/yaml/CreateServiceTest.java +++ b/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/yaml/CreateServiceTest.java @@ -19,8 +19,10 @@ import io.fabric8.kubernetes.api.model.Service; import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; +import org.citrusframework.http.server.HttpServer; import org.citrusframework.kubernetes.actions.CreateServiceAction; import org.citrusframework.yaml.YamlTestLoader; +import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.Test; @@ -28,6 +30,8 @@ public class CreateServiceTest extends AbstractYamlActionTest { @Test public void shouldLoadKubernetesActions() { + context.getReferenceResolver().bind("myServer", Mockito.mock(HttpServer.class)); + YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/kubernetes/yaml/create-service-test.yaml"); testLoader.load(); diff --git a/connectors/citrus-kubernetes/src/test/resources/org/citrusframework/kubernetes/xml/create-service-test.xml b/connectors/citrus-kubernetes/src/test/resources/org/citrusframework/kubernetes/xml/create-service-test.xml index 5858cba0f3..0b2b605726 100644 --- a/connectors/citrus-kubernetes/src/test/resources/org/citrusframework/kubernetes/xml/create-service-test.xml +++ b/connectors/citrus-kubernetes/src/test/resources/org/citrusframework/kubernetes/xml/create-service-test.xml @@ -20,11 +20,11 @@ Sample test in XML - + - + diff --git a/connectors/citrus-kubernetes/src/test/resources/org/citrusframework/kubernetes/yaml/create-service-test.yaml b/connectors/citrus-kubernetes/src/test/resources/org/citrusframework/kubernetes/yaml/create-service-test.yaml index c54f826388..001aa90a74 100644 --- a/connectors/citrus-kubernetes/src/test/resources/org/citrusframework/kubernetes/yaml/create-service-test.yaml +++ b/connectors/citrus-kubernetes/src/test/resources/org/citrusframework/kubernetes/yaml/create-service-test.yaml @@ -8,12 +8,14 @@ actions: namespace: "test" createService: name: "my-service-1" + autoCreateServerBinding: false - kubernetes: client: "k8sClient" namespace: "test" createService: name: "my-service-2" + server: "myServer" ports: - port: "80" targetPort: "8888" diff --git a/connectors/pom.xml b/connectors/pom.xml index 189b6b3ddc..151fabcdb2 100644 --- a/connectors/pom.xml +++ b/connectors/pom.xml @@ -18,6 +18,7 @@ citrus-openapi citrus-docker citrus-kubernetes + citrus-knative citrus-selenium citrus-sql citrus-jbang-connector diff --git a/pom.xml b/pom.xml index ef0a629496..e64c9c72af 100644 --- a/pom.xml +++ b/pom.xml @@ -242,6 +242,7 @@ 6.13.3 6.13.3 3.8.0 + 6.13.3 2.22.1 5.13.0 3.2.0 @@ -1039,6 +1040,12 @@ ${jakarta.validation.version} + + io.fabric8 + knative-client + ${knative-client.version} + + io.netty netty-handler diff --git a/runtime/citrus-xml/src/main/resources/org/citrusframework/schema/xml/testcase/citrus-testcase-4.4.0-SNAPSHOT.xsd b/runtime/citrus-xml/src/main/resources/org/citrusframework/schema/xml/testcase/citrus-testcase-4.4.0-SNAPSHOT.xsd index d147e6bc55..676e1331fd 100644 --- a/runtime/citrus-xml/src/main/resources/org/citrusframework/schema/xml/testcase/citrus-testcase-4.4.0-SNAPSHOT.xsd +++ b/runtime/citrus-xml/src/main/resources/org/citrusframework/schema/xml/testcase/citrus-testcase-4.4.0-SNAPSHOT.xsd @@ -729,6 +729,7 @@ + @@ -1445,6 +1446,8 @@ + + @@ -1667,6 +1670,148 @@ + + + Connect with Knative to manage resources on the cluster + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/runtime/citrus-xml/src/main/resources/org/citrusframework/schema/xml/testcase/citrus-testcase.xsd b/runtime/citrus-xml/src/main/resources/org/citrusframework/schema/xml/testcase/citrus-testcase.xsd index d147e6bc55..676e1331fd 100644 --- a/runtime/citrus-xml/src/main/resources/org/citrusframework/schema/xml/testcase/citrus-testcase.xsd +++ b/runtime/citrus-xml/src/main/resources/org/citrusframework/schema/xml/testcase/citrus-testcase.xsd @@ -729,6 +729,7 @@ + @@ -1445,6 +1446,8 @@ + + @@ -1667,6 +1670,148 @@ + + + Connect with Knative to manage resources on the cluster + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/maven/citrus-maven-plugin/pom.xml b/tools/maven/citrus-maven-plugin/pom.xml index b8f436205a..9c18c40c32 100644 --- a/tools/maven/citrus-maven-plugin/pom.xml +++ b/tools/maven/citrus-maven-plugin/pom.xml @@ -40,7 +40,7 @@ org.apache.maven maven-core - 3.9.6 + ${maven.version} provided