package jnpf.bizcommon.onlyoffice.service.impl;
|
|
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
import jnpf.bizcommon.onlyoffice.entity.OnlyOfficeSessionEntity;
|
import jnpf.bizcommon.onlyoffice.mapper.OnlyOfficeSessionMapper;
|
import jnpf.exception.DataException;
|
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
import org.junit.Before;
|
import org.junit.Test;
|
import org.springframework.dao.DuplicateKeyException;
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.fail;
|
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.isNull;
|
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 OnlyOfficeTemplatePublishFenceServiceTest {
|
|
private OnlyOfficeSessionMapper mapper;
|
private OnlyOfficeTemplatePublishFenceService service;
|
|
@Before
|
public void setUp() {
|
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""),
|
OnlyOfficeSessionEntity.class);
|
mapper = mock(OnlyOfficeSessionMapper.class);
|
service = new OnlyOfficeTemplatePublishFenceService(mapper);
|
}
|
|
@Test
|
public void idleSessionCanBeAtomicallyClaimedForPublishing() {
|
OnlyOfficeSessionEntity existing = session(OnlyOfficeSessionEntity.SessionStatus.IDLE);
|
when(mapper.selectOne(any())).thenReturn(existing);
|
AtomicReference<UpdateWrapper<OnlyOfficeSessionEntity>> update = new AtomicReference<>();
|
when(mapper.update(isNull(), any())).thenAnswer(invocation -> {
|
update.set(invocation.getArgument(1));
|
return 1;
|
});
|
|
String token = service.acquire("tenant-1", "template-1", "template.docx", "annex");
|
|
assertNotNull(token);
|
assertFalse(token.trim().isEmpty());
|
update.get().getSqlSegment();
|
assertTrue(update.get().getSqlSet().contains("session_status"));
|
assertTrue(update.get().getSqlSet().contains("publish_token"));
|
assertTrue(update.get().getParamNameValuePairs().containsValue(
|
OnlyOfficeSessionEntity.SessionStatus.IDLE));
|
assertTrue(update.get().getParamNameValuePairs().containsValue(token));
|
}
|
|
@Test
|
public void missingSessionIsInsertedDirectlyAsPublishing() {
|
when(mapper.selectOne(any())).thenReturn(null);
|
AtomicReference<OnlyOfficeSessionEntity> inserted = new AtomicReference<>();
|
when(mapper.insert(any(OnlyOfficeSessionEntity.class))).thenAnswer(invocation -> {
|
inserted.set(invocation.getArgument(0));
|
return 1;
|
});
|
|
String token = service.acquire("tenant-1", "template-1", "template.docx", "annex");
|
|
assertEquals("tenant-1", inserted.get().getTenantId());
|
assertEquals("template-1", inserted.get().getBizDataId());
|
assertEquals("template.docx", inserted.get().getFileId());
|
assertEquals("annex", inserted.get().getFileType());
|
assertEquals(Integer.valueOf(OnlyOfficeSessionEntity.SessionStatus.PUBLISHING),
|
inserted.get().getSessionStatus());
|
assertEquals(token, inserted.get().getPublishToken());
|
assertNull(inserted.get().getLockUserId());
|
}
|
|
@Test
|
public void editingSavingFailedAndPublishingSessionsRejectPublishFence() {
|
int[] blocked = {
|
OnlyOfficeSessionEntity.SessionStatus.EDITING,
|
OnlyOfficeSessionEntity.SessionStatus.SAVING,
|
OnlyOfficeSessionEntity.SessionStatus.SAVE_FAILED,
|
OnlyOfficeSessionEntity.SessionStatus.PUBLISHING
|
};
|
for (int status : blocked) {
|
when(mapper.selectOne(any())).thenReturn(session(status));
|
expectDataException(() -> service.acquire(
|
"tenant-1", "template-1", "template.docx", "annex"));
|
}
|
verify(mapper, never()).update(isNull(), any());
|
}
|
|
@Test
|
public void concurrentInsertConflictIsRereadAndRejectedWithoutSecondRow() {
|
when(mapper.selectOne(any())).thenReturn(null,
|
session(OnlyOfficeSessionEntity.SessionStatus.EDITING));
|
when(mapper.insert(any(OnlyOfficeSessionEntity.class)))
|
.thenThrow(new DuplicateKeyException("duplicate file"));
|
|
expectDataException(() -> service.acquire(
|
"tenant-1", "template-1", "template.docx", "annex"));
|
}
|
|
@Test
|
public void releaseRequiresExactPublishingToken() {
|
AtomicReference<UpdateWrapper<OnlyOfficeSessionEntity>> release = new AtomicReference<>();
|
when(mapper.update(isNull(), any())).thenAnswer(invocation -> {
|
release.set(invocation.getArgument(1));
|
return 1;
|
});
|
|
assertTrue(service.release("tenant-1", "template-1", "template.docx", "annex", "token-1"));
|
|
release.get().getSqlSegment();
|
assertTrue(release.get().getParamNameValuePairs().containsValue("token-1"));
|
assertTrue(release.get().getParamNameValuePairs().containsValue(
|
OnlyOfficeSessionEntity.SessionStatus.PUBLISHING));
|
assertTrue(release.get().getSqlSet().contains("session_status"));
|
assertTrue(release.get().getSqlSet().contains("publish_token"));
|
|
when(mapper.update(isNull(), any(Wrapper.class))).thenReturn(0);
|
assertFalse(service.release(
|
"tenant-1", "template-1", "template.docx", "annex", "old-token"));
|
}
|
|
private static OnlyOfficeSessionEntity session(int status) {
|
OnlyOfficeSessionEntity session = new OnlyOfficeSessionEntity();
|
session.setId("session-1");
|
session.setTenantId("tenant-1");
|
session.setFileId("template.docx");
|
session.setFileType("annex");
|
session.setBizModule("eln.template");
|
session.setBizDataId("template-1");
|
session.setDocKey("doc-key-1");
|
session.setVersionNo(1);
|
session.setVersion(3);
|
session.setSessionStatus(status);
|
return session;
|
}
|
|
private static DataException expectDataException(Runnable action) {
|
try {
|
action.run();
|
fail("预期抛出 DataException");
|
return null;
|
} catch (DataException expected) {
|
assertFalse(expected.getMessage().trim().isEmpty());
|
return expected;
|
}
|
}
|
}
|