org.apache.atlas.TestUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.atlas.TestUtils.java

Source

/**
 * 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;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Provider;
import org.apache.atlas.listener.EntityChangeListener;
import org.apache.atlas.listener.TypesChangeListener;
import org.apache.atlas.repository.MetadataRepository;
import org.apache.atlas.repository.graph.AtlasGraphProvider;
import org.apache.atlas.repository.graph.GraphBackedMetadataRepository;
import org.apache.atlas.repository.graph.GraphBackedSearchIndexer;
import org.apache.atlas.repository.graph.GraphHelper;
import org.apache.atlas.repository.graphdb.AtlasGraph;
import org.apache.atlas.repository.graphdb.GremlinVersion;
import org.apache.atlas.repository.typestore.GraphBackedTypeStore;
import org.apache.atlas.repository.typestore.ITypeStore;
import org.apache.atlas.services.DefaultMetadataService;
import org.apache.atlas.services.MetadataService;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.atlas.typesystem.IInstance;
import org.apache.atlas.typesystem.ITypedReferenceableInstance;
import org.apache.atlas.typesystem.Referenceable;
import org.apache.atlas.typesystem.TypesDef;
import org.apache.atlas.typesystem.json.InstanceSerialization;
import org.apache.atlas.typesystem.persistence.Id;
import org.apache.atlas.typesystem.types.*;
import org.apache.atlas.typesystem.types.DataTypes.TypeCategory;
import org.apache.atlas.typesystem.types.cache.DefaultTypeCache;
import org.apache.atlas.typesystem.types.cache.TypeCache;
import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.apache.atlas.util.AtlasRepositoryConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang.RandomStringUtils;
import org.codehaus.jettison.json.JSONArray;
import org.testng.Assert;
import org.testng.SkipException;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.apache.atlas.typesystem.types.utils.TypesUtil.*;
import static org.testng.Assert.assertEquals;

/**
 * Test utility class.
 */
public final class TestUtils {

    public static final long TEST_DATE_IN_LONG = 1418265358440L;

    public static final String EMPLOYEES_ATTR = "employees";
    public static final String DEPARTMENT_ATTR = "department";
    public static final String ASSETS_ATTR = "assets";

    public static final String POSITIONS_ATTR = "positions";
    public static final String ASSET_TYPE = "TestAsset";

    public static final String DATABASE_TYPE = "hive_database";
    public static final String DATABASE_NAME = "foo";
    public static final String TABLE_TYPE = "hive_table";
    public static final String PROCESS_TYPE = "hive_process";
    public static final String COLUMN_TYPE = "column_type";
    public static final String TABLE_NAME = "bar";
    public static final String CLASSIFICATION = "classification";
    public static final String PII = "PII";
    public static final String SUPER_TYPE_NAME = "Base";
    public static final String STORAGE_DESC_TYPE = "hive_storagedesc";
    public static final String PARTITION_STRUCT_TYPE = "partition_struct_type";
    public static final String PARTITION_CLASS_TYPE = "partition_class_type";
    public static final String SERDE_TYPE = "serdeType";
    public static final String COLUMNS_MAP = "columnsMap";
    public static final String COLUMNS_ATTR_NAME = "columns";

    public static final String NAME = "name";

    private TestUtils() {
    }

