/** * 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; import com.google.common.collect.ImmutableSet; import org.apache.atlas.AtlasException; import org.apache.atlas.typesystem.IStruct; import org.apache.atlas.typesystem.ITypedInstance; import org.apache.atlas.typesystem.ITypedStruct; import org.apache.atlas.typesystem.Struct; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import static org.apache.atlas.typesystem.types.utils.TypesUtil.createClassTypeDef; import static org.apache.atlas.typesystem.types.utils.TypesUtil.createOptionalAttrDef; import static org.apache.atlas.typesystem.types.utils.TypesUtil.createRequiredAttrDef; import static org.apache.atlas.typesystem.types.utils.TypesUtil.createTraitTypeDef; /** * Unit tests for type inheritance. */ public class TypeInheritanceTest extends BaseTest { @BeforeMethod public void setup() throws Exception { TypeSystem.getInstance().reset(); super.setup(); } /* * Type Hierarchy is: * A(a) * B(b) extends A */ @Test public void testSimpleInheritance() throws AtlasException { HierarchicalTypeDefinition A = createClassTypeDef("A", null, createRequiredAttrDef("a", DataTypes.INT_TYPE)); HierarchicalTypeDefinition B = createClassTypeDef("B", ImmutableSet.of("A"), createOptionalAttrDef("b", DataTypes.BOOLEAN_TYPE)); defineClasses(A, B); ClassType BType = getTypeSystem().getDataType(ClassType.class, "B"); Struct s1 = new Struct("B"); s1.set("b", true); s1.set("a", 1); ITypedInstance ts = BType.convert(s1, Multiplicity.REQUIRED); Assert.assertEquals(ts.toString(), "{\n" + "\tid : (type: B, id: <unassigned>)\n" + "\tb : \ttrue\n" + "\ta : \t1\n" + "}"); } /* * Type Hierarchy is: * A(a, b) * B(b) extends A */ @Test public void testSimpleInheritanceWithOverrides() throws AtlasException { HierarchicalTypeDefinition A = createClassTypeDef("A", null, createRequiredAttrDef("a", DataTypes.INT_TYPE), createRequiredAttrDef("b", DataTypes.BOOLEAN_TYPE)); HierarchicalTypeDefinition B = createClassTypeDef("B", ImmutableSet.of("A"), createOptionalAttrDef("b", DataTypes.BOOLEAN_TYPE)); defineClasses(A, B); ClassType BType = getTypeSystem().getDataType(ClassType.class, "B"); Struct s1 = new Struct("B"); s1.set("b", true); s1.set("a", 1); s1.set("A.B.b", false); ITypedInstance ts = BType.convert(s1, Multiplicity.REQUIRED); Assert.assertEquals(ts.toString(), "{\n" + "\tid : (type: B, id: <unassigned>)\n" + "\tb : \ttrue\n" + "\ta : \t1\n" + "\tA.B.b : \tfalse\n" + "}"); } /* * Type Hierarchy is: * A(a) * B(b) extends A * C(c) extends B * D(d) extends C */ @Test public void testMultiLevelInheritance() throws AtlasException { HierarchicalTypeDefinition A = createClassTypeDef("A", null, createRequiredAttrDef("a", DataTypes.INT_TYPE)); HierarchicalTypeDefinition B = createClassTypeDef("B", ImmutableSet.of("A"), createOptionalAttrDef("b", DataTypes.BOOLEAN_TYPE)); HierarchicalTypeDefinition C = createClassTypeDef("C", ImmutableSet.of("B"), createOptionalAttrDef("c", DataTypes.BYTE_TYPE)); HierarchicalTypeDefinition D = createClassTypeDef("D", ImmutableSet.of("C"), createOptionalAttrDef("d", DataTypes.SHORT_TYPE)); defineClasses(A, B, C, D); ClassType DType = getTypeSystem().getDataType(ClassType.class, "D"); Struct s1 = new Struct("D"); s1.set("d", 1); s1.set("c", 1); s1.set("b", true); s1.set("a", 1); ITypedInstance ts = DType.convert(s1, Multiplicity.REQUIRED); Assert.assertEquals(ts.toString(), "{\n" + "\tid : (type: D, id: <unassigned>)\n" + "\td : \t1\n" + "\tc : \t1\n" + "\tb : \ttrue\n" + "\ta : \t1\n" + "}"); } /* * Type Hierarchy is: * A(a,b,c,d) * B(b) extends A * C(c) extends A * D(d) extends B,C * * - There are a total of 11 fields in an instance of D * - an attribute that is hidden by a SubType can referenced by prefixing it with the * complete Path. * For e.g. the 'b' attribute in A (that is a superType for B) is hidden the 'b' attribute * in B. * So it is availabel by the name 'A.B.D.b' * * - Another way to set attributes is to cast. Casting a 'D' instance of 'B' makes the 'A.B.D * .b' attribute * available as 'A.B.b'. Casting one more time to an 'A' makes the 'A.B.b' attribute * available as 'b'. */ @Test public void testDiamondInheritance() throws AtlasException { HierarchicalTypeDefinition A = createTraitTypeDef("A", null, createRequiredAttrDef("a", DataTypes.INT_TYPE), createOptionalAttrDef("b", DataTypes.BOOLEAN_TYPE), createOptionalAttrDef("c", DataTypes.BYTE_TYPE), createOptionalAttrDef("d", DataTypes.SHORT_TYPE)); HierarchicalTypeDefinition B = createTraitTypeDef("B", ImmutableSet.of("A"), createOptionalAttrDef("b", DataTypes.BOOLEAN_TYPE)); HierarchicalTypeDefinition C = createTraitTypeDef("C", ImmutableSet.of("A"), createOptionalAttrDef("c", DataTypes.BYTE_TYPE)); HierarchicalTypeDefinition D = createTraitTypeDef("D", ImmutableSet.of("B", "C"), createOptionalAttrDef("d", DataTypes.SHORT_TYPE)); defineTraits(A, B, C, D); TraitType DType = getTypeSystem().getDataType(TraitType.class, "D"); Struct s1 = new Struct("D"); s1.set("d", 1); s1.set("c", 1); s1.set("b", true); s1.set("a", 1); s1.set("A.B.D.b", true); s1.set("A.B.D.c", 2); s1.set("A.B.D.d", 2); s1.set("A.C.D.a", 3); s1.set("A.C.D.b", false); s1.set("A.C.D.c", 3); s1.set("A.C.D.d", 3); ITypedStruct ts = DType.convert(s1, Multiplicity.REQUIRED); Assert.assertEquals(ts.toString(), "{\n" + "\td : \t1\n" + "\tb : \ttrue\n" + "\tc : \t1\n" + "\ta : \t1\n" + "\tA.B.D.b : \ttrue\n" + "\tA.B.D.c : \t2\n" + "\tA.B.D.d : \t2\n" + "\tA.C.D.a : \t3\n" + "\tA.C.D.b : \tfalse\n" + "\tA.C.D.c : \t3\n" + "\tA.C.D.d : \t3\n" + "}"); /* * cast to B and set the 'b' attribute on A. */ TraitType BType = getTypeSystem().getDataType(TraitType.class, "B"); IStruct s2 = DType.castAs(ts, "B"); s2.set("A.B.b", false); Assert.assertEquals(ts.toString(), "{\n" + "\td : \t1\n" + "\tb : \ttrue\n" + "\tc : \t1\n" + "\ta : \t1\n" + "\tA.B.D.b : \tfalse\n" + "\tA.B.D.c : \t2\n" + "\tA.B.D.d : \t2\n" + "\tA.C.D.a : \t3\n" + "\tA.C.D.b : \tfalse\n" + "\tA.C.D.c : \t3\n" + "\tA.C.D.d : \t3\n" + "}"); /* * cast again to A and set the 'b' attribute on A. */ IStruct s3 = BType.castAs(s2, "A"); s3.set("b", true); Assert.assertEquals(ts.toString(), "{\n" + "\td : \t1\n" + "\tb : \ttrue\n" + "\tc : \t1\n" + "\ta : \t1\n" + "\tA.B.D.b : \ttrue\n" + "\tA.B.D.c : \t2\n" + "\tA.B.D.d : \t2\n" + "\tA.C.D.a : \t3\n" + "\tA.C.D.b : \tfalse\n" + "\tA.C.D.c : \t3\n" + "\tA.C.D.d : \t3\n" + "}"); } }