com.github.zxl0714.redismock.CommandExecutor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of redis-mock Show documentation
Show all versions of redis-mock Show documentation
A simple redis java mock for unit testing.
The newest version!
package com.github.zxl0714.redismock;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.github.zxl0714.redismock.expecptions.WrongNumberOfArgumentsException;
import com.github.zxl0714.redismock.expecptions.WrongValueTypeException;
import com.github.zxl0714.redismock.expecptions.InternalException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import static com.github.zxl0714.redismock.Utils.*;
/**
* Created by Xiaolu on 2015/4/20.
*/
public class CommandExecutor {
private final RedisBase base;
public static List getSupportedCommands() {
ImmutableList.Builder builder = new ImmutableList.Builder();
Method[] methods = CommandExecutor.class.getMethods();
for (Method method : methods) {
Class>[] params = method.getParameterTypes();
if (params.length == 1 && params[0].getName().equals(List.class.getName())
&& method.getReturnType().getName().equals(Slice.class.getName())) {
builder.add(method.getName());
}
}
return builder.build();
}
public CommandExecutor(RedisBase base) {
this.base = base;
}
public Slice set(List params) throws WrongNumberOfArgumentsException {
checkArgumentsNumberEquals(params, 2);
base.rawPut(params.get(0), params.get(1), -1L);
return Response.OK;
}
public Slice setex(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 3);
try {
long ttl = Long.parseLong(new String(params.get(1).data())) * 1000;
base.rawPut(params.get(0), params.get(2), ttl);
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR value is not an integer or out of range");
}
return Response.OK;
}
public Slice psetex(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 3);
try {
long ttl = Long.parseLong(new String(params.get(1).data()));
base.rawPut(params.get(0), params.get(2), ttl);
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR value is not an integer or out of range");
}
return Response.OK;
}
public Slice setnx(List params) throws WrongNumberOfArgumentsException {
checkArgumentsNumberEquals(params, 2);
if (base.rawGet(params.get(0)) == null) {
base.rawPut(params.get(0), params.get(1), -1L);
return Response.integer(1);
}
return Response.integer(0);
}
public Slice setbit(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 3);
Slice value = base.rawGet(params.get(0));
byte bit;
try {
bit = Byte.parseByte(params.get(2).toString());
if (bit != 0 && bit != 1) {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR bit is not an integer or out of range");
}
int pos;
try {
pos = Integer.parseInt(params.get(1).toString());
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR bit offset is not an integer or out of range");
}
if (pos < 0) {
throw new WrongValueTypeException("ERR bit offset is not an integer or out of range");
}
if (value == null) {
byte[] data = new byte[pos / 8 + 1];
Arrays.fill(data, (byte) 0);
data[pos / 8] = (byte) (bit << (pos % 8));
base.rawPut(params.get(0), new Slice(data), -1L);
return Response.integer(0L);
}
long original;
if (pos / 8 >= value.length()) {
byte[] data = new byte[pos / 8 + 1];
Arrays.fill(data, (byte) 0);
for (int i = 0; i < value.length(); i++) {
data[i] = value.data()[i];
}
data[pos / 8] = (byte) (bit << (pos % 8));
original = 0;
base.rawPut(params.get(0), new Slice(data), -1L);
} else {
byte[] data = value.data();
if ((data[pos / 8] & (1 << (pos % 8))) != 0) {
original = 1;
} else {
original = 0;
}
data[pos / 8] |= (byte) (1 << (pos % 8));
data[pos / 8] &= (byte) (bit << (pos % 8));
base.rawPut(params.get(0), new Slice(data), -1L);
}
return Response.integer(original);
}
public Slice append(List params) throws WrongNumberOfArgumentsException {
checkArgumentsNumberEquals(params, 2);
Slice key = params.get(0);
Slice value = params.get(1);
Slice s = base.rawGet(key);
if (s == null) {
base.rawPut(key, value, -1L);
return Response.integer(value.length());
}
byte[] b = new byte[s.length() + value.length()];
for (int i = 0; i < s.length(); i++) {
b[i] = s.data()[i];
}
for (int i = s.length(); i < s.length() + value.length(); i++) {
b[i] = value.data()[i - s.length()];
}
base.rawPut(key, new Slice(b), -1L);
return Response.integer(b.length);
}
public Slice get(List params) throws WrongNumberOfArgumentsException {
checkArgumentsNumberEquals(params, 1);
Slice value = base.rawGet(params.get(0));
return Response.bulkString(value);
}
public Slice getbit(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 2);
Slice value = base.rawGet(params.get(0));
int pos;
try {
pos = Integer.parseInt(params.get(1).toString());
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR bit offset is not an integer or out of range");
}
if (pos < 0) {
throw new WrongValueTypeException("ERR bit offset is not an integer or out of range");
}
if (value == null) {
return Response.integer(0L);
}
if (pos >= value.length() * 8) {
return Response.integer(0L);
}
if ((value.data()[pos / 8] & (1 << (pos % 8))) != 0) {
return Response.integer(1);
}
return Response.integer(0);
}
public Slice ttl(List params) throws WrongNumberOfArgumentsException {
checkArgumentsNumberEquals(params, 1);
Long pttl = base.getTTL(params.get(0));
if (pttl == null) {
return Response.integer(-2L);
}
if (pttl == -1) {
return Response.integer(-1L);
}
return Response.integer((pttl + 999) / 1000);
}
public Slice pttl(List params) throws WrongNumberOfArgumentsException {
checkArgumentsNumberEquals(params, 1);
Long pttl = base.getTTL(params.get(0));
if (pttl == null) {
return Response.integer(-2L);
}
if (pttl == -1) {
return Response.integer(-1L);
}
return Response.integer(pttl);
}
public Slice expire(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 2);
try {
long pttl = Long.parseLong(new String(params.get(1).data())) * 1000;
return Response.integer(base.setTTL(params.get(0), pttl));
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR value is not an integer or out of range");
}
}
public Slice pexpire(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 2);
try {
long pttl = Long.parseLong(new String(params.get(1).data()));
return Response.integer(base.setTTL(params.get(0), pttl));
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR value is not an integer or out of range");
}
}
public Slice incr(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 1);
Slice key = params.get(0);
Slice v = base.rawGet(key);
if (v == null) {
base.rawPut(key, new Slice("1"), -1L);
return Response.integer(1L);
}
try {
long r = Long.parseLong(new String(v.data())) + 1;
base.rawPut(key, new Slice(String.valueOf(r)), -1L);
return Response.integer(r);
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR value is not an integer or out of range");
}
}
public Slice incrby(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 2);
try {
Slice key = params.get(0);
long d = Long.parseLong(String.valueOf(params.get(1)));
Slice v = base.rawGet(key);
if (v == null) {
base.rawPut(key, new Slice(String.valueOf(d)), -1L);
return Response.integer(d);
}
long r = Long.parseLong(new String(v.data())) + d;
base.rawPut(key, new Slice(String.valueOf(r)), -1L);
return Response.integer(r);
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR value is not an integer or out of range");
}
}
public Slice decr(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 1);
Slice key = params.get(0);
Slice v = base.rawGet(key);
if (v == null) {
base.rawPut(key, new Slice("-1"), -1L);
return Response.integer(-1L);
}
try {
long r = Long.parseLong(new String(v.data())) - 1;
base.rawPut(key, new Slice(String.valueOf(r)), -1L);
return Response.integer(r);
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR value is not an integer or out of range");
}
}
public Slice decrby(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 2);
try {
Slice key = params.get(0);
long d = Long.parseLong(String.valueOf(params.get(1)));
Slice v = base.rawGet(key);
if (v == null) {
base.rawPut(key, new Slice(String.valueOf(-d)), -1L);
return Response.integer(-d);
}
long r = Long.parseLong(new String(v.data())) - d;
base.rawPut(key, new Slice(String.valueOf(r)), -1L);
return Response.integer(r);
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR value is not an integer or out of range");
}
}
public Slice pfcount(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberGreater(params, 0);
Set set = Sets.newHashSet();
for (Slice key : params) {
Slice data = base.rawGet(key);
if (data == null) {
continue;
}
try {
Set s = deserializeObject(data);
set.addAll(s);
} catch (Exception e) {
throw new WrongValueTypeException("WRONGTYPE Key is not a valid HyperLogLog string value.");
}
}
return Response.integer((long) set.size());
}
public Slice pfadd(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException, InternalException {
checkArgumentsNumberGreater(params, 1);
Slice key = params.get(0);
Slice data = base.rawGet(key);
boolean first;
Set set;
int prev;
if (data == null) {
set = Sets.newHashSet();
first = true;
prev = 0;
} else {
try {
set = deserializeObject(data);
} catch (Exception e) {
throw new WrongValueTypeException("WRONGTYPE Key is not a valid HyperLogLog string value.");
}
first = false;
prev = set.size();
}
for (Slice v : params.subList(1, params.size())) {
set.add(v);
}
try {
Slice out = serializeObject(set);
if (first) {
base.rawPut(key, out, -1L);
} else {
base.rawPut(key, out, null);
}
} catch (Exception e) {
throw new InternalException(e.getMessage());
}
if (prev != set.size()) {
return Response.integer(1L);
}
return Response.integer(0L);
}
public Slice pfmerge(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException, InternalException {
checkArgumentsNumberGreater(params, 0);
Slice dst = params.get(0);
Slice data = base.rawGet(dst);
boolean first;
Set set;
if (data == null) {
set = Sets.newHashSet();
first = true;
} else {
try {
set = deserializeObject(data);
} catch (Exception e) {
throw new WrongValueTypeException("WRONGTYPE Key is not a valid HyperLogLog string value.");
}
first = false;
}
for (Slice v : params.subList(1, params.size())) {
Slice src = base.rawGet(v);
if (src != null) {
try {
Set s = deserializeObject(src);
set.addAll(s);
} catch (Exception e) {
throw new WrongValueTypeException("WRONGTYPE Key is not a valid HyperLogLog string value.");
}
}
}
try {
Slice out = serializeObject(set);
if (first) {
base.rawPut(dst, out, -1L);
} else {
base.rawPut(dst, out, null);
}
} catch (Exception e) {
throw new InternalException(e.getMessage());
}
return Response.OK;
}
public Slice mget(List params) throws WrongNumberOfArgumentsException {
checkArgumentsNumberGreater(params, 0);
ImmutableList.Builder builder = new ImmutableList.Builder();
for (Slice key : params) {
builder.add(Response.bulkString(base.rawGet(key)));
}
return Response.array(builder.build());
}
public Slice mset(List params) throws WrongNumberOfArgumentsException {
checkArgumentsNumberGreater(params, 0);
checkArgumentsNumberFactor(params, 2);
for (int i = 0; i < params.size(); i += 2) {
base.rawPut(params.get(i), params.get(i + 1), -1L);
}
return Response.OK;
}
public Slice getset(List params) throws WrongNumberOfArgumentsException {
checkArgumentsNumberEquals(params, 2);
Slice value = base.rawGet(params.get(0));
base.rawPut(params.get(0), params.get(1), -1L);
return Response.bulkString(value);
}
public Slice strlen(List params) throws WrongNumberOfArgumentsException {
checkArgumentsNumberEquals(params, 1);
Slice value = base.rawGet(params.get(0));
if (value == null) {
return Response.integer(0);
}
return Response.integer(value.length());
}
public Slice del(List params) throws WrongNumberOfArgumentsException {
checkArgumentsNumberGreater(params, 0);
int count = 0;
for (Slice key : params) {
Slice value = base.rawGet(key);
base.del(key);
if (value != null) {
count++;
}
}
return Response.integer(count);
}
public Slice exists(List params) throws WrongNumberOfArgumentsException {
checkArgumentsNumberEquals(params, 1);
if (base.rawGet(params.get(0)) != null) {
return Response.integer(1);
}
return Response.integer(0);
}
public Slice expireat(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 2);
try {
long deadline = Long.parseLong(new String(params.get(1).data())) * 1000;
return Response.integer(base.setDeadline(params.get(0), deadline));
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR value is not an integer or out of range");
}
}
public Slice pexpireat(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 2);
try {
long deadline = Long.parseLong(new String(params.get(1).data()));
return Response.integer(base.setDeadline(params.get(0), deadline));
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR value is not an integer or out of range");
}
}
public Slice lpush(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException, InternalException {
checkArgumentsNumberGreater(params, 1);
Slice key = params.get(0);
Slice data = base.rawGet(key);
LinkedList list;
try {
if (data != null) {
list = deserializeObject(data);
} else {
list = Lists.newLinkedList();
}
} catch (Exception e) {
throw new WrongValueTypeException("WRONGTYPE Operation against a key holding the wrong kind of value");
}
for (int i = 1; i < params.size(); i++) {
list.addFirst(params.get(i));
}
try {
base.rawPut(key, serializeObject(list), -1L);
} catch (Exception e) {
throw new InternalException(e.getMessage());
}
return Response.integer(list.size());
}
public Slice lpushx(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException, InternalException {
checkArgumentsNumberGreater(params, 1);
Slice key = params.get(0);
Slice data = base.rawGet(key);
LinkedList list;
try {
if (data != null) {
list = deserializeObject(data);
} else {
return Response.integer(0);
}
} catch (Exception e) {
throw new WrongValueTypeException("WRONGTYPE Operation against a key holding the wrong kind of value");
}
for (int i = 1; i < params.size(); i++) {
list.addFirst(params.get(i));
}
try {
base.rawPut(key, serializeObject(list), -1L);
} catch (Exception e) {
throw new InternalException(e.getMessage());
}
return Response.integer(list.size());
}
public Slice lrange(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 3);
Slice key = params.get(0);
Slice data = base.rawGet(key);
LinkedList list;
try {
if (data != null) {
list = deserializeObject(data);
} else {
list = Lists.newLinkedList();
}
} catch (Exception e) {
throw new WrongValueTypeException("WRONGTYPE Operation against a key holding the wrong kind of value");
}
int start;
int end;
try {
start = Integer.parseInt(params.get(1).toString());
end = Integer.parseInt(params.get(2).toString());
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR value is not an integer or out of range");
}
if (start < 0) {
start = list.size() + start;
if (start < 0) {
start = 0;
}
}
if (end < 0) {
end = list.size() + end;
if (end < 0) {
end = 0;
}
}
ImmutableList.Builder builder = new ImmutableList.Builder();
for (int i = start; i <= end && i < list.size(); i++) {
builder.add(Response.bulkString(list.get(i)));
}
return Response.array(builder.build());
}
public Slice llen(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 1);
Slice key = params.get(0);
Slice data = base.rawGet(key);
LinkedList list;
try {
if (data != null) {
list = deserializeObject(data);
} else {
list = Lists.newLinkedList();
}
} catch (Exception e) {
throw new WrongValueTypeException("WRONGTYPE Operation against a key holding the wrong kind of value");
}
return Response.integer(list.size());
}
public Slice lpop(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException, InternalException {
checkArgumentsNumberEquals(params, 1);
Slice key = params.get(0);
Slice data = base.rawGet(key);
LinkedList list;
try {
if (data != null) {
list = deserializeObject(data);
} else {
return Response.NULL;
}
} catch (Exception e) {
throw new WrongValueTypeException("WRONGTYPE Operation against a key holding the wrong kind of value");
}
if (list.isEmpty()) {
return Response.NULL;
}
Slice v = list.removeFirst();
try {
base.rawPut(key, serializeObject(list), -1L);
} catch (Exception e) {
throw new InternalException(e.getMessage());
}
return Response.bulkString(v);
}
public Slice lindex(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException {
checkArgumentsNumberEquals(params, 2);
Slice key = params.get(0);
Slice data = base.rawGet(key);
LinkedList list;
try {
if (data != null) {
list = deserializeObject(data);
} else {
return Response.NULL;
}
} catch (Exception e) {
throw new WrongValueTypeException("WRONGTYPE Operation against a key holding the wrong kind of value");
}
int index;
try {
index = Integer.parseInt(params.get(1).toString());
} catch (NumberFormatException e) {
throw new WrongValueTypeException("ERR value is not an integer or out of range");
}
if (index < 0) {
index = list.size() + index;
if (index < 0) {
return Response.NULL;
}
}
if (index >= list.size()) {
return Response.NULL;
}
return Response.bulkString(list.get(index));
}
public Slice rpush(List params) throws WrongNumberOfArgumentsException, WrongValueTypeException, InternalException {
checkArgumentsNumberGreater(params, 1);
Slice key = params.get(0);
Slice data = base.rawGet(key);
LinkedList list;
try {
if (data != null) {
list = deserializeObject(data);
} else {
list = Lists.newLinkedList();
}
} catch (Exception e) {
throw new WrongValueTypeException("WRONGTYPE Operation against a key holding the wrong kind of value");
}
for (int i = 1; i < params.size(); i++) {
list.addLast(params.get(i));
}
try {
base.rawPut(key, serializeObject(list), -1L);
} catch (Exception e) {
throw new InternalException(e.getMessage());
}
return Response.integer(list.size());
}
public synchronized Slice execCommand(RedisCommand command) {
Preconditions.checkArgument(command.getParameters().size() > 0);
List params = command.getParameters();
String name = new String(params.get(0).data()).toLowerCase();
try {
Method method = this.getClass().getMethod(name, List.class);
return (Slice) method.invoke(this, params.subList(1, params.size()));
} catch (IllegalAccessException e) {
throw new NoSuchElementException();
} catch (InvocationTargetException e) {
Throwable err = e.getTargetException();
if (err instanceof WrongValueTypeException) {
return Response.error(err.getMessage());
} else if (err instanceof WrongNumberOfArgumentsException) {
return Response.error(String.format("ERR wrong number of arguments for '%s' command", name));
}
return Response.error(e.getMessage());
} catch (NoSuchMethodException e) {
return Response.error(String.format("ERR unknown or disabled command '%s'", name));
}
}
}