    /**
     * Dumps the graph in GSON format in the path returned.
     *
     * @param graph handle to graph
     * @return path to the dump file
     * @throws Exception
     */
    public static String dumpGraph(AtlasGraph<?, ?> graph) throws Exception {
        File tempFile = File.createTempFile("graph", ".gson");
        System.out.println("tempFile.getPath() = " + tempFile.getPath());
        GraphHelper.dumpToLog(graph);
        FileOutputStream os = null;
        try {
            os = new FileOutputStream(tempFile);
            graph.exportToGson(os);
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return tempFile.getPath();
    }

    /**
     * Class Hierarchy is:
     * Department(name : String, employees : Array[Person])
     * Person(name : String, department : Department, manager : Manager)
     * Manager(subordinates : Array[Person]) extends Person
     * <p/>
     * Persons can have SecurityClearance(level : Int) clearance.
     */
    public static void defineDeptEmployeeTypes(TypeSystem ts) throws AtlasException {

        String _description = "_description";
        EnumTypeDefinition orgLevelEnum = new EnumTypeDefinition("OrgLevel", "OrgLevel" + _description,
                new EnumValue("L1", 1), new EnumValue("L2", 2));

        StructTypeDefinition addressDetails = createStructTypeDef("Address", "Address" + _description,
                createRequiredAttrDef("street", DataTypes.STRING_TYPE),
                createRequiredAttrDef("city", DataTypes.STRING_TYPE));

        HierarchicalTypeDefinition<ClassType> deptTypeDef = createClassTypeDef(DEPARTMENT_TYPE,
                "Department" + _description, ImmutableSet.<String>of(),
                createRequiredAttrDef(NAME, DataTypes.STRING_TYPE),
                new AttributeDefinition(EMPLOYEES_ATTR, String.format("array<%s>", "Person"), Multiplicity.OPTIONAL,
                        true, DEPARTMENT_ATTR),
                new AttributeDefinition(POSITIONS_ATTR,
                        String.format("map<%s,%s>", DataTypes.STRING_TYPE.getName(), "Person"),
                        Multiplicity.OPTIONAL, false, null));

        HierarchicalTypeDefinition<ClassType> personTypeDef = createClassTypeDef("Person", "Person" + _description,
                ImmutableSet.<String>of(), createRequiredAttrDef(NAME, DataTypes.STRING_TYPE),
                createOptionalAttrDef("orgLevel", "OrgLevel"), createOptionalAttrDef("address", "Address"),
                new AttributeDefinition(DEPARTMENT_ATTR, "Department", Multiplicity.REQUIRED, false,
                        EMPLOYEES_ATTR),
                new AttributeDefinition("manager", "Manager", Multiplicity.OPTIONAL, false, "subordinates"),
                new AttributeDefinition("mentor", "Person", Multiplicity.OPTIONAL, false, null),
                new AttributeDefinition(ASSETS_ATTR, String.format("array<%s>", ASSET_TYPE), Multiplicity.OPTIONAL,
                        false, null),
                createOptionalAttrDef("birthday", DataTypes.DATE_TYPE),
                createOptionalAttrDef("hasPets", DataTypes.BOOLEAN_TYPE),
                createOptionalAttrDef("numberOfCars", DataTypes.BYTE_TYPE),
                createOptionalAttrDef("houseNumber", DataTypes.SHORT_TYPE),
                createOptionalAttrDef("carMileage", DataTypes.INT_TYPE),
                createOptionalAttrDef("shares", DataTypes.LONG_TYPE),
                createOptionalAttrDef("salary", DataTypes.DOUBLE_TYPE),
                createOptionalAttrDef("age", DataTypes.FLOAT_TYPE),
                createOptionalAttrDef("numberOfStarsEstimate", DataTypes.BIGINTEGER_TYPE),
                createOptionalAttrDef("approximationOfPi", DataTypes.BIGDECIMAL_TYPE),
                createOptionalAttrDef("isOrganDonor", DataTypes.BOOLEAN_TYPE));

        HierarchicalTypeDefinition<ClassType> assetTypeDef = createClassTypeDef(ASSET_TYPE, "Asset" + _description,
                ImmutableSet.<String>of(), createRequiredAttrDef(NAME, DataTypes.STRING_TYPE),
                new AttributeDefinition("childAssets", String.format("array<%s>", ASSET_TYPE),
                        Multiplicity.OPTIONAL, false, null));

        HierarchicalTypeDefinition<ClassType> managerTypeDef = createClassTypeDef("Manager",
                "Manager" + _description, ImmutableSet.of("Person"), new AttributeDefinition("subordinates",
                        String.format("array<%s>", "Person"), Multiplicity.COLLECTION, false, "manager"));

        HierarchicalTypeDefinition<TraitType> securityClearanceTypeDef = createTraitTypeDef("SecurityClearance",
                "SecurityClearance" + _description, ImmutableSet.<String>of(),
                createRequiredAttrDef("level", DataTypes.INT_TYPE));

        ts.defineTypes(ImmutableList.of(orgLevelEnum), ImmutableList.of(addressDetails),
                ImmutableList.of(securityClearanceTypeDef),
                ImmutableList.of(deptTypeDef, personTypeDef, managerTypeDef, assetTypeDef));
    }

    public static final String DEPARTMENT_TYPE = "Department";
    public static final String PERSON_TYPE = "Person";

    public static ITypedReferenceableInstance createDeptEg1(TypeSystem ts) throws AtlasException {
        Referenceable hrDept = new Referenceable(DEPARTMENT_TYPE);
        Referenceable john = new Referenceable(PERSON_TYPE);

        Referenceable jane = new Referenceable("Manager", "SecurityClearance");
        Referenceable johnAddr = new Referenceable("Address");
        Referenceable janeAddr = new Referenceable("Address");
        Referenceable julius = new Referenceable("Manager");
        Referenceable juliusAddr = new Referenceable("Address");
        Referenceable max = new Referenceable("Person");
        Referenceable maxAddr = new Referenceable("Address");

        hrDept.set(NAME, "hr");
        john.set(NAME, "John");
        john.set(DEPARTMENT_ATTR, hrDept);
        johnAddr.set("street", "Stewart Drive");
        johnAddr.set("city", "Sunnyvale");
        john.set("address", johnAddr);

        john.set("birthday", new Date(1950, 5, 15));
        john.set("isOrganDonor", true);
        john.set("hasPets", true);
        john.set("numberOfCars", 1);
        john.set("houseNumber", 153);
        john.set("carMileage", 13364);
        john.set("shares", 15000);
        john.set("salary", 123345.678);
        john.set("age", 50);
        john.set("numberOfStarsEstimate", new BigInteger("1000000000000000000000"));
        john.set("approximationOfPi",
                new BigDecimal("3.141592653589793238462643383279502884197169399375105820974944592307816406286"));

        jane.set(NAME, "Jane");
        jane.set(DEPARTMENT_ATTR, hrDept);
        janeAddr.set("street", "Great America Parkway");
        janeAddr.set("city", "Santa Clara");
        jane.set("address", janeAddr);
        janeAddr.set("street", "Great America Parkway");

        julius.set(NAME, "Julius");
        julius.set(DEPARTMENT_ATTR, hrDept);
        juliusAddr.set("street", "Madison Ave");
        juliusAddr.set("city", "Newtonville");
        julius.set("address", juliusAddr);
        julius.set("subordinates", ImmutableList.<Referenceable>of());

        max.set(NAME, "Max");
        max.set(DEPARTMENT_ATTR, hrDept);
        maxAddr.set("street", "Ripley St");
        maxAddr.set("city", "Newton");
        max.set("address", maxAddr);
        max.set("manager", jane);
        max.set("mentor", julius);
        max.set("birthday", new Date(1979, 3, 15));
        max.set("isOrganDonor", true);
        max.set("hasPets", true);
        max.set("age", 36);
        max.set("numberOfCars", 2);
        max.set("houseNumber", 17);
        max.set("carMileage", 13);
        max.set("shares", Long.MAX_VALUE);
        max.set("salary", Double.MAX_VALUE);
        max.set("numberOfStarsEstimate", new BigInteger("1000000000000000000000000000000"));
        max.set("approximationOfPi", new BigDecimal("3.1415926535897932"));

        john.set("manager", jane);
        john.set("mentor", max);
        hrDept.set(EMPLOYEES_ATTR, ImmutableList.of(john, jane, julius, max));

        jane.set("subordinates", ImmutableList.of(john, max));

        jane.getTrait("SecurityClearance").set("level", 1);

        ClassType deptType = ts.getDataType(ClassType.class, "Department");
        ITypedReferenceableInstance hrDept2 = deptType.convert(hrDept, Multiplicity.REQUIRED);
        Assert.assertNotNull(hrDept2);

        return hrDept2;
    }

    public static TypesDef simpleType() {
        HierarchicalTypeDefinition<ClassType> superTypeDefinition = createClassTypeDef("h_type",
                ImmutableSet.<String>of(), createOptionalAttrDef("attr", DataTypes.STRING_TYPE));

        StructTypeDefinition structTypeDefinition = new StructTypeDefinition("s_type", "structType",
                new AttributeDefinition[] { createRequiredAttrDef(NAME, DataTypes.STRING_TYPE) });

        HierarchicalTypeDefinition<TraitType> traitTypeDefinition = createTraitTypeDef("t_type", "traitType",
                ImmutableSet.<String>of());

        EnumValue values[] = { new EnumValue("ONE", 1), };

        EnumTypeDefinition enumTypeDefinition = new EnumTypeDefinition("e_type", "enumType", values);
        return TypesUtil.getTypesDef(ImmutableList.of(enumTypeDefinition), ImmutableList.of(structTypeDefinition),
                ImmutableList.of(traitTypeDefinition), ImmutableList.of(superTypeDefinition));
    }

    public static TypesDef simpleTypeUpdated() {
        HierarchicalTypeDefinition<ClassType> superTypeDefinition = createClassTypeDef("h_type",
                ImmutableSet.<String>of(), createOptionalAttrDef("attr", DataTypes.STRING_TYPE));

        HierarchicalTypeDefinition<ClassType> newSuperTypeDefinition = createClassTypeDef("new_h_type",
                ImmutableSet.<String>of(), createOptionalAttrDef("attr", DataTypes.STRING_TYPE));

        StructTypeDefinition structTypeDefinition = new StructTypeDefinition("s_type", "structType",
                new AttributeDefinition[] { createRequiredAttrDef(NAME, DataTypes.STRING_TYPE) });

        HierarchicalTypeDefinition<TraitType> traitTypeDefinition = createTraitTypeDef("t_type", "traitType",
                ImmutableSet.<String>of());

        EnumValue values[] = { new EnumValue("ONE", 1), };

        EnumTypeDefinition enumTypeDefinition = new EnumTypeDefinition("e_type", "enumType", values);
        return TypesUtil.getTypesDef(ImmutableList.of(enumTypeDefinition), ImmutableList.of(structTypeDefinition),
                ImmutableList.of(traitTypeDefinition),
                ImmutableList.of(superTypeDefinition, newSuperTypeDefinition));
    }

    public static TypesDef simpleTypeUpdatedDiff() {
        HierarchicalTypeDefinition<ClassType> newSuperTypeDefinition = createClassTypeDef("new_h_type",
                ImmutableSet.<String>of(), createOptionalAttrDef("attr", DataTypes.STRING_TYPE));

        return TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(),
                ImmutableList.<StructTypeDefinition>of(), ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(),
                ImmutableList.of(newSuperTypeDefinition));
    }

