package org.zstack.test.search;
import junit.framework.Assert;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.identity.SessionInventory;
import org.zstack.header.query.APIQueryMessage;
import org.zstack.header.query.QueryCondition;
import org.zstack.header.query.QueryOp;
import org.zstack.header.query.Unqueryable;
import org.zstack.header.rest.APINoSee;
import org.zstack.test.Api;
import org.zstack.utils.FieldUtils;
import org.zstack.utils.Utils;
import org.zstack.utils.gson.JSONObjectUtil;
import org.zstack.utils.logging.CLogger;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
public class QueryTestValidator {
private static final CLogger logger = Utils.getLogger(QueryTestValidator.class);
private static List<Field> getFieldToTest(Object inventory) {
List<Field> fs = FieldUtils.getAllFields(inventory.getClass());
List<Field> ret = new ArrayList<Field>();
for (Field f : fs) {
if (Collection.class.isAssignableFrom(f.getType())) {
continue;
}
if (f.isAnnotationPresent(Unqueryable.class)) {
continue;
}
if (f.isAnnotationPresent(APINoSee.class)) {
continue;
}
ret.add(f);
}
return ret;
}
private static boolean compareInventory(Object actual, Object expected, List<Field> toTest) throws IllegalArgumentException, IllegalAccessException {
for (Field f : expected.getClass().getDeclaredFields()) {
if (!toTest.contains(f)) {
continue;
}
try {
Field af = actual.getClass().getDeclaredField(f.getName());
af.setAccessible(true);
Object av = af.get(actual);
f.setAccessible(true);
Object ev = f.get(expected);
if (ev == null && av == null) {
continue;
}
if (ev != null && !ev.equals(av)) {
logger.warn(String.format("Field[%s], expected value:%s, actual value: %s", f.getName(), ev, av));
return false;
}
} catch (NoSuchFieldException e) {
return false;
}
}
return true;
}
private static void validateHasInventory(List actual, Object expected, List<Field> toTest) throws IllegalArgumentException, IllegalAccessException {
for (Object a : actual) {
if (compareInventory(a, expected, toTest)) {
return;
}
}
StringBuilder sb = new StringBuilder();
sb.append("\n============================================================");
sb.append(String.format("\nexpected inventory: \n%s", JSONObjectUtil.toJsonString(expected)));
sb.append(String.format("\nactual inventory: \n%s", JSONObjectUtil.toJsonString(actual)));
sb.append("\n============================================================");
logger.warn(sb.toString());
Assert.fail();
}
public static <T> void validateEQ(APIQueryMessage msg, Api api, Class<T> replyClass, Object inventory, SessionInventory session) {
try {
List<Field> toTest = getFieldToTest(inventory);
for (Field f : toTest) {
f.setAccessible(true);
Object value = f.get(inventory);
QueryCondition c = new QueryCondition();
c.setName(f.getName());
if (value != null) {
c.setOp(QueryOp.EQ.toString());
c.setValue(value.toString());
} else {
c.setOp(QueryOp.IS_NULL.toString());
c.setValues(null);
}
msg.getConditions().add(c);
T reply = api.query(msg, replyClass, session);
Field invField = replyClass.getDeclaredField("inventories");
invField.setAccessible(true);
List lst = (List) invField.get(reply);
Assert.assertFalse(lst.isEmpty());
validateHasInventory(lst, inventory, toTest);
}
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
}
public static <T> void validateEQ(APIQueryMessage msg, Api api, Class<T> replyClass, Object inventory) {
validateEQ(msg, api, replyClass, inventory, api.getAdminSession());
}
public static <T> void validateRandomEQConjunction(APIQueryMessage msg, Api api, Class<T> replyClass, Object inventory, int conjunctedFieldNum) {
validateRandomEQConjunction(msg, api, replyClass, inventory, api.getAdminSession(), conjunctedFieldNum);
}
public static <T> void validateRandomEQConjunction(APIQueryMessage msg, Api api, Class<T> replyClass, Object inventory, SessionInventory session, int conjunctedFieldNum) {
List<Field> toTest = getFieldToTest(inventory);
if (conjunctedFieldNum > toTest.size()) {
throw new CloudRuntimeException(String.format("totally %s fields to test, but you requires %s", toTest.isEmpty(), conjunctedFieldNum));
}
List<Field> randomFields = new ArrayList<Field>();
for (int i = 0; i < conjunctedFieldNum; i++) {
Random r = new Random();
int index = r.nextInt(toTest.size());
Field f = toTest.get(index);
randomFields.add(f);
}
try {
for (Field f : randomFields) {
f.setAccessible(true);
Object value = f.get(inventory);
QueryCondition c = new QueryCondition();
c.setName(f.getName());
if (value != null) {
c.setOp(QueryOp.EQ.toString());
c.setValue(value.toString());
} else {
c.setOp(QueryOp.IS_NULL.toString());
c.setValues(null);
}
msg.getConditions().add(c);
}
T reply = api.query(msg, replyClass, session);
Field invField = replyClass.getDeclaredField("inventories");
invField.setAccessible(true);
List lst = (List) invField.get(reply);
Assert.assertFalse(lst.isEmpty());
validateHasInventory(lst, inventory, toTest);
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
}
}