blob: dd813a1ccd9db55d096975987197698d8f153a2d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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
*
* 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.apache.camel.component.jcache.policy;
import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.Caching;
import javax.cache.configuration.MutableConfiguration;
import org.apache.camel.Exchange;
import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.language.simple.types.SimpleIllegalSyntaxException;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JCachePolicyProcessorTest extends JCachePolicyTestBase {
private static final Logger LOG = LoggerFactory.getLogger(JCachePolicyProcessorTest.class);
//Basic test to verify value gets cached and route is not executed for the second time
@Test
public void testValueGetsCached() throws Exception {
final String key = randomString();
MockEndpoint mock = getMockEndpoint("mock:value");
Cache cache = lookupCache("simple");
//Send first, key is not in cache
Object responseBody = this.template().requestBody("direct:cached-simple", key);
//We got back the value, mock was called once, value got cached.
assertEquals(generateValue(key), cache.get(key));
assertEquals(generateValue(key), responseBody);
assertEquals(1, mock.getExchanges().size());
//Send again, key is already in cache
responseBody = this.template().requestBody("direct:cached-simple", key);
//We got back the stored value, but the mock was not called again
assertEquals(generateValue(key), cache.get(key));
assertEquals(generateValue(key), responseBody);
assertEquals(1, mock.getExchanges().size());
}
//Verify policy applies only on the section of the route wrapped
@Test
public void testPartial() throws Exception {
final String key = randomString();
MockEndpoint mock = getMockEndpoint("mock:value");
MockEndpoint mockUnwrapped = getMockEndpoint("mock:unwrapped");
//Send first, key is not in cache
Object responseBody = this.template().requestBody("direct:cached-partial", key);
//We got back the value, mock was called once, value got cached.
Cache cache = lookupCache("simple");
assertEquals(generateValue(key), cache.get(key));
assertEquals(generateValue(key), responseBody);
assertEquals(1, mock.getExchanges().size());
assertEquals(1, mockUnwrapped.getExchanges().size());
//Send again, key is already in cache
responseBody = this.template().requestBody("direct:cached-partial", key);
//We got back the stored value, the mock was not called again, but the unwrapped mock was
assertEquals(generateValue(key), cache.get(key));
assertEquals(generateValue(key), responseBody);
assertEquals(1, mock.getExchanges().size());
assertEquals(2, mockUnwrapped.getExchanges().size());
}
//Cache is closed
@Test
public void testClosedCache() throws Exception {
final String key = randomString();
MockEndpoint mock = getMockEndpoint("mock:value");
//Send first, key is not in cache
Object responseBody = this.template().requestBody("direct:cached-closed", key);
//We got back the value, mock was called once
assertEquals(generateValue(key), responseBody);
assertEquals(1, mock.getExchanges().size());
//Send again, cache is closed
responseBody = this.template().requestBody("direct:cached-closed", key);
//We got back the stored value, mock was called again
assertEquals(generateValue(key), responseBody);
assertEquals(2, mock.getExchanges().size());
}
//Key is already stored
@Test
public void testValueWasCached() throws Exception {
final String key = randomString();
final String value = "test";
MockEndpoint mock = getMockEndpoint("mock:value");
//Prestore value in cache
Cache cache = lookupCache("simple");
cache.put(key, value);
//Send first, key is already in cache
Object responseBody = this.template().requestBody("direct:cached-simple", key);
//We got back the value, mock was not called, cache was not modified
assertEquals(value, cache.get(key));
assertEquals(value, responseBody);
assertEquals(0, mock.getExchanges().size());
}
//Null final body
@Test
public void testNullResult() throws Exception {
final String key = randomString();
MockEndpoint mock = getMockEndpoint("mock:value");
mock.whenAnyExchangeReceived(e -> e.getMessage().setBody(null));
//Send first
this.template().requestBody("direct:cached-simple", key);
assertEquals(1, mock.getExchanges().size());
//Send again, nothing was cached
this.template().requestBody("direct:cached-simple", key);
assertEquals(2, mock.getExchanges().size());
}
//Use a key expression ${header.mykey}
@Test
public void testKeyExpression() throws Exception {
final String key = randomString();
final String body = randomString();
MockEndpoint mock = getMockEndpoint("mock:value");
Cache cache = lookupCache("simple");
//Send first, key is not in cache
Object responseBody = this.template().requestBodyAndHeader("direct:cached-byheader", body, "mykey", key);
//We got back the value, mock was called once, value got cached.
assertEquals(generateValue(body), cache.get(key));
assertEquals(generateValue(body), responseBody);
assertEquals(1, mock.getExchanges().size());
//Send again, use another body, but the same key
responseBody = this.template().requestBodyAndHeader("direct:cached-byheader", randomString(), "mykey", key);
//We got back the stored value, and the mock was not called again
assertEquals(generateValue(body), cache.get(key));
assertEquals(generateValue(body), responseBody);
assertEquals(1, mock.getExchanges().size());
}
//Key is null, ${header.mykey} is not set
@Test
public void testKeyNull() throws Exception {
final String key = randomString();
String body = randomString();
MockEndpoint mock = getMockEndpoint("mock:value");
Cache cache = lookupCache("simple");
//Send first, expected header is not set
Object responseBody = this.template().requestBody("direct:cached-byheader", body);
//We got back the value, mock was called once, nothing is cached.
assertFalse(cache.containsKey("null"));
assertFalse(cache.containsKey(""));
assertFalse(cache.containsKey(key));
assertEquals(generateValue(body), responseBody);
assertEquals(1, mock.getExchanges().size());
//Send again, use another body, but the same key
body = randomString();
responseBody = this.template().requestBody("direct:cached-byheader", body);
//We got back the value, mock was called again, nothing is cached
assertFalse(cache.containsKey("null"));
assertFalse(cache.containsKey(""));
assertFalse(cache.containsKey(key));
assertEquals(generateValue(body), responseBody);
assertEquals(2, mock.getExchanges().size());
}
//Use an invalid key expression causing an exception
@Test
public void testInvalidKeyExpression() throws Exception {
final String body = randomString();
MockEndpoint mock = getMockEndpoint("mock:value");
Cache cache = lookupCache("simple");
//Send
Exchange response = this.template().request("direct:cached-invalidkey",
e -> e.getMessage().setBody(body));
//Exception is on the exchange, cache is empty, onException was called.
assertIsInstanceOf(SimpleIllegalSyntaxException.class, response.getException().getCause());
assertEquals("exception-" + body, response.getMessage().getBody());
assertEquals(0, mock.getExchanges().size());
assertFalse(cache.iterator().hasNext());
}
//Value is cached after handled exception
@Test
public void testHandledException() throws Exception {
final String key = randomString();
MockEndpoint mock = getMockEndpoint("mock:value");
Cache cache = lookupCache("simple");
//Send first, key is not in cache
Object responseBody = this.template().requestBody("direct:cached-exception", key);
//We got back the value after exception handler, mock was called once, value got cached.
assertEquals("handled-" + generateValue(key), cache.get(key));
assertEquals("handled-" + generateValue(key), responseBody);
assertEquals(1, mock.getExchanges().size());
}
//Nothing is cached after an unhandled exception
@Test
public void testException() throws Exception {
final String key = randomString();
MockEndpoint mock = getMockEndpoint("mock:value");
mock.whenAnyExchangeReceived(e -> {
throw new RuntimeException("unexpected");
});
Cache cache = lookupCache("simple");
//Send
Exchange response = this.template().request("direct:cached-exception",
e -> e.getMessage().setBody(key));
//Exception is on the exchange, cache is empty
assertEquals("unexpected", response.getException().getMessage());
assertEquals(1, mock.getExchanges().size());
assertFalse(cache.iterator().hasNext());
}
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
public void configure() {
CacheManager cacheManager = Caching.getCachingProvider().getCacheManager();
//Simple cache - with default config
Cache cache = cacheManager.createCache("simple", new MutableConfiguration<>());
JCachePolicy jcachePolicy = new JCachePolicy();
jcachePolicy.setCache(cache);
from("direct:cached-simple")
.policy(jcachePolicy)
.to("mock:value");
//Example to wrap only part of the route
from("direct:cached-partial")
.policy(jcachePolicy)
.log(LoggingLevel.DEBUG, LOG, "Executing route, not found in cache. body:${body}")
.to("mock:value")
.end()
.log(LoggingLevel.DEBUG, LOG, "This is always called. body:${body}")
.to("mock:unwrapped");
//Cache after exception handling
from("direct:cached-exception")
.onException(Exception.class)
.onWhen(exceptionMessage().isEqualTo("test"))
.handled(true)
.setBody(simple("handled-${body}"))
.end()
.policy(jcachePolicy)
.to("mock:value")
.throwException(new Exception("test"));
//Closed cache
cache = cacheManager.createCache("closed", new MutableConfiguration<>());
cache.close();
jcachePolicy = new JCachePolicy();
jcachePolicy.setCache(cache);
from("direct:cached-closed")
.policy(jcachePolicy)
.to("mock:value");
//Use ${header.mykey} as the key
jcachePolicy = new JCachePolicy();
jcachePolicy.setCache(cacheManager.getCache("simple"));
jcachePolicy.setKeyExpression(simple("${header.mykey}"));
from("direct:cached-byheader")
.policy(jcachePolicy)
.to("mock:value");
//Use an invalid keyExpression
jcachePolicy = new JCachePolicy();
jcachePolicy.setCache(cacheManager.getCache("simple"));
jcachePolicy.setKeyExpression(simple("${unexpected}"));
from("direct:cached-invalidkey")
.onException(Exception.class)
.setBody(simple("exception-${body}"))
.end()
.policy(jcachePolicy)
.to("mock:value");
}
};
}
}