    public static TypesDef defineHiveTypes() {
        String _description = "_description";
        HierarchicalTypeDefinition<ClassType> superTypeDefinition = createClassTypeDef(SUPER_TYPE_NAME,
                ImmutableSet.<String>of(), createOptionalAttrDef("namespace", DataTypes.STRING_TYPE),
                createOptionalAttrDef("cluster", DataTypes.STRING_TYPE),
                createOptionalAttrDef("colo", DataTypes.STRING_TYPE));
        HierarchicalTypeDefinition<ClassType> databaseTypeDefinition = createClassTypeDef(DATABASE_TYPE,
                DATABASE_TYPE + _description, ImmutableSet.of(SUPER_TYPE_NAME),
                TypesUtil.createUniqueRequiredAttrDef(NAME, DataTypes.STRING_TYPE),
                createOptionalAttrDef("created", DataTypes.DATE_TYPE),
                createOptionalAttrDef("isReplicated", DataTypes.BOOLEAN_TYPE),
                new AttributeDefinition("parameters",
                        new DataTypes.MapType(DataTypes.STRING_TYPE, DataTypes.STRING_TYPE).getName(),
                        Multiplicity.OPTIONAL, false, null),
                createRequiredAttrDef("description", DataTypes.STRING_TYPE));

        StructTypeDefinition structTypeDefinition = new StructTypeDefinition("serdeType",
                "serdeType" + _description,
                new AttributeDefinition[] { createRequiredAttrDef(NAME, DataTypes.STRING_TYPE),
                        createRequiredAttrDef("serde", DataTypes.STRING_TYPE),
                        createOptionalAttrDef("description", DataTypes.STRING_TYPE) });

        EnumValue values[] = { new EnumValue("MANAGED", 1), new EnumValue("EXTERNAL", 2), };

        EnumTypeDefinition enumTypeDefinition = new EnumTypeDefinition("tableType", "tableType" + _description,
                values);

        HierarchicalTypeDefinition<ClassType> columnsDefinition = createClassTypeDef(COLUMN_TYPE,
                ImmutableSet.<String>of(), createUniqueRequiredAttrDef(NAME, DataTypes.STRING_TYPE),
                createRequiredAttrDef("type", DataTypes.STRING_TYPE));

        StructTypeDefinition partitionDefinition = new StructTypeDefinition("partition_struct_type",
                "partition_struct_type" + _description,
                new AttributeDefinition[] { createRequiredAttrDef(NAME, DataTypes.STRING_TYPE), });

        AttributeDefinition[] attributeDefinitions = new AttributeDefinition[] {
                new AttributeDefinition("location", DataTypes.STRING_TYPE.getName(), Multiplicity.OPTIONAL, false,
                        null),
                new AttributeDefinition("inputFormat", DataTypes.STRING_TYPE.getName(), Multiplicity.OPTIONAL,
                        false, null),
                new AttributeDefinition("outputFormat", DataTypes.STRING_TYPE.getName(), Multiplicity.OPTIONAL,
                        false, null),
                new AttributeDefinition("compressed", DataTypes.BOOLEAN_TYPE.getName(), Multiplicity.REQUIRED,
                        false, null),
                new AttributeDefinition("numBuckets", DataTypes.INT_TYPE.getName(), Multiplicity.OPTIONAL, false,
                        null), };

        HierarchicalTypeDefinition<ClassType> storageDescClsDef = new HierarchicalTypeDefinition<>(ClassType.class,
                STORAGE_DESC_TYPE, STORAGE_DESC_TYPE + _description, ImmutableSet.of(SUPER_TYPE_NAME),
                attributeDefinitions);

        AttributeDefinition[] partClsAttributes = new AttributeDefinition[] {
                new AttributeDefinition("values", DataTypes.arrayTypeName(DataTypes.STRING_TYPE.getName()),
                        Multiplicity.OPTIONAL, false, null),
                new AttributeDefinition("table", TABLE_TYPE, Multiplicity.REQUIRED, false, null),
                new AttributeDefinition("createTime", DataTypes.LONG_TYPE.getName(), Multiplicity.OPTIONAL, false,
                        null),
                new AttributeDefinition("lastAccessTime", DataTypes.LONG_TYPE.getName(), Multiplicity.OPTIONAL,
                        false, null),
                new AttributeDefinition("sd", STORAGE_DESC_TYPE, Multiplicity.REQUIRED, true, null),
                new AttributeDefinition("columns", DataTypes.arrayTypeName(COLUMN_TYPE), Multiplicity.OPTIONAL,
                        true, null),
                new AttributeDefinition("parameters",
                        new DataTypes.MapType(DataTypes.STRING_TYPE, DataTypes.STRING_TYPE).getName(),
                        Multiplicity.OPTIONAL, false, null), };

        HierarchicalTypeDefinition<ClassType> partClsDef = new HierarchicalTypeDefinition<>(ClassType.class,
                "partition_class_type", "partition_class_type" + _description, ImmutableSet.of(SUPER_TYPE_NAME),
                partClsAttributes);

        HierarchicalTypeDefinition<ClassType> processClsType = new HierarchicalTypeDefinition<>(ClassType.class,
                PROCESS_TYPE, PROCESS_TYPE + _description, ImmutableSet.<String>of(),
                new AttributeDefinition[] { new AttributeDefinition("outputs", "array<" + TABLE_TYPE + ">",
                        Multiplicity.OPTIONAL, false, null) });

        HierarchicalTypeDefinition<ClassType> tableTypeDefinition = createClassTypeDef(TABLE_TYPE,
                TABLE_TYPE + _description, ImmutableSet.of(SUPER_TYPE_NAME),
                TypesUtil.createUniqueRequiredAttrDef(NAME, DataTypes.STRING_TYPE),
                createRequiredAttrDef("description", DataTypes.STRING_TYPE),
                createRequiredAttrDef("type", DataTypes.STRING_TYPE),
                createOptionalAttrDef("created", DataTypes.DATE_TYPE),
                // enum
                new AttributeDefinition("tableType", "tableType", Multiplicity.REQUIRED, false, null),
                // array of strings
                new AttributeDefinition("columnNames", String.format("array<%s>", DataTypes.STRING_TYPE.getName()),
                        Multiplicity.OPTIONAL, false, null),
                // array of classes
                new AttributeDefinition("columns", String.format("array<%s>", COLUMN_TYPE), Multiplicity.OPTIONAL,
                        true, null),
                // array of structs
                new AttributeDefinition("partitions", String.format("array<%s>", "partition_struct_type"),
                        Multiplicity.OPTIONAL, true, null),
                // map of primitives
                new AttributeDefinition("parametersMap",
                        DataTypes.mapTypeName(DataTypes.STRING_TYPE.getName(), DataTypes.STRING_TYPE.getName()),
                        Multiplicity.OPTIONAL, true, null),
                //map of classes -
                new AttributeDefinition(COLUMNS_MAP,
                        DataTypes.mapTypeName(DataTypes.STRING_TYPE.getName(), COLUMN_TYPE), Multiplicity.OPTIONAL,
                        true, null),
                //map of structs
                new AttributeDefinition("partitionsMap",
                        DataTypes.mapTypeName(DataTypes.STRING_TYPE.getName(), "partition_struct_type"),
                        Multiplicity.OPTIONAL, true, null),
                // struct reference
                new AttributeDefinition("serde1", "serdeType", Multiplicity.OPTIONAL, false, null),
                new AttributeDefinition("serde2", "serdeType", Multiplicity.OPTIONAL, false, null),
                // class reference
                new AttributeDefinition("database", DATABASE_TYPE, Multiplicity.REQUIRED, false, null),
                //class reference as composite
                new AttributeDefinition("databaseComposite", DATABASE_TYPE, Multiplicity.OPTIONAL, true, null));

        HierarchicalTypeDefinition<TraitType> piiTypeDefinition = createTraitTypeDef(PII, PII + _description,
                ImmutableSet.<String>of());

        HierarchicalTypeDefinition<TraitType> classificationTypeDefinition = createTraitTypeDef(CLASSIFICATION,
                CLASSIFICATION + _description, ImmutableSet.<String>of(),
                createRequiredAttrDef("tag", DataTypes.STRING_TYPE));

        HierarchicalTypeDefinition<TraitType> fetlClassificationTypeDefinition = createTraitTypeDef(
                "fetl" + CLASSIFICATION, "fetl" + CLASSIFICATION + _description, ImmutableSet.of(CLASSIFICATION),
                createRequiredAttrDef("tag", DataTypes.STRING_TYPE));

        return TypesUtil.getTypesDef(ImmutableList.of(enumTypeDefinition),
                ImmutableList.of(structTypeDefinition, partitionDefinition),
                ImmutableList.of(classificationTypeDefinition, fetlClassificationTypeDefinition, piiTypeDefinition),
                ImmutableList.of(superTypeDefinition, databaseTypeDefinition, columnsDefinition,
                        tableTypeDefinition, storageDescClsDef, partClsDef, processClsType));
    }

