/** * 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<>(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); } }