package org.ovirt.engine.api.restapi.resource;
import static org.ovirt.engine.api.restapi.test.util.TestHelper.eqActionParams;
import static org.ovirt.engine.api.restapi.test.util.TestHelper.eqQueryParams;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.easymock.IAnswer;
import org.easymock.IMocksControl;
import org.easymock.classextension.EasyMock;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.ovirt.engine.api.common.invocation.Current;
import org.ovirt.engine.api.common.security.auth.Principal;
import org.ovirt.engine.api.model.BaseResource;
import org.ovirt.engine.api.model.Fault;
import org.ovirt.engine.api.model.Link;
import org.ovirt.engine.core.common.action.VdcActionParametersBase;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VdcReturnValueBase;
import org.ovirt.engine.core.common.businessentities.AsyncTaskStatus;
import org.ovirt.engine.core.common.interfaces.BackendLocal;
import org.ovirt.engine.core.common.interfaces.ErrorTranslator;
import org.ovirt.engine.core.common.interfaces.SearchType;
import org.ovirt.engine.core.common.queries.GetTasksStatusesByTasksIDsParameters;
import org.ovirt.engine.core.common.queries.SearchParameters;
import org.ovirt.engine.core.common.queries.VdcQueryParametersBase;
import org.ovirt.engine.core.common.queries.VdcQueryReturnValue;
import org.ovirt.engine.core.common.queries.VdcQueryType;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.api.restapi.logging.MessageBundle;
import org.ovirt.engine.api.restapi.types.Mapper;
import org.ovirt.engine.api.restapi.types.MappingLocator;
import org.ovirt.engine.api.restapi.util.SessionHelper;
import static org.ovirt.engine.api.restapi.test.util.TestHelper.eqSearchParams;
public abstract class AbstractBackendResourceTest<R extends BaseResource, Q /* extends IVdcQueryable */>
extends Assert {
protected static final Guid[] GUIDS = { new Guid("00000000-0000-0000-0000-000000000000"),
new Guid("11111111-1111-1111-1111-111111111111"),
new Guid("22222222-2222-2222-2222-222222222222"),
new Guid("33333333-3333-3333-3333-333333333333") };
protected static final Guid NON_EXISTANT_GUID = new Guid("99999999-9999-9999-9999-999999999999");
protected static final String[] NAMES = { "sedna", "eris", "orcus" };
protected static final String[] DESCRIPTIONS = { "top notch entity", "a fine example",
"state of the art" };
protected static final String URI_ROOT = "http://localhost:8088";
protected static final String BASE_PATH = "/api";
protected static final String URI_BASE = URI_ROOT + BASE_PATH;
protected static final String BUNDLE_PATH = "org/ovirt/engine/api/restapi/logging/Messages";
protected static final String CANT_DO = "circumstances outside our control";
protected static final String FAILURE = "a fine mess";
protected static final String BACKEND_FAILED_SERVER_LOCALE = "Ruckenende ist kaput";
protected static final String BACKEND_FAILED_CLIENT_LOCALE = "Theip ar an obair";
protected static final String INCOMPLETE_PARAMS_REASON_SERVER_LOCALE = "Unvollstandig Parameter";
protected static final String INCOMPLETE_PARAMS_DETAIL_SERVER_LOCALE = " erforderlich fur ";
protected static final Locale CLIENT_LOCALE = new Locale("ga", "IE");
protected static int SERVER_ERROR = 500;
protected static int BAD_REQUEST = 400;
protected static final String USER = "Aladdin";
protected static final String SECRET = "open sesame";
protected static final String DOMAIN = "Maghreb.Maghreb.Maghreb.com";
protected BackendLocal backend;
protected Current current;
protected Principal principal;
protected SessionHelper sessionHelper;
protected MappingLocator mapperLocator;
protected Locale locale;
protected HttpHeaders httpHeaders;
protected List<Locale> locales;
protected List<String> accepts;
protected MessageBundle messageBundle;
protected IMocksControl control;
@Before
public void setUp() {
control = EasyMock.createNiceControl();
backend = control.createMock(BackendLocal.class);
current = control.createMock(Current.class);
sessionHelper = new SessionHelper();
sessionHelper.setCurrent(current);
principal = new Principal(USER, SECRET, DOMAIN);
expect(current.get(Principal.class)).andReturn(principal).anyTimes();
httpHeaders = control.createMock(HttpHeaders.class);
locales = new ArrayList<Locale>();
expect(httpHeaders.getAcceptableLanguages()).andReturn(locales).anyTimes();
accepts = new ArrayList<String>();
expect(httpHeaders.getRequestHeader("Accept")).andReturn(accepts).anyTimes();
mapperLocator = new MappingLocator();
mapperLocator.populate();
locale = Locale.getDefault();
Locale.setDefault(Locale.GERMANY);
messageBundle = new MessageBundle();
messageBundle.setPath(BUNDLE_PATH);
messageBundle.populate();
init();
}
protected <F, T> Mapper<F, T> getMapper(Class<F> from, Class<T> to) {
return mapperLocator.getMapper(from, to);
}
@After
public void tearDown() {
Locale.setDefault(locale);
control.verify();
}
protected void initResource(AbstractBackendResource<R, Q> resource) {
resource.setBackend(backend);
resource.setMappingLocator(mapperLocator);
resource.setSessionHelper(sessionHelper);
resource.setMessageBundle(messageBundle);
resource.setHttpHeaders(httpHeaders);
}
protected abstract void init();
protected abstract Q getEntity(int index);
protected void verifyModel(R model, int index) {
assertEquals(GUIDS[index].toString(), model.getId());
assertEquals(NAMES[index], model.getName());
assertEquals(DESCRIPTIONS[index], model.getDescription());
verifyLinks(model);
}
protected UriInfo setUpBasicUriExpectations() {
UriInfo uriInfo = control.createMock(UriInfo.class);
expect(uriInfo.getBaseUri()).andReturn(URI.create(URI_BASE)).anyTimes();
return uriInfo;
}
protected <E> void setUpGetEntityExpectations(VdcQueryType query,
Class<? extends VdcQueryParametersBase> clz, String[] names, Object[] values, E entity)
throws Exception {
VdcQueryReturnValue queryResult = control.createMock(VdcQueryReturnValue.class);
expect(backend.RunQuery(eq(query), eqQueryParams(clz, addSession(names), addSession(values)))).andReturn(
queryResult);
expect(queryResult.getSucceeded()).andReturn(true).anyTimes();
expect(queryResult.getReturnValue()).andReturn(entity).anyTimes();
}
protected <E> void setUpGetEntityExpectations(String query,
SearchType type,
E entity) throws Exception {
VdcQueryReturnValue queryResult = control.createMock(VdcQueryReturnValue.class);
SearchParameters params = new SearchParameters(query, type);
expect(backend.RunQuery(eq(VdcQueryType.Search),
eqSearchParams(params))).andReturn(queryResult);
expect(queryResult.getSucceeded()).andReturn(true).anyTimes();
List<E> entities = new ArrayList<E>();
entities.add(entity);
expect(queryResult.getReturnValue()).andReturn(entities).anyTimes();
}
protected void setUpEntityQueryExpectations(VdcQueryType query,
Class<? extends VdcQueryParametersBase> queryClass,
String[] queryNames,
Object[] queryValues,
Object queryReturn) {
setUpEntityQueryExpectations(query, queryClass, queryNames, queryValues, queryReturn, null);
}
protected void setUpEntityQueryExpectations(VdcQueryType query,
Class<? extends VdcQueryParametersBase> queryClass,
String[] queryNames,
Object[] queryValues,
Object queryReturn,
Object failure) {
VdcQueryReturnValue queryResult = control.createMock(VdcQueryReturnValue.class);
expect(queryResult.getSucceeded()).andReturn(failure == null).anyTimes();
if (failure == null) {
expect(queryResult.getReturnValue()).andReturn(queryReturn).anyTimes();
} else {
if (failure instanceof String) {
expect(queryResult.getExceptionString()).andReturn((String) failure).anyTimes();
setUpL10nExpectations((String)failure);
} else if (failure instanceof Exception) {
expect(queryResult.getExceptionString()).andThrow((Exception) failure).anyTimes();
}
}
expect(backend.RunQuery(eq(query),
eqQueryParams(queryClass,
addSession(queryNames),
addSession(queryValues)))).andReturn(queryResult);
}
protected UriInfo setUpActionExpectations(VdcActionType task,
Class<? extends VdcActionParametersBase> clz, String[] names, Object[] values,
boolean canDo, boolean success) {
return setUpActionExpectations(task, clz, names, values, canDo, success, null, true);
}
protected UriInfo setUpActionExpectations(VdcActionType task,
Class<? extends VdcActionParametersBase> clz, String[] names, Object[] values,
boolean canDo, boolean success, boolean reply) {
return setUpActionExpectations(task, clz, names, values, canDo, success, null, reply);
}
protected UriInfo setUpActionExpectations(VdcActionType task,
Class<? extends VdcActionParametersBase> clz, String[] names, Object[] values,
boolean canDo, boolean success, Object taskReturn, boolean replay) {
return setUpActionExpectations(task, clz, names, values, canDo, success, taskReturn, null, replay);
}
protected UriInfo setUpActionExpectations(VdcActionType task,
Class<? extends VdcActionParametersBase> clz,
String[] names,
Object[] values,
boolean canDo,
boolean success,
Object taskReturn,
String baseUri,
boolean replay) {
return setUpActionExpectations(task, clz, names, values, canDo, success, taskReturn, null, null, baseUri, replay);
}
protected UriInfo setUpActionExpectations(VdcActionType task,
Class<? extends VdcActionParametersBase> clz,
String[] names,
Object[] values,
boolean canDo,
boolean success,
Object taskReturn,
ArrayList<Guid> asyncTasks,
ArrayList<AsyncTaskStatus> asyncStatuses,
String baseUri,
boolean replay) {
VdcReturnValueBase result = control.createMock(VdcReturnValueBase.class);
expect(result.getCanDoAction()).andReturn(canDo).anyTimes();
if (canDo) {
expect(result.getSucceeded()).andReturn(success).anyTimes();
if (success) {
if (taskReturn != null) {
expect(result.getActionReturnValue()).andReturn(taskReturn).anyTimes();
}
} else {
expect(result.getExecuteFailedMessages()).andReturn(asList(FAILURE)).anyTimes();
setUpL10nExpectations(asList(FAILURE));
}
} else {
expect(result.getCanDoActionMessages()).andReturn(asList(CANT_DO)).anyTimes();
setUpL10nExpectations(asList(CANT_DO));
}
expect(backend.RunAction(eq(task), eqActionParams(clz, addSession(names), addSession(values)))).andReturn(result);
expect(result.getHasAsyncTasks()).andReturn(asyncTasks != null).anyTimes();
if (asyncTasks != null) {
expect(result.getTaskIdList()).andReturn(asyncTasks).anyTimes();
VdcQueryReturnValue monitorResult = control.createMock(VdcQueryReturnValue.class);
expect(monitorResult.getSucceeded()).andReturn(success).anyTimes();
expect(monitorResult.getReturnValue()).andReturn(asyncStatuses).anyTimes();
expect(backend.RunQuery(eq(VdcQueryType.GetTasksStatusesByTasksIDs),
eqQueryParams(GetTasksStatusesByTasksIDsParameters.class,
addSession(new String[]{}),
addSession(new Object[]{})))).andReturn(monitorResult);
}
UriInfo uriInfo = setUpBasicUriExpectations();
if (baseUri != null) {
expect(uriInfo.getPath()).andReturn(baseUri).anyTimes();
}
if (replay) {
control.replay();
}
return uriInfo;
}
protected void setUpL10nExpectations(String error) {
ErrorTranslator translator = control.createMock(ErrorTranslator.class);
IAnswer<String> answer = new IAnswer<String>() {
public String answer() {
return EasyMock.getCurrentArguments() != null && EasyMock.getCurrentArguments().length > 0
? mockl10n((String)EasyMock.getCurrentArguments()[0])
: null;
}
};
if (!locales.isEmpty()) {
expect(translator.TranslateErrorTextSingle(eq(error), eq(locales.get(0)))).andAnswer(answer).anyTimes();
} else {
expect(translator.TranslateErrorTextSingle(eq(error))).andAnswer(answer).anyTimes();
}
expect(backend.getErrorsTranslator()).andReturn(translator).anyTimes();
}
protected void setUpL10nExpectations(ArrayList<String> errors) {
ErrorTranslator errorTranslator = control.createMock(ErrorTranslator.class);
if (!locales.isEmpty()) {
expect(errorTranslator.TranslateErrorText(eq(errors), eq(locales.get(0)))).andReturn(mockl10n(errors)).anyTimes();
} else {
expect(errorTranslator.TranslateErrorText(eq(errors))).andReturn(mockl10n(errors)).anyTimes();
}
expect(backend.getErrorsTranslator()).andReturn(errorTranslator);
}
protected List<String> mockl10n(List<String> errors) {
ArrayList<String> ret = new ArrayList<String>();
for (String error : errors) {
ret.add(mockl10n(error));
}
return ret;
}
protected String mockl10n(String s) {
return s.startsWith("l10n...") ? s : "l10n..." + s;
}
protected void verifyRemove(Response response) {
assertNotNull(response);
assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
}
protected void verifyLinks(BaseResource model) {
assertNotNull(model.getHref());
assertTrue(model.getHref().startsWith("/api"));
for (Link link : model.getLinks()) {
assertTrue(link.getHref().startsWith("/api"));
}
}
protected void verifyFault(WebApplicationException wae, String detail) {
verifyFault(wae, BACKEND_FAILED_SERVER_LOCALE, asList(mockl10n(detail)).toString(), BAD_REQUEST);
}
protected void verifyFault(WebApplicationException wae, String reason, String detail, int status) {
assertEquals(status, wae.getResponse().getStatus());
assertTrue(wae.getResponse().getEntity() instanceof Fault);
Fault fault = (Fault) wae.getResponse().getEntity();
assertEquals(reason, fault.getReason());
assertEquals(detail, fault.getDetail());
}
protected void verifyFault(WebApplicationException wae, String reason, Throwable t) {
assertEquals(SERVER_ERROR, wae.getResponse().getStatus());
assertTrue(wae.getResponse().getEntity() instanceof Fault);
Fault fault = (Fault) wae.getResponse().getEntity();
assertEquals(reason, fault.getReason());
assertNotNull(fault.getDetail());
assertTrue("expected detail to include: " + t.getMessage(),
fault.getDetail().indexOf(t.getMessage()) != -1);
}
protected void verifyFault(Response response, String detail) {
assertEquals(BAD_REQUEST, response.getStatus());
assertTrue(response.getEntity() instanceof Fault);
Fault fault = (Fault) response.getEntity();
assertEquals(BACKEND_FAILED_SERVER_LOCALE, fault.getReason());
assertEquals(asList(mockl10n(detail)).toString(), fault.getDetail());
}
protected void verifyIncompleteException(WebApplicationException wae, String type, String method, String... fields) {
assertEquals(400, wae.getResponse().getStatus());
Fault fault = (Fault)wae.getResponse().getEntity();
assertNotNull(fault);
assertEquals(INCOMPLETE_PARAMS_REASON_SERVER_LOCALE, fault.getReason());
assertEquals(type + " " + Arrays.asList(fields) + INCOMPLETE_PARAMS_DETAIL_SERVER_LOCALE + method, fault.getDetail());
}
protected void verifyNotFoundException(WebApplicationException wae) {
assertEquals(404, wae.getResponse().getStatus());
}
protected <T> ArrayList<T> asList(T element) {
ArrayList<T> list = new ArrayList<T>();
list.add(element);
return list;
}
protected String[] addSession(String... names) {
String[] ret = new String[names.length + 1];
for (int i = 0 ; i < names.length ; i++) {
ret[i] = names[i];
}
ret[names.length] = "SessionId";
return ret;
}
protected Object[] addSession(Object... values) {
Object[] ret = new Object[values.length + 1];
for (int i = 0 ; i < values.length ; i++) {
ret[i] = values[i];
}
ret[values.length] = sessionHelper.getSessionId(principal);
return ret;
}
}