    public static Collection<IDataType> createHiveTypes(TypeSystem typeSystem) throws Exception {
        if (!typeSystem.isRegistered(TABLE_TYPE)) {
            TypesDef typesDef = defineHiveTypes();
            return typeSystem.defineTypes(typesDef).values();
        }
        return new ArrayList<>();
    }

    public static final String randomString() {
        return RandomStringUtils.randomAlphanumeric(10);
    }

    public static Referenceable createDBEntity() {
        Referenceable entity = new Referenceable(DATABASE_TYPE);
        String dbName = RandomStringUtils.randomAlphanumeric(10);
        entity.set(NAME, dbName);
        entity.set("description", "us db");
        return entity;
    }

    public static Referenceable createTableEntity(String dbId) {
        Referenceable entity = new Referenceable(TABLE_TYPE);
        String tableName = RandomStringUtils.randomAlphanumeric(10);
        entity.set(NAME, tableName);
        entity.set("description", "random table");
        entity.set("type", "type");
        entity.set("tableType", "MANAGED");
        entity.set("database", new Id(dbId, 0, DATABASE_TYPE));
        entity.set("created", new Date());
        return entity;
    }

    public static Referenceable createColumnEntity() {
        Referenceable entity = new Referenceable(COLUMN_TYPE);
        entity.set(NAME, RandomStringUtils.randomAlphanumeric(10));
        entity.set("type", "VARCHAR(32)");
        return entity;
    }

