Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -2063,6 +2063,50 @@ void test_getOutputPortsPaginated(TestNamespace ns) throws Exception {
assertEquals(2, outputPortsByName.getData().size());
}

@Test
void test_getPorts_survivingPortsKeepIdentityWhenOneDeleted(TestNamespace ns) throws Exception {
Domain domain = getOrCreateDomain(ns);

CreateDataProduct create =
new CreateDataProduct()
.withName(ns.prefix("dp_deleted_port"))
.withDescription("Data product for deleted-port attribution test")
.withDomains(List.of(domain.getFullyQualifiedName()));
DataProduct dataProduct = createEntity(create);

Table table1 = createTestTable(ns, "del_port_1", domain);
Table table2 = createTestTable(ns, "del_port_2", domain);
Table table3 = createTestTable(ns, "del_port_3", domain);

bulkAddInputPorts(
dataProduct.getFullyQualifiedName(),
new BulkAssets()
.withAssets(
List.of(
table1.getEntityReference(),
table2.getEntityReference(),
table3.getEntityReference())));

// Soft-delete a port. getPaginatedPorts fetches ports with NON_DELETED, so this row drops out
// of the entity fetch while its relationship record remains — the exact condition under which
// index-based mapping misattributed or silently dropped the surviving ports.
SdkClients.adminClient().tables().delete(table2.getId().toString());

ResultList<Map<String, Object>> inputPorts = getInputPorts(dataProduct.getId(), 10, 0);

List<UUID> returnedIds = new ArrayList<>();
for (Map<String, Object> port : inputPorts.getData()) {
returnedIds.add(getEntityId(port));
}

// Each surviving port must be present exactly once and carry its own id — never the deleted
// port's id and never a neighbour's data.
assertEquals(2, returnedIds.size());
assertTrue(returnedIds.contains(table1.getId()));
assertTrue(returnedIds.contains(table3.getId()));
assertFalse(returnedIds.contains(table2.getId()));
}

@Test
void test_addPort_rejectsNonDataAssetEntity(TestNamespace ns) throws Exception {
Domain domain = getOrCreateDomain(ns);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -652,17 +652,18 @@ private ResultList<EntityWithType> getPaginatedPorts(
refsByType.computeIfAbsent(record.getType(), k -> new ArrayList<>()).add(ref);
}

// Bulk fetch entities by type and collect in order
// Bulk fetch entities by type, keyed by each entity's own id. NON_DELETED filtering and the
// absence of an ORDER BY mean getEntities may return fewer entities than requested and in a
// different order, so keying by request-list index would misattribute or drop rows.
// Use empty string if fields is null to avoid NPE
String fieldsToFetch = fields != null ? fields : "";
Map<UUID, EntityWithType> entitiesById = new HashMap<>();
for (Map.Entry<String, List<EntityReference>> entry : refsByType.entrySet()) {
String entityType = entry.getKey();
List<EntityInterface> entitiesOfType =
Entity.getEntities(entry.getValue(), fieldsToFetch, NON_DELETED);
for (int i = 0; i < entitiesOfType.size(); i++) {
entitiesById.put(
entry.getValue().get(i).getId(), new EntityWithType(entitiesOfType.get(i), entityType));
for (EntityInterface entity : entitiesOfType) {
entitiesById.put(entity.getId(), new EntityWithType(entity, entityType));
}
}

Expand Down Expand Up @@ -759,8 +760,10 @@ protected BulkOperationResult bulkAssetsOperation(
for (Map.Entry<String, List<EntityReference>> entry : assetsByType.entrySet()) {
List<EntityInterface> entitiesOfType =
Entity.getEntities(entry.getValue(), "domains,dataProducts", ALL);
for (int i = 0; i < entitiesOfType.size(); i++) {
assetEntitiesMap.put(entry.getValue().get(i).getId(), entitiesOfType.get(i));
// Key by each entity's own id; getEntities may reorder or drop rows relative to the
// request list, so request-index zipping would validate the wrong asset.
for (EntityInterface entity : entitiesOfType) {
assetEntitiesMap.put(entity.getId(), entity);
}
}
}
Expand Down
Loading