From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master

---
 jnpf-biz-common/jnpf-biz-common-onlyoffice/src/test/java/jnpf/bizcommon/onlyoffice/service/impl/OnlyOfficeServiceImplTest.java |  170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 170 insertions(+), 0 deletions(-)

diff --git a/jnpf-biz-common/jnpf-biz-common-onlyoffice/src/test/java/jnpf/bizcommon/onlyoffice/service/impl/OnlyOfficeServiceImplTest.java b/jnpf-biz-common/jnpf-biz-common-onlyoffice/src/test/java/jnpf/bizcommon/onlyoffice/service/impl/OnlyOfficeServiceImplTest.java
new file mode 100644
index 0000000..13893d5
--- /dev/null
+++ b/jnpf-biz-common/jnpf-biz-common-onlyoffice/src/test/java/jnpf/bizcommon/onlyoffice/service/impl/OnlyOfficeServiceImplTest.java
@@ -0,0 +1,170 @@
+package jnpf.bizcommon.onlyoffice.service.impl;
+
+import com.sun.net.httpserver.HttpServer;
+import jnpf.base.UserInfo;
+import jnpf.bizcommon.onlyoffice.entity.OnlyOfficeConfigParam;
+import jnpf.bizcommon.onlyoffice.entity.OnlyOfficeCallbackParam;
+import jnpf.bizcommon.onlyoffice.entity.OnlyOfficeProperties;
+import jnpf.bizcommon.onlyoffice.entity.OnlyOfficeSessionEntity;
+import jnpf.bizcommon.onlyoffice.mapper.OnlyOfficeSessionMapper;
+import jnpf.exception.DataException;
+import jnpf.file.FileApi;
+import jnpf.file.FileUploadApi;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.net.InetSocketAddress;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class OnlyOfficeServiceImplTest {
+
+    private HttpServer server;
+    private OnlyOfficeSessionMapper sessionMapper;
+    private FileApi fileApi;
+    private FileUploadApi fileUploadApi;
+    private OnlyOfficeServiceImpl service;
+
+    @Before
+    public void setUp() throws Exception {
+        server = HttpServer.create(new InetSocketAddress(0), 0);
+        server.createContext("/saved.docx", exchange -> {
+            byte[] body = "saved-document".getBytes();
+            exchange.sendResponseHeaders(200, body.length);
+            exchange.getResponseBody().write(body);
+            exchange.close();
+        });
+        server.start();
+
+        sessionMapper = mock(OnlyOfficeSessionMapper.class);
+        fileApi = mock(FileApi.class);
+        fileUploadApi = mock(FileUploadApi.class);
+        when(fileApi.getPath("annex")).thenReturn("WebAnnexFile");
+        OnlyOfficeProperties properties = new OnlyOfficeProperties();
+        properties.setJwtSecret("test-secret");
+        service = new OnlyOfficeServiceImpl(properties, sessionMapper,
+                mock(OnlyOfficePluginResolver.class), mock(OnlyOfficeFillTicketIssuer.class), fileApi, fileUploadApi);
+    }
+
+    @After
+    public void tearDown() {
+        server.stop(0);
+    }
+
+    @Test
+    public void saveBackReplacesOriginalFile() {
+        OnlyOfficeSessionEntity session = session();
+        when(fileUploadApi.replaceFile(any(), eq("WebAnnexFile/"), eq("template.docx"))).thenReturn(true);
+
+        invokeSaveBack(session, callback(), true);
+
+        verify(fileUploadApi).replaceFile(any(), eq("WebAnnexFile/"), eq("template.docx"));
+        verify(fileUploadApi, never()).uploadFile(any(), any(), any());
+        assertEquals(Integer.valueOf(2), session.getVersionNo());
+    }
+
+    @Test
+    public void failedReplacementDoesNotAdvanceSession() {
+        OnlyOfficeSessionEntity session = session();
+        when(fileUploadApi.replaceFile(any(), eq("WebAnnexFile/"), eq("template.docx"))).thenReturn(false);
+
+        try {
+            invokeSaveBack(session, callback(), true);
+            fail("expected replacement failure");
+        } catch (DataException e) {
+            assertEquals("鏂囦欢鏈嶅姟鍐欏洖鏂囨。澶辫触", e.getMessage());
+        }
+
+        assertEquals(Integer.valueOf(1), session.getVersionNo());
+        assertNull(session.getLastSaveTime());
+        verify(sessionMapper, never()).updateById(any(OnlyOfficeSessionEntity.class));
+    }
+
+    @Test
+    public void viewModeHidesCollaborationMenu() {
+        OnlyOfficeConfigParam param = new OnlyOfficeConfigParam();
+        param.setFileId("template.docx");
+        param.setFileName("template.docx");
+        param.setBizScene("ordinary.view");
+        UserInfo user = new UserInfo();
+        user.setUserId("user-1");
+        user.setUserName("Tester");
+
+        Map<String, Object> config = invokeAssembleConfig(param, session(), user);
+        Map<String, Object> document = castMap(config.get("document"));
+        Map<String, Object> permissions = castMap(document.get("permissions"));
+        Map<String, Object> editorConfig = castMap(config.get("editorConfig"));
+        Map<String, Object> customization = castMap(editorConfig.get("customization"));
+
+        assertEquals(false, permissions.get("comment"));
+        assertEquals(false, permissions.get("review"));
+        assertEquals(false, customization.get("comments"));
+    }
+
+    private OnlyOfficeSessionEntity session() {
+        OnlyOfficeSessionEntity session = new OnlyOfficeSessionEntity();
+        session.setFileId("template.docx");
+        session.setFileType("annex");
+        session.setVersionNo(1);
+        session.setDocKey("key-1");
+        return session;
+    }
+
+    private OnlyOfficeCallbackParam callback() {
+        OnlyOfficeCallbackParam callback = new OnlyOfficeCallbackParam();
+        callback.setStatus(OnlyOfficeCallbackParam.Status.READY_FOR_SAVING);
+        callback.setUrl("http://127.0.0.1:" + server.getAddress().getPort() + "/saved.docx");
+        return callback;
+    }
+
+    private void invokeSaveBack(OnlyOfficeSessionEntity session, OnlyOfficeCallbackParam callback, boolean rotateKey) {
+        try {
+            Method method = OnlyOfficeServiceImpl.class.getDeclaredMethod(
+                    "saveBack", OnlyOfficeSessionEntity.class, OnlyOfficeCallbackParam.class, boolean.class);
+            method.setAccessible(true);
+            method.invoke(service, session, callback, rotateKey);
+        } catch (InvocationTargetException e) {
+            if (e.getCause() instanceof RuntimeException) {
+                throw (RuntimeException) e.getCause();
+            }
+            throw new RuntimeException(e.getCause());
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private Map<String, Object> invokeAssembleConfig(OnlyOfficeConfigParam param,
+                                                      OnlyOfficeSessionEntity session,
+                                                      UserInfo user) {
+        try {
+            Method method = OnlyOfficeServiceImpl.class.getDeclaredMethod("assembleConfig",
+                    OnlyOfficeConfigParam.class, OnlyOfficeSessionEntity.class, String.class, String.class,
+                    String.class, UserInfo.class, List.class);
+            method.setAccessible(true);
+            return (Map<String, Object>) method.invoke(service, param, session, "word", "docx", "view", user,
+                    Collections.emptyList());
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private Map<String, Object> castMap(Object value) {
+        return (Map<String, Object>) value;
+    }
+}

--
Gitblit v1.8.0