[Add][Change][Fix] CacheStore-Redis 完善整体单元测试项, 修复单元测试不够严谨的问题;

[Add] RedisTestUtils 增加 Redis 测试工具类;
[Add] RedisUtilsTest 增加针对 RedisUtils 的单元测试类;
[Add] SimpleRedisCacheStore, RedisCacheStoreTest 将 RedisCacheStore 的测试项从 RedisSingleCacheStore 单元测试中分离;
[Change] RedisCacheStore 分离 'getKeyString(CacheKey)' 方法的具体实现到 RedisUtils;
[Change] RedisSingleCacheStore 调整构造器参数检查过程, 排除空标识或 null 参数;
[Change] RedisSingleCacheStoreTest 重写 RedisSingleCacheStore 单元测试类, 使其更加严谨;
[Change] RedisMapCacheStore 优化 'clearMap()' 方法执行过程, 清除不可能分支, 调整构造器参数检查过程, 排除空标识或 null 参数;
[Change] RedisMapCacheStoreTest 优化测试项, 使其更加严谨;
[Change] RedisListCacheStore 优化文档内容, 清除不可能分支;
[Change] RedisListCacheStoreTest 补充断言消息;
[Fix] RedisCacheStore 修复了 'keySet()' 方法中返回的 key 不正确的问题;
This commit is contained in:
2021-01-16 01:26:31 +08:00
parent 997b942a27
commit 92175377c4
11 changed files with 874 additions and 271 deletions

View File

