blob: b88b8c55a6a5d30e7b797305b497a7d733aef989 [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
package org.eclipse.mdm.businessobjects.boundary.integrationtest;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.fail;
import java.util.NoSuchElementException;
import org.eclipse.mdm.api.atfxadapter.ATFXContextFactory;
import org.eclipse.mdm.api.base.ConnectionException;
import org.eclipse.mdm.api.base.model.Entity;
import org.eclipse.mdm.api.dflt.ApplicationContext;
import org.eclipse.mdm.api.dflt.model.EntityFactory;
import org.eclipse.mdm.businessobjects.entity.MDMEntityResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.restassured.RestAssured;
import io.restassured.authentication.FormAuthConfig;
import io.restassured.authentication.FormAuthScheme;
import io.vavr.collection.HashMap;
import io.vavr.collection.HashSet;
import io.vavr.collection.Map;
import io.vavr.collection.Set;
import io.vavr.control.Try;
/*
* @author Johannes Stamm, Peak Solution GmbH Nuernberg
*/
public abstract class ResourceIntegrationTest {
private static Logger LOGGER = LoggerFactory.getLogger(ResourceIntegrationTest.class);
private static final String HOST = "localhost";
private static final String PORT = "8080";
private static final String BASE_PATH = "org.eclipse.mdm.nucleus";
private static final String API_PATH = "mdm";
private static final String ENV_PATH = "environments";
protected static final String SOURCE_NAME = "PODS";
private static final String AUTH_USERNAME = "sa";
private static final String AUTH_PASSWORD = "sa";
protected static final String TESTDATA_ENTITY_ID = "entityId";
protected static final String TESTDATA_ENTITY_NAME = "entityName";
protected static final String TESTDATA_ENTITY_TYPE = "entityType";
protected static final String TESTDATA_CONTEXT_GROUP = "contextGroup";
protected static final String TESTDATA_CREATE_JSON_BODY = "createJSONBody";
protected static final String TESTDATA_NUMBER_OF_VALUES = "NumberOfValues";
protected static final String TESTDATA_UPDATE_JSON_BODY = "updateJSONBody";
protected static final String TESTDATA_RESOURCE_URI = "resourceURI";
protected static final String TESTDATA_RANDOM_DATA = "RANDOM_DATA";
private static final String RANDOM_ENTITY_NAME_SUFFIX = "_" + Long.toHexString(System.currentTimeMillis());
public enum TestType {
CREATE, FIND, FINDALL, PATCH, DELETE, UPDATE_CONTEXT, FIND_CONTEXT;
}
protected static Map<Class<?>, Set<TestType>> testsToSkip = HashMap.empty();
protected static Map<Class<?>, Map<String, String>> testDataMap = HashMap.empty();
// if this is set, the resource URI for find() is constructed with the name as
// the PATH_PARAM
protected static Map<Class<?>, Boolean> findByName = HashMap.empty();
/**
* The context class must be set by implementing tests as the context to get
* from and put test data values to
*/
private static Class<?> contextClass;
static EntityFactory ENTITY_FACTORY;
static {
java.util.Map<String, String> map = HashMap
.of("atfxfile", "src/test/resources/mdm_complete_application_model_500.xml", //
"freetext.active", "false", //
"entityConfigRepositoryLoaderClass",
"org.eclipse.mdm.api.odsadapter.lookup.config.DefaultEntityConfigRepositoryLoader") //
.toJavaMap();
try {
ApplicationContext context = new ATFXContextFactory().connect(map);
ENTITY_FACTORY = context.getEntityFactory().get();
} catch (ConnectionException e1) {
fail("ATFXContextFactory could not be initialized");
}
}
static {
// configure URI
StringBuilder baseURI = new StringBuilder();
baseURI.append("http://").append(HOST).append(":").append(PORT).append("/").append(BASE_PATH).append("/")
.append(API_PATH);
RestAssured.baseURI = baseURI.toString();
RestAssured.basePath = ENV_PATH + "/" + SOURCE_NAME;
LOGGER.debug("RestAssured set up to " + RestAssured.baseURI + "/" + RestAssured.basePath);
// setup authentication
// PreemptiveBasicAuthScheme authScheme = new PreemptiveBasicAuthScheme();
FormAuthScheme authScheme = new FormAuthScheme();
authScheme.setConfig(new FormAuthConfig("/" + BASE_PATH + "/j_security_check", "j_username", "j_password"));
authScheme.setUserName(AUTH_USERNAME);
authScheme.setPassword(AUTH_PASSWORD);
RestAssured.authentication = authScheme;
LOGGER.debug("RestAssured authentication set to credentials [" + AUTH_USERNAME + "]/[" + AUTH_PASSWORD + "]");
}
/**
* Gets value with key from the testDataMap. The value map is thereby
* automatically identified by the implementing class.
*
* @param key key to get value for
* @return value for given key
*/
protected static String getTestDataValue(String key) {
return getTestDataValue(getContextClass(), key);
}
/**
* Gets value with key from the testDataMap using the context specified by
* contextClass
*
* @param contextClass the class of the test implementation
* @param key key to get value for
* @return value for given key
*/
protected static String getTestDataValue(Class<?> contextClass, String key) {
return testDataMap.get(contextClass)
.map(valueMap -> valueMap.get(key).getOrElseThrow(() -> new NoSuchElementException("Key [" + key
+ "] not found in test data value map in context [" + contextClass.getSimpleName() + "]")))
.get();
}
/**
* Checks if a test data value is present for the given key
*
* @param key key to check presence of test data value for
* @return true, if a test data value for the given key exists, false if not
*/
protected static boolean isTestDataValuePresent(String key) {
return testDataMap.get(getContextClass()).map(valueMap -> valueMap.get(key).isDefined()).get();
}
/**
* Removes the test data value for the given key. If the key is not present,
* nothing happens.
*
* @param key key to remove test data value for
*/
protected static void removeTestDataValue(String key) {
testDataMap.get(getContextClass()).map(valueMap -> valueMap.remove(key))
.map(newValueMap -> testDataMap = testDataMap.put(getContextClass(), newValueMap));
}
/**
* Puts value with key in the testDataMap. The value map is thereby
* automatically identified by the implementing class.
*
* @param key key to store value under
* @param value value to store
*/
protected static void putTestDataValue(String key, String value) {
Map<String, String> entityTestData = testDataMap.getOrElse(getContextClass(), HashMap.empty());
String valueWithSuffix = value;
// randomize name to allow failure runs not to require to reset the
// database in case the name of the entity must be unique
// do not append suffix if name is randomly generated
if (key.equals(TESTDATA_ENTITY_NAME) && !value.equals(TESTDATA_RANDOM_DATA)
&& (entityTestData.get(TESTDATA_ENTITY_NAME).isEmpty()
|| !entityTestData.get(TESTDATA_ENTITY_NAME).get().equals(TESTDATA_RANDOM_DATA))) {
// append suffix if it was not already appended or an already suffixed value was
// used for a new one (e.g: TplAttr.name and CatAttr.name)
if (!value.endsWith(RANDOM_ENTITY_NAME_SUFFIX)) {
valueWithSuffix = value + RANDOM_ENTITY_NAME_SUFFIX;
}
}
entityTestData = entityTestData.put(key, valueWithSuffix);
testDataMap = testDataMap.put(getContextClass(), entityTestData);
}
/**
* Gets the context class set by a test implementation used to store context
* aware test data
*
* @return the context class of the test implementation
*/
protected static Class<?> getContextClass() {
assertThat(contextClass, is(notNullValue()));
return contextClass;
}
/**
* Sets the context class used to store context aware test data. This method
* must be called by any test implementation before using
* {@link getTestDataValue} or {@link putTestDataValue}
*
* @param clazz the context class set by a test implementation
*/
protected static void setContextClass(Class<?> clazz) {
contextClass = clazz;
testsToSkip = testsToSkip.put(clazz, HashSet.empty());
LOGGER = LoggerFactory.getLogger(clazz);
}
/**
* Set the test with the given {@link TestType} to be skipped
*
* @param testType the test to skip
*/
protected static void skipTest(TestType test) {
testsToSkip.get(getContextClass()).map(tests -> tests.add(test))
.map(newTests -> testsToSkip = testsToSkip.put(getContextClass(), newTests));
}
/**
* Sets the option findByName to either true or false. If it's set to true, the
* URI for find() is constructed with the name rather than with the id of the
* entity as the PATH_PARAM
*
* @param findByName if find() should use the name instead of the id of the
* entity
*/
protected static void setFindByName(boolean findByNameValue) {
findByName = findByName.put(getContextClass(), findByNameValue);
}
/**
* Gets the logger
*
* @return logger configured to current context class
*/
protected static Logger getLogger() {
return LOGGER;
}
/**
* Returns a Json representation of the given entity, based on the default
* ObjectMapper.
*
* @param entity entity to get Json representation for
* @return json representation of given entity
*/
static String toJson(Entity entity) {
MDMEntityResponse response = new MDMEntityResponse(entity.getClass(), entity);
ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
String json = Try.of(() -> mapper.writeValueAsString(response)).onFailure(e -> fail(e.toString()))
.getOrElse("");
return removeEmptyAttributes(new JsonParser().parse(json)).toString();
}
private static JsonElement removeEmptyAttributes(JsonElement jsonElement) {
if (jsonElement.isJsonObject()) {
JsonObject retObject = new JsonObject();
jsonElement.getAsJsonObject().entrySet().stream().forEach(entry -> {
if (entry.getValue().isJsonPrimitive()) {
if (entry.getValue().getAsString().length() != 0) {
retObject.add(entry.getKey(), entry.getValue());
}
} else if (!entry.getValue().isJsonNull()) {
retObject.add(entry.getKey(), removeEmptyAttributes(entry.getValue()));
}
});
if (jsonElement.getAsJsonObject().entrySet().stream().filter(entry -> entry.getKey().equals("value"))
.count() > 0
&& retObject.entrySet().stream().filter(entry -> entry.getKey().equals("value")).count() == 0)
return new JsonObject();
else
return retObject;
} else if (jsonElement.isJsonArray()) {
JsonArray retArray = new JsonArray();
jsonElement.getAsJsonArray().forEach(entry -> {
if (entry.isJsonPrimitive()) {
if (entry.getAsString().length() != 0) {
retArray.add(entry);
}
} else if (!entry.isJsonNull()) {
JsonElement elem = removeEmptyAttributes(entry);
if (((JsonObject) elem).equals(new JsonObject())) {
// do nothing
} else {
retArray.add(elem);
}
}
});
return retArray;
}
throw new RuntimeException("NOT IMPLEMENTED");
}
}