/* * Copyright 2014 mango.jfaster.org * * The Mango Project 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.jfaster.mango.operator.cache; import org.hamcrest.Matchers; import org.jfaster.mango.binding.BoundSql; import org.jfaster.mango.datasource.DataSourceFactoryGroup; import org.jfaster.mango.datasource.SimpleDataSourceFactory; import org.jfaster.mango.descriptor.MethodDescriptor; import org.jfaster.mango.descriptor.ParameterDescriptor; import org.jfaster.mango.descriptor.ReturnDescriptor; import org.jfaster.mango.interceptor.InterceptorChain; import org.jfaster.mango.jdbc.ListSupplier; import org.jfaster.mango.mapper.RowMapper; import org.jfaster.mango.operator.Config; import org.jfaster.mango.operator.Operator; import org.jfaster.mango.operator.OperatorFactory; import org.jfaster.mango.stat.MetaStat; import org.jfaster.mango.stat.OneExecuteStat; import org.jfaster.mango.support.*; import org.jfaster.mango.support.model4table.User; import org.jfaster.mango.util.reflect.TypeToken; import org.junit.Test; import javax.sql.DataSource; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.*; import java.util.concurrent.TimeUnit; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; /** * @author ash */ @SuppressWarnings("unchecked") public class CacheableQueryOperatorTest { @Test public void testQuerySingleKeyHit() throws Exception { TypeToken<Integer> pt = TypeToken.of(Integer.class); TypeToken<User> rt = TypeToken.of(User.class); String srcSql = "select * from user where id=:1"; Operator operator = getOperator(pt, rt, srcSql, new CacheHandlerAdapter() { @Override public Object get(String key, Type type, Class<?> daoClass) { assertThat(key, Matchers.equalTo("user_1")); return new User(); } }, new MockCacheBy("")); operator.setJdbcOperations(new JdbcOperationsAdapter()); OneExecuteStat stat = OneExecuteStat.create(); operator.execute(new Object[]{1}, stat); assertThat(stat.getHitCount(), Matchers.equalTo(1L)); } @Test public void testQuerySingleKeyMiss() throws Exception { TypeToken<Integer> pt = TypeToken.of(Integer.class); TypeToken<User> rt = TypeToken.of(User.class); String srcSql = "select * from user where id=:1"; Operator operator = getOperator(pt, rt, srcSql, new CacheHandlerAdapter() { @Override public Object get(String key, Type type, Class<?> daoClass) { assertThat(key, Matchers.equalTo("user_1")); return null; } @Override public void set(String key, Object value, int expires, Class<?> daoClass) { assertThat(key, Matchers.equalTo("user_1")); assertThat(expires, Matchers.equalTo((int) TimeUnit.DAYS.toSeconds(1))); } }, new MockCacheBy("")); operator.setJdbcOperations(new JdbcOperationsAdapter() { @Override public <T> T queryForObject(DataSource ds, BoundSql boundSql, RowMapper<T> rowMapper) { String sql = boundSql.getSql(); Object[] args = boundSql.getArgs().toArray(); String descSql = "select * from user where id=?"; assertThat(sql, Matchers.equalTo(descSql)); assertThat(args.length, Matchers.equalTo(1)); assertThat(args[0], Matchers.equalTo((Object) 1)); return (T) new User(); } }); OneExecuteStat stat = OneExecuteStat.create(); operator.execute(new Object[]{1}, stat); assertThat(stat.getMissCount(), Matchers.equalTo(1L)); } @Test public void testQueryMultiKeyAllHit() throws Exception { TypeToken<List<Integer>> pt = new TypeToken<List<Integer>>() { }; TypeToken<List<User>> rt = new TypeToken<List<User>>() { }; String srcSql = "select * from user where id in (:1)"; Operator operator = getOperator(pt, rt, srcSql, new CacheHandlerAdapter() { @Override public Map<String, Object> getBulk(Set<String> keys, Type type, Class<?> daoClass) { Map<String, Object> map = new HashMap<String, Object>(); map.put("user_1", new User()); map.put("user_2", new User()); map.put("user_3", new User()); assertThat(keys, Matchers.equalTo(map.keySet())); return map; } }, new MockCacheBy("")); operator.setJdbcOperations(new JdbcOperationsAdapter()); OneExecuteStat stat = OneExecuteStat.create(); operator.execute(new Object[]{Arrays.asList(1, 2, 3)}, stat); assertThat(stat.getHitCount(), equalTo(3L)); assertThat(((CacheableQueryOperator) operator).propertyOfMapperInvoker.getName(), equalTo("id")); } @Test public void testQueryMultiKeyAllMiss() throws Exception { TypeToken<List<Integer>> pt = new TypeToken<List<Integer>>() { }; TypeToken<List<User>> rt = new TypeToken<List<User>>() { }; String srcSql = "select * from user where id in (:1)"; final Set<String> keys = new HashSet<String>(); final Set<String> setKeys = new HashSet<String>(); keys.add("user_1"); keys.add("user_2"); keys.add("user_3"); Operator operator = getOperator(pt, rt, srcSql, new CacheHandlerAdapter() { @Override public Map<String, Object> getBulk(Set<String> keys, Type type, Class<?> daoClass) { assertThat(keys, Matchers.equalTo(keys)); return null; } @Override public void set(String key, Object value, int expires, Class<?> daoClass) { setKeys.add(key); } }, new MockCacheBy("")); operator.setJdbcOperations(new JdbcOperationsAdapter() { @Override public <T> List<T> queryForList(DataSource ds, BoundSql boundSql, ListSupplier listSupplier, RowMapper<T> rowMapper) { String sql = boundSql.getSql(); Object[] args = boundSql.getArgs().toArray(); String descSql = "select * from user where id in (?,?,?)"; assertThat(sql, Matchers.equalTo(descSql)); assertThat(args.length, Matchers.equalTo(3)); assertThat(args[0], Matchers.equalTo((Object) 1)); assertThat(args[1], Matchers.equalTo((Object) 2)); assertThat(args[2], Matchers.equalTo((Object) 3)); List<T> users = new ArrayList<T>(); users.add((T) new User(1, "1")); users.add((T) new User(2, "2")); users.add((T) new User(3, "3")); return users; } }); OneExecuteStat stat = OneExecuteStat.create(); operator.execute(new Object[]{Arrays.asList(1, 2, 3)}, stat); assertThat(stat.getMissCount(), Matchers.equalTo(3L)); assertThat(keys, Matchers.equalTo(setKeys)); } @Test public void testQueryMultiKey() throws Exception { TypeToken<List<Integer>> pt = new TypeToken<List<Integer>>() { }; TypeToken<List<User>> rt = new TypeToken<List<User>>() { }; String srcSql = "select * from user where id in (:1)"; final Set<String> keys = new HashSet<String>(); final Set<String> setKeys = new HashSet<String>(); keys.add("user_1"); keys.add("user_2"); keys.add("user_3"); Operator operator = getOperator(pt, rt, srcSql, new CacheHandlerAdapter() { @Override public Map<String, Object> getBulk(Set<String> keys, Type type, Class<?> daoClass) { assertThat(keys, Matchers.equalTo(keys)); Map<String, Object> map = new HashMap<String, Object>(); map.put("user_2", new User()); return map; } @Override public void set(String key, Object value, int expires, Class<?> daoClass) { setKeys.add(key); } }, new MockCacheBy("")); operator.setJdbcOperations(new JdbcOperationsAdapter() { @Override public <T> List<T> queryForList(DataSource ds, BoundSql boundSql, ListSupplier listSupplier, RowMapper<T> rowMapper) { String sql = boundSql.getSql(); Object[] args = boundSql.getArgs().toArray(); String descSql = "select * from user where id in (?,?)"; assertThat(sql, Matchers.equalTo(descSql)); assertThat(args.length, Matchers.equalTo(2)); assertThat(args[0], Matchers.equalTo((Object) 1)); assertThat(args[1], Matchers.equalTo((Object) 3)); List<T> users = new ArrayList<T>(); users.add((T) new User(1, "1")); users.add((T) new User(3, "3")); return users; } }); OneExecuteStat stat = OneExecuteStat.create(); operator.execute(new Object[]{Arrays.asList(1, 2, 3)}, stat); assertThat(stat.getHitCount(), Matchers.equalTo(1L)); assertThat(stat.getMissCount(), Matchers.equalTo(2L)); keys.remove("user_2"); assertThat(keys, Matchers.equalTo(setKeys)); } @Test public void testQueryMultiKeyPropertyOfMapper() throws Exception { TypeToken<List<Integer>> pt = new TypeToken<List<Integer>>() { }; TypeToken<List<X>> rt = new TypeToken<List<X>>() { }; String srcSql = "select * from user where msg_id in (:1)"; Operator operator = getOperator(pt, rt, srcSql, new CacheHandlerAdapter() { }, new MockCacheBy("")); assertThat(((CacheableQueryOperator) operator).propertyOfMapperInvoker.getName(), equalTo("msgId")); } private static class X { private int msgId; private String content; public int getMsgId() { return msgId; } public void setMsgId(int msgId) { this.msgId = msgId; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } private Operator getOperator(TypeToken<?> pt, TypeToken<?> rt, String srcSql, CacheHandler ch, MockCacheBy cacheBy) throws Exception { List<Annotation> pAnnos = new ArrayList<Annotation>(); pAnnos.add(cacheBy); ParameterDescriptor p = ParameterDescriptor.create(0, pt.getType(), pAnnos, "1"); List<ParameterDescriptor> pds = Arrays.asList(p); List<Annotation> methodAnnos = new ArrayList<Annotation>(); methodAnnos.add(new MockDB()); methodAnnos.add(new MockCache("user", Day.class)); methodAnnos.add(new MockSQL(srcSql)); ReturnDescriptor rd = ReturnDescriptor.create(rt.getType(), methodAnnos); MethodDescriptor md = MethodDescriptor.create(null, null, rd, pds); DataSourceFactoryGroup group = new DataSourceFactoryGroup(); group.addDataSourceFactory(new SimpleDataSourceFactory(DataSourceConfig.getDataSource())); OperatorFactory factory = new OperatorFactory(group, ch, new InterceptorChain(), new Config()); Operator operator = factory.getOperator(md, MetaStat.create()); return operator; } }