mirror of
				https://github.com/open-metadata/OpenMetadata.git
				synced 2025-10-30 18:17:53 +00:00 
			
		
		
		
	Prep v1.1.7 migrations to address test cases & suites (#13345)
* Prep v1.1.7 migrations to address test cases * get or create executable suite * Format * Fix tests * Add postgres
This commit is contained in:
		
							parent
							
								
									d8ef497b9e
								
							
						
					
					
						commit
						2c3ff8dc08
					
				| @ -103,7 +103,7 @@ base_requirements = { | ||||
|     VERSIONS["pymysql"], | ||||
|     "python-dateutil>=2.8.1", | ||||
|     "python-jose~=3.3", | ||||
|     "PyYAML", | ||||
|     "PyYAML~=6.0", | ||||
|     "requests>=2.23", | ||||
|     "requests-aws4auth~=1.1",  # Only depends on requests as external package. Leaving as base. | ||||
|     "setuptools~=66.0.0", | ||||
|  | ||||
| @ -344,7 +344,7 @@ public final class Entity { | ||||
|   public static EntityRepository<? extends EntityInterface> getEntityRepository(@NonNull String entityType) { | ||||
|     EntityRepository<? extends EntityInterface> entityRepository = ENTITY_REPOSITORY_MAP.get(entityType); | ||||
|     if (entityRepository == null) { | ||||
|       throw EntityNotFoundException.byMessage(CatalogExceptionMessage.entityTypeNotFound(entityType)); | ||||
|       throw EntityNotFoundException.byMessage(CatalogExceptionMessage.entityRepositoryNotFound(entityType)); | ||||
|     } | ||||
|     return entityRepository; | ||||
|   } | ||||
|  | ||||
| @ -95,6 +95,10 @@ public final class CatalogExceptionMessage { | ||||
|     return String.format("Entity type %s not found", entityType); | ||||
|   } | ||||
| 
 | ||||
|   public static String entityRepositoryNotFound(String entityType) { | ||||
|     return String.format("Entity repository for %s not found. Is the ENTITY_TYPE_MAP initialized?", entityType); | ||||
|   } | ||||
| 
 | ||||
|   public static String entityRelationshipNotFound( | ||||
|       String entityType, UUID id, String relationshipName, String toEntityType) { | ||||
|     return String.format( | ||||
|  | ||||
| @ -1357,6 +1357,10 @@ public abstract class EntityRepository<T extends EntityInterface> { | ||||
|     return getFromEntityRef(toId, Relationship.CONTAINS, null, true); | ||||
|   } | ||||
| 
 | ||||
|   public EntityReference getContainer(UUID toId, String fromEntityType) { | ||||
|     return getFromEntityRef(toId, Relationship.CONTAINS, fromEntityType, true); | ||||
|   } | ||||
| 
 | ||||
|   public EntityReference getFromEntityRef( | ||||
|       UUID toId, Relationship relationship, String fromEntityType, boolean mustHaveRelationship) { | ||||
|     List<EntityRelationshipRecord> records = findFromRecords(toId, entityType, relationship, fromEntityType); | ||||
|  | ||||
| @ -158,7 +158,7 @@ public class TableRepository extends EntityRepository<Table> { | ||||
|   } | ||||
| 
 | ||||
|   private void setDefaultFields(Table table) { | ||||
|     EntityReference schemaRef = getContainer(table.getId()); | ||||
|     EntityReference schemaRef = getContainer(table.getId(), DATABASE_SCHEMA); | ||||
|     DatabaseSchema schema = Entity.getEntity(schemaRef, "", ALL); | ||||
|     table.withDatabaseSchema(schemaRef).withDatabase(schema.getDatabase()).withService(schema.getService()); | ||||
|   } | ||||
|  | ||||
| @ -0,0 +1,35 @@ | ||||
| package org.openmetadata.service.migration.mysql.v117; | ||||
| 
 | ||||
| import static org.openmetadata.service.migration.utils.V114.MigrationUtil.fixTestSuites; | ||||
| import static org.openmetadata.service.migration.utils.V117.MigrationUtil.fixTestCases; | ||||
| 
 | ||||
| import lombok.SneakyThrows; | ||||
| import org.jdbi.v3.core.Handle; | ||||
| import org.openmetadata.service.jdbi3.CollectionDAO; | ||||
| import org.openmetadata.service.migration.api.MigrationProcessImpl; | ||||
| import org.openmetadata.service.migration.utils.MigrationFile; | ||||
| 
 | ||||
| public class Migration extends MigrationProcessImpl { | ||||
|   private CollectionDAO collectionDAO; | ||||
|   private Handle handle; | ||||
| 
 | ||||
|   public Migration(MigrationFile migrationFile) { | ||||
|     super(migrationFile); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void initialize(Handle handle) { | ||||
|     super.initialize(handle); | ||||
|     this.handle = handle; | ||||
|     this.collectionDAO = handle.attach(CollectionDAO.class); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   @SneakyThrows | ||||
|   public void runDataMigration() { | ||||
|     // tests cases coming from dbt for case-sensitive services are not properly linked to a table | ||||
|     fixTestCases(handle, collectionDAO); | ||||
|     // Try again the 1.1.6 test suite migration | ||||
|     fixTestSuites(collectionDAO); | ||||
|   } | ||||
| } | ||||
| @ -1,22 +1,29 @@ | ||||
| package org.openmetadata.service.migration.utils.V114; | ||||
| 
 | ||||
| import static org.openmetadata.service.Entity.*; | ||||
| import static org.openmetadata.service.migration.utils.v110.MigrationUtil.getTestSuite; | ||||
| import static org.openmetadata.service.migration.utils.v110.MigrationUtil.groupTestCasesByTable; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.openmetadata.schema.api.tests.CreateTestSuite; | ||||
| import org.openmetadata.schema.tests.TestCase; | ||||
| import org.openmetadata.schema.tests.TestSuite; | ||||
| import org.openmetadata.schema.type.Include; | ||||
| import org.openmetadata.schema.type.Relationship; | ||||
| import org.openmetadata.service.Entity; | ||||
| import org.openmetadata.service.exception.EntityNotFoundException; | ||||
| import org.openmetadata.service.jdbi3.CollectionDAO; | ||||
| import org.openmetadata.service.jdbi3.ListFilter; | ||||
| import org.openmetadata.service.jdbi3.TestSuiteRepository; | ||||
| import org.openmetadata.service.resources.feeds.MessageParser; | ||||
| import org.openmetadata.service.util.EntityUtil; | ||||
| import org.openmetadata.service.util.FullyQualifiedName; | ||||
| 
 | ||||
| @Slf4j | ||||
| public class MigrationUtil { | ||||
|   private MigrationUtil() { | ||||
|     /* Cannot create object  util class*/ | ||||
| @ -54,10 +61,11 @@ public class MigrationUtil { | ||||
|     // TestSuite | ||||
|     Map<String, ArrayList<TestCase>> testCasesGroupByTable = groupTestCasesByTable(collectionDAO); | ||||
|     for (String tableFQN : testCasesGroupByTable.keySet()) { | ||||
|       try { | ||||
|         List<TestCase> testCases = testCasesGroupByTable.get(tableFQN); | ||||
|         String executableTestSuiteFQN = tableFQN + ".testSuite"; | ||||
|         TestSuite executableTestSuite = | ||||
|           testSuiteRepository.getDao().findEntityByName(executableTestSuiteFQN, "fqnHash", Include.ALL); | ||||
|             getOrCreateExecutableTestSuite(collectionDAO, testCases, testSuiteRepository, executableTestSuiteFQN); | ||||
|         for (TestCase testCase : testCases) { | ||||
|           // we are setting mustHaveRelationship to "false" to not throw any error. | ||||
|           List<CollectionDAO.EntityRelationshipRecord> existingRelations = | ||||
| @ -67,7 +75,7 @@ public class MigrationUtil { | ||||
|             for (CollectionDAO.EntityRelationshipRecord existingTestSuiteRel : existingRelations) { | ||||
|               try { | ||||
|                 TestSuite existingTestSuite = testSuiteRepository.getDao().findEntityById(existingTestSuiteRel.getId()); | ||||
|               if (existingTestSuite.getExecutable() | ||||
|                 if (Boolean.TRUE.equals(existingTestSuite.getExecutable()) | ||||
|                     && existingTestSuite.getFullyQualifiedName().equals(executableTestSuiteFQN)) { | ||||
|                   // There is a native test suite associated with this testCase. | ||||
|                   relationWithExecutableTestSuiteExists = true; | ||||
| @ -93,7 +101,7 @@ public class MigrationUtil { | ||||
|                 executableTestSuite.getExecutableEntityReference().getId(), TABLE, Relationship.CONTAINS, TEST_SUITE); | ||||
|         for (CollectionDAO.EntityRelationshipRecord testSuiteRel : testSuiteRels) { | ||||
|           try { | ||||
|           TestSuite existingTestSuite = testSuiteRepository.getDao().findEntityById(testSuiteRel.getId()); | ||||
|             testSuiteRepository.getDao().findEntityById(testSuiteRel.getId()); | ||||
|           } catch (EntityNotFoundException ex) { | ||||
|             // if testsuite cannot be retrieved but the relation exists, then this is orphaned relation, we will | ||||
|             // delete the relation | ||||
| @ -105,6 +113,53 @@ public class MigrationUtil { | ||||
|                 Relationship.CONTAINS); | ||||
|           } | ||||
|         } | ||||
|       } catch (Exception exc) { | ||||
|         LOG.error( | ||||
|             String.format("Error trying to migrate tests from Table [%s] due to [%s]", tableFQN, exc.getMessage())); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private static TestSuite getOrCreateExecutableTestSuite( | ||||
|       CollectionDAO collectionDAO, | ||||
|       List<TestCase> testCases, | ||||
|       TestSuiteRepository testSuiteRepository, | ||||
|       String executableTestSuiteFQN) { | ||||
|     try { | ||||
|       // Try to return the Executable Test Suite that should exist | ||||
|       return testSuiteRepository.getDao().findEntityByName(executableTestSuiteFQN, "fqnHash", Include.ALL); | ||||
|     } catch (EntityNotFoundException exc) { | ||||
|       // If it does not exist, create it and return it | ||||
|       MessageParser.EntityLink entityLink = | ||||
|           MessageParser.EntityLink.parse(testCases.stream().findFirst().get().getEntityLink()); | ||||
|       TestSuite newExecutableTestSuite = | ||||
|           getTestSuite( | ||||
|                   collectionDAO, | ||||
|                   new CreateTestSuite() | ||||
|                       .withName(FullyQualifiedName.buildHash(executableTestSuiteFQN)) | ||||
|                       .withDisplayName(executableTestSuiteFQN) | ||||
|                       .withExecutableEntityReference(entityLink.getEntityFQN()), | ||||
|                   "ingestion-bot") | ||||
|               .withExecutable(true) | ||||
|               .withFullyQualifiedName(executableTestSuiteFQN); | ||||
|       testSuiteRepository.prepareInternal(newExecutableTestSuite, false); | ||||
|       testSuiteRepository | ||||
|           .getDao() | ||||
|           .insert("fqnHash", newExecutableTestSuite, newExecutableTestSuite.getFullyQualifiedName()); | ||||
|       // add relationship between executable TestSuite with Table | ||||
|       testSuiteRepository.addRelationship( | ||||
|           newExecutableTestSuite.getExecutableEntityReference().getId(), | ||||
|           newExecutableTestSuite.getId(), | ||||
|           Entity.TABLE, | ||||
|           TEST_SUITE, | ||||
|           Relationship.CONTAINS); | ||||
| 
 | ||||
|       // add relationship between all the testCases that are created against a table with native test suite. | ||||
|       for (TestCase testCase : testCases) { | ||||
|         testSuiteRepository.addRelationship( | ||||
|             newExecutableTestSuite.getId(), testCase.getId(), TEST_SUITE, TEST_CASE, Relationship.CONTAINS); | ||||
|       } | ||||
|       return newExecutableTestSuite; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,65 @@ | ||||
| package org.openmetadata.service.migration.utils.V117; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| import org.jdbi.v3.core.Handle; | ||||
| import org.openmetadata.schema.entity.data.Table; | ||||
| import org.openmetadata.schema.tests.TestCase; | ||||
| import org.openmetadata.schema.type.Include; | ||||
| import org.openmetadata.service.jdbi3.CollectionDAO; | ||||
| import org.openmetadata.service.jdbi3.ListFilter; | ||||
| import org.openmetadata.service.jdbi3.TableRepository; | ||||
| import org.openmetadata.service.jdbi3.TestCaseRepository; | ||||
| import org.openmetadata.service.resources.databases.DatasourceConfig; | ||||
| import org.openmetadata.service.resources.feeds.MessageParser; | ||||
| import org.openmetadata.service.util.EntityUtil; | ||||
| import org.openmetadata.service.util.JsonUtils; | ||||
| 
 | ||||
| public class MigrationUtil { | ||||
|   private MigrationUtil() { | ||||
|     /* Cannot create object  util class*/ | ||||
|   } | ||||
| 
 | ||||
|   private static final String MYSQL_LIST_TABLE_FQNS = | ||||
|       "SELECT JSON_UNQUOTE(JSON_EXTRACT(json, '$.fullyQualifiedName')) FROM table_entity"; | ||||
|   private static final String POSTGRES_LIST_TABLE_FQNS = "SELECT json #>> '{fullyQualifiedName}' FROM table_entity"; | ||||
| 
 | ||||
|   public static void fixTestCases(Handle handle, CollectionDAO collectionDAO) { | ||||
|     TestCaseRepository testCaseRepository = new TestCaseRepository(collectionDAO); | ||||
|     TableRepository tableRepository = new TableRepository(collectionDAO); | ||||
|     List<TestCase> testCases = | ||||
|         testCaseRepository.listAll(new EntityUtil.Fields(Set.of("id")), new ListFilter(Include.ALL)); | ||||
| 
 | ||||
|     try { | ||||
|       List<String> fqnList; | ||||
|       if (Boolean.TRUE.equals(DatasourceConfig.getInstance().isMySQL())) { | ||||
|         fqnList = handle.createQuery(MYSQL_LIST_TABLE_FQNS).mapTo(String.class).list(); | ||||
|       } else { | ||||
|         fqnList = handle.createQuery(POSTGRES_LIST_TABLE_FQNS).mapTo(String.class).list(); | ||||
|       } | ||||
|       Map<String, String> tableMap = new HashMap<>(); | ||||
|       for (String fqn : fqnList) { | ||||
|         tableMap.put(fqn.toLowerCase(), fqn); | ||||
|       } | ||||
| 
 | ||||
|       for (TestCase testCase : testCases) { | ||||
|         // Create New Executable Test Suites | ||||
|         MessageParser.EntityLink entityLink = MessageParser.EntityLink.parse(testCase.getEntityLink()); | ||||
|         String fqn = entityLink.getEntityFQN(); | ||||
|         Table table = JsonUtils.readValue(tableRepository.getDao().findJsonByFqn(fqn, Include.ALL), Table.class); | ||||
|         if (table == null) { | ||||
|           String findTableFQN = tableMap.get(fqn.toLowerCase()); | ||||
|           MessageParser.EntityLink newEntityLink = | ||||
|               new MessageParser.EntityLink(entityLink.getEntityType(), findTableFQN); | ||||
|           testCase.setEntityLink(newEntityLink.getLinkString()); | ||||
|           testCase.setEntityFQN(findTableFQN); | ||||
|           collectionDAO.testCaseDAO().update(testCase); | ||||
|         } | ||||
|       } | ||||
|     } catch (Exception exc) { | ||||
|       throw exc; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -58,7 +58,7 @@ public class MigrationUtil { | ||||
|   public static void addQueryService(Handle handle, CollectionDAO collectionDAO) { | ||||
|     QueryRepository queryRepository = new QueryRepository(collectionDAO); | ||||
| 
 | ||||
|     try (handle) { | ||||
|     try { | ||||
|       handle | ||||
|           .createQuery(QUERY_LIST_SERVICE) | ||||
|           .mapToMap() | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Pere Miquel Brull
						Pere Miquel Brull