Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,33 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.openmetadata.it.factories.DatabaseSchemaTestFactory;
import org.openmetadata.it.factories.DatabaseServiceTestFactory;
import org.openmetadata.it.util.SdkClients;
import org.openmetadata.it.util.TestNamespace;
import org.openmetadata.schema.api.CreateTaskDetails;
import org.openmetadata.schema.api.data.CreateGlossary;
import org.openmetadata.schema.api.data.CreateGlossaryTerm;
import org.openmetadata.schema.api.data.TermReference;
import org.openmetadata.schema.api.feed.CreateThread;
import org.openmetadata.schema.entity.data.DatabaseSchema;
import org.openmetadata.schema.entity.data.Glossary;
import org.openmetadata.schema.entity.data.GlossaryTerm;
import org.openmetadata.schema.entity.feed.Thread;
import org.openmetadata.schema.entity.services.DatabaseService;
import org.openmetadata.schema.entity.teams.User;
import org.openmetadata.schema.type.Column;
import org.openmetadata.schema.type.ColumnDataType;
import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.EntityStatus;
import org.openmetadata.schema.type.TagLabel;
import org.openmetadata.schema.type.TaskType;
import org.openmetadata.schema.type.TermRelation;
import org.openmetadata.schema.type.ThreadType;
import org.openmetadata.schema.utils.ResultList;
import org.openmetadata.sdk.client.OpenMetadataClient;
import org.openmetadata.sdk.fluent.Columns;
import org.openmetadata.sdk.fluent.Tables;
import org.openmetadata.sdk.models.ListParams;
import org.openmetadata.sdk.models.ListResponse;
import org.openmetadata.sdk.network.HttpMethod;
Expand Down Expand Up @@ -2570,4 +2579,309 @@ void test_glossaryTermEntityStatusFiltering(TestNamespace ns) {
assertEquals(
2, ourMultiStatusTerms.size(), "Both terms should be returned with multi-status filter");
}

// ===================================================================
// ASSET ENDPOINT TESTS WITH PARENT FILTER
// ===================================================================

@Test
void get_assetsCountsWithParentFilter(TestNamespace ns) throws Exception {
OpenMetadataClient client = SdkClients.adminClient();

// Create two glossaries with terms
CreateGlossary createGlossary1 =
new CreateGlossary()
.withName(ns.prefix("asset_count_glossary1"))
.withDescription("Glossary 1 for asset count test");
Glossary glossary1 = client.glossaries().create(createGlossary1);

CreateGlossary createGlossary2 =
new CreateGlossary()
.withName(ns.prefix("asset_count_glossary2"))
.withDescription("Glossary 2 for asset count test");
Glossary glossary2 = client.glossaries().create(createGlossary2);

// Create terms in glossary1
CreateGlossaryTerm termReq1 =
new CreateGlossaryTerm()
.withName(ns.prefix("count_term1"))
.withGlossary(glossary1.getFullyQualifiedName())
.withDescription("Term 1 in glossary 1");
GlossaryTerm term1 = createEntity(termReq1);

CreateGlossaryTerm termReq2 =
new CreateGlossaryTerm()
.withName(ns.prefix("count_term2"))
.withGlossary(glossary1.getFullyQualifiedName())
.withDescription("Term 2 in glossary 1");
GlossaryTerm term2 = createEntity(termReq2);

// Create term in glossary2
CreateGlossaryTerm termReq3 =
new CreateGlossaryTerm()
.withName(ns.prefix("count_term3"))
.withGlossary(glossary2.getFullyQualifiedName())
.withDescription("Term in glossary 2");
GlossaryTerm term3 = createEntity(termReq3);

// Get counts with parent=glossary1 — should only include glossary1's terms
String countsWithParent = getAssetCounts(client, glossary1.getFullyQualifiedName());
assertNotNull(countsWithParent);
ObjectMapper mapper = new ObjectMapper();
JsonNode filteredCounts = mapper.readTree(countsWithParent);
assertTrue(
filteredCounts.has(term1.getFullyQualifiedName()), "Should contain term1 from glossary1");
assertTrue(
filteredCounts.has(term2.getFullyQualifiedName()), "Should contain term2 from glossary1");
assertFalse(
filteredCounts.has(term3.getFullyQualifiedName()),
"Should not contain terms from glossary2 when filtering by glossary1");

// Get counts without parent — should include all terms
String countsWithoutParent = getAssetCounts(client, null);
assertNotNull(countsWithoutParent);
JsonNode unfilteredCounts = mapper.readTree(countsWithoutParent);
assertTrue(
unfilteredCounts.has(term1.getFullyQualifiedName()), "Unfiltered should contain term1");
assertTrue(
unfilteredCounts.has(term2.getFullyQualifiedName()), "Unfiltered should contain term2");
assertTrue(
unfilteredCounts.has(term3.getFullyQualifiedName()), "Unfiltered should contain term3");
}

