/*
* Copyright 2016 Red Hat, Inc.
* <p>
* Red Hat licenses this file to you 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 io.fabric8.funktion.agent;
import io.fabric8.funktion.agent.support.CamelTester;
import io.fabric8.funktion.agent.support.TestRouteBuilder;
import io.fabric8.funktion.model.Funktion;
import io.fabric8.kubernetes.api.KubernetesHelper;
import org.apache.camel.model.dataformat.JsonLibrary;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import static io.fabric8.utils.URLUtils.pathJoin;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Fail.fail;
/**
* This test case will spin up a new Funktion Subscription with a YAML file in a new Deployment then assert
* that the Funktion flow writes the correct data to Elasticsearch running inside Kubernetes then ensure the
* subscription is torn down again
*/
public class AgentKT {
private static final transient Logger LOG = LoggerFactory.getLogger(AgentKT.class);
protected Agent agent = new Agent();
@Test
public void testAgentSubscribe() throws Throwable {
String elasticSearchPath = "/testagent/funktion/1";
String namespace = agent.getCurrentNamespace();
String elasticsearchURL = getHttpServiceURL(namespace, "elasticsearch");
String elasticSearchResource = pathJoin(elasticsearchURL, elasticSearchPath);
deleteResource(elasticSearchResource);
LOG.info("Creating a subscription in namespace: " + namespace);
String expectedName = getClass().getName();
SamplePayload payload = new SamplePayload(expectedName, new Date());
String body = KubernetesHelper.toJson(payload);
LOG.info("Sending JSON: " + body);
SubscribeResponse response = null;
try {
Funktion funktion = new Funktion();
funktion.createFlow().trace(true).logResult(true).singleMessageMode(true).
endpoint("timer://cheese?fixedRate=true&period=5000").
setBody(body).
endpoint("http://elasticsearch:9200" + elasticSearchPath);
Map<String, String> applicationProperties = new HashMap<>();
applicationProperties.put("foo", "bar");
SubscribeRequest request = new SubscribeRequest(namespace, funktion, applicationProperties);
LOG.info("Creating a flow");
response = agent.subscribe(request);
LOG.info("Created a Subscription at " + response.getNamespace() + "/" + response.getName());
assertThat(response.getNamespace()).describedAs("namespace").isEqualTo(namespace);
assertWaitForResults(namespace, elasticSearchResource, payload);
} finally {
if (response != null) {
LOG.info("Deleting the Subscription at " + response.getNamespace() + "/" + response.getName());
agent.unsubscribe(response.getNamespace(), response.getName());
LOG.info("Deleted the Subscription at " + response.getNamespace() + "/" + response.getName());
}
}
}
private void deleteResource(String resource) {
LOG.info("trying to delete " + resource);
RestTemplate restTemplate = new RestTemplate();
try {
restTemplate.delete(resource);
} catch (RestClientException e) {
LOG.info("Ignoring delete exception on resource: " + resource + " as it may not exist: " + e);
}
// lets assert it does not exist any more
try {
ResponseEntity<String> response = restTemplate.getForEntity(resource, String.class);
fail("Should not have found resource: " + resource + " with: " + response.getBody());
} catch (HttpClientErrorException e) {
String responseBody = e.getResponseBodyAsString();
int statusCode = e.getRawStatusCode();
LOG.info("As expected we could not find resource " + resource + " and got status: " + statusCode + " with: " + responseBody);
assertThat(statusCode).describedAs("Response code after getting " + resource + " with result: " + responseBody).isGreaterThanOrEqualTo(400);
}
}
private void assertWaitForResults(String namespace, String elasticSearchResource, SamplePayload payload) throws Throwable {
final String pollUrl = pathJoin(elasticSearchResource, "/_source");
LOG.info("Querying elasticsearch URL: " + pollUrl);
CamelTester.assertIsSatisfied(new TestRouteBuilder() {
@Override
protected void configureTest() throws Exception {
// expectations
results.expectedBodiesReceived(payload);
results.setResultWaitTime(60 * 1000L);
from("timer://poller?delay=10000&period=2000").errorHandler(deadLetterChannel(errors)).
to(pollUrl).
unmarshal().json(JsonLibrary.Jackson, SamplePayload.class).
to(results);
}
});
}
protected String getHttpServiceURL(String namespace, String serviceName) {
String answer = KubernetesHelper.getServiceURL(agent.getKubernetesClient(), serviceName, namespace, "http", true);
assertThat(answer).describedAs("Could not find service URL " + namespace + "/" + serviceName).isNotEmpty();
return answer;
}
}