    /**
     * Creates an entity in the graph and does basic validation
     * of the GuidMapping that was created in the process.
     *
     */
    public static String createInstance(MetadataService metadataService, Referenceable entity) throws Exception {
        RequestContext.createContext();

        String entityjson = InstanceSerialization.toJson(entity, true);
        JSONArray entitiesJson = new JSONArray();
        entitiesJson.put(entityjson);
        CreateUpdateEntitiesResult creationResult = metadataService.createEntities(entitiesJson.toString());
        Map<String, String> guidMap = creationResult.getGuidMapping().getGuidAssignments();
        Map<Id, Referenceable> referencedObjects = findReferencedObjects(entity);

        for (Map.Entry<Id, Referenceable> entry : referencedObjects.entrySet()) {
            Id foundId = entry.getKey();
            if (foundId.isUnassigned()) {
                String guid = guidMap.get(entry.getKey()._getId());
                Referenceable obj = entry.getValue();
                loadAndDoSimpleValidation(guid, obj, metadataService);
            }
        }
        List<String> guids = creationResult.getCreatedEntities();
        if (guids != null && guids.size() > 0) {
            return guids.get(guids.size() - 1);
        }
        return null;
    }

    private static Map<Id, Referenceable> findReferencedObjects(Referenceable ref) {
        Map<Id, Referenceable> result = new HashMap<>();
        findReferencedObjects(ref, result);
        return result;
    }

