package alien4cloud.component.dao;
import static org.junit.Assert.*;
import static org.springframework.util.Assert.isNull;
import static org.springframework.util.Assert.isTrue;
import java.beans.IntrospectionException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.action.admin.indices.exists.types.TypesExistsRequest;
import org.elasticsearch.action.admin.indices.exists.types.TypesExistsResponse;
import org.elasticsearch.action.get.GetResponse;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import alien4cloud.dao.ElasticSearchDAO;
import alien4cloud.dao.IGenericSearchDAO;
import alien4cloud.dao.model.FetchContext;
import alien4cloud.exception.IndexingServiceException;
import alien4cloud.model.application.Application;
import alien4cloud.model.common.Tag;
import org.alien4cloud.tosca.model.definitions.CapabilityDefinition;
import org.alien4cloud.tosca.model.types.NodeType;
import org.alien4cloud.tosca.model.types.AbstractToscaType;
import org.alien4cloud.tosca.model.definitions.PropertyDefinition;
import org.alien4cloud.tosca.model.definitions.RequirementDefinition;
import alien4cloud.rest.utils.JsonUtil;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application-context-test.xml")
@Slf4j
public class EsDaoCrudTest extends AbstractDAOTest {
private final ObjectMapper jsonMapper = new ObjectMapper();
private List<Tag> threeTags = Lists.newArrayList(new Tag("node.icon", "my-icon.png"), new Tag("tag1", "My free tag with my free content (tag-0)"), new Tag(
"tag2", "Tag2 content"));
@Resource(name = "alien-es-dao")
private IGenericSearchDAO dao;
private NodeType indexedNodeTypeTest = null;
@Before
public void before() throws Exception {
super.before();
prepareToscaElement();
}
@Test
public void testInitIndexes() throws InterruptedException, ExecutionException, JsonGenerationException, JsonMappingException, IntrospectionException,
IOException {
assertIndexExists(ElasticSearchDAO.TOSCA_ELEMENT_INDEX, true);
assertIndexExists("toto", false);
assertTypeExists(ElasticSearchDAO.TOSCA_ELEMENT_INDEX, NodeType.class, true);
assertTypeExists(ElasticSearchDAO.TOSCA_ELEMENT_INDEX, "tata", false);
}
@Test
public void saveToscaComponentTest() throws IndexingServiceException, IOException {
dao.save(indexedNodeTypeTest);
String typeName1 = indexedNodeTypeTest.getClass().getSimpleName().toLowerCase();
assertDocumentExisit(ElasticSearchDAO.TOSCA_ELEMENT_INDEX, typeName1, indexedNodeTypeTest.getId(), true);
GetResponse resp = getDocument(ElasticSearchDAO.TOSCA_ELEMENT_INDEX, typeName1, indexedNodeTypeTest.getId());
log.info(resp.getSourceAsString());
NodeType nt = jsonMapper.readValue(resp.getSourceAsString(), NodeType.class);
assertBeanEqualsToOriginal(nt);
refresh();
}
@Test(expected = IndexingServiceException.class)
public void indexingNotSupportedToscaComponentTest() throws IndexingServiceException {
dao.save(new String());
}
@Test
public void findByIdTest() throws IndexingServiceException, JsonProcessingException {
saveDataToES(indexedNodeTypeTest);
NodeType nt = dao.findById(NodeType.class, indexedNodeTypeTest.getId());
assertBeanEqualsToOriginal(nt);
nt = dao.findById(NodeType.class, indexedNodeTypeTest.getId());
assertBeanEqualsToOriginal(nt);
nt = dao.findById(NodeType.class, "5");
isNull(nt);
// findByIds
List<NodeType> lnt = dao.findByIds(NodeType.class, new String[] { indexedNodeTypeTest.getId() });
List<NodeType> lnt2 = dao.findByIds(NodeType.class, new String[] { indexedNodeTypeTest.getId(), "5" });
isTrue(!lnt.isEmpty());
isTrue(!lnt2.isEmpty());
assertEquals(1, lnt.size());
assertEquals(1, lnt2.size());
nt = lnt.get(0);
assertBeanEqualsToOriginal(nt);
nt = lnt2.get(0);
assertBeanEqualsToOriginal(nt);
// findByIdsWithContext
saveApplications();
List<Application> apps = dao.findByIdsWithContext(Application.class, FetchContext.SUMMARY, new String[] { "1", "2", "8" });
log.info("Search: " + JsonUtil.toString(apps));
assertNotNull(apps);
assertFalse(apps.isEmpty());
assertEquals(2, apps.size());
String[] expectedId = new String[] { "1", "2" };
String[] ids = null;
String[] expectedNames = new String[] { "app1", "app2" };
String[] names = null;
for (Application application : apps) {
ids = ArrayUtils.add(ids, application.getId());
names = ArrayUtils.add(names, application.getName());
assertNull(application.getDescription());
}
Arrays.sort(expectedId);
Arrays.sort(ids);
Arrays.sort(expectedNames);
Arrays.sort(names);
assertArrayEquals(expectedId, ids);
assertArrayEquals(expectedNames, names);
}
private void saveApplications() {
Application app = new Application();
app.setId("1");
app.setName("app1");
app.setDescription("this is app1");
dao.save(app);
app.setId("2");
app.setName("app2");
app.setDescription("this is app2");
dao.save(app);
app.setId("3");
app.setName("app3");
app.setDescription("this is app3");
dao.save(app);
refresh();
}
@Test
public void deleteToscaComponentSuccessfulTest() throws IndexingServiceException, JsonProcessingException {
String typeName1 = indexedNodeTypeTest.getClass().getSimpleName();
saveDataToES(indexedNodeTypeTest);
dao.delete(NodeType.class, indexedNodeTypeTest.getId());
assertDocumentExisit(ElasticSearchDAO.TOSCA_ELEMENT_INDEX, typeName1, indexedNodeTypeTest.getId(), false);
saveDataToES(indexedNodeTypeTest);
dao.delete(NodeType.class, indexedNodeTypeTest.getId());
assertDocumentExisit(ElasticSearchDAO.TOSCA_ELEMENT_INDEX, typeName1, indexedNodeTypeTest.getId(), false);
saveDataToES(indexedNodeTypeTest);
dao.delete(indexedNodeTypeTest.getClass(), indexedNodeTypeTest.getId());
assertDocumentExisit(ElasticSearchDAO.TOSCA_ELEMENT_INDEX, typeName1, indexedNodeTypeTest.getId(), false);
}
@Test(expected = IndexingServiceException.class)
public void unsupportedIndexedDeletionTest() throws JsonProcessingException, IndexingServiceException {
saveDataToES(indexedNodeTypeTest);
dao.delete(PropertyDefinition.class, "");
}
@Test
public void createAndUpdateToscaElement() {
// Saving indexednodetype with creationdate
dao.save(indexedNodeTypeTest);
NodeType indexedNodeType = dao.findById(NodeType.class, indexedNodeTypeTest.getId());
assertEquals(indexedNodeType.getCreationDate(), indexedNodeTypeTest.getCreationDate());
// Updating
List<Tag> updatedTags = Lists.newArrayList();
updatedTags.add(new Tag("tag2", "UPDATE tag2 value"));
updatedTags.add(new Tag("NEWTAG", "UPDATE new tag"));
updateAndSaveIndexedToscaElement(updatedTags);
indexedNodeType = dao.findById(NodeType.class, indexedNodeTypeTest.getId());
assertEquals(indexedNodeType.getCreationDate(), indexedNodeTypeTest.getCreationDate());
assertTrue(indexedNodeType.getTags().contains(new Tag("NEWTAG", null)));
assertTrue("LastUpdateDate date should be greater than creationDate date", indexedNodeType.getLastUpdateDate().after(indexedNodeType.getCreationDate()));
}
private void updateAndSaveIndexedToscaElement(final List<Tag> tags) {
Date creationDate = indexedNodeTypeTest.getCreationDate();
indexedNodeTypeTest.getTags().addAll(tags);
// Update after creation
indexedNodeTypeTest.getLastUpdateDate().setTime(creationDate.getTime() + 3600);
dao.save(indexedNodeTypeTest);
}
private void assertIndexExists(String indexName, boolean expected) throws InterruptedException, ExecutionException {
final ActionFuture<IndicesExistsResponse> indexExistFuture = nodeClient.admin().indices().exists(new IndicesExistsRequest(indexName));
final IndicesExistsResponse response = indexExistFuture.get();
assertEquals(expected, response.isExists());
}
private void assertTypeExists(String indexName, Class<?> clazz, boolean expected) throws InterruptedException, ExecutionException, JsonGenerationException,
JsonMappingException, IntrospectionException, IOException {
assertTypeExists(indexName, clazz.getSimpleName().toLowerCase(), expected);
}
private void assertTypeExists(String indexName, String typeToCheck, boolean expected) throws InterruptedException, ExecutionException,
JsonGenerationException, JsonMappingException, IntrospectionException, IOException {
final ActionFuture<TypesExistsResponse> typeExistsFuture = nodeClient.admin().indices()
.typesExists(new TypesExistsRequest(new String[] { indexName }, typeToCheck));
final TypesExistsResponse response = typeExistsFuture.get();
assertEquals(expected, response.isExists());
}
private void assertDocumentExisit(String indexName, String typeName, String id, boolean expected) {
GetResponse response = getDocument(indexName, typeName, id);
assertEquals(expected, response.isExists());
assertEquals(expected, !response.isSourceEmpty());
}
private GetResponse getDocument(String indexName, String typeName, String id) {
return nodeClient.prepareGet(indexName, typeName, id).execute().actionGet();
}
private void prepareToscaElement() {
List<CapabilityDefinition> capa = Arrays.asList(new CapabilityDefinition("container", "container", 1), new CapabilityDefinition("container1",
"container1", 1), new CapabilityDefinition("container2", "container2", 1), new CapabilityDefinition("container3", "container3", 1));
List<RequirementDefinition> req = Arrays.asList(new RequirementDefinition("Runtime", "Runtime"), new RequirementDefinition("server", "server"),
new RequirementDefinition("blob", "blob"));
List<String> der = Arrays.asList("Parent1", "Parent2");
indexedNodeTypeTest = TestModelUtil.createIndexedNodeType("1", "positive", "1.0", "", capa, req, der, new ArrayList<String>(0), threeTags, new Date(),
new Date());
}
private void saveDataToES(AbstractToscaType element) throws JsonProcessingException {
String json = jsonMapper.writeValueAsString(element);
String typeName = NodeType.class.getSimpleName().toLowerCase();
nodeClient.prepareIndex(ElasticSearchDAO.TOSCA_ELEMENT_INDEX, typeName).setSource(json).setRefresh(true).execute().actionGet();
assertDocumentExisit(ElasticSearchDAO.TOSCA_ELEMENT_INDEX, typeName, element.getId(), true);
refresh();
}
private <T> void assertBeanEqualsToOriginal(T bean) {
if (bean instanceof NodeType) {
NodeType indexedNodeType = (NodeType) bean;
assertEquals(indexedNodeTypeTest.getId(), indexedNodeType.getId());
assertEquals(indexedNodeTypeTest.getArchiveName(), indexedNodeType.getArchiveName());
assertEquals(0, indexedNodeType.getDefaultCapabilities().size());
assertEquals(indexedNodeTypeTest.getRequirements().size(), indexedNodeType.getRequirements().size());
assertEquals(indexedNodeTypeTest.getTags().size(), indexedNodeType.getTags().size());
assertEquals(indexedNodeTypeTest.getTags(), threeTags);
}
}
}