@ -20,10 +20,7 @@ package net.lamgc.cgj.bot.cache.redis;
import net.lamgc.cgj.bot.cache.CacheKey;
import net.lamgc.cgj.bot.cache.CacheStore;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
/**
*
@ -44,7 +41,7 @@ public abstract class RedisCacheStore<V> implements CacheStore<V> {
* @return 返回 Key 前缀.
*/
protected String getKeyString(CacheKey cacheKey) {
return RedisUtils.toRedisCacheKey(getKeyPrefix(), cacheKey);
return RedisUtils.toRedisCacheKey(getKeyPrefix(), Objects.requireNonNull(cacheKey));
}
/**
@ -105,7 +102,7 @@ public abstract class RedisCacheStore<V> implements CacheStore<V> {
final int prefixLength = getKeyPrefix().length();
Set<String> newKeys = new HashSet<>();
for (String key : keys) {
newKeys.add(key.substring(prefixLength));
newKeys.add(key.substring(prefixLength + 1));
}
return newKeys;
}

View File

@ -68,17 +68,6 @@ public class RedisListCacheStore<E> extends RedisCacheStore<List<E>> implements
return result;
}
/**
* {@inheritDoc}
*
* <p>注意: 在 Redis 实现中, 该功能通过一段 Lua 脚本实现,
* 由于 Redis 并没有原生支持该功能, 所以只能用脚本遍历查找.
* 如果 List 元素过多, 可能会导致执行缓慢且影响后续操作, 谨慎使用.
* @param key 待操作的缓存项键名.
* @param index 欲删除元素的索引, 从 0 开始.
* @return 如果元素存在且删除成功, 返回 true.
* @throws NullPointerException 当 key 为 null 时抛出.
*/
@Override
public boolean removeElement(CacheKey key, int index) {
List<String> keys = new ArrayList<>(1);
@ -98,8 +87,9 @@ public class RedisListCacheStore<E> extends RedisCacheStore<List<E>> implements
@Override
public boolean addElement(CacheKey key, E element) {
Objects.requireNonNull(element);
return connectionPool.executeRedis(jedis ->
connectionPool.executeRedis(jedis ->
jedis.lpush(getKeyString(key), converter.to(element)) != RedisUtils.RETURN_CODE_FAILED);
return true;
}
@Override
@ -115,14 +105,15 @@ public class RedisListCacheStore<E> extends RedisCacheStore<List<E>> implements
valueStrings[i] = converter.to(values.get(i));
}
return connectionPool.executeRedis(jedis ->
connectionPool.executeRedis(jedis ->
jedis.lpush(getKeyString(key), valueStrings) != RedisUtils.RETURN_CODE_FAILED);
return true;
}
/**
* {@inheritDoc}
*
* <p>注意: 在 Redis 实现中, 该功能通过一段 Lua 脚本实现,
* <p> 注意: 在 Redis 实现中, 该功能通过一段 Lua 脚本实现,
* 由于 Redis 并没有原生支持该功能, 所以只能用脚本遍历查找.
* 如果 List 元素过多, 可能会导致执行缓慢且影响后续操作, 谨慎使用.
* @param key 待检查的缓存项键名.

View File

@ -17,7 +17,6 @@
package net.lamgc.cgj.bot.cache.redis;
import com.google.common.base.Strings;
import net.lamgc.cgj.bot.cache.CacheKey;
import net.lamgc.cgj.bot.cache.MapCacheStore;
import net.lamgc.cgj.bot.cache.convert.StringConverter;
@ -38,8 +37,11 @@ public class RedisMapCacheStore<V> extends RedisCacheStore<Map<String, V>> imple
public RedisMapCacheStore(RedisConnectionPool connectionPool, String keyPrefix, StringConverter<V> converter) {
super(connectionPool);
this.connectionPool = connectionPool;
keyPrefix = Strings.nullToEmpty(keyPrefix).trim();
if (!keyPrefix.isEmpty() && keyPrefix.endsWith(RedisUtils.KEY_SEPARATOR)) {
keyPrefix = Objects.requireNonNull(keyPrefix).trim();
if (keyPrefix.isEmpty()) {
throw new IllegalArgumentException("Key prefix cannot be empty.");
}
if (keyPrefix.endsWith(RedisUtils.KEY_SEPARATOR)) {
this.keyPrefix = keyPrefix;
} else {
this.keyPrefix = keyPrefix + RedisUtils.KEY_SEPARATOR;
@ -100,10 +102,11 @@ public class RedisMapCacheStore<V> extends RedisCacheStore<Map<String, V>> imple
public boolean put(CacheKey key, String field, V value) {
Objects.requireNonNull(field);
Objects.requireNonNull(value);
return connectionPool.executeRedis(jedis -> {
connectionPool.executeRedis(jedis -> {
String keyString = getKeyString(key);
return jedis.hset(keyString, field, converter.to(value)) == RedisUtils.RETURN_CODE_OK;
return jedis.hset(keyString, field, converter.to(value));
});
return true;
}
@Override
@ -162,17 +165,7 @@ public class RedisMapCacheStore<V> extends RedisCacheStore<Map<String, V>> imple
@Override
public boolean clearMap(CacheKey key) {
Set<String> fields = mapFieldSet(key);
if (fields == null) {
return false;
} else if (fields.size() == 0) {
return true;
}
String[] fieldsArray = new String[fields.size()];
fields.toArray(fieldsArray);
return connectionPool.executeRedis(jedis ->
jedis.hdel(getKeyString(key), fieldsArray) != RedisUtils.RETURN_CODE_FAILED);
return remove(key);
}
}

View File

@ -17,7 +17,6 @@
package net.lamgc.cgj.bot.cache.redis;
import com.google.common.base.Strings;
import net.lamgc.cgj.bot.cache.CacheKey;
import net.lamgc.cgj.bot.cache.SingleCacheStore;
import net.lamgc.cgj.bot.cache.convert.StringConverter;
@ -41,8 +40,11 @@ public class RedisSingleCacheStore<V> extends RedisCacheStore<V> implements Sing
public RedisSingleCacheStore(RedisConnectionPool connectionPool, String keyPrefix, StringConverter<V> converter) {
super(connectionPool);
this.connectionPool = connectionPool;
keyPrefix = Strings.nullToEmpty(keyPrefix).trim();
if (!keyPrefix.isEmpty() && keyPrefix.endsWith(RedisUtils.KEY_SEPARATOR)) {
keyPrefix = Objects.requireNonNull(keyPrefix).trim();
if (keyPrefix.isEmpty()) {
throw new IllegalArgumentException("Key prefix cannot be empty.");
}
if (keyPrefix.endsWith(RedisUtils.KEY_SEPARATOR)) {
this.keyPrefix = keyPrefix;
} else {
this.keyPrefix = keyPrefix + RedisUtils.KEY_SEPARATOR;

View File

@ -0,0 +1,211 @@
/*
* Copyright (C) 2021 LamGC
*
* ContentGrabbingJi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License.
*
* ContentGrabbingJi 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. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.lamgc.cgj.bot.cache.redis;
import net.lamgc.cgj.bot.cache.CacheKey;
import org.junit.*;
import redis.clients.jedis.Jedis;
import java.util.HashSet;
import java.util.Set;
import static net.lamgc.cgj.bot.cache.redis.util.RedisTestUtils.assertDeleteIfExist;
import static net.lamgc.cgj.bot.cache.redis.util.RedisTestUtils.randomString;
/**
* @see RedisCacheStore
*/
public class RedisCacheStoreTest {
private final static String KEY_PREFIX = "test:store";
private static RedisConnectionPool connectionPool;
private static RedisCacheStore<String> cacheStore;
private static Jedis jedis;
@BeforeClass
public static void beforeAllTest() {
jedis = new Jedis();
connectionPool = new RedisConnectionPool();
cacheStore = new SimpleRedisCacheStore(connectionPool, KEY_PREFIX);
}
@AfterClass
public static void afterAllTest() {
if (jedis != null && jedis.isConnected()) {
jedis.close();
}
connectionPool.close();
}
@Before
public void beforeTest() {
clearAllKey();
}
@After
public void afterTest() {
clearAllKey();
}
private void clearAllKey() {
Set<String> keys = jedis.keys(RedisUtils.toRedisCacheKey(KEY_PREFIX, RedisUtils.CACHE_KEY_ALL));
if (keys.isEmpty()) {
return;
}
String[] keyArray = new String[keys.size()];
keys.toArray(keyArray);
Assert.assertEquals("Failed to delete test key.",
keyArray.length, jedis.del(keyArray).intValue());
}
@Test
public void setTimeToLiveTest() {
final CacheKey key = new CacheKey("test_set_time_to_live");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
final long timeToLive = 500;
assertDeleteIfExist(jedis, keyString);
Assert.assertFalse("TTL set successfully for nonexistent key.", cacheStore.setTimeToLive(key, timeToLive));
Assert.assertTrue("Failed to set key value for test.", RedisUtils.isOk(jedis.set(keyString, "value")));
Assert.assertTrue("Failed to set TTL on key value.", cacheStore.setTimeToLive(key, timeToLive));
long currentTTL = jedis.ttl(keyString);
Assert.assertTrue("TTL was not set successfully.", currentTTL >= 0);
Assert.assertTrue("The actual set TTL is greater than expected.",
currentTTL < timeToLive);
Assert.assertTrue("Failed to clear TTL on key value.", cacheStore.setTimeToLive(key, -1));
currentTTL = jedis.ttl(keyString);
Assert.assertTrue("TTL was not clear successfully.", currentTTL < 0);
}
@Test
public void getTimeToLiveTest() {
final CacheKey key = new CacheKey("test_get_time_to_live");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
final long timeToLive = 500;
assertDeleteIfExist(jedis, keyString);
Assert.assertEquals("The getTimeToLive() method returned a positive integer for a nonexistent key.",
-1, cacheStore.getTimeToLive(key));
Assert.assertTrue("Failed to set key value for test.", RedisUtils.isOk(jedis.set(keyString, "value")));
Assert.assertEquals("Failed to set TTL on key value.", 1, jedis.pexpire(keyString, timeToLive).intValue());
long currentTTL = cacheStore.getTimeToLive(key);
Assert.assertTrue("TTL failed to get.", currentTTL > 0);
Assert.assertTrue("The actual set TTL is greater than expected.",
currentTTL <= timeToLive);
Assert.assertTrue("The actual set TTL is greater than expected.",
currentTTL >= (timeToLive - 5));
Assert.assertEquals("Failed to clear TTL on key value.",
1, jedis.persist(keyString).intValue());
currentTTL = cacheStore.getTimeToLive(key);
Assert.assertTrue("TTL was not clear successfully.", currentTTL < 0);
}
@Test
public void sizeTest() {
final String keyPrefix =
RedisUtils.toRedisCacheKey(KEY_PREFIX, new CacheKey("test_size")) + ':';
final String allKey = RedisUtils.toRedisCacheKey(keyPrefix, RedisUtils.CACHE_KEY_ALL);
for (int i = 0; i < 50; i++) {
Assert.assertTrue("Failed to add key.", RedisUtils.isOk(
jedis.set(
RedisUtils.toRedisCacheKey(keyPrefix, new CacheKey(randomString(8))),
randomString(10)
)));
Assert.assertEquals("Inconsistent number of keys.", jedis.keys(allKey).size(), cacheStore.size());
}
}
@Test
public void existsTest() {
final CacheKey key = new CacheKey("test_exists");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
assertDeleteIfExist(jedis, keyString);
Assert.assertFalse("The exists() method returned 'true' for a nonexistent key.", cacheStore.exists(key));
Assert.assertTrue("Failed to set key value for test.", RedisUtils.isOk(jedis.set(keyString, "value")));
Assert.assertTrue("The exists() method returned 'false' for the existing key.", cacheStore.exists(key));
}
@Test
public void removeTest() {
final CacheKey key = new CacheKey("test_remove");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
assertDeleteIfExist(jedis, keyString);
Assert.assertFalse("Attempt to delete nonexistent key succeeded.", cacheStore.remove(key));
Assert.assertTrue("Failed to set key value for test.", RedisUtils.isOk(jedis.set(keyString, "value")));
Assert.assertTrue("Key deletion failed.", cacheStore.remove(key));
}
@Test
public void clearTest() {
final CacheKey key = new CacheKey("test_clear");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
final String externalKey = "test:external";
Assert.assertTrue("Failed to set external key.", RedisUtils.isOk(jedis.set(externalKey, "externalValue")));
Assert.assertTrue("Failed to set test key.", RedisUtils.isOk(jedis.set(keyString, "testValue")));
Assert.assertNotEquals("The cache store is empty.",
0, jedis.keys(RedisUtils.toRedisCacheKey(KEY_PREFIX, RedisUtils.CACHE_KEY_ALL)).size());
Assert.assertTrue(cacheStore.clear());
Assert.assertEquals("The cache store is not empty.",
0, jedis.keys(RedisUtils.toRedisCacheKey(KEY_PREFIX, RedisUtils.CACHE_KEY_ALL)).size());
Assert.assertTrue("External key removed.", jedis.exists(externalKey));
}
@Test
public void keySetTest() {
clearAllKey();
Set<String> actualKeys = cacheStore.keySet();
Assert.assertNotNull("keySet() returned 'null'.", actualKeys);
Assert.assertEquals("CacheStore is empty, but keySet() is not empty.", 0, actualKeys.size());
Set<String> expectKeys = new HashSet<>();
for (int i = 0; i < 50; i++) {
String nextKey = randomString(10);
expectKeys.add(nextKey);
Assert.assertTrue("Failed to set key value for test.",
RedisUtils.isOk(jedis.set(KEY_PREFIX + RedisUtils.KEY_SEPARATOR + nextKey, nextKey)));
}
actualKeys = cacheStore.keySet();
Assert.assertNotNull("keySet() returned 'null'.", actualKeys);
Assert.assertEquals("Number of keys not as expected.", expectKeys.size(), actualKeys.size());
for (String actualKey : actualKeys) {
Assert.assertTrue(String.format("Key '%s' does not belong to the expected key.", actualKey),
expectKeys.contains(actualKey));
}
}
}

View File

@ -21,10 +21,7 @@ import net.lamgc.cgj.bot.cache.CacheKey;
import net.lamgc.cgj.bot.cache.ListCacheStore;
import net.lamgc.cgj.bot.cache.convert.StringConverter;
import net.lamgc.cgj.bot.cache.convert.StringToStringConverter;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.*;
import redis.clients.jedis.Jedis;
import java.lang.reflect.Field;
@ -35,18 +32,26 @@ import java.util.*;
*/
public class RedisListCacheStoreTest {
private final Jedis jedis = new Jedis();
private static Jedis jedis;
private final static StringConverter<String> CONVERTER = new StringToStringConverter();
private final static String IDENTIFY = "test:list";
private static RedisConnectionPool connectionPool;
@BeforeClass
public static void beforeAllTest() {
jedis = new Jedis();
connectionPool = new RedisConnectionPool();
connectionPool.reconnectRedis();
Assert.assertTrue("Redis is not connected.", connectionPool.available());
}
@AfterClass
public static void afterAllTest() {
if (jedis != null) {
jedis.close();
}
}
private ListCacheStore<String> newListCacheStore() {
return new RedisListCacheStore<>(connectionPool, IDENTIFY, CONVERTER);
}
@ -72,10 +77,12 @@ public class RedisListCacheStoreTest {
final Field prefixField = RedisListCacheStore.class.getDeclaredField("keyPrefix");
prefixField.setAccessible(true);
String prefix = (String) prefixField.get(new RedisListCacheStore<>(connectionPool, IDENTIFY, CONVERTER));
Assert.assertTrue(prefix.endsWith(RedisUtils.KEY_SEPARATOR));
Assert.assertTrue("The prefix does not contain a separator at the end.",
prefix.endsWith(RedisUtils.KEY_SEPARATOR));
prefix = (String) prefixField.get(new RedisListCacheStore<>(connectionPool,
IDENTIFY + RedisUtils.KEY_SEPARATOR, CONVERTER));
Assert.assertTrue(prefix.endsWith(RedisUtils.KEY_SEPARATOR));
Assert.assertTrue("The separator at the end of the prefix is missing.",
prefix.endsWith(RedisUtils.KEY_SEPARATOR));
prefixField.setAccessible(false);
}
@ -95,10 +102,14 @@ public class RedisListCacheStoreTest {
final CacheKey listKey = new CacheKey("list_add_element");
final String element = "test";
final String listKeyStr = RedisUtils.toRedisCacheKey(IDENTIFY, listKey);
Assert.assertTrue(listCacheStore.addElement(listKey, element));
final int lastCount = jedis.llen(listKeyStr).intValue();
Assert.assertTrue("The operation to be tested failed.",
listCacheStore.addElement(listKey, element));
Assert.assertEquals(1, jedis.llen(listKeyStr).intValue());
Assert.assertEquals(element, jedis.lpop(listKeyStr));
Assert.assertEquals("The key value has no change to the quantity.",
lastCount + 1, jedis.llen(listKeyStr).intValue());
Assert.assertEquals("The value of pop is different from that of push.",
element, jedis.lpop(listKeyStr));
}
@Test
@ -117,12 +128,14 @@ public class RedisListCacheStoreTest {
jedis.exists(listKeyStr),
listCacheStore.addElements(listKey, Collections.emptyList()));
Assert.assertTrue("The operation to be tested failed.",
listCacheStore.addElements(listKey, expectedElements));
Assert.assertTrue(listCacheStore.addElements(listKey, expectedElements));
Assert.assertEquals(expectedElements.size(), jedis.llen(listKeyStr).intValue());
Assert.assertEquals("The quantity is not as expected.",
expectedElements.size(), jedis.llen(listKeyStr).intValue());
Set<String> actualElements = getListElements(listKeyStr);
Assert.assertTrue(actualElements.containsAll(expectedElements));
Assert.assertTrue("The added value is not as expected.",
actualElements.containsAll(expectedElements));
Assert.assertEquals("Key does not exist, but adding empty collection failed.",
jedis.exists(listKeyStr),
@ -146,7 +159,8 @@ public class RedisListCacheStoreTest {
jedis.del(listKeyStr);
Assert.assertFalse(listCacheStore.removeElement(listKey, "NoExistElement"));
Assert.assertFalse("The operation to be tested failed.",
listCacheStore.removeElement(listKey, "NoExistElement"));
Assert.assertNotEquals("The expected create operation failed.",
RedisUtils.RETURN_CODE_FAILED, jedis.lpush(listKeyStr, expectedElementsArr).intValue());
@ -158,9 +172,11 @@ public class RedisListCacheStoreTest {
expectedElements.remove(deletedIndex);
Assert.assertEquals(expectedElements.size(), jedis.llen(listKeyStr).intValue());
Assert.assertEquals("The quantity is not as expected.",
expectedElements.size(), jedis.llen(listKeyStr).intValue());
Set<String> actualElements = getListElements(listKeyStr);
Assert.assertTrue(actualElements.containsAll(expectedElements));
Assert.assertTrue("The added value is not as expected.",
actualElements.containsAll(expectedElements));
}
@Test
@ -180,10 +196,11 @@ public class RedisListCacheStoreTest {
jedis.del(listKeyStr);
// 尝试删除不存在的 Key
Assert.assertFalse(listCacheStore.removeElement(listKey, 0));
Assert.assertFalse("The attempt to delete a value that does not exist succeeded.",
listCacheStore.removeElement(listKey, 0));
Assert.assertNotEquals("The expected create operation failed.",
RedisUtils.RETURN_CODE_FAILED, jedis.lpush(listKeyStr, expectedElementsArr).intValue());
Assert.assertFalse(
Assert.assertFalse("The attempt to delete the value of the illegal index succeeded.",
listCacheStore.removeElement(listKey, jedis.llen(listKeyStr).intValue()));
Random random = new Random();
@ -195,9 +212,11 @@ public class RedisListCacheStoreTest {
expectedElements.remove(deletedElement);
Assert.assertEquals(expectedElements.size(), jedis.llen(listKeyStr).intValue());
Assert.assertEquals("The quantity is not as expected.",
expectedElements.size(), jedis.llen(listKeyStr).intValue());
Set<String> actualElements = getListElements(listKeyStr);
Assert.assertTrue(actualElements.containsAll(expectedElements));
Assert.assertTrue("The added value is not as expected.",
actualElements.containsAll(expectedElements));
}
@Test
@ -215,7 +234,7 @@ public class RedisListCacheStoreTest {
final String[] expectedElementsArr = new String[expectedElements.size()];
expectedElements.toArray(expectedElementsArr);
Assert.assertNotEquals(-1, jedis.lpush(listKeyStr, expectedElementsArr).intValue());
jedis.lpush(listKeyStr, expectedElementsArr);
Set<String> actualElements = getListElements(listKeyStr);
expectedElements.add("f");
@ -224,7 +243,7 @@ public class RedisListCacheStoreTest {
expectedElements.add("i");
for (String expectedElement : expectedElements) {
Assert.assertEquals(String.format("Make a difference: '%s'", expectedElement),
Assert.assertEquals(String.format("Make a difference: '%s'.", expectedElement),
actualElements.contains(expectedElement),
listCacheStore.containsElement(listKey, expectedElement));
}
@ -236,9 +255,11 @@ public class RedisListCacheStoreTest {
final CacheKey listKey = new CacheKey("list_is_empty");
final String listKeyStr = RedisUtils.toRedisCacheKey(IDENTIFY, listKey);
Assert.assertEquals(!jedis.exists(listKeyStr), listCacheStore.isEmpty(listKey));
Assert.assertEquals("Key does not exist but returns 'true'",
!jedis.exists(listKeyStr), listCacheStore.isEmpty(listKey));
jedis.lpush(listKeyStr, "test");
Assert.assertEquals(jedis.exists(listKeyStr), !listCacheStore.isEmpty(listKey));
Assert.assertEquals("Key does exist but returns 'false'.",
jedis.exists(listKeyStr), !listCacheStore.isEmpty(listKey));
}
@Test
@ -257,15 +278,18 @@ public class RedisListCacheStoreTest {
long beforeLength = jedis.llen(listKeyStr);
if (jedis.llen(listKeyStr) == 0) {
Assert.assertEquals(-1, listCacheStore.elementsLength(listKey));
Assert.assertEquals("The list was empty but returned a value other than '-1' or '0'.",
-1, listCacheStore.elementsLength(listKey));
} else {
Assert.assertEquals(beforeLength, listCacheStore.elementsLength(listKey));
Assert.assertEquals("The length of the list is incorrect.",
beforeLength, listCacheStore.elementsLength(listKey));
}
jedis.del(listKeyStr);
jedis.lpush(listKeyStr, expectedElementsArr);
Assert.assertEquals(jedis.llen(listKeyStr).intValue(), listCacheStore.elementsLength(listKey));
Assert.assertEquals("The length of the list is incorrect.",
jedis.llen(listKeyStr).intValue(), listCacheStore.elementsLength(listKey));
}
@Test
@ -282,13 +306,16 @@ public class RedisListCacheStoreTest {
final String[] expectedElementsArr = new String[expectedElements.size()];
expectedElements.toArray(expectedElementsArr);
Assert.assertEquals(jedis.exists(listKeyStr), listCacheStore.clearCollection(listKey));
Assert.assertEquals("The list does not exist but returns 'true'.",
jedis.exists(listKeyStr), listCacheStore.clearCollection(listKey));
jedis.lpush(listKeyStr, expectedElementsArr);
Assert.assertTrue(listCacheStore.clearCollection(listKey));
Assert.assertEquals(0, jedis.llen(listKeyStr).intValue());
Assert.assertFalse(jedis.exists(listKeyStr));
Assert.assertTrue("The operation to be tested failed.",
listCacheStore.clearCollection(listKey));
Assert.assertEquals("The list is not empty after the clear operation",
0, jedis.llen(listKeyStr).intValue());
Assert.assertFalse("The list is still exist", jedis.exists(listKeyStr));
}
@Test
@ -308,7 +335,7 @@ public class RedisListCacheStoreTest {
Collections.reverse(expectedElements);
for (int i = 0; i < expectedElements.size(); i++) {
Assert.assertEquals("index: " + i, expectedElements.get(i),
Assert.assertEquals("Wrong value, index: " + i, expectedElements.get(i),
listCacheStore.getElement(listKey, i));
}
}
@ -342,7 +369,8 @@ public class RedisListCacheStoreTest {
List<String> actualElements = listCacheStore.getElementsByRange(listKey, start, length);
for (int i = 0; i < length; i++) {
Assert.assertEquals(expectedElements.get(start + i), actualElements.get(i));
Assert.assertEquals("Wrong value, index: " + i,
expectedElements.get(start + i), actualElements.get(i));
}
}

View File

@ -21,55 +21,100 @@ package net.lamgc.cgj.bot.cache.redis;
import com.google.common.base.Throwables;
import net.lamgc.cgj.bot.cache.CacheKey;
import net.lamgc.cgj.bot.cache.MapCacheStore;
import net.lamgc.cgj.bot.cache.convert.StringConverter;
import net.lamgc.cgj.bot.cache.convert.StringToStringConverter;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.*;
import org.junit.rules.TemporaryFolder;
import redis.clients.jedis.Jedis;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static net.lamgc.cgj.bot.cache.redis.util.RedisTestUtils.assertDeleteIfExist;
import static net.lamgc.cgj.bot.cache.redis.util.RedisTestUtils.randomString;
/**
* @see RedisMapCacheStore
*/
public class RedisMapCacheStoreTest {
private final static RedisCacheStoreFactory factory;
private final static TemporaryFolder tempFolder = TemporaryFolder.builder().build();
private final static String KEY_PREFIX = "test:map";
private final static StringConverter<String> CONVERTER = new StringToStringConverter();
private final static RedisCacheStoreFactory factory = new RedisCacheStoreFactory();
static {
private static MapCacheStore<String> cacheStore;
private static Jedis jedis;
@BeforeClass
public static void beforeAll() {
jedis = new Jedis();
try {
tempFolder.create();
} catch (IOException e) {
Assert.fail(Throwables.getStackTraceAsString(e));
return;
}
factory = new RedisCacheStoreFactory();
try {
factory.initial(tempFolder.newFolder("cache-redis"));
factory.initial(tempFolder.newFolder("Redis"));
cacheStore =
factory.newMapCacheStore(KEY_PREFIX, CONVERTER);
} catch (IOException e) {
Assert.fail(Throwables.getStackTraceAsString(e));
}
}
private final static MapCacheStore<String> cacheStore = factory.newMapCacheStore("test:map", new StringToStringConverter());
@AfterClass
public static void afterAll() {
if (jedis != null) {
jedis.close();
}
}
@Before
public void before() {
Assert.assertTrue(cacheStore.clear());
Assert.assertTrue("Clear execution failed before the test started.", cacheStore.clear());
}
@After
public void after() {
Assert.assertTrue(cacheStore.clear());
Assert.assertTrue("After the test, clear execution failed", cacheStore.clear());
}
@Test(expected = IllegalArgumentException.class)
public void emptyPrefixTest() {
factory.newMapCacheStore("", CONVERTER);
}
@Test(expected = NullPointerException.class)
public void nullPrefixTest() {
factory.newMapCacheStore(null, CONVERTER);
}
@Test
public void prefixCheck() throws NoSuchFieldException, IllegalAccessException {
final Field prefixField = RedisMapCacheStore.class.getDeclaredField("keyPrefix");
prefixField.setAccessible(true);
String prefix = (String) prefixField.get(factory.newMapCacheStore(KEY_PREFIX, CONVERTER));
Assert.assertTrue("The prefix does not contain a separator at the end.",
prefix.endsWith(RedisUtils.KEY_SEPARATOR));
prefix = (String) prefixField.get(factory.newMapCacheStore(
KEY_PREFIX + RedisUtils.KEY_SEPARATOR, CONVERTER));
Assert.assertTrue("The separator at the end of the prefix is missing.",
prefix.endsWith(RedisUtils.KEY_SEPARATOR));
prefixField.setAccessible(false);
}
@Test
public void nullThrowTest() {
final CacheKey key = new CacheKey("testKey");
final CacheKey key = new CacheKey("test_null_throw");
Assert.assertThrows(NullPointerException.class, () -> cacheStore.mapSize(null));
Assert.assertThrows(NullPointerException.class, () -> cacheStore.mapFieldSet(null));
Assert.assertThrows(NullPointerException.class, () -> cacheStore.mapValueSet(null));
@ -90,86 +135,280 @@ public class RedisMapCacheStoreTest {
}
@Test
public void keyNotExistTest() {
final CacheKey key = new CacheKey("testKey");
HashMap<String, String> testMap = new HashMap<>();
testMap.put("testField", "value");
public void putTest() {
final CacheKey key = new CacheKey("test_put");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
final String field = "field01";
final String value = "value01";
// 例外情况: 因为 Redis 对空 Map 的处理机制, 导致返回只能为空.
Assert.assertEquals(0, cacheStore.mapSize(key));
// 例外情况: mapIsEmpty 在 Redis 没有相应指令, 所以是依靠 mapSize 实现的,
// 同样因 mapSize 的原因, 不存在等于空.
Assert.assertTrue(cacheStore.mapIsEmpty(key));
Assert.assertFalse(cacheStore.clearMap(key));
Assert.assertFalse(cacheStore.containsField(key, "Field"));
Assert.assertFalse(cacheStore.removeField(key, "Field"));
Assert.assertNull(cacheStore.get(key, "Field"));
Assert.assertTrue(cacheStore.put(key, "Field", "value"));
Assert.assertTrue("clearMap operation failed!", cacheStore.remove(key));
Assert.assertTrue(cacheStore.putAll(key, testMap));
Assert.assertTrue("clearMap operation failed!", cacheStore.remove(key));
Assert.assertTrue(cacheStore.putIfNotExist(key, "Field", "value"));
if (jedis.hexists(keyString, field)) {
Assert.assertEquals("The field used by the test is occupied and deletion failed.",
1, jedis.hdel(keyString, field).intValue());
}
Assert.assertTrue("The operation to be tested failed.", cacheStore.put(key, field, value));
Assert.assertTrue("The field does not exist after put.", jedis.hexists(keyString, field));
Assert.assertEquals("The value of the field changes after put.", value, jedis.hget(keyString, field));
}
@Test
public void putAndGetTest() {
final CacheKey key = new CacheKey("testKey");
final Map<String, String> expectedMap = new HashMap<>();
expectedMap.put("test01", "testValue01");
expectedMap.put("test02", "testValue02");
expectedMap.put("test03", "testValue03");
expectedMap.put("test04", "testValue04");
expectedMap.put("test05", "testValue05");
expectedMap.put("test06", "testValue06");
public void getTest() {
final CacheKey key = new CacheKey("test_get");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
final String field = "field01";
final String value = "value01";
// put/get, mapIsEmpty, containsField
Assert.assertTrue("put operation failed!", cacheStore.put(key, "test00", "testValue00"));
Assert.assertTrue(cacheStore.containsField(key, "test00"));
Assert.assertEquals("testValue00", cacheStore.get(key, "test00"));
Assert.assertTrue("removeField operation failed!", cacheStore.removeField(key, "test00"));
assertDeleteIfExist(jedis, keyString);
Assert.assertNull("Method returned a non null value for a field that does not exist.",
cacheStore.get(key, field));
// putIfNotExist
Assert.assertTrue(cacheStore.putIfNotExist(key, "test00", "testValue00"));
Assert.assertFalse(cacheStore.putIfNotExist(key, "test00", "testValue00"));
Assert.assertTrue("clearMap operation failed!", cacheStore.clearMap(key));
Assert.assertTrue("Failed to set the field used by the test.",
jedis.hset(keyString, field, value).intValue() >= 0);
Assert.assertTrue("The field used by the test does not exist.",
jedis.hexists(keyString, field));
// putAll
// empty map, key no exist
Assert.assertFalse(cacheStore.putAll(key, new HashMap<>()));
// non-empty map
Assert.assertTrue(cacheStore.putAll(key, expectedMap));
Assert.assertTrue(expectedMap.keySet().containsAll(cacheStore.mapFieldSet(key)));
Assert.assertTrue(expectedMap.values().containsAll(cacheStore.mapValueSet(key)));
// empty map, key exist
Assert.assertTrue(cacheStore.putAll(key, new HashMap<>()));
Assert.assertEquals("The obtained field value does not match the expected value.",
value, cacheStore.get(key, field));
}
@Test
public void fieldChangeTest() {
final CacheKey key = new CacheKey("testKey");
final Map<String, String> expectedMap = new HashMap<>();
expectedMap.put("test01", "testValue01");
expectedMap.put("test02", "testValue02");
expectedMap.put("test03", "testValue03");
expectedMap.put("test04", "testValue04");
expectedMap.put("test05", "testValue05");
expectedMap.put("test06", "testValue06");
public void putAllTest() {
final CacheKey key = new CacheKey("test_put_all");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
// mapSize, clearMap, mapIsEmpty 测试
Assert.assertTrue("putAll operation failed!", cacheStore.putAll(key, expectedMap));
Assert.assertEquals(expectedMap.size(), cacheStore.mapSize(key));
Assert.assertTrue(cacheStore.clearMap(key));
Assert.assertEquals(0, cacheStore.mapSize(key));
Assert.assertTrue(cacheStore.mapIsEmpty(key));
final Map<String, String> expectMap = new HashMap<>();
expectMap.put("field01", "value01");
expectMap.put("field02", "value02");
expectMap.put("field03", "value03");
expectMap.put("field04", "value04");
expectMap.put("field05", "value05");
expectMap.put("field06", "value06");
expectMap.put("field07", "value07");
// removeField 多分支测试
Assert.assertTrue("put operation failed!", cacheStore.put(key, "test00", "testValue00"));
Assert.assertTrue(cacheStore.containsField(key, "test00"));
Assert.assertEquals("testValue00", cacheStore.get(key, "test00"));
Assert.assertTrue("removeField operation failed!", cacheStore.removeField(key, "test00"));
Assert.assertFalse(cacheStore.removeField(key, "test00"));
assertDeleteIfExist(jedis, keyString);
Assert.assertEquals("The key does not exist, but the empty collection was added successfully.",
jedis.exists(keyString),
cacheStore.putAll(key, Collections.emptyMap()));
Assert.assertTrue("The operation to be tested failed.", cacheStore.putAll(key, expectMap));
Map<String, String> actualMap = jedis.hgetAll(keyString);
for (String actualKey : actualMap.keySet()) {
Assert.assertTrue("Field does not exist in the expected.", expectMap.containsKey(actualKey));
Assert.assertEquals("The value of field " + actualKey + " does not match the expected value.",
expectMap.get(actualKey), actualMap.get(actualKey));
}
Assert.assertEquals("Key does not exist, but adding empty collection failed.",
jedis.exists(keyString),
cacheStore.putAll(key, Collections.emptyMap()));
}
@Test
public void putIfNotExistTest() {
final CacheKey key = new CacheKey("test_put_if_not_exist");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
final String field = "field01";
final String value = "value01";
if (jedis.hexists(keyString, field)) {
Assert.assertEquals("The field used by the test is occupied and deletion failed.",
1, jedis.hdel(keyString, field).intValue());
}
Assert.assertTrue("Field does not exist but put failed.", cacheStore.putIfNotExist(key, field, value));
Assert.assertFalse("Field does exist but put successful.", cacheStore.putIfNotExist(key, field, value));
}
@Test
public void mapSizeTest() {
final CacheKey key = new CacheKey("test_map_size");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
final Map<String, String> expectMap = new HashMap<>();
expectMap.put("field01", "value01");
expectMap.put("field02", "value02");
expectMap.put("field03", "value03");
expectMap.put("field04", "value04");
expectMap.put("field05", "value05");
expectMap.put("field06", "value06");
expectMap.put("field07", "value07");
assertDeleteIfExist(jedis, keyString);
Assert.assertEquals("Non 0 returned when map does not exist.", 0, cacheStore.mapSize(key));
Assert.assertEquals("The number of test fields prepared is inconsistent.",
expectMap.size(), jedis.hset(keyString, expectMap).intValue());
Assert.assertEquals("The number of fields obtained does not match the actual number.",
expectMap.size(), cacheStore.mapSize(key));
}
@Test
public void mapIsEmptyTest() {
final CacheKey key = new CacheKey("test_put_if_not_exist");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
final String field = "field01";
final String value = "value01";
if (jedis.hlen(keyString) != 0) {
Assert.assertFalse("Map exists but returns 'true'.", cacheStore.mapIsEmpty(key));
Assert.assertEquals("Failed to delete map.", 1, jedis.del(keyString).intValue());
Assert.assertTrue("Map not exists but returns 'false'.", cacheStore.mapIsEmpty(key));
} else {
Assert.assertTrue("Map not exists but returns 'false'.", cacheStore.mapIsEmpty(key));
Assert.assertEquals("Failed to set field value for test.",
1, jedis.hset(keyString, field, value).intValue());
Assert.assertFalse("Map exists but returns 'true'.", cacheStore.mapIsEmpty(key));
}
}
@Test
public void mapFieldSetTest() {
final CacheKey key = new CacheKey("test_map_field_set");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
final Map<String, String> expectMap = new HashMap<>();
expectMap.put("field01", "value01");
expectMap.put("field02", "value02");
expectMap.put("field03", "value03");
expectMap.put("field04", "value04");
expectMap.put("field05", "value05");
expectMap.put("field06", "value06");
expectMap.put("field07", "value07");
assertDeleteIfExist(jedis, keyString);
Assert.assertNull("The mapFieldSet() method returned a non null value for a nonexistent map." +
"(If the map does not exist, null should be returned instead of an empty set)",
cacheStore.mapFieldSet(key));
Assert.assertEquals("The number of test fields prepared is inconsistent.",
expectMap.size(), jedis.hset(keyString, expectMap).intValue());
Set<String> fieldSet = cacheStore.mapFieldSet(key);
Assert.assertNotNull("Method returns 'null' for the existing map.", fieldSet);
Assert.assertTrue("The actual set is different from the expectation.",
fieldSet.containsAll(expectMap.keySet()));
Assert.assertTrue("The actual set is different from the expectation.",
expectMap.keySet().containsAll(fieldSet));
}
@Test
public void mapValueSetTest() {
final CacheKey key = new CacheKey("test_map_value_set");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
final Map<String, String> expectMap = new HashMap<>();
expectMap.put("field01", "value01");
expectMap.put("field02", "value02");
expectMap.put("field03", "value03");
expectMap.put("field04", "value04");
expectMap.put("field05", "value05");
expectMap.put("field06", "value06");
expectMap.put("field07", "value07");
assertDeleteIfExist(jedis, keyString);
Assert.assertNull("The mapValueSet() method returned a non null value for a nonexistent map." +
"(If the map does not exist, null should be returned instead of an empty set)",
cacheStore.mapValueSet(key));
Assert.assertEquals("The number of test fields prepared is inconsistent.",
expectMap.size(), jedis.hset(keyString, expectMap).intValue());
Set<String> valueSet = cacheStore.mapValueSet(key);
Assert.assertNotNull("Method returns 'null' for the existing map.", valueSet);
Assert.assertTrue("The actual set is different from the expectation.",
valueSet.containsAll(expectMap.values()));
Assert.assertTrue("The actual set is different from the expectation.",
expectMap.values().containsAll(valueSet));
}
@Test
public void removeFieldTest() {
final CacheKey key = new CacheKey("test_remove_field");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
final String field = "field";
final String value = "value";
final Map<String, String> expectMap = new HashMap<>();
expectMap.put("field01", "value01");
expectMap.put("field02", "value02");
expectMap.put("field03", "value03");
expectMap.put("field04", "value04");
expectMap.put("field05", "value05");
expectMap.put("field06", "value06");
expectMap.put("field07", "value07");
assertDeleteIfExist(jedis, keyString);
Assert.assertFalse("Returns 'true' when trying to delete a field in a nonexistent map.",
cacheStore.removeField(key, "field"));
Assert.assertEquals("Failed to add field for test.",
1, jedis.hset(keyString, field, value).intValue());
Assert.assertFalse("Returns 'true' when trying to delete a field that does not exist in the map.",
cacheStore.removeField(key, randomString(10)));
assertDeleteIfExist(jedis, keyString);
Assert.assertEquals("Failed to add field for test.",
expectMap.size(), jedis.hset(keyString, expectMap).intValue());
for (String expectField : expectMap.keySet()) {
Assert.assertTrue("The attempt to delete an existing field failed: '" + expectField + "'.",
cacheStore.removeField(key, expectField));
}
}
@Test
public void containsFieldTest() {
final CacheKey key = new CacheKey("test_contains_field");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
final String field = "field";
final String value = "value";
assertDeleteIfExist(jedis, keyString);
Assert.assertFalse("Returns 'true' when trying to check for a map that does not exist.",
cacheStore.containsField(key, "field"));
Assert.assertEquals("Failed to add field for test.",
1, jedis.hset(keyString, field, value).intValue());
Assert.assertFalse("Returns 'true' when trying to check for a field that does not exist.",
cacheStore.removeField(key, randomString(10)));
Assert.assertTrue("An attempt to check for existing fields returned 'false'.",
cacheStore.containsField(key, field));
}
@Test
public void clearMapTest() {
final CacheKey key = new CacheKey("test_remove_field");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
final Map<String, String> expectMap = new HashMap<>();
expectMap.put("field01", "value01");
expectMap.put("field02", "value02");
expectMap.put("field03", "value03");
expectMap.put("field04", "value04");
expectMap.put("field05", "value05");
expectMap.put("field06", "value06");
expectMap.put("field07", "value07");
assertDeleteIfExist(jedis, keyString);
Assert.assertFalse("Attempt to empty nonexistent map succeeded.", cacheStore.clearMap(key));
Assert.assertEquals("Failed to add field for test.",
expectMap.size(), jedis.hset(keyString, expectMap).intValue());
Assert.assertTrue("The operation to be tested failed.", cacheStore.clearMap(key));
Assert.assertEquals("After the clear operation, the map still contains fields.",
0, jedis.hlen(keyString).intValue());
}
}

View File

@ -17,18 +17,16 @@
package net.lamgc.cgj.bot.cache.redis;
import com.google.common.base.Throwables;
import net.lamgc.cgj.bot.cache.CacheKey;
import net.lamgc.cgj.bot.cache.SingleCacheStore;
import net.lamgc.cgj.bot.cache.convert.StringConverter;
import net.lamgc.cgj.bot.cache.convert.StringToStringConverter;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.*;
import redis.clients.jedis.Jedis;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.Field;
import static net.lamgc.cgj.bot.cache.redis.util.RedisTestUtils.*;
/**
* @see RedisCacheStore
@ -36,139 +34,109 @@ import java.util.Map;
*/
public class RedisSingleCacheStoreTest {
private final static RedisCacheStoreFactory factory;
private final static TemporaryFolder tempFolder = TemporaryFolder.builder().build();
private final static String KEY_PREFIX = "test:single";
private final static StringConverter<String> CONVERTER = new StringToStringConverter();
static {
try {
tempFolder.create();
} catch (IOException e) {
Assert.fail(Throwables.getStackTraceAsString(e));
}
factory = new RedisCacheStoreFactory();
try {
factory.initial(tempFolder.newFolder("cache-redis"));
} catch (IOException e) {
Assert.fail(Throwables.getStackTraceAsString(e));
}
private static Jedis jedis;
private final RedisConnectionPool connectionPool = new RedisConnectionPool();
private final SingleCacheStore<String> cacheStore =
new RedisSingleCacheStore<>(connectionPool, KEY_PREFIX, CONVERTER);
@BeforeClass
public static void beforeAllTest() {
jedis = new Jedis();
}
private final static SingleCacheStore<String> cacheStore = factory.newSingleCacheStore("test:single", new StringToStringConverter());
@AfterClass
public static void afterAllTest() {
if (jedis != null && jedis.isConnected()) {
jedis.close();
}
}
@Before
public void before() {
Assert.assertTrue(cacheStore.clear());
Assert.assertTrue("Clear execution failed before the test started.", cacheStore.clear());
}
@After
public void after() {
Assert.assertTrue("After the test, clear execution failed", cacheStore.clear());
}
@Test(expected = IllegalArgumentException.class)
public void emptyPrefixTest() {
new RedisSingleCacheStore<>(connectionPool, "", CONVERTER);
}
@Test(expected = NullPointerException.class)
public void nullPrefixTest() {
new RedisSingleCacheStore<>(connectionPool, null, CONVERTER);
}
@Test
public void nullThrowTest() {
final SingleCacheStore<String> tempCacheStore = factory.newSingleCacheStore("test:single" + RedisUtils.KEY_SEPARATOR, new StringToStringConverter());
final CacheKey key = new CacheKey("testKey");
// RedisSingleCacheStore
Assert.assertThrows(NullPointerException.class, () -> tempCacheStore.set(null, "testValue"));
Assert.assertThrows(NullPointerException.class, () -> tempCacheStore.set(key, null));
Assert.assertThrows(NullPointerException.class, () -> tempCacheStore.get(null));
Assert.assertThrows(NullPointerException.class, () -> tempCacheStore.setIfNotExist(null, "testValue"));
Assert.assertThrows(NullPointerException.class, () -> tempCacheStore.setIfNotExist(key, null));
// RedisCacheStore
Assert.assertThrows(NullPointerException.class, () -> tempCacheStore.exists(null));
Assert.assertThrows(NullPointerException.class, () -> tempCacheStore.getTimeToLive(null));
Assert.assertThrows(NullPointerException.class, () -> tempCacheStore.setTimeToLive(null, 0));
Assert.assertThrows(NullPointerException.class, () -> tempCacheStore.remove(null));
public void prefixCheck() throws NoSuchFieldException, IllegalAccessException {
final Field prefixField = RedisSingleCacheStore.class.getDeclaredField("keyPrefix");
prefixField.setAccessible(true);
String prefix = (String) prefixField.get(new RedisSingleCacheStore<>(connectionPool, KEY_PREFIX, CONVERTER));
Assert.assertTrue("The prefix does not contain a separator at the end.",
prefix.endsWith(RedisUtils.KEY_SEPARATOR));
prefix = (String) prefixField.get(new RedisSingleCacheStore<>(connectionPool,
KEY_PREFIX + RedisUtils.KEY_SEPARATOR, CONVERTER));
Assert.assertTrue("The separator at the end of the prefix is missing.",
prefix.endsWith(RedisUtils.KEY_SEPARATOR));
prefixField.setAccessible(false);
}
@Test
public void setAndGetTest() {
final CacheKey key = new CacheKey("testKey");
final String value = "testValue";
Assert.assertTrue("Set operation failed!", cacheStore.set(key, value));
Assert.assertEquals(value, cacheStore.get(key));
Assert.assertTrue("Remove operation failed!", cacheStore.remove(key));
Assert.assertNull("Set operation failed!", cacheStore.get(key));
@Test
public void setTest() {
final CacheKey key = new CacheKey("test_set");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
String value = randomString(10);
assertDeleteIfExist(jedis, keyString);
Assert.assertTrue("Failed to set value on specified key.", cacheStore.set(key, value));
Assert.assertEquals("The value set does not match the expected value.",
value, jedis.get(keyString));
value = randomString(12);
Assert.assertTrue("Cannot rewritten the value of an existing key.", cacheStore.set(key, value));
Assert.assertEquals("The rewritten value does not match the expected value.",
value, jedis.get(keyString));
}
@Test
public void setIfNotExistTest() {
final CacheKey key = new CacheKey("testKey");
final String value = "testValue";
final String value2 = "testValue02";
Assert.assertTrue("Set operation failed!", cacheStore.set(key, value));
final CacheKey key = new CacheKey("test_set_if_not_exist");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
String value = randomString(10);
assertDeleteIfExist(jedis, keyString);
Assert.assertFalse(cacheStore.setIfNotExist(key, value2));
Assert.assertEquals(value, cacheStore.get(key));
Assert.assertTrue("Failed to set value on specified key.", cacheStore.setIfNotExist(key, value));
Assert.assertEquals("The value set does not match the expected value.",
value, jedis.get(keyString));
value = randomString(12);
Assert.assertFalse("Write value to existing key succeeded.", cacheStore.setIfNotExist(key, value));
Assert.assertNotEquals("The key value is modified and the method setIfNotExist() returns 'false'.",
value, jedis.get(keyString));
}
@Test
public void expireTest() throws InterruptedException {
final CacheKey key = new CacheKey("testKey");
final String value = "testValue";
public void getTest() {
final CacheKey key = new CacheKey("test_get");
final String keyString = RedisUtils.toRedisCacheKey(KEY_PREFIX, key);
String value = randomString(10);
assertDeleteIfExist(jedis, keyString);
// Cache
Assert.assertFalse(cacheStore.setTimeToLive(key, 300));
Assert.assertEquals(-1, cacheStore.getTimeToLive(key));
Assert.assertNull("The get() method returned a non null value for a nonexistent key.",
cacheStore.get(key));
// TTL 到期被动检查测试: 使用 exists 经 expire 检查失败后返回 false.
Assert.assertTrue("Set operation failed!", cacheStore.set(key, value));
Assert.assertTrue("SetTTL operation failed!", cacheStore.setTimeToLive(key, 200));
Assert.assertNotEquals(-1, cacheStore.getTimeToLive(key));
Thread.sleep(300);
Assert.assertFalse(cacheStore.exists(key));
Assert.assertTrue("Failed to set test key.", RedisUtils.isOk(jedis.set(keyString, value)));
// 取消 TTL 测试
Assert.assertTrue("Set operation failed!", cacheStore.set(key, value));
Assert.assertTrue("SetTTL operation failed!", cacheStore.setTimeToLive(key, 200));
Assert.assertTrue("SetTTL operation failed!", cacheStore.setTimeToLive(key, -1));
Thread.sleep(300);
Assert.assertTrue(cacheStore.exists(key));
Assert.assertEquals(-1, cacheStore.getTimeToLive(key));
Assert.assertEquals("The value obtained does not match the expected value.",
value, cacheStore.get(key));
}
@Test
public void removeTest() {
final CacheKey key = new CacheKey("testKey");
final String value = "testValue";
// 删除不存在Cache测试
Assert.assertFalse(cacheStore.remove(key));
// 删除存在的Cache测试
Assert.assertTrue("Set operation failed!", cacheStore.set(key, value));
Assert.assertTrue(cacheStore.remove(key));
}
@Test
public void clearTest() {
final SingleCacheStore<String> secondSingleCacheStore =
factory.newSingleCacheStore("test:single_b", new StringToStringConverter());
final CacheKey key = new CacheKey("testKey");
final String value = "testValue";
Assert.assertTrue("Set operation failed!", cacheStore.set(key, value));
Assert.assertTrue("Set operation failed!", secondSingleCacheStore.set(key, value));
Assert.assertTrue(cacheStore.exists(key));
Assert.assertTrue("Clear operation failed!", cacheStore.clear());
Assert.assertFalse(cacheStore.exists(key));
Assert.assertTrue(secondSingleCacheStore.exists(key));
}
@Test
public void sizeAndKeySetTest() {
Map<String, String> expectedMap = new HashMap<>();
expectedMap.put("test01", "testValue01");
expectedMap.put("test02", "testValue02");
expectedMap.put("test03", "testValue03");
expectedMap.put("test04", "testValue04");
expectedMap.put("test05", "testValue05");
expectedMap.put("test06", "testValue06");
Assert.assertEquals(0, cacheStore.size());
expectedMap.forEach((key, value) -> cacheStore.set(new CacheKey(key), value));
Assert.assertEquals(expectedMap.size(), cacheStore.size());
Assert.assertTrue(expectedMap.keySet().containsAll(cacheStore.keySet()));
Assert.assertTrue(cacheStore.keySet().containsAll(expectedMap.keySet()));
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2021 LamGC
*
* ContentGrabbingJi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License.
*
* ContentGrabbingJi 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. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.lamgc.cgj.bot.cache.redis;
import net.lamgc.cgj.bot.cache.CacheKey;
import org.junit.Assert;
import org.junit.Test;
/**
* @see RedisUtils
*/
public class RedisUtilsTest {
@Test
public void isOkTest() {
Assert.assertTrue(RedisUtils.isOk("OK"));
Assert.assertTrue(RedisUtils.isOk("ok"));
Assert.assertFalse(RedisUtils.isOk("Failed"));
}
@Test
public void toRedisCacheKey() {
final CacheKey key = new CacheKey("test");
final String prefix = "prefix";
Assert.assertEquals("prefix:test", RedisUtils.toRedisCacheKey(prefix, key));
Assert.assertEquals("prefix:test", RedisUtils.toRedisCacheKey(prefix + RedisUtils.KEY_SEPARATOR, key));
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2021 LamGC
*
* ContentGrabbingJi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License.
*
* ContentGrabbingJi 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. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.lamgc.cgj.bot.cache.redis;
public class SimpleRedisCacheStore extends RedisCacheStore<String> {
private final String keyPrefix;
protected SimpleRedisCacheStore(RedisConnectionPool connectionPool, String keyPrefix) {
super(connectionPool);
this.keyPrefix = keyPrefix;
}
@Override
protected String getKeyPrefix() {
return keyPrefix;
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (C) 2021 LamGC
*
* ContentGrabbingJi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License.
*
* ContentGrabbingJi 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. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.lamgc.cgj.bot.cache.redis.util;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.lamgc.cgj.bot.cache.redis.RedisConnectionProperties;
import net.lamgc.cgj.bot.cache.redis.RedisUtils;
import org.junit.Assert;
import redis.clients.jedis.Jedis;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.Random;
/**
*
* @author LamGC
*/
public final class RedisTestUtils {
private RedisTestUtils() {}
private final static Gson GSON_INSTANCE = new GsonBuilder()
.serializeNulls()
.setPrettyPrinting()
.create();
/**
* 创建测试用配置文件.
* @param testDirectory 组件文件夹.
* @param properties 配置对象.
* @throws IOException 当配置文件写入失败时抛出.
*/
public static void createConnectionProperties(File testDirectory, RedisConnectionProperties properties)
throws IOException {
File propertiesFile = new File(testDirectory, "Redis/" + RedisUtils.PROPERTIES_FILE_NAME);
Files.write(propertiesFile.toPath(),
GSON_INSTANCE.toJson(properties).getBytes(StandardCharsets.UTF_8),
StandardOpenOption.CREATE);
}
/**
* 如果存在键, 则删除, 如果失败则判定断言失败.
* @param jedis Jedis 对象.
* @param keyString 待删除的键名.
*/
public static void assertDeleteIfExist(Jedis jedis, String keyString) {
if (jedis.exists(keyString)) {
Assert.assertEquals("The key used by the test is occupied and deletion failed.",
1, jedis.del(keyString).intValue());
}
}
/**
* 随机字符串.
* @param length 长度.
* @return 返回指定长度的随机字符串.
*/
public static String randomString(int length) {
final char[] chars = new char[] {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
};
StringBuilder buffer = new StringBuilder(length);
Random random = new Random();
for (int i = 0; i < length; i++) {
buffer.append(chars[random.nextInt(chars.length)]);
}
return buffer.toString();
}
}