@Test
void get_assetsCountsWithNoParent(TestNamespace ns) {
OpenMetadataClient client = SdkClients.adminClient();

// Calling without parent should succeed and return a response
String counts = getAssetCounts(client, null);
assertNotNull(counts);
}

@Test
void get_termAssetsById_withParentFilter(TestNamespace ns) throws Exception {
OpenMetadataClient client = SdkClients.adminClient();

CreateGlossary createGlossary =
new CreateGlossary()
.withName(ns.prefix("idag"))
.withDescription("Glossary for assets by id test");
Glossary glossary = client.glossaries().create(createGlossary);

// Create parent term and child term (short names to stay within tagFQN varchar(256) limit)
CreateGlossaryTerm parentReq =
new CreateGlossaryTerm()
.withName("p1")
.withGlossary(glossary.getFullyQualifiedName())
.withDescription("Parent term");
GlossaryTerm parentTerm = createEntity(parentReq);

CreateGlossaryTerm childReq =
new CreateGlossaryTerm()
.withName("c1")
.withGlossary(glossary.getFullyQualifiedName())
.withParent(parentTerm.getFullyQualifiedName())
.withDescription("Child term");
GlossaryTerm childTerm = createEntity(childReq);

// Create a table tagged with the child term so there is a real asset to find
DatabaseService service = DatabaseServiceTestFactory.createPostgres(ns);
DatabaseSchema schema = DatabaseSchemaTestFactory.createSimple(ns, service);
Column col = Columns.build("id").withType(ColumnDataType.BIGINT).create();
TagLabel glossaryTag =
new TagLabel()
.withTagFQN(childTerm.getFullyQualifiedName())
.withSource(TagLabel.TagSource.GLOSSARY);
Tables.create()
.name(ns.prefix("idt"))
.inSchema(schema.getFullyQualifiedName())
.withColumns(List.of(col))
.withTags(List.of(glossaryTag))
.execute();

ObjectMapper mapper = new ObjectMapper();

// Wait for ES to index the tagged asset, then verify matching parent returns it
Awaitility.await("wait for asset to appear for child term with matching parent")
.atMost(java.time.Duration.ofSeconds(30))
.pollInterval(java.time.Duration.ofSeconds(2))
.untilAsserted(
() -> {
String res =
getTermAssetsById(
client, childTerm.getId().toString(), parentTerm.getFullyQualifiedName());
JsonNode node = mapper.readTree(res);
assertTrue(
node.path("paging").path("total").asInt() > 0,
"Matching parent should return the tagged asset");
});

// Query parent term assets with parent filter = glossary — should succeed
String parentResult =
getTermAssetsById(client, parentTerm.getId().toString(), glossary.getFullyQualifiedName());
assertNotNull(parentResult);

// Query child term assets with a non-matching parent — should return empty (total=0)
String emptyResult =
getTermAssetsById(client, childTerm.getId().toString(), "nonexistent.glossary");
JsonNode emptyNode = mapper.readTree(emptyResult);
assertEquals(
0,
emptyNode.path("paging").path("total").asInt(),
"Non-matching parent should return empty result");
}

