blob: f885a6b822d8e20ccf894d535dada35390e126f7 [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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.typesystem.types.cache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.apache.atlas.AtlasException;
import org.apache.atlas.typesystem.types.ClassType;
import org.apache.atlas.typesystem.types.DataTypes;
import org.apache.atlas.typesystem.types.DataTypes.TypeCategory;
import org.apache.atlas.typesystem.types.EnumType;
import org.apache.atlas.typesystem.types.EnumValue;
import org.apache.atlas.typesystem.types.IDataType;
import org.apache.atlas.typesystem.types.StructType;
import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.TypeSystem;
import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
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 static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
/**
* Tests functional behavior of {@link DefaultTypeCache}
*/
@SuppressWarnings("rawtypes")
public class DefaultTypeCacheTest {
private String CLASSTYPE_CUSTOMER = "Customer";
private String STRUCTTYPE_ADDRESS = "Address";
private String TRAITTYPE_PRIVILEGED = "Privileged";
private String ENUMTYPE_SHIPPING = "Shipping";
private String UNKNOWN_TYPE = "UndefinedType";
private ClassType customerType;
private StructType addressType;
private TraitType privilegedTrait;
private EnumType shippingEnum;
private DefaultTypeCache cache;
@BeforeClass
public void onetimeSetup() throws Exception {
// init TypeSystem
TypeSystem ts = TypeSystem.getInstance().reset();
// Customer ClassType
customerType = ts.defineClassType(TypesUtil
.createClassTypeDef(CLASSTYPE_CUSTOMER, ImmutableSet.<String>of(),
TypesUtil.createRequiredAttrDef("name", DataTypes.STRING_TYPE),
TypesUtil.createRequiredAttrDef("id", DataTypes.LONG_TYPE)));
// Address StructType
addressType = ts.defineStructType(STRUCTTYPE_ADDRESS, true,
TypesUtil.createRequiredAttrDef("first line", DataTypes.STRING_TYPE),
TypesUtil.createOptionalAttrDef("second line", DataTypes.STRING_TYPE),
TypesUtil.createRequiredAttrDef("city", DataTypes.STRING_TYPE),
TypesUtil.createRequiredAttrDef("pincode", DataTypes.INT_TYPE));
// Privileged TraitType
privilegedTrait = ts.defineTraitType(TypesUtil
.createTraitTypeDef(TRAITTYPE_PRIVILEGED, ImmutableSet.<String>of(),
TypesUtil.createRequiredAttrDef("category", DataTypes.INT_TYPE)));
// Shipping EnumType
shippingEnum = ts.defineEnumType(TypesUtil.createEnumTypeDef(ENUMTYPE_SHIPPING,
new EnumValue("Domestic", 1), new EnumValue("International", 2)));
}
@BeforeMethod
public void eachTestSetup() throws Exception {
cache = new DefaultTypeCache();
cache.put(customerType);
cache.put(addressType);
cache.put(privilegedTrait);
cache.put(shippingEnum);
}
@Test
public void testCacheGetType() throws Exception {
IDataType custType = cache.get(CLASSTYPE_CUSTOMER);
verifyType(custType, CLASSTYPE_CUSTOMER, ClassType.class);
IDataType addrType = cache.get(STRUCTTYPE_ADDRESS);
verifyType(addrType, STRUCTTYPE_ADDRESS, StructType.class);
IDataType privTrait = cache.get(TRAITTYPE_PRIVILEGED);
verifyType(privTrait, TRAITTYPE_PRIVILEGED, TraitType.class);
IDataType shippingEnum = cache.get(ENUMTYPE_SHIPPING);
verifyType(shippingEnum, ENUMTYPE_SHIPPING, EnumType.class);
assertNull(cache.get(UNKNOWN_TYPE));
}
@Test
public void testCacheGetTypeByCategory() throws Exception {
IDataType custType = cache.get(TypeCategory.CLASS, CLASSTYPE_CUSTOMER);
verifyType(custType, CLASSTYPE_CUSTOMER, ClassType.class);
IDataType addrType = cache.get(TypeCategory.STRUCT, STRUCTTYPE_ADDRESS);
verifyType(addrType, STRUCTTYPE_ADDRESS, StructType.class);
IDataType privTrait = cache.get(TypeCategory.TRAIT, TRAITTYPE_PRIVILEGED);
verifyType(privTrait, TRAITTYPE_PRIVILEGED, TraitType.class);
IDataType shippingEnum = cache.get(TypeCategory.ENUM, ENUMTYPE_SHIPPING);
verifyType(shippingEnum, ENUMTYPE_SHIPPING, EnumType.class);
assertNull(cache.get(UNKNOWN_TYPE));
}
private void verifyType(IDataType actualType, String expectedName, Class<? extends IDataType> typeClass) {
assertNotNull(actualType, "The " + expectedName + " type not in cache");
assertTrue(typeClass.isInstance(actualType));
assertEquals(actualType.getName(), expectedName, "The type name does not match");
}
@Test
public void testCacheHasType() throws Exception {
assertTrue(cache.has(CLASSTYPE_CUSTOMER));
assertTrue(cache.has(STRUCTTYPE_ADDRESS));
assertTrue(cache.has(TRAITTYPE_PRIVILEGED));
assertTrue(cache.has(ENUMTYPE_SHIPPING));
assertFalse(cache.has(UNKNOWN_TYPE));
}
@Test
public void testCacheHasTypeByCategory() throws Exception {
assertTrue(cache.has(TypeCategory.CLASS, CLASSTYPE_CUSTOMER));
assertTrue(cache.has(TypeCategory.STRUCT, STRUCTTYPE_ADDRESS));
assertTrue(cache.has(TypeCategory.TRAIT, TRAITTYPE_PRIVILEGED));
assertTrue(cache.has(TypeCategory.ENUM, ENUMTYPE_SHIPPING));
assertFalse(cache.has(UNKNOWN_TYPE));
}
@Test
public void testCacheGetAllTypeNames() throws Exception {
List<String> allTypeNames = new ArrayList<String>(cache.getAllTypeNames());
Collections.sort(allTypeNames);
final int EXPECTED_TYPE_COUNT = 4;
assertEquals(allTypeNames.size(), EXPECTED_TYPE_COUNT, "Total number of types does not match.");
assertEquals(STRUCTTYPE_ADDRESS, allTypeNames.get(0));
assertEquals(CLASSTYPE_CUSTOMER, allTypeNames.get(1));
assertEquals(TRAITTYPE_PRIVILEGED, allTypeNames.get(2));
assertEquals(ENUMTYPE_SHIPPING, allTypeNames.get(3));
}
private Collection<String> getTypeNamesByCategory(final TypeCategory category)
throws AtlasException {
return cache.getTypeNames(new HashMap<TypeCache.TYPE_FILTER, String>() {{
put(TypeCache.TYPE_FILTER.CATEGORY, category.name());
}});
}
@Test
public void testCacheGetTypeNamesByCategory() throws Exception {
List<String> classTypes = new ArrayList(getTypeNamesByCategory(TypeCategory.CLASS));
final int EXPECTED_CLASSTYPE_COUNT = 1;
assertEquals(classTypes.size(), EXPECTED_CLASSTYPE_COUNT);
assertEquals(CLASSTYPE_CUSTOMER, classTypes.get(0));
List<String> structTypes = new ArrayList(getTypeNamesByCategory(TypeCategory.STRUCT));
final int EXPECTED_STRUCTTYPE_COUNT = 1;
assertEquals(structTypes.size(), EXPECTED_STRUCTTYPE_COUNT);
assertEquals(STRUCTTYPE_ADDRESS, structTypes.get(0));
List<String> traitTypes = new ArrayList(getTypeNamesByCategory(TypeCategory.TRAIT));
final int EXPECTED_TRAITTYPE_COUNT = 1;
assertEquals(traitTypes.size(), EXPECTED_TRAITTYPE_COUNT);
assertEquals(TRAITTYPE_PRIVILEGED, traitTypes.get(0));
List<String> enumTypes = new ArrayList(getTypeNamesByCategory(TypeCategory.ENUM));
final int EXPECTED_ENUMTYPE_COUNT = 1;
assertEquals(enumTypes.size(), EXPECTED_ENUMTYPE_COUNT);
assertEquals(ENUMTYPE_SHIPPING, enumTypes.get(0));
}
@Test
public void testCacheBulkInsert() throws Exception {
List<IDataType> allTypes = new ArrayList<>();
allTypes.add(customerType);
allTypes.add(addressType);
allTypes.add(privilegedTrait);
allTypes.add(shippingEnum);
// create a new cache instead of using the one setup for every method call
cache = new DefaultTypeCache();
cache.putAll(allTypes);
IDataType custType = cache.get(CLASSTYPE_CUSTOMER);
verifyType(custType, CLASSTYPE_CUSTOMER, ClassType.class);
IDataType addrType = cache.get(STRUCTTYPE_ADDRESS);
verifyType(addrType, STRUCTTYPE_ADDRESS, StructType.class);
IDataType privTrait = cache.get(TRAITTYPE_PRIVILEGED);
verifyType(privTrait, TRAITTYPE_PRIVILEGED, TraitType.class);
IDataType shippingEnum = cache.get(ENUMTYPE_SHIPPING);
verifyType(shippingEnum, ENUMTYPE_SHIPPING, EnumType.class);
}
@Test
public void testCacheRemove() throws Exception {
cache.remove(CLASSTYPE_CUSTOMER);
assertNull(cache.get(CLASSTYPE_CUSTOMER));
assertFalse(cache.has(CLASSTYPE_CUSTOMER));
assertTrue(getTypeNamesByCategory(TypeCategory.CLASS).isEmpty());
final int EXPECTED_TYPE_COUNT = 3;
assertEquals(cache.getAllTypeNames().size(), EXPECTED_TYPE_COUNT);
}
@Test
public void testCacheRemoveByCategory() throws Exception {
cache.remove(TypeCategory.CLASS, CLASSTYPE_CUSTOMER);
assertNull(cache.get(CLASSTYPE_CUSTOMER));
assertFalse(cache.has(CLASSTYPE_CUSTOMER));
assertTrue(getTypeNamesByCategory(TypeCategory.CLASS).isEmpty());
final int EXPECTED_TYPE_COUNT = 3;
assertEquals(cache.getAllTypeNames().size(), EXPECTED_TYPE_COUNT);
}
@Test
public void testCacheClear() throws Exception {
cache.clear();
assertNull(cache.get(CLASSTYPE_CUSTOMER));
assertFalse(cache.has(CLASSTYPE_CUSTOMER));
assertNull(cache.get(STRUCTTYPE_ADDRESS));
assertFalse(cache.has(STRUCTTYPE_ADDRESS));
assertNull(cache.get(TRAITTYPE_PRIVILEGED));
assertFalse(cache.has(TRAITTYPE_PRIVILEGED));
assertNull(cache.get(ENUMTYPE_SHIPPING));
assertFalse(cache.has(ENUMTYPE_SHIPPING));
assertTrue(getTypeNamesByCategory(TypeCategory.CLASS).isEmpty());
assertTrue(getTypeNamesByCategory(TypeCategory.STRUCT).isEmpty());
assertTrue(getTypeNamesByCategory(TypeCategory.TRAIT).isEmpty());
assertTrue(getTypeNamesByCategory(TypeCategory.ENUM).isEmpty());
assertTrue(cache.getAllTypeNames().isEmpty());
}
@Test(expectedExceptions = AtlasException.class)
public void testPutTypeWithNullType() throws Exception {
cache.put(null);
fail("Null type should be not allowed in 'put'");
}
@Test(expectedExceptions = AtlasException.class)
public void testPutTypeWithInvalidType() throws Exception {
cache.put(DataTypes.BOOLEAN_TYPE);
fail("type should only be an instance of ClassType | EnumType | StructType | TraitType in 'put'");
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testGetTypeWithNullCategory() throws Exception {
cache.get(null, CLASSTYPE_CUSTOMER);
fail("Null TypeCategory should be not allowed in 'get'");
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testGetTypeWithInvalidCategory() throws Exception {
cache.get(TypeCategory.PRIMITIVE, DataTypes.BOOLEAN_TYPE.getName());
fail("TypeCategory should only be one of TypeCategory.CLASS | ENUM | STRUCT | TRAIT in 'get'");
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testCacheHasTypeWithNullCategory() throws Exception {
cache.has(null, CLASSTYPE_CUSTOMER);
fail("Null TypeCategory should be not allowed in 'has'");
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testCacheHasTypeWithInvalidCategory() throws Exception {
cache.has(TypeCategory.PRIMITIVE, DataTypes.BOOLEAN_TYPE.getName());
fail("TypeCategory should only be one of TypeCategory.CLASS | ENUM | STRUCT | TRAIT in 'has'");
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testCacheGetTypeNamesByInvalidCategory() throws Exception {
getTypeNamesByCategory(TypeCategory.PRIMITIVE);
fail("TypeCategory should only be one of TypeCategory.CLASS | ENUM | STRUCT | TRAIT in 'getNames'");
}
@Test(expectedExceptions = AtlasException.class)
public void testCacheBulkInsertWithNullType() throws Exception {
List<IDataType> allTypes = new ArrayList<>();
allTypes.add(null);
// create a new cache instead of using the one setup for every method call
cache = new DefaultTypeCache();
cache.putAll(allTypes);
fail("Null type should be not allowed in 'putAll'");
}
@Test(expectedExceptions = AtlasException.class)
public void testCacheBulkInsertWithInvalidType() throws Exception {
List<IDataType> allTypes = new ArrayList<>();
allTypes.add(DataTypes.BOOLEAN_TYPE);
// create a new cache instead of using the one setup for every method call
cache = new DefaultTypeCache();
cache.putAll(allTypes);
fail("type should only one of ClassType | EnumType | StructType | TraitType in 'putAll'");
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testCacheRemoveByNullCategory() throws Exception {
cache.remove(null, CLASSTYPE_CUSTOMER);
fail("Null type should be not allowed in 'remove'");
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testCacheRemoveByInvalidCategory() throws Exception {
cache.remove(TypeCategory.PRIMITIVE, DataTypes.BOOLEAN_TYPE.getName());
fail("TypeCategory should only be one of TypeCategory.CLASS | ENUM | STRUCT | TRAIT in 'remove'");
}
@Test
public void testGetTypesByFilter() throws Exception {
// init TypeSystem
TypeSystem ts = TypeSystem.getInstance().reset();
ts.defineClassType(TypesUtil.createClassTypeDef("A", ImmutableSet.<String>of()));
ts.defineClassType(TypesUtil.createClassTypeDef("A1", ImmutableSet.of("A")));
ts.defineClassType(TypesUtil.createClassTypeDef("B", ImmutableSet.<String>of()));
ts.defineClassType(TypesUtil.createClassTypeDef("C", ImmutableSet.of("B", "A")));
//supertype ~ A
ImmutableList<String> results = ts.getTypeNames(new HashMap<TypeCache.TYPE_FILTER, String>() {{
put(TypeCache.TYPE_FILTER.SUPERTYPE, "A");
}});
assertTrue(results.containsAll(Arrays.asList("A1", "C")), "Results: " + results);
//!supertype doesn't return the type itself
results = ts.getTypeNames(new HashMap<TypeCache.TYPE_FILTER, String>() {{
put(TypeCache.TYPE_FILTER.NOT_SUPERTYPE, "A");
}});
assertTrue(results.containsAll(Arrays.asList("B")), "Results: " + results);
//supertype ~ A && supertype !~ B
results = ts.getTypeNames(new HashMap<TypeCache.TYPE_FILTER, String>() {{
put(TypeCache.TYPE_FILTER.SUPERTYPE, "A");
put(TypeCache.TYPE_FILTER.NOT_SUPERTYPE, "B");
}});
assertTrue(results.containsAll(Arrays.asList("A1")), "Results: " + results);
//none of category trait
results = ts.getTypeNames(new HashMap<TypeCache.TYPE_FILTER, String>() {{
put(TypeCache.TYPE_FILTER.CATEGORY, TypeCategory.TRAIT.name());
put(TypeCache.TYPE_FILTER.SUPERTYPE, "A");
}});
assertTrue(results.isEmpty(), "Results: " + results);
//no filter returns all types
results = ts.getTypeNames(null);
assertTrue(results.containsAll(Arrays.asList("A", "A1", "B", "C")), "Results: " + results);
results = ts.getTypeNames(new HashMap<TypeCache.TYPE_FILTER, String>());
assertTrue(results.containsAll(Arrays.asList("A", "A1", "B", "C")), "Results: " + results);
//invalid category
try {
ts.getTypeNames(new HashMap<TypeCache.TYPE_FILTER, String>() {{
put(TypeCache.TYPE_FILTER.CATEGORY, "A");
}});
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
//expected
}
//invalid supertype
results = ts.getTypeNames(new HashMap<TypeCache.TYPE_FILTER, String>() {{
put(TypeCache.TYPE_FILTER.SUPERTYPE, "X");
}});
assertTrue(results.isEmpty(), "Expected empty result for non-existent type 'X'. Found: " + results);
//invalid supertype
results = ts.getTypeNames(new HashMap<TypeCache.TYPE_FILTER, String>() {{
put(TypeCache.TYPE_FILTER.NOT_SUPERTYPE, "X");
}});
assertTrue(results.containsAll(Arrays.asList("A", "A1", "B", "C")), "Results: " + results);
}
}