package jnpf.dmsMapper;
|
|
import jnpf.dmsDatabase.DmsUuidTypeHandler;
|
import jnpf.dmsPermission.DmsUserFolderPermissionPrincipal;
|
import jnpf.dmsPermission.DmsUserFolderPermissionTreeQuery;
|
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
|
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.io.IOException;
|
import java.io.InputStream;
|
import java.io.UncheckedIOException;
|
import java.util.ArrayList;
|
import java.util.Arrays;
|
import java.util.Collections;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
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 DmsUserFolderPermissionTreeMapperSqlTest {
|
private Configuration configuration;
|
|
@BeforeEach
|
void setUp() {
|
configuration = new Configuration();
|
configuration.getTypeHandlerRegistry().register(UUID.class, DmsUuidTypeHandler.class);
|
try (InputStream stream = getClass().getResourceAsStream(
|
"/mapper/DmsUserFolderPermissionTreeMapper.xml")) {
|
new XMLMapperBuilder(stream, configuration,
|
"mapper/DmsUserFolderPermissionTreeMapper.xml",
|
configuration.getSqlFragments()).parse();
|
} catch (IOException e) {
|
throw new UncheckedIOException(e);
|
}
|
}
|
|
@Test
|
void resolvesActivePermissionsFromTheCurrentFolderAndItsAncestors() {
|
String sql = sql(query());
|
|
assertTrue(sql.startsWith("WITH RECURSIVE input_principals"));
|
assertTrue(sql.contains("jsonb_array_elements(CAST(? AS jsonb))"));
|
assertTrue(sql.contains("p.resource_type = 'FOLDER'"));
|
assertTrue(sql.contains("p.resource_scope IN ('SELF', 'SUBTREE')"));
|
assertTrue(sql.contains("p.action_code IN ('READ', 'PRINT')"));
|
assertTrue(sql.contains("p.revoked_at IS NULL"));
|
assertTrue(sql.contains("p.valid_from <= CURRENT_TIMESTAMP"));
|
assertTrue(sql.contains("CURRENT_TIMESTAMP < p.valid_to"));
|
assertTrue(sql.contains("p.used_count < p.max_use_count"));
|
assertTrue(sql.contains("FROM parent_ancestors child JOIN public.dms_folders parent"));
|
assertTrue(sql.contains("parent.id = child.parent_id"));
|
assertTrue(sql.contains("FROM navigation_ancestors child JOIN public.dms_folders parent"));
|
assertTrue(sql.contains("permission.resource_scope = 'SUBTREE'"));
|
assertTrue(sql.contains("permission.folder_id IN ( SELECT ancestor.id "
|
+ "FROM parent_ancestors ancestor )"));
|
assertFalse(sql.contains("expanded_folder_permissions"));
|
assertFalse(sql.contains("child.parent_id = parent.folder_id"));
|
}
|
|
@Test
|
void matchesEverySupportedResolvedPrincipalKind() {
|
String sql = sql(query());
|
|
assertTrue(sql.contains("p.principal_type = 'USER' AND ip.principal_kind = 'USER'"));
|
assertTrue(sql.contains("p.principal_type = 'ORG' AND p.include_child_orgs = FALSE "
|
+ "AND ip.principal_kind = 'ORG_DIRECT'"));
|
assertTrue(sql.contains("p.principal_type = 'ORG' AND p.include_child_orgs = TRUE "
|
+ "AND ip.principal_kind = 'ORG_ANCESTOR'"));
|
assertTrue(sql.contains("p.principal_type = 'POSITION' "
|
+ "AND ip.principal_kind = 'POSITION'"));
|
assertTrue(sql.contains("p.principal_type = 'ROLE' AND ip.principal_kind = 'ROLE'"));
|
assertTrue(sql.contains("p.principal_type = 'GROUP' AND ip.principal_kind = 'GROUP'"));
|
}
|
|
@Test
|
void bindsAllPrincipalsAsOneJsonPayload() {
|
DmsUserFolderPermissionTreeQuery query = query();
|
BoundSql boundSql = boundSql(query);
|
|
assertEquals(1, boundSql.getParameterMappings().stream()
|
.filter(value -> "q.principalsJson".equals(value.getProperty())).count());
|
assertTrue(query.getPrincipalsJson().startsWith("["));
|
assertTrue(query.getPrincipalsJson().contains("\"userId\":\"user-1\""));
|
assertTrue(query.getPrincipalsJson().contains("\"principalKind\":\"ORG_DIRECT\""));
|
assertEquals(1, occurrences(normalize(boundSql.getSql()), "jsonb_array_elements(CAST(? AS jsonb))"));
|
}
|
|
@Test
|
void largePrincipalCollectionStillUsesOneBindParameter() {
|
DmsUserFolderPermissionTreeQuery query = query();
|
List<DmsUserFolderPermissionPrincipal> principals = new ArrayList<>();
|
for (int index = 0; index < 25000; index++) {
|
principals.add(principal("user-" + (index % 50), "GROUP", "group-" + index));
|
}
|
query.setPrincipals(principals);
|
|
BoundSql boundSql = boundSql(query);
|
|
assertEquals(1, boundSql.getParameterMappings().stream()
|
.filter(value -> "q.principalsJson".equals(value.getProperty())).count());
|
assertTrue(query.getPrincipalsJson().contains("\"principalId\":\"group-24999\""));
|
}
|
|
@Test
|
void pagesFoldersBeforeJoiningUserActionsAndUsesVisibleChildren() {
|
DmsUserFolderPermissionTreeQuery query = query();
|
query.setParentId(UUID.fromString("018f0000-0000-7000-8000-000000000601"));
|
query.setCursorSortCode(2048L);
|
query.setCursorId(UUID.fromString("018f0000-0000-7000-8000-000000000602"));
|
|
String sql = sql(query);
|
|
assertTrue(sql.contains("folder.parent_id = ?"));
|
assertTrue(sql.contains("folder.sort_code > ?"));
|
assertTrue(sql.contains("folder.sort_code = ? AND folder.id > ?"));
|
assertTrue(sql.contains("ORDER BY folder.sort_code, folder.id LIMIT ?"));
|
assertTrue(sql.contains("FROM public.dms_folders child WHERE child.tenant_id = ? "
|
+ "AND child.parent_id = folder.id"));
|
assertTrue(sql.contains("LEFT JOIN effective_page_permissions permission "
|
+ "ON permission.folder_id = folder.id"));
|
assertTrue(sql.indexOf("LIMIT ?") < sql.indexOf("LEFT JOIN effective_page_permissions"));
|
assertTrue(sql.endsWith("ORDER BY folder.sort_code, folder.id, "
|
+ "permission.user_id, permission.action_code"));
|
}
|
|
@Test
|
void emptyPrincipalCollectionUsesAnEmptyJsonArray() {
|
DmsUserFolderPermissionTreeQuery query = query();
|
query.setPrincipals(Collections.emptyList());
|
|
String sql = sql(query);
|
|
assertEquals("[]", query.getPrincipalsJson());
|
assertTrue(sql.contains("jsonb_array_elements(CAST(? AS jsonb))"));
|
assertFalse(sql.contains("VALUES"));
|
}
|
|
private DmsUserFolderPermissionTreeQuery query() {
|
DmsUserFolderPermissionTreeQuery query = new DmsUserFolderPermissionTreeQuery();
|
query.setTenantId("tenant-1");
|
query.setLimit(21);
|
query.setPrincipals(Arrays.asList(
|
principal("user-1", "USER", "user-1"),
|
principal("user-1", "ORG_DIRECT", "org-direct"),
|
principal("user-1", "ORG_ANCESTOR", "org-parent"),
|
principal("user-1", "POSITION", "position-1"),
|
principal("user-2", "ROLE", "role-1"),
|
principal("user-2", "GROUP", "group-1")));
|
return query;
|
}
|
|
private DmsUserFolderPermissionPrincipal principal(String userId, String kind, String id) {
|
return new DmsUserFolderPermissionPrincipal(userId, kind, id);
|
}
|
|
private String sql(DmsUserFolderPermissionTreeQuery query) {
|
return normalize(boundSql(query).getSql());
|
}
|
|
private BoundSql boundSql(DmsUserFolderPermissionTreeQuery query) {
|
MappedStatement statement = configuration.getMappedStatement(
|
DmsUserFolderPermissionTreeMapper.class.getName() + ".selectTree");
|
Map<String, Object> parameters = new HashMap<>();
|
parameters.put("q", query);
|
return statement.getBoundSql(parameters);
|
}
|
|
private String normalize(String sql) {
|
return sql.replaceAll("\\s+", " ").trim();
|
}
|
|
private int occurrences(String value, String token) {
|
int result = 0;
|
int offset = 0;
|
while ((offset = value.indexOf(token, offset)) >= 0) {
|
result++;
|
offset += token.length();
|
}
|
return result;
|
}
|
}
|