    private static void findReferencedObjects(Referenceable ref, Map<Id, Referenceable> seen) {

        Id guid = ref.getId();
        if (seen.containsKey(guid)) {
            return;
        }
        seen.put(guid, ref);
        for (Map.Entry<String, Object> attr : ref.getValuesMap().entrySet()) {
            Object value = attr.getValue();
            if (value instanceof Referenceable) {
                findReferencedObjects((Referenceable) value, seen);
            } else if (value instanceof List) {
                for (Object o : (List) value) {
                    if (o instanceof Referenceable) {
                        findReferencedObjects((Referenceable) o, seen);
                    }
                }
            } else if (value instanceof Map) {
                for (Object o : ((Map) value).values()) {
                    if (o instanceof Referenceable) {
                        findReferencedObjects((Referenceable) o, seen);
                    }
                }
            }
        }
    }

    /**
     * Clears the state in the request context.
     *
     */
    public static void resetRequestContext() {
        //reset the context while preserving the user
        String user = RequestContext.get().getUser();
        RequestContext.createContext();
        RequestContext.get().setUser(user);
    }

    /**
     * Triggers the Atlas initialization process using the specified MetadataRepository.
     * This causes the built-in types and their indices to be created.
     */
    public static void setupGraphProvider(MetadataRepository repo) throws AtlasException {
        TypeCache typeCache = null;
        try {
            typeCache = AtlasRepositoryConfiguration.getTypeCache().newInstance();
        } catch (Throwable t) {
            typeCache = new DefaultTypeCache();
        }
        final GraphBackedSearchIndexer indexer = new GraphBackedSearchIndexer(new AtlasTypeRegistry());
        Provider<TypesChangeListener> indexerProvider = new Provider<TypesChangeListener>() {

            @Override
            public TypesChangeListener get() {
                return indexer;
            }
        };

        Configuration config = ApplicationProperties.get();
        ITypeStore typeStore = new GraphBackedTypeStore();
        DefaultMetadataService defaultMetadataService = new DefaultMetadataService(repo, typeStore,
                Collections.singletonList(indexerProvider), new ArrayList<Provider<EntityChangeListener>>(),
                TypeSystem.getInstance(), config, typeCache);

        //commit the created types
        getGraph().commit();

    }

