fix: reverted deprecated fields on testSuite (#19284)

Added deprecated fields with a notice. This is to ensure migrations that use them do not break.
This commit is contained in:
Imri Paran 2025-01-09 04:34:17 +02:00 committed by GitHub
parent 78e8d360a5
commit 7d05902945
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 137 additions and 26 deletions

View File

@ -0,0 +1,76 @@
package org.openmetadata.annotations;
import com.fasterxml.jackson.databind.JsonNode;
import com.sun.codemodel.JAnnotationUse;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JMethod;
import java.lang.reflect.Field;
import java.util.TreeMap;
import org.jsonschema2pojo.AbstractAnnotator;
/** Add {@link Deprecated} annotation to generated Java classes */
public class DeprecatedAnnotator extends AbstractAnnotator {
/** Add {@link Deprecated} annotation to property fields */
@Override
public void propertyField(
JFieldVar field, JDefinedClass clazz, String propertyName, JsonNode propertyNode) {
super.propertyField(field, clazz, propertyName, propertyNode);
if (propertyNode.get("deprecated") != null && propertyNode.get("deprecated").asBoolean()) {
field.annotate(Deprecated.class);
}
}
/** Add {@link Deprecated} annotation to getter methods */
@Override
public void propertyGetter(JMethod getter, JDefinedClass clazz, String propertyName) {
super.propertyGetter(getter, clazz, propertyName);
addDeprecatedAnnotationIfApplies(getter, propertyName);
}
/** Add {@link Deprecated} annotation to setter methods */
@Override
public void propertySetter(JMethod setter, JDefinedClass clazz, String propertyName) {
super.propertySetter(setter, clazz, propertyName);
addDeprecatedAnnotationIfApplies(setter, propertyName);
}
/**
* Use reflection methods to access the {@link JDefinedClass} of the {@link JMethod} object. If
* the {@link JMethod} is pointing to a field annotated with {@link Deprecated} then annotates
* the {@link JMethod} object with {@link Deprecated}
*/
private void addDeprecatedAnnotationIfApplies(JMethod jMethod, String propertyName) {
try {
Field outerClassField = JMethod.class.getDeclaredField("outer");
outerClassField.setAccessible(true);
JDefinedClass outerClass = (JDefinedClass) outerClassField.get(jMethod);
TreeMap<String, JFieldVar> insensitiveFieldsMap =
new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
insensitiveFieldsMap.putAll(outerClass.fields());
if (insensitiveFieldsMap.containsKey(propertyName)
&& insensitiveFieldsMap.get(propertyName).annotations().stream()
.anyMatch(
annotation ->
Deprecated.class.getName().equals(getAnnotationClassName(annotation)))) {
jMethod.annotate(Deprecated.class);
}
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private String getAnnotationClassName(JAnnotationUse annotation) {
try {
Field clazzField = JAnnotationUse.class.getDeclaredField("clazz");
clazzField.setAccessible(true);
return ((JClass) clazzField.get(annotation)).fullName();
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -19,6 +19,10 @@ public class OpenMetadataAnnotator extends CompositeAnnotator {
public OpenMetadataAnnotator() { public OpenMetadataAnnotator() {
// we can add multiple annotators // we can add multiple annotators
super(new ExposedAnnotator(), new MaskedAnnotator(), new PasswordAnnotator()); super(
new ExposedAnnotator(),
new MaskedAnnotator(),
new PasswordAnnotator(),
new DeprecatedAnnotator());
} }
} }

View File

@ -25,8 +25,9 @@ public class MigrationUtil {
testSuiteRepository.listAll( testSuiteRepository.listAll(
new EntityUtil.Fields(Set.of("id")), new ListFilter(Include.ALL)); new EntityUtil.Fields(Set.of("id")), new ListFilter(Include.ALL));
for (TestSuite suite : testSuites) { for (TestSuite suite : testSuites) {
if (Boolean.TRUE.equals(suite.getBasic()) && suite.getBasicEntityReference() != null) { if (Boolean.TRUE.equals(suite.getExecutable())
String tableFQN = suite.getBasicEntityReference().getFullyQualifiedName(); && suite.getExecutableEntityReference() != null) {
String tableFQN = suite.getExecutableEntityReference().getFullyQualifiedName();
String suiteFQN = tableFQN + ".testSuite"; String suiteFQN = tableFQN + ".testSuite";
suite.setName(suiteFQN); suite.setName(suiteFQN);
suite.setFullyQualifiedName(suiteFQN); suite.setFullyQualifiedName(suiteFQN);

View File

@ -48,13 +48,13 @@ public class MigrationUtil {
testSuiteRepository.listAll( testSuiteRepository.listAll(
new EntityUtil.Fields(Set.of("id")), new ListFilter(Include.ALL)); new EntityUtil.Fields(Set.of("id")), new ListFilter(Include.ALL));
for (TestSuite suite : testSuites) { for (TestSuite suite : testSuites) {
if (suite.getBasicEntityReference() != null if (suite.getExecutableEntityReference() != null
&& (!suite.getBasic() || !suite.getFullyQualifiedName().contains("testSuite"))) { && (!suite.getExecutable() || !suite.getFullyQualifiedName().contains("testSuite"))) {
String tableFQN = suite.getBasicEntityReference().getFullyQualifiedName(); String tableFQN = suite.getExecutableEntityReference().getFullyQualifiedName();
String suiteFQN = tableFQN + ".testSuite"; String suiteFQN = tableFQN + ".testSuite";
suite.setName(suiteFQN); suite.setName(suiteFQN);
suite.setFullyQualifiedName(suiteFQN); suite.setFullyQualifiedName(suiteFQN);
suite.setBasic(true); suite.setExecutable(true);
collectionDAO.testSuiteDAO().update(suite); collectionDAO.testSuiteDAO().update(suite);
} }
} }
@ -80,7 +80,7 @@ public class MigrationUtil {
try { try {
TestSuite existingTestSuite = TestSuite existingTestSuite =
testSuiteRepository.getDao().findEntityById(existingTestSuiteRel.getId()); testSuiteRepository.getDao().findEntityById(existingTestSuiteRel.getId());
if (Boolean.TRUE.equals(existingTestSuite.getBasic()) if (Boolean.TRUE.equals(existingTestSuite.getExecutable())
&& existingTestSuite.getFullyQualifiedName().equals(executableTestSuiteFQN)) { && existingTestSuite.getFullyQualifiedName().equals(executableTestSuiteFQN)) {
// There is a native test suite associated with this testCase. // There is a native test suite associated with this testCase.
relationWithExecutableTestSuiteExists = true; relationWithExecutableTestSuiteExists = true;
@ -111,7 +111,7 @@ public class MigrationUtil {
// check from table -> nativeTestSuite there should only one relation // check from table -> nativeTestSuite there should only one relation
List<CollectionDAO.EntityRelationshipRecord> testSuiteRels = List<CollectionDAO.EntityRelationshipRecord> testSuiteRels =
testSuiteRepository.findToRecords( testSuiteRepository.findToRecords(
executableTestSuite.getBasicEntityReference().getId(), executableTestSuite.getExecutableEntityReference().getId(),
TABLE, TABLE,
Relationship.CONTAINS, Relationship.CONTAINS,
TEST_SUITE); TEST_SUITE);
@ -122,7 +122,7 @@ public class MigrationUtil {
// if testsuite cannot be retrieved but the relation exists, then this is orphaned // if testsuite cannot be retrieved but the relation exists, then this is orphaned
// relation, we will delete the relation // relation, we will delete the relation
testSuiteRepository.deleteRelationship( testSuiteRepository.deleteRelationship(
executableTestSuite.getBasicEntityReference().getId(), executableTestSuite.getExecutableEntityReference().getId(),
TABLE, TABLE,
testSuiteRel.getId(), testSuiteRel.getId(),
TEST_SUITE, TEST_SUITE,
@ -158,9 +158,9 @@ public class MigrationUtil {
new CreateTestSuite() new CreateTestSuite()
.withName(FullyQualifiedName.buildHash(executableTestSuiteFQN)) .withName(FullyQualifiedName.buildHash(executableTestSuiteFQN))
.withDisplayName(executableTestSuiteFQN) .withDisplayName(executableTestSuiteFQN)
.withBasicEntityReference(entityLink.getEntityFQN()), .withExecutableEntityReference(entityLink.getEntityFQN()),
"ingestion-bot") "ingestion-bot")
.withBasic(true) .withExecutable(true)
.withFullyQualifiedName(executableTestSuiteFQN); .withFullyQualifiedName(executableTestSuiteFQN);
testSuiteRepository.prepareInternal(newExecutableTestSuite, false); testSuiteRepository.prepareInternal(newExecutableTestSuite, false);
testSuiteRepository testSuiteRepository
@ -169,7 +169,7 @@ public class MigrationUtil {
"fqnHash", newExecutableTestSuite, newExecutableTestSuite.getFullyQualifiedName()); "fqnHash", newExecutableTestSuite, newExecutableTestSuite.getFullyQualifiedName());
// add relationship between executable TestSuite with Table // add relationship between executable TestSuite with Table
testSuiteRepository.addRelationship( testSuiteRepository.addRelationship(
newExecutableTestSuite.getBasicEntityReference().getId(), newExecutableTestSuite.getExecutableEntityReference().getId(),
newExecutableTestSuite.getId(), newExecutableTestSuite.getId(),
Entity.TABLE, Entity.TABLE,
TEST_SUITE, TEST_SUITE,

View File

@ -460,16 +460,17 @@ public class MigrationUtil {
.withDescription(create.getDescription()) .withDescription(create.getDescription())
.withDisplayName(create.getDisplayName()) .withDisplayName(create.getDisplayName())
.withName(create.getName()); .withName(create.getName());
if (create.getBasicEntityReference() != null) { if (create.getExecutableEntityReference() != null) {
Table table = Table table =
Entity.getEntityByName(Entity.TABLE, create.getBasicEntityReference(), "", Include.ALL); Entity.getEntityByName(
Entity.TABLE, create.getExecutableEntityReference(), "", Include.ALL);
EntityReference entityReference = EntityReference entityReference =
new EntityReference() new EntityReference()
.withId(table.getId()) .withId(table.getId())
.withFullyQualifiedName(table.getFullyQualifiedName()) .withFullyQualifiedName(table.getFullyQualifiedName())
.withName(table.getName()) .withName(table.getName())
.withType(Entity.TABLE); .withType(Entity.TABLE);
testSuite.setBasicEntityReference(entityReference); testSuite.setExecutableEntityReference(entityReference);
} }
return testSuite; return testSuite;
} }
@ -516,9 +517,9 @@ public class MigrationUtil {
new CreateTestSuite() new CreateTestSuite()
.withName(FullyQualifiedName.buildHash(nativeTestSuiteFqn)) .withName(FullyQualifiedName.buildHash(nativeTestSuiteFqn))
.withDisplayName(nativeTestSuiteFqn) .withDisplayName(nativeTestSuiteFqn)
.withBasicEntityReference(entityLink.getEntityFQN()), .withExecutableEntityReference(entityLink.getEntityFQN()),
"ingestion-bot") "ingestion-bot")
.withBasic(true) .withExecutable(true)
.withFullyQualifiedName(nativeTestSuiteFqn); .withFullyQualifiedName(nativeTestSuiteFqn);
testSuiteRepository.prepareInternal(newExecutableTestSuite, false); testSuiteRepository.prepareInternal(newExecutableTestSuite, false);
try { try {
@ -533,7 +534,7 @@ public class MigrationUtil {
} }
// add relationship between executable TestSuite with Table // add relationship between executable TestSuite with Table
testSuiteRepository.addRelationship( testSuiteRepository.addRelationship(
newExecutableTestSuite.getBasicEntityReference().getId(), newExecutableTestSuite.getExecutableEntityReference().getId(),
newExecutableTestSuite.getId(), newExecutableTestSuite.getId(),
Entity.TABLE, Entity.TABLE,
TEST_SUITE, TEST_SUITE,
@ -564,7 +565,7 @@ public class MigrationUtil {
ListFilter filter = new ListFilter(Include.ALL); ListFilter filter = new ListFilter(Include.ALL);
List<TestSuite> testSuites = testSuiteRepository.listAll(new Fields(Set.of("id")), filter); List<TestSuite> testSuites = testSuiteRepository.listAll(new Fields(Set.of("id")), filter);
for (TestSuite testSuite : testSuites) { for (TestSuite testSuite : testSuites) {
testSuite.setBasic(false); testSuite.setExecutable(false);
List<CollectionDAO.EntityRelationshipRecord> ingestionPipelineRecords = List<CollectionDAO.EntityRelationshipRecord> ingestionPipelineRecords =
collectionDAO collectionDAO
.relationshipDAO() .relationshipDAO()

View File

@ -106,16 +106,16 @@ public class MigrationUtilV111 {
suite = JsonUtils.readValue(pgObject.getValue(), TestSuite.class); suite = JsonUtils.readValue(pgObject.getValue(), TestSuite.class);
} }
// Only Test Suite which are executable needs to be updated // Only Test Suite which are executable needs to be updated
if (Boolean.TRUE.equals(suite.getBasic())) { if (Boolean.TRUE.equals(suite.getExecutable())) {
if (suite.getBasicEntityReference() != null) { if (suite.getExecutableEntityReference() != null) {
updateTestSuite(handle, suite, updateSql); updateTestSuite(handle, suite, updateSql);
} else { } else {
String entityName = StringUtils.replaceOnce(suite.getDisplayName(), ".testSuite", ""); String entityName = StringUtils.replaceOnce(suite.getDisplayName(), ".testSuite", "");
try { try {
Table table = collectionDAO.tableDAO().findEntityByName(entityName, Include.ALL); Table table = collectionDAO.tableDAO().findEntityByName(entityName, Include.ALL);
// Update Test Suite // Update Test Suite
suite.setBasic(true); suite.setExecutable(true);
suite.setBasicEntityReference(table.getEntityReference()); suite.setExecutableEntityReference(table.getEntityReference());
updateTestSuite(handle, suite, updateSql); updateTestSuite(handle, suite, updateSql);
removeDuplicateTestCases(collectionDAO, handle, getSql); removeDuplicateTestCases(collectionDAO, handle, getSql);
} catch (Exception ex) { } catch (Exception ex) {
@ -133,9 +133,9 @@ public class MigrationUtilV111 {
} }
public static void updateTestSuite(Handle handle, TestSuite suite, String updateSql) { public static void updateTestSuite(Handle handle, TestSuite suite, String updateSql) {
if (suite.getBasicEntityReference() != null) { if (suite.getExecutableEntityReference() != null) {
try { try {
EntityReference executableEntityRef = suite.getBasicEntityReference(); EntityReference executableEntityRef = suite.getExecutableEntityReference();
// Run new Migrations // Run new Migrations
suite.setName(String.format("%s.testSuite", executableEntityRef.getName())); suite.setName(String.format("%s.testSuite", executableEntityRef.getName()));
suite.setFullyQualifiedName( suite.setFullyQualifiedName(

View File

@ -37,6 +37,11 @@
"description": "Entity reference the test suite needs to execute the test against. Only applicable if the test suite is basic.", "description": "Entity reference the test suite needs to execute the test against. Only applicable if the test suite is basic.",
"$ref": "../../type/basic.json#/definitions/fullyQualifiedEntityName" "$ref": "../../type/basic.json#/definitions/fullyQualifiedEntityName"
}, },
"executableEntityReference": {
"description": "DEPRECATED in 1.6.2: use 'basicEntityReference'",
"$ref": "../../type/basic.json#/definitions/fullyQualifiedEntityName",
"deprecated": true
},
"domain": { "domain": {
"description": "Fully qualified name of the domain the Table belongs to.", "description": "Fully qualified name of the domain the Table belongs to.",
"type": "string" "type": "string"

View File

@ -125,10 +125,20 @@
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },
"executable": {
"description": "DEPRECATED in 1.6.2: Use 'basic'",
"type": "boolean",
"deprecated": true
},
"basicEntityReference": { "basicEntityReference": {
"description": "Entity reference the test suite needs to execute the test against. Only applicable if the test suite is basic.", "description": "Entity reference the test suite needs to execute the test against. Only applicable if the test suite is basic.",
"$ref": "../type/entityReference.json" "$ref": "../type/entityReference.json"
}, },
"executableEntityReference": {
"description": "DEPRECATED in 1.6.2: Use 'basicEntityReference'.",
"$ref": "../type/entityReference.json",
"deprecated": true
},
"summary": { "summary": {
"description": "Summary of the previous day test cases execution for this test suite.", "description": "Summary of the previous day test cases execution for this test suite.",
"$ref": "./basic.json#/definitions/testSummary" "$ref": "./basic.json#/definitions/testSummary"

View File

@ -31,6 +31,10 @@ export interface CreateTestSuite {
* Fully qualified name of the domain the Table belongs to. * Fully qualified name of the domain the Table belongs to.
*/ */
domain?: string; domain?: string;
/**
* DEPRECATED in 1.6.2: use 'basicEntityReference'
*/
executableEntityReference?: string;
/** /**
* Name that identifies this test suite. * Name that identifies this test suite.
*/ */

View File

@ -50,6 +50,14 @@ export interface TestSuite {
* the table it belongs to. * the table it belongs to.
*/ */
domain?: EntityReference; domain?: EntityReference;
/**
* DEPRECATED in 1.6.2: Use 'basic'
*/
executable?: boolean;
/**
* DEPRECATED in 1.6.2: Use 'basicEntityReference'.
*/
executableEntityReference?: EntityReference;
/** /**
* FullyQualifiedName same as `name`. * FullyQualifiedName same as `name`.
*/ */
@ -127,6 +135,8 @@ export interface TestSuite {
* Domain the test Suite belongs to. When not set, the test Suite inherits the domain from * Domain the test Suite belongs to. When not set, the test Suite inherits the domain from
* the table it belongs to. * the table it belongs to.
* *
* DEPRECATED in 1.6.2: Use 'basicEntityReference'.
*
* Owners of this TestCase definition. * Owners of this TestCase definition.
* *
* This schema defines the EntityReferenceList type used for referencing an entity. * This schema defines the EntityReferenceList type used for referencing an entity.