package jnpf.dmsService; import jnpf.dmsEntity.storage.*; import jnpf.dmsMapper.DmsRevisionEditMapper; import jnpf.exception.DataException; import jnpf.util.JsonUtil; import org.junit.jupiter.api.Test; import java.util.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class DmsRevisionEditServiceTest { @Test public void nonEditableSourcesReceiveFreshVerifiableReceiptsWithoutOldUploadTokens() { for (String extension : List.of("txt", "pdf", "doc", "docx")) { DmsRevisionEditMapper mapper = mock(DmsRevisionEditMapper.class); DmsRevisionEditSource source = source(); source.setFiles(JsonUtil.getObjectToString(List.of(Map.of("fileId", "original", "name", "source." + extension, "uploadReceipt", "expired-upload", "laiyuan_muban_id", "template")))); when(mapper.sources("tenant", "owner", "source", "model")).thenReturn(List.of(source)); Map tickets = new HashMap<>(); DmsRevisionEditService service = new DmsRevisionEditService(mapper, tickets::get, (json, ttl) -> { tickets.put("receipt", json); return "receipt"; }); Map file = (Map)((List)service.prepare(request(), "tenant", "owner").get(0).get("files")).get(0); assertEquals("receipt", file.get("revisionEditReceipt")); assertFalse(file.containsKey("uploadReceipt")); Map verified = (Map) service.verify(request()).get("file"); assertEquals("source." + extension, verified.get("name")); assertEquals("template", verified.get("laiyuan_muban_id")); source.setFiles(JsonUtil.getObjectToString(List.of(Map.of("fileId", "original", "name", "source." + extension, "uploadReceipt", "expired-upload")))); Map ordinary = (Map)((List)service.prepare(request(), "tenant", "owner").get(0).get("files")).get(0); assertFalse(ordinary.containsKey("laiyuan_muban_id")); assertFalse(((Map)service.verify(request()).get("file")).containsKey("laiyuan_muban_id")); when(mapper.sources("tenant", "owner", "source", "model")).thenReturn(List.of()); assertThrows(DataException.class, () -> service.verify(request())); } } @Test public void unchangedSourceReturnsCompleteTrustedJsonButEditedCopyDoesNot() throws Exception { DmsRevisionEditMapper mapper = mock(DmsRevisionEditMapper.class); DmsRevisionEditSource source = source(); String original = "{\"fileId\":\"original\",\"name\":\"source.txt\",\"uploadReceipt\":\"historical-owner-token\",\"fileVersionId\":null}"; source.setFiles("[" + original + "]"); when(mapper.sources("tenant", "owner", "source", "model")).thenReturn(List.of(source)); Map grant = proof(); grant.put("file", Map.of("fileId", "original", "name", "source.txt")); grant.put("sourceFileJson", "forged"); DmsRevisionEditService service = new DmsRevisionEditService(mapper, token -> JsonUtil.getObjectToString(grant), (json, ttl) -> "issued"); Map verified = service.verify(request()); com.fasterxml.jackson.databind.ObjectMapper json = new com.fasterxml.jackson.databind.ObjectMapper(); assertEquals(json.readTree(original), json.readTree((String)verified.get("sourceFileJson"))); assertFalse(((Map)verified.get("file")).containsKey("laiyuan_muban_id")); grant.put("file", Map.of("fileId", "copy", "name", "source.docx")); assertFalse(service.verify(request()).containsKey("sourceFileJson")); } private static void assertThrows(Class type, Runnable action) { try { action.run(); } catch (Throwable error) { if (type.isInstance(error)) return; throw error; } fail("Expected " + type.getSimpleName()); } private DmsRevisionEditRequest request() { DmsRevisionEditRequest r = new DmsRevisionEditRequest(); r.setTenantId("tenant"); r.setOwnerId("owner"); r.setModelId("model"); r.setSourceItemId("source"); r.setField("wenjian"); r.setParentField(""); r.setReceipt("receipt"); return r; } private DmsRevisionEditSource source() { DmsRevisionEditSource s = new DmsRevisionEditSource(); s.setVersionId("version"); s.setField("wenjian"); s.setParentField(""); s.setFiles("[{\"fileId\":\"original\",\"name\":\"source.docx\"}]"); return s; } private Map proof() { Map p = new HashMap<>(); p.put("purpose", "dms-revision-edit"); p.put("tenantId", "tenant"); p.put("ownerId", "owner"); p.put("modelId", "model"); p.put("sourceItemId", "source"); p.put("field", "wenjian"); p.put("parentField", ""); p.put("versionId", "version"); p.put("originFileId", "original"); p.put("expiresAt", System.currentTimeMillis()+60000); p.put("file", Map.of("fileId", "copy", "name", "source.docx")); return p; } @Test public void receiptRevalidatesCanonicalSourceAndRejectsTampering() { DmsRevisionEditMapper mapper = mock(DmsRevisionEditMapper.class); when(mapper.sources("tenant","owner","source","model")).thenReturn(List.of(source())); Map current = proof(); DmsRevisionEditService service = new DmsRevisionEditService(mapper, token -> JsonUtil.getObjectToString(current), (json, ttl) -> "issued"); assertEquals("copy", ((Map)service.verify(request()).get("file")).get("fileId")); for (String field : List.of("purpose", "tenantId", "ownerId", "modelId", "field", "parentField", "versionId", "originFileId")) { Object original = current.put(field, "foreign"); assertThrows(DataException.class, () -> service.verify(request())); current.put(field, original); } current.put("expiresAt", 1); assertThrows(DataException.class, () -> service.verify(request())); } @Test public void sourceRemovedAfterIssuanceIsRejected() { DmsRevisionEditMapper mapper = mock(DmsRevisionEditMapper.class); DmsRevisionEditService service = new DmsRevisionEditService(mapper, token -> JsonUtil.getObjectToString(proof()), (json, ttl) -> "issued"); assertThrows(DataException.class, () -> service.verify(request())); } @Test public void prepareUsesOnlyServerFilesAndBindsChildVersion() { DmsRevisionEditMapper mapper = mock(DmsRevisionEditMapper.class); DmsRevisionEditSource child = source(); child.setParentField("jilu_mingxi"); child.setField("jilu_wenjian"); when(mapper.sources("tenant","owner","source","model")).thenReturn(List.of(child)); DmsRevisionEditService service = new DmsRevisionEditService(mapper, token -> null, (json, ttl) -> { Map proof = JsonUtil.getJsonToBean(json, Map.class); assertEquals("jilu_mingxi", proof.get("parentField")); assertEquals("version", proof.get("versionId")); assertEquals("original", proof.get("originFileId")); assertEquals(14400L, ttl.longValue()); return "issued"; }); List> rows = service.prepare(request(), "tenant", "owner"); assertEquals("issued", ((Map)((List)rows.get(0).get("files")).get(0)).get("revisionEditReceipt")); } }