blob: 7e2edd85eab09da8aa025d23ed0eace09bfbfa4d [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.atlas.service;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasException;
import org.apache.atlas.EntityAuditEvent;
import org.apache.atlas.RequestContext;
import org.apache.atlas.TestOnlyModule;
import org.apache.atlas.TestUtils;
import org.apache.atlas.discovery.graph.GraphBackedDiscoveryService;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.listener.ChangedTypeDefs;
import org.apache.atlas.listener.EntityChangeListener;
import org.apache.atlas.listener.TypeDefChangeListener;
import org.apache.atlas.query.QueryParams;
import org.apache.atlas.repository.audit.EntityAuditRepository;
import org.apache.atlas.repository.audit.HBaseBasedAuditRepository;
import org.apache.atlas.repository.audit.HBaseTestUtils;
import org.apache.atlas.repository.graph.AtlasGraphProvider;
import org.apache.atlas.services.DefaultMetadataService;
import org.apache.atlas.services.MetadataService;
import org.apache.atlas.type.AtlasTypeUtil;
import org.apache.atlas.typesystem.IReferenceableInstance;
import org.apache.atlas.typesystem.IStruct;
import org.apache.atlas.typesystem.ITypedReferenceableInstance;
import org.apache.atlas.typesystem.Referenceable;
import org.apache.atlas.typesystem.Struct;
import org.apache.atlas.typesystem.TypesDef;
import org.apache.atlas.typesystem.exception.EntityNotFoundException;
import org.apache.atlas.typesystem.exception.TypeNotFoundException;
import org.apache.atlas.typesystem.json.InstanceSerialization;
import org.apache.atlas.typesystem.json.TypesSerialization;
import org.apache.atlas.typesystem.persistence.Id;
import org.apache.atlas.typesystem.types.AttributeDefinition;
import org.apache.atlas.typesystem.types.ClassType;
import org.apache.atlas.typesystem.types.DataTypes;
import org.apache.atlas.typesystem.types.EnumValue;
import org.apache.atlas.typesystem.types.HierarchicalTypeDefinition;
import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.TypeSystem;
import org.apache.atlas.typesystem.types.ValueConversionException;
import org.apache.atlas.typesystem.types.cache.TypeCache;
import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.apache.atlas.utils.ParamChecker;
import org.apache.commons.lang.RandomStringUtils;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.testng.Assert;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.apache.atlas.TestUtils.*;
import static org.apache.atlas.typesystem.types.utils.TypesUtil.createClassTypeDef;
import static org.apache.atlas.typesystem.types.utils.TypesUtil.createOptionalAttrDef;
import static org.testng.Assert.*;
@Guice(modules = TestOnlyModule.class)
public class DefaultMetadataServiceTest {
@Inject
private MetadataService metadataService;
private TypeDefChangeListener typeDefChangeListener;
@Inject
private EntityAuditRepository auditRepository;
@Inject
private GraphBackedDiscoveryService discoveryService;
private Referenceable db = createDBEntity();
private Referenceable table;
private Id tableId;
private final String NAME = "name";
@BeforeTest
public void setUp() throws Exception {
typeDefChangeListener = (DefaultMetadataService)metadataService;
metadataService = TestUtils.addSessionCleanupWrapper(metadataService);
if (auditRepository instanceof HBaseBasedAuditRepository) {
HBaseTestUtils.startCluster();
((HBaseBasedAuditRepository) auditRepository).start();
}
TestUtils.resetRequestContext();
RequestContext.get().setUser("testuser");
TypesDef typesDef = TestUtils.defineHiveTypes();
try {
metadataService.getTypeDefinition(TestUtils.TABLE_TYPE);
} catch (TypeNotFoundException e) {
metadataService.createType(TypesSerialization.toJson(typesDef));
}
String dbGUid = TestUtils.createInstance(metadataService, db);
table = createTableEntity(dbGUid);
String tableGuid = TestUtils.createInstance(metadataService, table);
String tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
table = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
tableId = new Id(tableGuid, 0, TestUtils.TABLE_TYPE);
}
@AfterTest
public void shutdown() throws Exception {
try {
TypeSystem.getInstance().reset();
if (auditRepository instanceof HBaseBasedAuditRepository) {
((HBaseBasedAuditRepository) auditRepository).stop();
HBaseTestUtils.stopCluster();
}
}
finally {
AtlasGraphProvider.cleanup();
}
}
private AtlasClient.EntityResult updateInstance(Referenceable entity) throws Exception {
RequestContext.createContext();
ParamChecker.notNull(entity, "Entity");
ParamChecker.notNull(entity.getId(), "Entity");
String entityjson = InstanceSerialization.toJson(entity, true);
JSONArray entitiesJson = new JSONArray();
entitiesJson.put(entityjson);
return metadataService.updateEntities(entitiesJson.toString()).getEntityResult();
}
@Test(expectedExceptions = TypeNotFoundException.class)
public void testCreateEntityWithUnknownDatatype() throws Exception {
Referenceable entity = new Referenceable("Unknown datatype");
String dbName = RandomStringUtils.randomAlphanumeric(10);
entity.set(NAME, dbName);
entity.set("description", "us db");
TestUtils.createInstance(metadataService, entity);
Assert.fail(TypeNotFoundException.class.getSimpleName() + " was expected but none thrown.");
}
@Test
public void testCreateEntityWithUniqueAttribute() throws Exception {
//name is the unique attribute
Referenceable entity = createDBEntity();
String id = TestUtils.createInstance(metadataService, entity);
assertAuditEvents(id, EntityAuditEvent.EntityAuditAction.ENTITY_CREATE);
//using the same name should succeed, but not create another entity
String newId = TestUtils.createInstance(metadataService, entity);
assertNull(newId);
//Same entity, but different qualified name should succeed
entity.set(NAME, TestUtils.randomString());
newId = TestUtils.createInstance(metadataService, entity);
Assert.assertNotEquals(newId, id);
}
@Test
//Titan doesn't allow some reserved chars in property keys. Verify that atlas encodes these
//See GraphHelper.encodePropertyKey()
public void testSpecialCharacters() throws Exception {
//Verify that type can be created with reserved characters in typename, attribute name
String strAttrName = randomStrWithReservedChars();
String arrayAttrName = randomStrWithReservedChars();
String mapAttrName = randomStrWithReservedChars();
HierarchicalTypeDefinition<ClassType> typeDefinition =
createClassTypeDef("test_type_"+ RandomStringUtils.randomAlphanumeric(10), ImmutableSet.<String>of(),
createOptionalAttrDef(strAttrName, DataTypes.STRING_TYPE),
new AttributeDefinition(arrayAttrName, DataTypes.arrayTypeName(DataTypes.STRING_TYPE.getName()),
Multiplicity.OPTIONAL, false, null),
new AttributeDefinition(mapAttrName,
DataTypes.mapTypeName(DataTypes.STRING_TYPE.getName(), DataTypes.STRING_TYPE.getName()),
Multiplicity.OPTIONAL, false, null));
metadataService.createType(TypesSerialization.toJson(typeDefinition, false));
//verify that entity can be created with reserved characters in string value, array value and map key and value
Referenceable entity = new Referenceable(typeDefinition.typeName);
entity.set(strAttrName, randomStrWithReservedChars());
entity.set(arrayAttrName, new ArrayList<String>() {{ add(randomStrWithReservedChars()); }});
entity.set(mapAttrName, new HashMap<String, String>() {{
put(randomStrWithReservedChars(), randomStrWithReservedChars());
}});
String id = createInstance(metadataService, entity);
//Verify that get entity definition returns actual values with reserved characters
Referenceable instance =
InstanceSerialization.fromJsonReferenceable(metadataService.getEntityDefinitionJson(id), true);
assertReferenceableEquals(instance, entity);
//Verify that search with reserved characters works - for string attribute
String query =
String.format("`%s` where `%s` = '%s'", typeDefinition.typeName, strAttrName, entity.get(strAttrName));
String responseJson = discoveryService.searchByDSL(query, new QueryParams(1, 0));
JSONObject response = new JSONObject(responseJson);
assertEquals(response.getJSONArray("rows").length(), 1);
}
//equals excluding the id
private void assertReferenceableEquals(Referenceable actual, Referenceable expected) {
List<String> traits = actual.getTraits();
Map<String, IStruct> traitsMap = new HashMap<>();
for (String trait : traits) {
traitsMap.put(trait, actual.getTrait(trait));
}
Referenceable newActual = new Referenceable(expected.getId(), actual.getTypeName(), actual.getValuesMap(),
traits, traitsMap);
assertEquals(newActual, expected);
}
private String randomStrWithReservedChars() {
return randomString() + "\"${}%";
}
@Test
public void testAddDeleteTrait() throws Exception {
Referenceable entity = createDBEntity();
String id = TestUtils.createInstance(metadataService, entity);
//add trait
Struct tag = new Struct(TestUtils.PII);
metadataService.addTrait(id, InstanceSerialization.toJson(tag, true));
List<String> traits = metadataService.getTraitNames(id);
assertEquals(traits.size(), 1);
assertEquals(traits.get(0), PII);
//getTrait
IStruct traitDefinition = metadataService.getTraitDefinition(id, PII);
Assert.assertNotNull(traitDefinition);
assertEquals(traitDefinition.getValuesMap().size(), 0);
//delete trait
metadataService.deleteTrait(id, PII);
traits = metadataService.getTraitNames(id);
assertEquals(traits.size(), 0);
//add trait again
metadataService.addTrait(id, InstanceSerialization.toJson(tag, true));
traits = metadataService.getTraitNames(id);
assertEquals(traits.size(), 1);
assertEquals(traits.get(0), PII);
}
@Test
public void testEntityAudit() throws Exception {
//create entity
Referenceable entity = createDBEntity();
String id = TestUtils.createInstance(metadataService, entity);
assertAuditEvents(id, EntityAuditEvent.EntityAuditAction.ENTITY_CREATE);
Struct tag = new Struct(TestUtils.PII);
metadataService.addTrait(id, InstanceSerialization.toJson(tag, true));
assertAuditEvents(id, EntityAuditEvent.EntityAuditAction.TAG_ADD);
metadataService.deleteTrait(id, TestUtils.PII);
assertAuditEvents(id, EntityAuditEvent.EntityAuditAction.TAG_DELETE);
metadataService.updateEntityAttributeByGuid(id, "description", "new description");
assertAuditEvents(id, EntityAuditEvent.EntityAuditAction.ENTITY_UPDATE);
metadataService.deleteEntities(Arrays.asList(id));
assertAuditEvents(id, EntityAuditEvent.EntityAuditAction.ENTITY_DELETE);
}
private AtlasClient.EntityResult deleteEntities(String... guids) throws AtlasException {
RequestContext.createContext();
return metadataService.deleteEntities(Arrays.asList(guids));
}
private void assertAuditEvents(String id, EntityAuditEvent.EntityAuditAction expectedAction) throws Exception {
List<EntityAuditEvent> events =
auditRepository.listEvents(id, null, (short) 10);
for (EntityAuditEvent event : events) {
if (event.getAction() == expectedAction) {
return;
}
}
fail("Expected audit action " + expectedAction);
}
private void assertAuditEvents(String entityId, int numEvents) throws Exception {
List<EntityAuditEvent> events = metadataService.getAuditEvents(entityId, null, (short) numEvents);
assertNotNull(events);
assertEquals(events.size(), numEvents);
}
@Test
public void testCreateEntityWithUniqueAttributeWithReference() throws Exception {
Referenceable db = createDBEntity();
String dbId = TestUtils.createInstance(metadataService, db);
//Assert that there is just 1 audit events and thats for entity create
assertAuditEvents(dbId, 1);
assertAuditEvents(dbId, EntityAuditEvent.EntityAuditAction.ENTITY_CREATE);
Referenceable table = new Referenceable(TestUtils.TABLE_TYPE);
table.set(NAME, TestUtils.randomString());
table.set("description", "random table");
table.set("type", "type");
table.set("tableType", "MANAGED");
table.set("database", new Id(dbId, 0, TestUtils.DATABASE_TYPE));
table.set("databaseComposite", db);
TestUtils.createInstance(metadataService, table);
//table create should re-use the db instance created earlier
String tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
Referenceable tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
Referenceable actualDb = (Referenceable) tableDefinition.get("databaseComposite");
assertEquals(actualDb.getId().id, dbId);
//Assert that as part table create, db is not created and audit event is not added to db
assertAuditEvents(dbId, 1);
}
@Test
public void testUpdateEntityByUniqueAttribute() throws Exception {
final List<String> colNameList = ImmutableList.of("col1", "col2");
Referenceable tableUpdated = new Referenceable(TestUtils.TABLE_TYPE, new HashMap<String, Object>() {{
put("columnNames", colNameList);
}});
metadataService.updateEntityByUniqueAttribute(table.getTypeName(), NAME, (String) table.get(NAME),
tableUpdated);
String tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
Referenceable tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
List<String> actualColumns = (List) tableDefinition.get("columnNames");
assertEquals(actualColumns, colNameList);
}
@Test
public void testUpdateEntityWithMap() throws Exception {
final Map<String, Struct> partsMap = new HashMap<>();
partsMap.put("part0", new Struct(TestUtils.PARTITION_STRUCT_TYPE,
new HashMap<String, Object>() {{
put(NAME, "test");
}}));
table.set("partitionsMap", partsMap);
updateInstance(table);
String tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
Referenceable tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
Assert.assertTrue(partsMap.get("part0").equalsContents(((Map<String, Struct>)tableDefinition.get("partitionsMap")).get("part0")));
//update map - add a map key
partsMap.put("part1", new Struct(TestUtils.PARTITION_STRUCT_TYPE,
new HashMap<String, Object>() {{
put(NAME, "test1");
}}));
table.set("partitionsMap", partsMap);
updateInstance(table);
tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
assertEquals(((Map<String, Struct>)tableDefinition.get("partitionsMap")).size(), 2);
Assert.assertTrue(partsMap.get("part1").equalsContents(((Map<String, Struct>)tableDefinition.get("partitionsMap")).get("part1")));
//update map - remove a key and add another key
partsMap.remove("part0");
partsMap.put("part2", new Struct(TestUtils.PARTITION_STRUCT_TYPE,
new HashMap<String, Object>() {{
put(NAME, "test2");
}}));
table.set("partitionsMap", partsMap);
updateInstance(table);
tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
assertEquals(((Map<String, Struct>)tableDefinition.get("partitionsMap")).size(), 2);
Assert.assertNull(((Map<String, Struct>)tableDefinition.get("partitionsMap")).get("part0"));
Assert.assertTrue(partsMap.get("part2").equalsContents(((Map<String, Struct>)tableDefinition.get("partitionsMap")).get("part2")));
//update struct value for existing map key
Struct partition2 = partsMap.get("part2");
partition2.set(NAME, "test2Updated");
updateInstance(table);
tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
assertEquals(((Map<String, Struct>)tableDefinition.get("partitionsMap")).size(), 2);
Assert.assertNull(((Map<String, Struct>)tableDefinition.get("partitionsMap")).get("part0"));
Assert.assertTrue(partsMap.get("part2").equalsContents(((Map<String, Struct>)tableDefinition.get("partitionsMap")).get("part2")));
//Test map pointing to a class
final Map<String, Referenceable> columnsMap = new HashMap<>();
Referenceable col0Type = new Referenceable(TestUtils.COLUMN_TYPE,
new HashMap<String, Object>() {{
put(NAME, "test1");
put("type", "string");
}});
columnsMap.put("col0", col0Type);
Referenceable col1Type = new Referenceable(TestUtils.COLUMN_TYPE,
new HashMap<String, Object>() {{
put(NAME, "test2");
put("type", "string");
}});
columnsMap.put("col1", col1Type);
table.set(TestUtils.COLUMNS_MAP, columnsMap);
updateInstance(table);
verifyMapUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columnsMap, TestUtils.COLUMNS_MAP);
//Swap elements
columnsMap.clear();
columnsMap.put("col0", col1Type);
columnsMap.put("col1", col0Type);
table.set(TestUtils.COLUMNS_MAP, columnsMap);
updateInstance(table);
verifyMapUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columnsMap, TestUtils.COLUMNS_MAP);
//Drop the first key and change the class type as well to col0
columnsMap.clear();
columnsMap.put("col0", col0Type);
table.set(TestUtils.COLUMNS_MAP, columnsMap);
updateInstance(table);
verifyMapUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columnsMap, TestUtils.COLUMNS_MAP);
//Clear state
table.setNull(TestUtils.COLUMNS_MAP);
updateInstance(table);
verifyMapUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), null, TestUtils.COLUMNS_MAP);
}
private void verifyMapUpdates(String typeName, String uniqAttrName, String uniqAttrValue,
Map<String, Referenceable> expectedMap, String mapAttrName) throws AtlasException {
String json =
metadataService.getEntityDefinition(typeName, uniqAttrName, uniqAttrValue);
Referenceable tableDefinition = InstanceSerialization.fromJsonReferenceable(json, true);
Map<String, Referenceable> actualMap = (Map<String, Referenceable>) tableDefinition.get(mapAttrName);
if (expectedMap == null && actualMap != null) {
//all are marked as deleted in case of soft delete
for (String key : actualMap.keySet()) {
assertEquals(actualMap.get(key).getId().state, Id.EntityState.DELETED);
}
} else if(expectedMap == null) {
//hard delete case
assertNull(actualMap);
} else {
assertTrue(actualMap.size() >= expectedMap.size());
for (String key : expectedMap.keySet()) {
assertTrue(actualMap.get(key).equalsContents(expectedMap.get(key)));
}
//rest of the keys are marked as deleted
List<String> extraKeys = new ArrayList<>(actualMap.keySet());
extraKeys.removeAll(expectedMap.keySet());
for (String key : extraKeys) {
assertEquals(actualMap.get(key).getId().getState(), Id.EntityState.DELETED);
}
}
}
@Test
public void testUpdateEntityAddAndUpdateArrayAttr() throws Exception {
//Update entity, add new array attribute
//add array of primitives
final List<String> colNameList = ImmutableList.of("col1", "col2");
Referenceable tableUpdated = new Referenceable(TestUtils.TABLE_TYPE, new HashMap<String, Object>() {{
put("columnNames", colNameList);
}});
metadataService.updateEntityPartialByGuid(tableId._getId(), tableUpdated);
String tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
Referenceable tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
List<String> actualColumns = (List) tableDefinition.get("columnNames");
assertEquals(actualColumns, colNameList);
//update array of primitives
final List<String> updatedColNameList = ImmutableList.of("col2", "col3");
tableUpdated = new Referenceable(TestUtils.TABLE_TYPE, new HashMap<String, Object>() {{
put("columnNames", updatedColNameList);
}});
metadataService.updateEntityPartialByGuid(tableId.getId()._getId(), tableUpdated);
tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
actualColumns = (List) tableDefinition.get("columnNames");
assertEquals(actualColumns, updatedColNameList);
}
private AtlasClient.EntityResult updateEntityPartial(String guid, Referenceable entity) throws AtlasException {
RequestContext.createContext();
return metadataService.updateEntityPartialByGuid(guid, entity).getEntityResult();
}
@Test
public void testUpdateEntityArrayOfClass() throws Exception {
//test array of class with id
final List<Referenceable> columns = new ArrayList<>();
Map<String, Object> values = new HashMap<>();
values.put(NAME, "col1");
values.put("type", "type");
Referenceable col1 = new Referenceable(TestUtils.COLUMN_TYPE, values);
columns.add(col1);
Referenceable tableUpdated = new Referenceable(TestUtils.TABLE_TYPE, new HashMap<String, Object>() {{
put(COLUMNS_ATTR_NAME, columns);
}});
AtlasClient.EntityResult entityResult = updateEntityPartial(tableId._getId(), tableUpdated);
assertEquals(entityResult.getCreatedEntities().size(), 1); //col1 created
assertEquals(entityResult.getUpdateEntities().size(), 1); //table updated
assertEquals(entityResult.getUpdateEntities().get(0), tableId._getId());
verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columns, COLUMNS_ATTR_NAME);
//Partial update. Add col2 But also update col1
Map<String, Object> valuesCol5 = new HashMap<>();
valuesCol5.put(NAME, "col2");
valuesCol5.put("type", "type");
Referenceable col2 = new Referenceable(TestUtils.COLUMN_TYPE, valuesCol5);
//update col1
col1.set("type", "type1");
columns.add(col2);
tableUpdated = new Referenceable(TestUtils.TABLE_TYPE, new HashMap<String, Object>() {{
put(COLUMNS_ATTR_NAME, columns);
}});
entityResult = updateEntityPartial(tableId._getId(), tableUpdated);
assertEquals(entityResult.getCreatedEntities().size(), 1); //col2 created
assertEquals(entityResult.getUpdateEntities().size(), 2); //table, col1 updated
verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columns, COLUMNS_ATTR_NAME);
//Complete update. Add array elements - col3,col4
Map<String, Object> values1 = new HashMap<>();
values1.put(NAME, "col3");
values1.put("type", "type");
Referenceable col3 = new Referenceable(TestUtils.COLUMN_TYPE, values1);
columns.add(col3);
Map<String, Object> values2 = new HashMap<>();
values2.put(NAME, "col4");
values2.put("type", "type");
Referenceable col4 = new Referenceable(TestUtils.COLUMN_TYPE, values2);
columns.add(col4);
table.set(COLUMNS_ATTR_NAME, columns);
entityResult = updateInstance(table);
assertEquals(entityResult.getCreatedEntities().size(), 2); //col3, col4 created
verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columns, COLUMNS_ATTR_NAME);
//Swap elements
columns.clear();
columns.add(col4);
columns.add(col3);
table.set(COLUMNS_ATTR_NAME, columns);
entityResult = updateInstance(table);
assertEquals(entityResult.getDeletedEntities().size(), 2); //col1, col2 are deleted
verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columns, COLUMNS_ATTR_NAME);
//drop a single column
columns.clear();
columns.add(col3);
table.set(COLUMNS_ATTR_NAME, columns);
entityResult = updateInstance(table);
assertEquals(entityResult.getDeletedEntities().size(), 1); //col4 deleted
verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columns, COLUMNS_ATTR_NAME);
//Remove a class reference/Id and insert another reference
//Also covers isComposite case since columns is a composite
values.clear();
columns.clear();
values.put(NAME, "col5");
values.put("type", "type");
Referenceable col5 = new Referenceable(TestUtils.COLUMN_TYPE, values);
columns.add(col5);
table.set(COLUMNS_ATTR_NAME, columns);
entityResult = updateInstance(table);
assertEquals(entityResult.getCreatedEntities().size(), 1); //col5 created
assertEquals(entityResult.getDeletedEntities().size(), 1); //col3 deleted
verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columns, COLUMNS_ATTR_NAME);
//Update array column to null
table.setNull(COLUMNS_ATTR_NAME);
entityResult = updateInstance(table);
assertEquals(entityResult.getDeletedEntities().size(), 1);
verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), null, COLUMNS_ATTR_NAME);
}
private void verifyArrayUpdates(String typeName, String uniqAttrName, String uniqAttrValue,
List<Referenceable> expectedArray, String arrAttrName) throws AtlasException {
String json = metadataService.getEntityDefinition(typeName, uniqAttrName, uniqAttrValue);
Referenceable entityDefinition = InstanceSerialization.fromJsonReferenceable(json, true);
List<Referenceable> actualArray = (List<Referenceable>) entityDefinition.get(arrAttrName);
if (expectedArray == null && actualArray != null) {
//all are marked as deleted in case of soft delete
for (Referenceable referenceable : actualArray) {
assertEquals(referenceable.getId().state, Id.EntityState.DELETED);
}
} else if(expectedArray == null) {
//hard delete case
assertNull(actualArray);
} else {
int index;
for (index = 0; index < expectedArray.size(); index++) {
Assert.assertTrue(actualArray.get(index).equalsContents(expectedArray.get(index)));
}
//Rest of the entities in the list are marked as deleted
for (; index < actualArray.size(); index++) {
assertEquals(actualArray.get(index).getId().state, Id.EntityState.DELETED);
}
}
}
@Test
public void testStructs() throws Exception {
Struct serdeInstance = new Struct(TestUtils.SERDE_TYPE);
serdeInstance.set(NAME, "serde1Name");
serdeInstance.set("serde", "test");
serdeInstance.set("description", "testDesc");
table.set("serde1", serdeInstance);
String newtableId = updateInstance(table).getUpdateEntities().get(0);
assertEquals(newtableId, tableId._getId());
String tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
Referenceable tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
Assert.assertNotNull(tableDefinition.get("serde1"));
Assert.assertTrue(serdeInstance.equalsContents(tableDefinition.get("serde1")));
//update struct attribute
serdeInstance.set("serde", "testUpdated");
updateInstance(table);
tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
Assert.assertTrue(serdeInstance.equalsContents(tableDefinition.get("serde1")));
//set to null
serdeInstance.setNull("description");
updateInstance(table);
tableDefinitionJson =
metadataService.getEntityDefinitionJson(tableId._getId());
tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
Assert.assertNull(((Struct) tableDefinition.get("serde1")).get("description"));
}
@Test
public void testCreateEntityWithReferenceableHavingIdNoValue() throws Exception {
//ATLAS-383 Test
Referenceable sdReferenceable = new Referenceable(TestUtils.STORAGE_DESC_TYPE);
sdReferenceable.set(AtlasClient.REFERENCEABLE_ATTRIBUTE_NAME, TestUtils.randomString());
sdReferenceable.set("compressed", "false");
sdReferenceable.set("location", "hdfs://tmp/hive-user");
String sdGuid = TestUtils.createInstance(metadataService, sdReferenceable);
Referenceable sdRef2 = new Referenceable(sdGuid, TestUtils.STORAGE_DESC_TYPE, null);
Referenceable partRef = new Referenceable(TestUtils.PARTITION_CLASS_TYPE);
partRef.set(AtlasClient.REFERENCEABLE_ATTRIBUTE_NAME, "part-unique");
partRef.set("values", ImmutableList.of("2014-10-01"));
partRef.set("table", table);
partRef.set("sd", sdRef2);
String partGuid = TestUtils.createInstance(metadataService, partRef);
Assert.assertNotNull(partGuid);
}
@Test
public void testClassUpdate() throws Exception {
//Create new db instance
final Referenceable databaseInstance = new Referenceable(TestUtils.DATABASE_TYPE);
databaseInstance.set(NAME, TestUtils.randomString());
databaseInstance.set("description", "new database");
String dbId = TestUtils.createInstance(metadataService, databaseInstance);
/*Update reference property with Id */
metadataService.updateEntityAttributeByGuid(tableId._getId(), "database", dbId);
String tableDefinitionJson =
metadataService.getEntityDefinitionJson(tableId._getId());
Referenceable tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
assertEquals(dbId, (((Id) tableDefinition.get("database"))._getId()));
/* Update with referenceable - TODO - Fails . Need to fix this */
/*final String dbName = TestUtils.randomString();
final Referenceable databaseInstance2 = new Referenceable(TestUtils.DATABASE_TYPE);
databaseInstance2.set(NAME, dbName);
databaseInstance2.set("description", "new database 2");
Referenceable updateTable = new Referenceable(TestUtils.TABLE_TYPE, new HashMap<String, Object>() {{
put("database", databaseInstance2);
}});
metadataService.updateEntityAttributeByGuid(tableId._getId(), updateTable);
tableDefinitionJson =
metadataService.getEntityDefinition(tableId._getId());
Referenceable tableDefinitionActual = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
String dbDefJson = metadataService.getEntityDefinition(TestUtils.DATABASE_TYPE, NAME, dbName);
Referenceable dbDef = InstanceSerialization.fromJsonReferenceable(dbDefJson, true);
Assert.assertNotEquals(dbId, (((Id) tableDefinitionActual.get("database"))._getId()));
Assert.assertEquals(dbDef.getObjectId()._getId(), (((Id) tableDefinitionActual.get("database"))._getId())); */
}
@Test
public void testArrayOfStructs() throws Exception {
//Add array of structs
TestUtils.dumpGraph(TestUtils.getGraph());
final Struct partition1 = new Struct(TestUtils.PARTITION_STRUCT_TYPE);
partition1.set(NAME, "part1");
final Struct partition2 = new Struct(TestUtils.PARTITION_STRUCT_TYPE);
partition2.set(NAME, "part2");
List<Struct> partitions = new ArrayList<Struct>(){{ add(partition1); add(partition2); }};
table.set("partitions", partitions);
String newtableId = updateInstance(table).getUpdateEntities().get(0);
assertEquals(newtableId, tableId._getId());
String tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
Referenceable tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
Assert.assertNotNull(tableDefinition.get("partitions"));
List<Struct> partitionsActual = (List<Struct>) tableDefinition.get("partitions");
assertPartitions(partitionsActual, partitions);
//add a new element to array of struct
final Struct partition3 = new Struct(TestUtils.PARTITION_STRUCT_TYPE);
partition3.set(NAME, "part3");
partitions.add(partition3);
table.set("partitions", partitions);
newtableId = updateInstance(table).getUpdateEntities().get(0);
assertEquals(newtableId, tableId._getId());
tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
Assert.assertNotNull(tableDefinition.get("partitions"));
partitionsActual = (List<Struct>) tableDefinition.get("partitions");
assertPartitions(partitionsActual, partitions);
//remove one of the struct values
partitions.remove(1);
table.set("partitions", partitions);
newtableId = updateInstance(table).getUpdateEntities().get(0);
assertEquals(newtableId, tableId._getId());
tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
Assert.assertNotNull(tableDefinition.get("partitions"));
partitionsActual = (List<Struct>) tableDefinition.get("partitions");
assertPartitions(partitionsActual, partitions);
//Update struct value within array of struct
partitions.get(0).set(NAME, "part4");
newtableId = updateInstance(table).getUpdateEntities().get(0);
assertEquals(newtableId, tableId._getId());
tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
Assert.assertNotNull(tableDefinition.get("partitions"));
partitionsActual = (List<Struct>) tableDefinition.get("partitions");
assertPartitions(partitionsActual, partitions);
//add a repeated element to array of struct
final Struct partition4 = new Struct(TestUtils.PARTITION_STRUCT_TYPE);
partition4.set(NAME, "part4");
partitions.add(partition4);
table.set("partitions", partitions);
newtableId = updateInstance(table).getUpdateEntities().get(0);
assertEquals(newtableId, tableId._getId());
tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
Assert.assertNotNull(tableDefinition.get("partitions"));
partitionsActual = (List<Struct>) tableDefinition.get("partitions");
assertPartitions(partitionsActual, partitions);
// Remove all elements. Should set array attribute to null
partitions.clear();
newtableId = updateInstance(table).getUpdateEntities().get(0);
assertEquals(newtableId, tableId._getId());
tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
Assert.assertNull(tableDefinition.get("partitions"));
}
private void assertPartitions(List<Struct> partitionsActual, List<Struct> partitions) {
assertEquals(partitionsActual.size(), partitions.size());
for (int index = 0; index < partitions.size(); index++) {
assertTrue(partitionsActual.get(index).equalsContents(partitions.get(index)));
}
}
@Test(expectedExceptions = ValueConversionException.class)
public void testCreateRequiredAttrNull() throws Exception {
//Update required attribute
Referenceable tableEntity = new Referenceable(TABLE_TYPE);
tableEntity.set(NAME, "table_" + TestUtils.randomString());
TestUtils.createInstance(metadataService, tableEntity);
Assert.fail("Expected exception while creating with required attribute null");
}
@Test(expectedExceptions = ValueConversionException.class)
public void testUpdateRequiredAttrToNull() throws Exception {
//Update required attribute
String tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
Referenceable tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
assertEquals(tableDefinition.get("description"), "random table");
table.setNull("description");
updateInstance(table);
Assert.fail("Expected exception while updating required attribute to null");
}
@Test
public void testCheckOptionalAttrValueRetention() throws Exception {
Referenceable entity = createDBEntity();
String dbId = TestUtils.createInstance(metadataService, entity);
entity = getEntity(dbId);
//The optional boolean attribute should have a non-null value
final String isReplicatedAttr = "isReplicated";
final String paramsAttr = "parameters";
Assert.assertNotNull(entity.get(isReplicatedAttr));
Assert.assertEquals(entity.get(isReplicatedAttr), Boolean.FALSE);
Assert.assertNull(entity.get(paramsAttr));
//Update to true
entity.set(isReplicatedAttr, Boolean.TRUE);
//Update array
final HashMap<String, String> params = new HashMap<String, String>() {{ put("param1", "val1"); put("param2", "val2"); }};
entity.set(paramsAttr, params);
//Complete update
updateInstance(entity);
entity = getEntity(dbId);
Assert.assertNotNull(entity.get(isReplicatedAttr));
Assert.assertEquals(entity.get(isReplicatedAttr), Boolean.TRUE);
Assert.assertEquals(entity.get(paramsAttr), params);
//Complete update without setting the attribute
Referenceable newEntity = createDBEntity();
//Reset name to the current DB name
newEntity.set(NAME, entity.get(NAME));
updateInstance(newEntity);
entity = getEntity(dbId);
Assert.assertNotNull(entity.get(isReplicatedAttr));
Assert.assertEquals(entity.get(isReplicatedAttr), Boolean.TRUE);
Assert.assertEquals(entity.get(paramsAttr), params);
}
private Referenceable getEntity(String guid) throws AtlasException {
String entityJson = metadataService.getEntityDefinitionJson(guid);
Assert.assertNotNull(entityJson);
return InstanceSerialization.fromJsonReferenceable(entityJson, true);
}
@Test
public void testUpdateOptionalAttrToNull() throws Exception {
String tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
Referenceable tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
//Update optional Attribute
Assert.assertNotNull(tableDefinition.get("created"));
//Update optional attribute
table.setNull("created");
String newtableId = updateInstance(table).getUpdateEntities().get(0);
assertEquals(newtableId, tableId._getId());
tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
Assert.assertNull(tableDefinition.get("created"));
}
@Test
public void testCreateEntityWithEnum ()throws Exception {
String tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
Referenceable tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
EnumValue tableType = (EnumValue) tableDefinition.get("tableType");
assertEquals(tableType, new EnumValue("MANAGED", 1));
}
@Test
public void testGetEntityByUniqueAttribute() throws Exception {
Referenceable entity = createDBEntity();
TestUtils.createInstance(metadataService, entity);
//get entity by valid qualified name
String entityJson = metadataService.getEntityDefinition(TestUtils.DATABASE_TYPE, NAME,
(String) entity.get(NAME));
Assert.assertNotNull(entityJson);
Referenceable referenceable = InstanceSerialization.fromJsonReferenceable(entityJson, true);
assertEquals(referenceable.get(NAME), entity.get(NAME));
//get entity by invalid qualified name
try {
metadataService.getEntityDefinition(TestUtils.DATABASE_TYPE, NAME, "random");
Assert.fail("Expected EntityNotFoundException");
} catch (EntityNotFoundException e) {
//expected
}
//get entity by non-unique attribute
try {
metadataService.getEntityDefinition(TestUtils.DATABASE_TYPE, "description",
(String) entity.get("description"));
Assert.fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
//expected
}
}
@Test
public void testDeleteEntities() throws Exception {
// Create a table entity, with 3 composite column entities
Referenceable dbEntity = createDBEntity();
String dbGuid = TestUtils.createInstance(metadataService, dbEntity);
Referenceable table1Entity = createTableEntity(dbGuid);
Referenceable col1 = createColumnEntity();
Referenceable col2 = createColumnEntity();
Referenceable col3 = createColumnEntity();
table1Entity.set(COLUMNS_ATTR_NAME, ImmutableList.of(col1, col2, col3));
TestUtils.createInstance(metadataService, table1Entity);
// Retrieve the table entities from the repository,
// to get their guids and the composite column guids.
String entityJson = metadataService.getEntityDefinition(TestUtils.TABLE_TYPE,
NAME, (String)table1Entity.get(NAME));
Assert.assertNotNull(entityJson);
table1Entity = InstanceSerialization.fromJsonReferenceable(entityJson, true);
List<IReferenceableInstance> table1Columns = (List<IReferenceableInstance>) table1Entity.get(COLUMNS_ATTR_NAME);
// Register an EntityChangeListener to verify the notification mechanism
// is working for deleteEntities().
EntitiesChangeListener listener = new EntitiesChangeListener();
metadataService.registerListener(listener);
//Delete one column
String columnId = table1Columns.get(0).getId()._getId();
AtlasClient.EntityResult entityResult = deleteEntities(columnId);
//column is deleted and table is updated
assertEquals(entityResult.getDeletedEntities().get(0), columnId);
assertEquals(entityResult.getUpdateEntities().get(0), table1Entity.getId()._getId());
//verify listener was called for updates and deletes
assertEquals(entityResult.getDeletedEntities(), listener.getDeletedEntities());
assertEquals(entityResult.getUpdateEntities(), listener.getUpdatedEntities());
// Delete the table entities. The deletion should cascade
// to their composite columns.
entityResult = deleteEntities(table1Entity.getId()._getId());
// Verify that deleteEntities() response has guids for tables and their composite columns.
Assert.assertTrue(entityResult.getDeletedEntities().contains(table1Entity.getId()._getId()));
Assert.assertTrue(entityResult.getDeletedEntities().contains(table1Columns.get(1).getId()._getId()));
Assert.assertTrue(entityResult.getDeletedEntities().contains(table1Columns.get(2).getId()._getId()));
// Verify that tables and their composite columns have been deleted from the repository.
assertEntityDeleted(TABLE_TYPE, NAME, table1Entity.get(NAME));
assertEntityDeleted(COLUMN_TYPE, NAME, col2.get(NAME));
assertEntityDeleted(COLUMN_TYPE, NAME, col3.get(NAME));
// Verify that the listener was notified about the deleted entities.
List<String> deletedEntitiesFromListener = listener.getDeletedEntities();
Assert.assertNotNull(deletedEntitiesFromListener);
assertEquals(deletedEntitiesFromListener.size(), entityResult.getDeletedEntities().size());
Assert.assertTrue(deletedEntitiesFromListener.containsAll(entityResult.getDeletedEntities()));
}
private void assertEntityDeleted(String typeName, String attributeName, Object attributeValue)
throws AtlasException {
try {
metadataService.getEntityDefinition(typeName, attributeName, (String) attributeValue);
fail("Expected EntityNotFoundException");
} catch(EntityNotFoundException e) {
//expected
}
}
@Test
public void testDeleteEntityByUniqueAttribute() throws Exception {
// Create a table entity, with 3 composite column entities
Referenceable dbEntity = createDBEntity();
String dbGuid = TestUtils.createInstance(metadataService, dbEntity);
Referenceable table1Entity = createTableEntity(dbGuid);
Referenceable col1 = createColumnEntity();
Referenceable col2 = createColumnEntity();
Referenceable col3 = createColumnEntity();
table1Entity.set(COLUMNS_ATTR_NAME, ImmutableList.of(col1, col2, col3));
TestUtils.createInstance(metadataService, table1Entity);
// to get their guids and the composite column guids.
String entityJson = metadataService.getEntityDefinition(TestUtils.TABLE_TYPE,
NAME, (String) table1Entity.get(NAME));
Assert.assertNotNull(entityJson);
table1Entity = InstanceSerialization.fromJsonReferenceable(entityJson, true);
List<IReferenceableInstance> table1Columns = (List<IReferenceableInstance>) table1Entity.get(COLUMNS_ATTR_NAME);
// Register an EntityChangeListener to verify the notification mechanism
// is working for deleteEntityByUniqueAttribute().
EntitiesChangeListener listener = new EntitiesChangeListener();
metadataService.registerListener(listener);
// Delete the table entities. The deletion should cascade
// to their composite columns.
List<String> deletedGuids = metadataService.deleteEntityByUniqueAttribute(TestUtils.TABLE_TYPE, NAME,
(String) table1Entity.get(NAME)).getDeletedEntities();
// Verify that deleteEntities() response has guids for tables and their composite columns.
Assert.assertTrue(deletedGuids.contains(table1Entity.getId()._getId()));
for (IReferenceableInstance column : table1Columns) {
Assert.assertTrue(deletedGuids.contains(column.getId()._getId()));
}
// Verify that tables and their composite columns have been deleted from the repository.
// Verify that tables and their composite columns have been deleted from the repository.
assertEntityDeleted(TABLE_TYPE, NAME, table1Entity.get(NAME));
assertEntityDeleted(COLUMN_TYPE, NAME, col1.get(NAME));
assertEntityDeleted(COLUMN_TYPE, NAME, col2.get(NAME));
assertEntityDeleted(COLUMN_TYPE, NAME, col3.get(NAME));
// Verify that the listener was notified about the deleted entities.
List<String> deletedEntitiesFromListener = listener.getDeletedEntities();
Assert.assertNotNull(deletedEntitiesFromListener);
assertEquals(deletedEntitiesFromListener.size(), deletedGuids.size());
Assert.assertTrue(deletedEntitiesFromListener.containsAll(deletedGuids));
}
@Test
public void testTypeUpdateFailureShouldRollBack() throws AtlasException, JSONException {
String typeName = "test_type_"+ RandomStringUtils.randomAlphanumeric(10);
HierarchicalTypeDefinition<ClassType> typeDef = TypesUtil.createClassTypeDef(
typeName, ImmutableSet.<String>of(),
TypesUtil.createUniqueRequiredAttrDef("test_type_attribute", DataTypes.STRING_TYPE));
TypesDef typesDef = new TypesDef(typeDef, false);
JSONObject type = metadataService.createType(TypesSerialization.toJson(typesDef));
Assert.assertNotNull(type.get(AtlasClient.TYPES));
HierarchicalTypeDefinition<ClassType> updatedTypeDef = TypesUtil.createClassTypeDef(
typeName, ImmutableSet.<String>of(),
TypesUtil.createUniqueRequiredAttrDef("test_type_attribute", DataTypes.STRING_TYPE),
TypesUtil.createRequiredAttrDef("test_type_invalid_attribute$", DataTypes.STRING_TYPE));
TypesDef updatedTypesDef = new TypesDef(updatedTypeDef, false);
try {
metadataService.updateType(TypesSerialization.toJson(updatedTypesDef));
fail("Expected AtlasException");
} catch (AtlasException e) {
//expected
}
//type definition should reflect old type
String typeDefinition = metadataService.getTypeDefinition(typeName);
typesDef = TypesSerialization.fromJson(typeDefinition);
assertEquals(typesDef.classTypes().head().attributeDefinitions.length, 1);
}
@Test
public void testTypeWithDotsCreationShouldNotBeCreated() throws AtlasException, JSONException {
String typeName = "test_.v1_type_XXXX";
HierarchicalTypeDefinition<ClassType> typeDef = TypesUtil.createClassTypeDef(
typeName, ImmutableSet.<String>of(),
TypesUtil.createUniqueRequiredAttrDef("test_type_attribute", DataTypes.STRING_TYPE));
TypesDef typesDef = new TypesDef(typeDef, false);
try {
metadataService.createType(TypesSerialization.toJson(typesDef));
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
assertTrue (e.getCause().getMessage().contains(AtlasTypeUtil.getInvalidTypeNameErrorMessage()), e.getCause().getMessage());
}
}
@Test
public void testAuditEventsInvalidParams() throws Exception {
//entity id can't be null
try {
metadataService.getAuditEvents(null, "key", (short) 10);
fail("expected IllegalArgumentException");
} catch(IllegalArgumentException e) {
//expected IllegalArgumentException
assertEquals(e.getMessage(), "entity id cannot be null");
}
//entity id can't be empty
try {
metadataService.getAuditEvents("", "key", (short) 10);
fail("expected IllegalArgumentException");
} catch(IllegalArgumentException e) {
//expected IllegalArgumentException
assertEquals(e.getMessage(), "entity id cannot be empty");
}
//start key can be null
metadataService.getAuditEvents("id", null, (short) 10);
//start key can't be emoty
try {
metadataService.getAuditEvents("id", "", (short) 10);
fail("expected IllegalArgumentException");
} catch(IllegalArgumentException e) {
//expected IllegalArgumentException
assertEquals(e.getMessage(), "start key cannot be empty");
}
//number of results can't be > max value
try {
metadataService.getAuditEvents("id", "key", (short) 10000);
fail("expected IllegalArgumentException");
} catch(IllegalArgumentException e) {
//expected IllegalArgumentException
assertEquals(e.getMessage(), "count should be <= 1000, current value 10000");
}
//number of results can't be <= 0
try {
metadataService.getAuditEvents("id", "key", (short) -1);
fail("expected IllegalArgumentException");
} catch(IllegalArgumentException e) {
//expected IllegalArgumentException
assertEquals(e.getMessage(), "count should be > 0, current value -1");
}
}
@Test
public void testOnChangeRefresh() {
try {
List<String> beforeChangeTypeNames = new ArrayList<>();
beforeChangeTypeNames.addAll(metadataService.getTypeNames(new HashMap<TypeCache.TYPE_FILTER, String>()));
typeDefChangeListener.onChange(new ChangedTypeDefs());
List<String> afterChangeTypeNames = new ArrayList<>();
afterChangeTypeNames.addAll(metadataService.getTypeNames(new HashMap<TypeCache.TYPE_FILTER, String>()));
Collections.sort(beforeChangeTypeNames);
Collections.sort(afterChangeTypeNames);
assertEquals(afterChangeTypeNames, beforeChangeTypeNames);
} catch (AtlasBaseException e) {
fail("Should've succeeded", e);
} catch (AtlasException e) {
fail("getTypeNames should've succeeded", e);
}
}
private static class EntitiesChangeListener implements EntityChangeListener {
private List<String> deletedEntities = new ArrayList<>();
private List<String> updatedEntities = new ArrayList<>();
@Override
public void onEntitiesAdded(Collection<ITypedReferenceableInstance> entities, boolean isImport)
throws AtlasException {
}
@Override
public void onEntitiesUpdated(Collection<ITypedReferenceableInstance> entities, boolean isImport)
throws AtlasException {
updatedEntities.clear();
for (ITypedReferenceableInstance entity : entities) {
updatedEntities.add(entity.getId()._getId());
}
}
@Override
public void onTraitsAdded(ITypedReferenceableInstance entity, Collection<? extends IStruct> traits)
throws AtlasException {
}
@Override
public void onTraitsDeleted(ITypedReferenceableInstance entity, Collection<String> traitNames)
throws AtlasException {
}
@Override
public void onTraitsUpdated(ITypedReferenceableInstance entity, Collection<? extends IStruct> traits)
throws AtlasException {
}
@Override
public void onEntitiesDeleted(Collection<ITypedReferenceableInstance> entities, boolean isImport)
throws AtlasException {
deletedEntities.clear();
for (ITypedReferenceableInstance entity : entities) {
deletedEntities.add(entity.getId()._getId());
}
}
public List<String> getDeletedEntities() {
return deletedEntities;
}
public List<String> getUpdatedEntities() {
return updatedEntities;
}
}
}