    public static AtlasGraph getGraph() {

        return AtlasGraphProvider.getGraphInstance();

    }

    /**
     * Adds a proxy wrapper around the specified MetadataService that automatically
     * resets the request context before every call.
     *
     * @param delegate
     * @return
     */
    public static MetadataService addSessionCleanupWrapper(final MetadataService delegate) {

        return (MetadataService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class[] { MetadataService.class }, new InvocationHandler() {

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        try {
                            resetRequestContext();
                            Object result = method.invoke(delegate, args);

                            return result;
                        } catch (InvocationTargetException e) {
                            e.getCause().printStackTrace();
                            throw e.getCause();
                        } catch (Throwable t) {
                            t.printStackTrace();
                            throw t;
                        }
                    }

                });
    }

    /**
     * Adds a proxy wrapper around the specified MetadataRepository that automatically
     * resets the request context before every call and either commits or rolls
     * back the graph transaction after every call.
     *
     * @param delegate
     * @return
     */
    public static MetadataRepository addTransactionWrapper(final MetadataRepository delegate) {
        return (MetadataRepository) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class[] { MetadataRepository.class }, new InvocationHandler() {

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        boolean useTransaction = GraphBackedMetadataRepository.class
                                .getMethod(method.getName(), method.getParameterTypes())
                                .isAnnotationPresent(GraphTransaction.class);
                        try {
                            resetRequestContext();
                            Object result = method.invoke(delegate, args);
                            if (useTransaction) {
                                System.out.println("Committing changes");
                                getGraph().commit();
                                System.out.println("Commit succeeded.");
                            }
                            return result;
                        } catch (InvocationTargetException e) {
                            e.getCause().printStackTrace();
                            if (useTransaction) {
                                System.out.println("Rolling back changes due to exception.");
                                getGraph().rollback();
                            }
                            throw e.getCause();
                        } catch (Throwable t) {
                            t.printStackTrace();
                            if (useTransaction) {
                                System.out.println("Rolling back changes due to exception.");
                                getGraph().rollback();
                            }
                            throw t;
                        }
                    }

                });
    }

    /**
     * Loads the entity and does sanity testing of the GuidMapping  that was
     * created during the operation.
     *
     */
    public static ITypedReferenceableInstance loadAndDoSimpleValidation(String guid, Referenceable original,
            MetadataRepository repositoryService) throws AtlasException {
        ITypedReferenceableInstance loaded = repositoryService.getEntityDefinition(guid);
        doSimpleValidation(original, loaded);
        return loaded;
    }

    /**
     * Loads the entity and does sanity testing of the GuidMapping that was
     * created during the operation.
     *
     */
    public static ITypedReferenceableInstance loadAndDoSimpleValidation(String guid, Referenceable original,
            MetadataService repositoryService) throws AtlasException {
        ITypedReferenceableInstance loaded = repositoryService.getEntityDefinition(guid);
        doSimpleValidation(original, loaded);
        return loaded;

    }

    private static void doSimpleValidation(Referenceable original, IInstance loaded) throws AtlasException {

        assertEquals(loaded.getTypeName(), original.getTypeName());
        ClassType ct = TypeSystem.getInstance().getDataType(ClassType.class, loaded.getTypeName());

        //compare primitive fields
        for (AttributeInfo field : ct.fieldMapping.fields.values()) {
            if (field.dataType().getTypeCategory() == TypeCategory.PRIMITIVE) {
                if (original.get(field.name) != null) {
                    Object rawLoadedValue = loaded.get(field.name);
                    Object rawProvidedValue = original.get(field.name);
                    Object convertedLoadedValue = field.dataType().convert(rawLoadedValue, Multiplicity.REQUIRED);
                    Object convertedProvidedValue = field.dataType().convert(rawProvidedValue,
                            Multiplicity.REQUIRED);

                    assertEquals(convertedLoadedValue, convertedProvidedValue);
                }
            }
        }
    }

    /**
     * Validates that the two String Collections contain the same items, without
     * regard to order.
     *
     */
    public static void assertContentsSame(Collection<String> actual, Collection<String> expected) {
        assertEquals(actual.size(), expected.size());
        Set<String> checker = new HashSet<>();
        checker.addAll(expected);
        checker.removeAll(actual);
        assertEquals(checker.size(), 0);
    }

    public static void skipForGremlin3EnabledGraphDb() throws SkipException {
        //ATLAS-1579 Currently, some tests are skipped for titan1 backened. As these tests are hard coded to use Gremlin2. See ATLAS-1579, ATLAS-1591 once it is fixed, please remove it.
        if (TestUtils.getGraph().getSupportedGremlinVersion() == GremlinVersion.THREE) {
            throw new SkipException("This test requires Gremlin2. Skipping test ");
        }
    }

}