package jnpf.dmsMapper; import jnpf.dmsDatabase.DmsUuidTypeHandler; import jnpf.dmsPermission.DmsFileCenterQuery; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.session.Configuration; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.util.Arrays; import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; class DmsFileCenterMapperSqlTest { private Configuration configuration; @BeforeEach void setUp() { configuration = new Configuration(); configuration.getTypeHandlerRegistry().register(UUID.class, DmsUuidTypeHandler.class); try (java.io.InputStream stream = getClass().getResourceAsStream("/mapper/DmsFileCenterMapper.xml")) { new org.apache.ibatis.builder.xml.XMLMapperBuilder(stream, configuration, "mapper/DmsFileCenterMapper.xml", configuration.getSqlFragments()).parse(); } catch (java.io.IOException e) { throw new java.io.UncheckedIOException(e); } } @Test void immediateChildrenBranchIsLimitedToApprovalReadGrantsInListingsAndNavigation() { var q = query(false); q.setImmediateParentOrgIds(java.util.List.of("parent")); for (String method : java.util.List.of("selectFolders", "selectCurrentDocuments", "selectSharedDocuments", "selectHistoricalVersions")) { String sql = sql(method, q); assertTrue(sql.contains("p.approved_org_scope = 'CHILDREN'")); assertTrue(sql.contains("p.granted_by_id = 'dms-approved-read'")); assertTrue(sql.contains("p.source_type = 'WORKFLOW'")); } } @Test void ordinaryFolderPageFiltersPermissionsBeforeStableLimit() { String sql = sql("selectFolders", query(false)); assertTrue(sql.contains("FROM public.dms_file_permissions p")); assertTrue(sql.contains("authorized_navigation_seeds")); assertTrue(sql.contains("authorized_navigation_ancestors")); assertTrue(sql.contains("SELECT granted.id, granted.parent_id")); assertTrue(sql.contains("SELECT document_folder.id, document_folder.parent_id")); assertTrue(sql.contains("SELECT version_folder.id, version_folder.parent_id")); assertTrue(sql.contains("p.resource_type = 'DOCUMENT'")); assertTrue(sql.contains("p.resource_type = 'FILE_VERSION'")); assertTrue(sql.contains("dms_access_exclusions")); assertTrue(sql.contains("UNION SELECT parent.id, parent.parent_id FROM authorized_navigation_ancestors child")); assertTrue(sql.contains("OR f.id IN (SELECT id FROM authorized_navigation_ancestors)")); assertTrue(sql.contains("p.principal_type = 'USER'")); assertTrue(sql.contains("p.principal_type = 'ORG'")); assertTrue(sql.contains("p.principal_type = 'POSITION'")); assertTrue(sql.contains("p.principal_type = 'ROLE'")); assertTrue(sql.contains("p.principal_type = 'GROUP'")); assertTrue(sql.contains("p.resource_scope = 'SUBTREE'")); assertTrue(sql.contains("f.f_delete_mark IS NULL")); assertTrue(sql.contains("ORDER BY f.sort_code, f.id LIMIT ?")); assertTrue(sql.indexOf("dms_file_permissions") < sql.indexOf("LIMIT ?")); assertFalse(sql.contains("SELECT *")); assertFalse(sql.contains("AS has_children")); } @Test void treeExpansionUsesVisibleChildrenIncludingNavigationAndInheritedRead() { DmsFileCenterQuery query = query(false); query.setIncludeFolderChildren(true); String sql = sql("selectFolders", query); String expansion = sql.substring(sql.indexOf(", EXISTS (SELECT 1 FROM public.dms_folders child_folder"), sql.indexOf(") AS has_children")); assertTrue(expansion.contains("child_folder.tenant_id = ?")); assertTrue(expansion.contains("child_folder.parent_id = f.id")); assertTrue(expansion.contains("child_folder.f_delete_mark IS NULL")); assertTrue(expansion.contains("child_folder.id IN (SELECT id FROM authorized_navigation_ancestors)")); assertTrue(expansion.contains("p.resource_id = child_folder.id")); assertTrue(expansion.contains("p.resource_scope = 'SUBTREE' AND (p.resource_id = f.id")); assertTrue(expansion.contains("p.resource_id IN (SELECT id FROM parent_ancestors)")); assertTrue(expansion.contains("p.action_code = 'READ'")); assertTrue(expansion.contains("p.revoked_at IS NULL")); assertTrue(expansion.contains("p.valid_from <= CURRENT_TIMESTAMP")); assertTrue(expansion.contains("CURRENT_TIMESTAMP < p.valid_to")); assertTrue(expansion.contains("p.used_count < p.max_use_count")); for (String principal : Arrays.asList("USER", "ORG", "POSITION", "ROLE", "GROUP")) { assertTrue(expansion.contains("p.principal_type = '" + principal + "'")); } } @Test void administratorTreeExpansionStillFiltersTenantAndDeletedChildren() { DmsFileCenterQuery query = query(true); query.setIncludeFolderChildren(true); String sql = sql("selectFolders", query); assertTrue(sql.contains("child_folder.tenant_id = ?")); assertTrue(sql.contains("child_folder.f_delete_mark IS NULL")); assertTrue(sql.contains(") AS has_children")); assertFalse(sql.contains("dms_file_permissions")); assertFalse(sql.contains("authorized_navigation_ancestors")); } @Test void administratorFolderPageDoesNotRequireAllowRows() { String sql = sql("selectFolders", query(true)); assertFalse(sql.contains("dms_file_permissions")); assertFalse(sql.contains("authorized_navigation_seeds")); assertFalse(sql.contains("authorized_navigation_ancestors")); assertTrue(sql.contains("f.f_delete_mark IS NULL")); assertTrue(sql.contains("ORDER BY f.sort_code, f.id LIMIT ?")); } @Test void folderCursorUsesSortCodeAndIdBoundary() { DmsFileCenterQuery query = query(true); query.setCursorSortCode(2048L); query.setCursorId(UUID.fromString("018f0000-0000-7000-8000-000000000603")); String sql = sql("selectFolders", query); assertTrue(sql.contains("f.sort_code > ?")); assertTrue(sql.contains("f.sort_code = ? AND f.id > ?")); assertFalse(sql.contains("f.name > ?")); } @Test void currentDocumentPageUsesEffectiveWindowResourceReadAndExclusionPriority() { String sql = sql("selectCurrentDocuments", query(false)); assertTrue(sql.contains("d.id, 'DOCUMENT' AS resource_type")); assertTrue(sql.contains("d.main_document_id IS NULL")); assertTrue(sql.contains("member.id=d.id OR member.main_document_id=d.id")); assertTrue(sql.contains("s.lifecycle_status = 'EFFECTIVE'")); assertTrue(sql.contains("s.effective_from <= CURRENT_TIMESTAMP")); assertTrue(sql.contains("CURRENT_TIMESTAMP < s.effective_to")); assertTrue(sql.contains("NOT EXISTS (SELECT 1 FROM public.dms_access_exclusions e")); assertTrue(sql.contains("p.resource_type = 'FOLDER'")); assertTrue(sql.contains("p.resource_type = 'DOCUMENT'")); assertTrue(sql.contains("p.resource_type = 'FILE_VERSION'")); assertTrue(sql.contains("ORDER BY COALESCE((SELECT initial_version.file_name")); } @Test void currentFileSearchUsesUnifiedFieldsAcrossFolderSubtree() { DmsFileCenterQuery query = query(false); query.setKeyword("Report"); query.setCursorName("Document A"); query.setCursorDocumentId(UUID.fromString("018f0000-0000-7000-8000-000000000701")); query.setCursorId(UUID.fromString("018f0000-0000-7000-8000-000000000702")); String sql = sql("selectCurrentFiles", query); assertTrue(sql.contains("SELECT v.id, 'FILE_VERSION' AS resource_type")); assertTrue(sql.contains("s.lifecycle_status = 'EFFECTIVE'")); assertTrue(sql.contains("s.review_cycle_months")); assertTrue(sql.contains("s.last_reviewed_on")); assertTrue(sql.contains("s.next_review_on")); assertTrue(sql.contains("WITH RECURSIVE folder_descendants")); assertTrue(sql.contains("child.parent_id = parent.id")); assertTrue(sql.contains("d.folder_id IN (SELECT id FROM folder_descendants)")); assertTrue(sql.contains("STRPOS(LOWER(COALESCE(v.file_name, '')), LOWER(?)) > 0")); assertTrue(sql.contains("STRPOS(LOWER(COALESCE(d.name, '')), LOWER(?)) > 0")); assertTrue(sql.contains("STRPOS(LOWER(COALESCE(d.document_no, '')), LOWER(?)) > 0")); assertFalse(sql.contains("STARTS_WITH")); assertTrue(sql.contains("d.id = ? AND v.id > ?")); assertTrue(sql.contains("dms_access_exclusions")); assertTrue(sql.contains("dms_file_permissions")); assertTrue(sql.contains("SELECT ancestor_id FROM search_folder_ancestors WHERE folder_id = d.folder_id")); assertTrue(sql.contains("ORDER BY d.name, d.id, v.id LIMIT ?")); assertBalancedParentheses(sql); } @Test void fileNameExistenceUsesDirectFolderExactNameAndCurrentVersions() { String sql = sql("fileNameExists", query(false)); assertTrue(sql.contains("d.folder_id = ?")); assertTrue(sql.contains("v.file_name = ?")); assertTrue(sql.contains("s.lifecycle_status = 'EFFECTIVE'")); assertTrue(sql.contains("d.access_status = 'enabled'")); assertTrue(sql.contains("d.tenant_id = ?")); assertFalse(sql.contains("dms_access_exclusions")); assertFalse(sql.contains("dms_file_permissions")); assertFalse(sql.contains("folder_descendants")); assertFalse(sql.contains("version_label =")); assertBalancedParentheses(sql); } @Test void administratorFileSearchKeepsBusinessScopeWithoutPermissionPredicates() { DmsFileCenterQuery query = query(true); query.setKeyword("玻思韬"); String sql = sql("selectCurrentFiles", query); assertTrue(sql.contains("d.tenant_id = ?")); assertTrue(sql.contains("d.folder_id IN (SELECT id FROM folder_descendants)")); assertTrue(sql.contains("s.lifecycle_status = 'EFFECTIVE'")); assertTrue(sql.contains("STRPOS(LOWER(COALESCE(d.name, '')), LOWER(?)) > 0")); assertFalse(sql.contains("dms_file_permissions")); assertFalse(sql.contains("dms_access_exclusions")); assertBalancedParentheses(sql); } @Test void historicalPageReturnsOneDocumentContainerForVisibleTerminalVersions() { DmsFileCenterQuery query = query(false); query.setCursorName("A"); query.setCursorDocumentId(UUID.fromString("018f0000-0000-7000-8000-000000000701")); String sql = sql("selectHistoricalVersions", query); assertTrue(sql.contains("d.id, 'DOCUMENT' AS resource_type")); assertTrue(sql.contains("d.main_document_id IS NULL")); assertTrue(sql.contains("member.id=d.id OR member.main_document_id=d.id")); assertTrue(sql.contains("AND EXISTS (SELECT 1 FROM public.dms_documents member")); assertHistoricalVisibility(sql); assertFalse(sql.contains("PENDING_EFFECTIVE")); assertFalse(sql.contains("v.version_no < ?")); assertFalse(sql.contains("v.id < ?")); assertTrue(sql.contains("p.resource_type = 'FOLDER'")); assertTrue(sql.contains("p.resource_type = 'DOCUMENT'")); assertTrue(sql.contains("p.resource_type = 'FILE_VERSION'")); assertTrue(sql.contains("ORDER BY COALESCE((SELECT initial_version.file_name")); } @Test void historicalFileSearchReturnsOnlyMatchingTerminalFileVersions() { DmsFileCenterQuery query = query(false); query.setKeyword("Archive"); query.setCursorName("Document A"); query.setCursorDocumentId(UUID.fromString("018f0000-0000-7000-8000-000000000701")); query.setCursorVersionNo(2L); query.setCursorId(UUID.fromString("018f0000-0000-7000-8000-000000000702")); String sql = sql("selectHistoricalFiles", query); assertTrue(sql.contains("SELECT v.id, 'FILE_VERSION' AS resource_type")); assertHistoricalVisibility(sql); assertFalse(sql.contains("PENDING_EFFECTIVE")); assertTrue(sql.contains("d.folder_id IN (SELECT id FROM folder_descendants)")); assertTrue(sql.contains("STRPOS(LOWER(COALESCE(v.file_name, '')), LOWER(?)) > 0")); assertTrue(sql.contains("STRPOS(LOWER(COALESCE(d.name, '')), LOWER(?)) > 0")); assertTrue(sql.contains("STRPOS(LOWER(COALESCE(d.document_no, '')), LOWER(?)) > 0")); assertTrue(sql.contains("v.version_no < ?")); assertTrue(sql.contains("dms_access_exclusions")); assertTrue(sql.contains("dms_file_permissions")); assertTrue(sql.contains("ORDER BY d.name, d.id, v.version_no DESC, v.id DESC LIMIT ?")); assertBalancedParentheses(sql); } @Test void currentDocumentDirectoryReturnsOnlyTheEffectiveVersion() { String sql = sql("selectCurrentDocumentVersions", query(false)); assertTrue(sql.contains("'FILE_VERSION' AS resource_type")); assertTrue(sql.contains("d.id = ?")); assertTrue(sql.contains("s.lifecycle_status = 'EFFECTIVE'")); assertTrue(sql.contains("s.effective_from <= CURRENT_TIMESTAMP")); assertTrue(sql.contains("CURRENT_TIMESTAMP < s.effective_to")); assertTrue(sql.contains("p.resource_type = 'FOLDER'")); assertTrue(sql.contains("p.resource_type = 'DOCUMENT'")); assertTrue(sql.contains("p.resource_type = 'FILE_VERSION'")); assertTrue(sql.contains("ORDER BY v.version_no DESC, v.id DESC LIMIT ?")); } @Test void documentVersionSearchUsesTheSameContainsFields() { DmsFileCenterQuery query = query(true); query.setKeyword("玻思韬"); String sql = sql("selectCurrentDocumentVersions", query); assertTrue(sql.contains("STRPOS(LOWER(COALESCE(v.file_name, '')), LOWER(?)) > 0")); assertTrue(sql.contains("STRPOS(LOWER(COALESCE(d.name, '')), LOWER(?)) > 0")); assertTrue(sql.contains("STRPOS(LOWER(COALESCE(d.document_no, '')), LOWER(?)) > 0")); assertFalse(sql.contains("LIKE CONCAT")); assertFalse(sql.contains("STARTS_WITH")); } @Test void historicalDocumentDirectoryIncludesElapsedVersionsBeforeWorkerRuns() { String sql = sql("selectDocumentVersions", query(false)); assertTrue(sql.contains("'FILE_VERSION' AS resource_type")); assertHistoricalVisibility(sql); assertTrue(sql.contains("s.lifecycle_status = 'EFFECTIVE' AND s.effective_to <= CURRENT_TIMESTAMP")); } @Test void sharedPageUsesOnlyDirectDocumentOrVersionAllow() { String sql = sql("selectSharedHistoricalVersions", query(false)); assertTrue(sql.contains("p.resource_type = 'DOCUMENT'")); assertTrue(sql.contains("p.resource_type = 'FILE_VERSION'")); assertFalse(sql.contains("p.resource_type = 'FOLDER'")); assertTrue(sql.contains("dms_access_exclusions")); } private void assertHistoricalVisibility(String sql) { assertTrue(sql.contains("IN ('SUPERSEDED', 'EXPIRED', 'REVOKED', 'OBSOLETE')")); assertTrue(sql.contains("s.lifecycle_status = 'INVALIDATED' AND s.approved_at IS NOT NULL")); assertFalse(sql.contains("PENDING_APPROVAL")); } private DmsFileCenterQuery query(boolean administrator) { DmsFileCenterQuery query = new DmsFileCenterQuery(); query.setTenantId("tenant-1"); query.setUserId("user-1"); query.setAdministrator(administrator); query.setParentId(UUID.fromString("018f0000-0000-7000-8000-000000000601")); query.setFolderId(UUID.fromString("018f0000-0000-7000-8000-000000000601")); query.setDocumentId(UUID.fromString("018f0000-0000-7000-8000-000000000602")); query.setDirectOrgIds(Arrays.asList("org-1")); query.setAncestorOrgIds(Arrays.asList("org-1", "org-root")); query.setPositionIds(Arrays.asList("position-1")); query.setRoleIds(Arrays.asList("role-1")); query.setPermissionGroupIds(Arrays.asList("group-1")); query.setLimit(51); return query; } private String sql(String method, DmsFileCenterQuery query) { MappedStatement statement = configuration.getMappedStatement( DmsFileCenterMapper.class.getName() + "." + method); BoundSql boundSql = statement.getBoundSql(java.util.Collections.singletonMap("q", query)); return boundSql.getSql().replaceAll("\\s+", " ").trim(); } private void assertBalancedParentheses(String sql) { long opening = sql.chars().filter(value -> value == '(').count(); long closing = sql.chars().filter(value -> value == ')').count(); assertEquals(opening, closing, sql); } }