@Test
void get_termAssetsByName_withParentFilter(TestNamespace ns) throws Exception {
OpenMetadataClient client = SdkClients.adminClient();

CreateGlossary createGlossary =
new CreateGlossary()
.withName(ns.prefix("nag"))
.withDescription("Glossary for assets by name test");
Glossary glossary = client.glossaries().create(createGlossary);

// Short names to stay within tagFQN varchar(256) limit
CreateGlossaryTerm parentReq =
new CreateGlossaryTerm()
.withName("p1")
.withGlossary(glossary.getFullyQualifiedName())
.withDescription("Parent term");
GlossaryTerm parentTerm = createEntity(parentReq);

CreateGlossaryTerm childReq =
new CreateGlossaryTerm()
.withName("c1")
.withGlossary(glossary.getFullyQualifiedName())
.withParent(parentTerm.getFullyQualifiedName())
.withDescription("Child term");
GlossaryTerm childTerm = createEntity(childReq);

// Create a table tagged with the child term
DatabaseService service = DatabaseServiceTestFactory.createPostgres(ns);
DatabaseSchema schema = DatabaseSchemaTestFactory.createSimple(ns, service);
Column col = Columns.build("id").withType(ColumnDataType.BIGINT).create();
TagLabel glossaryTag =
new TagLabel()
.withTagFQN(childTerm.getFullyQualifiedName())
.withSource(TagLabel.TagSource.GLOSSARY);
Tables.create()
.name(ns.prefix("nat"))
.inSchema(schema.getFullyQualifiedName())
.withColumns(List.of(col))
.withTags(List.of(glossaryTag))
.execute();

ObjectMapper mapper = new ObjectMapper();

// Wait for ES to index, then verify matching parent returns the asset
Awaitility.await("wait for asset to appear for child term by name with matching parent")
.atMost(java.time.Duration.ofSeconds(30))
.pollInterval(java.time.Duration.ofSeconds(2))
.untilAsserted(
() -> {
String res =
getTermAssetsByName(
client,
childTerm.getFullyQualifiedName(),
parentTerm.getFullyQualifiedName());
JsonNode node = mapper.readTree(res);
assertTrue(
node.path("paging").path("total").asInt() > 0,
"Matching parent should return the tagged asset");
});

// Query with non-matching parent — should return empty (total=0)
String emptyResult =
getTermAssetsByName(client, childTerm.getFullyQualifiedName(), "nonexistent.glossary");
JsonNode emptyNode = mapper.readTree(emptyResult);
assertEquals(
0,
emptyNode.path("paging").path("total").asInt(),
"Non-matching parent should return empty result");
}

@Test
void get_termAssetsById_withoutParentFilter(TestNamespace ns) {
OpenMetadataClient client = SdkClients.adminClient();

CreateGlossary createGlossary =
new CreateGlossary()
.withName(ns.prefix("noparent_assets_glossary"))
.withDescription("Glossary for assets without parent test");
Glossary glossary = client.glossaries().create(createGlossary);

CreateGlossaryTerm termReq =
new CreateGlossaryTerm()
.withName(ns.prefix("noparent_term"))
.withGlossary(glossary.getFullyQualifiedName())
.withDescription("Term for no-parent test");
GlossaryTerm term = createEntity(termReq);

// Without parent param — should return all assets for the term
String result = getTermAssetsById(client, term.getId().toString(), null);
assertNotNull(result);
}

@Test
void get_termAssetsByName_withoutParentFilter(TestNamespace ns) {
OpenMetadataClient client = SdkClients.adminClient();

CreateGlossary createGlossary =
new CreateGlossary()
.withName(ns.prefix("noparent_name_glossary"))
.withDescription("Glossary for name assets without parent test");
Glossary glossary = client.glossaries().create(createGlossary);

CreateGlossaryTerm termReq =
new CreateGlossaryTerm()
.withName(ns.prefix("noparent_name_term"))
.withGlossary(glossary.getFullyQualifiedName())
.withDescription("Term for no-parent name test");
GlossaryTerm term = createEntity(termReq);

// Without parent param — should return all assets for the term
String result = getTermAssetsByName(client, term.getFullyQualifiedName(), null);
assertNotNull(result);
}

private String getAssetCounts(OpenMetadataClient client, String parent) {
RequestOptions.Builder optionsBuilder = RequestOptions.builder();
if (parent != null) {
optionsBuilder.queryParam("parent", parent);
}
return client
.getHttpClient()
.executeForString(
HttpMethod.GET, "/v1/glossaryTerms/assets/counts", null, optionsBuilder.build());
}

private String getTermAssetsById(OpenMetadataClient client, String id, String parent) {
RequestOptions.Builder optionsBuilder = RequestOptions.builder();
optionsBuilder.queryParam("limit", "10");
optionsBuilder.queryParam("offset", "0");
if (parent != null) {
optionsBuilder.queryParam("parent", parent);
}
return client
.getHttpClient()
.executeForString(
HttpMethod.GET, "/v1/glossaryTerms/" + id + "/assets", null, optionsBuilder.build());
}

private String getTermAssetsByName(OpenMetadataClient client, String fqn, String parent) {
RequestOptions.Builder optionsBuilder = RequestOptions.builder();
optionsBuilder.queryParam("limit", "10");
optionsBuilder.queryParam("offset", "0");
if (parent != null) {
optionsBuilder.queryParam("parent", parent);
}
return client
.getHttpClient()
.executeForString(
HttpMethod.GET,
"/v1/glossaryTerms/name/" + fqn + "/assets",
null,
optionsBuilder.build());
}
}
Loading
Loading