118 lines
3.6 KiB
TypeScript
118 lines
3.6 KiB
TypeScript
|
|
/**
|
|||
|
|
* syncByVersion 游标同步单测(批次二③)
|
|||
|
|
*
|
|||
|
|
* 锁定基于版本号的精确增量恢复不变量:
|
|||
|
|
* 1. 成功同步并推进持久化游标
|
|||
|
|
* 2. full_sync=true 时退化(返回 false)
|
|||
|
|
* 3. 异常时退化(返回 false)
|
|||
|
|
* 4. 无 version(<=0)时直接退化
|
|||
|
|
*
|
|||
|
|
* 对标 Matrix resume 游标:断线恢复从全量轮询升级为精确增量。
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import { useMessageStore } from '../store';
|
|||
|
|
import { MessageSyncService } from '../services/MessageSyncService';
|
|||
|
|
import { messageService } from '@/services/message';
|
|||
|
|
import { messageRepository } from '@/database';
|
|||
|
|
|
|||
|
|
function createSyncService(): MessageSyncService {
|
|||
|
|
return new MessageSyncService(
|
|||
|
|
() => 'me',
|
|||
|
|
{ markAsRead: async () => {}, markAllAsRead: async () => {} } as any,
|
|||
|
|
{ getSenderInfo: async () => null, enrichMessagesWithSenderInfo: () => {} } as any,
|
|||
|
|
undefined
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
describe('syncByVersion 游标同步', () => {
|
|||
|
|
beforeEach(() => {
|
|||
|
|
useMessageStore.getState().reset();
|
|||
|
|
(messageRepository as any).__reset();
|
|||
|
|
(messageService as any).__reset();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('无变更时返回成功且推进游标', async () => {
|
|||
|
|
const serviceMock = messageService as any;
|
|||
|
|
serviceMock.__setSyncByVersionHandler((version: number) => ({
|
|||
|
|
current_version: version + 10,
|
|||
|
|
changes: [],
|
|||
|
|
full_sync: false,
|
|||
|
|
has_more: false,
|
|||
|
|
}));
|
|||
|
|
|
|||
|
|
const sync = createSyncService();
|
|||
|
|
const ok = await sync.syncByVersion(100);
|
|||
|
|
|
|||
|
|
expect(ok).toBe(true);
|
|||
|
|
// 游标推进到 current_version
|
|||
|
|
expect(useMessageStore.getState().syncVersion).toBe(110);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('full_sync=true 时退化为 false', async () => {
|
|||
|
|
const serviceMock = messageService as any;
|
|||
|
|
serviceMock.__setSyncByVersionHandler(() => ({
|
|||
|
|
current_version: 0,
|
|||
|
|
changes: [],
|
|||
|
|
full_sync: true,
|
|||
|
|
has_more: false,
|
|||
|
|
}));
|
|||
|
|
|
|||
|
|
const sync = createSyncService();
|
|||
|
|
const ok = await sync.syncByVersion(100);
|
|||
|
|
|
|||
|
|
expect(ok).toBe(false);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('API 抛异常时退化为 false', async () => {
|
|||
|
|
const serviceMock = messageService as any;
|
|||
|
|
serviceMock.__setSyncByVersionHandler(() => {
|
|||
|
|
throw new Error('网络故障');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const sync = createSyncService();
|
|||
|
|
const ok = await sync.syncByVersion(100);
|
|||
|
|
|
|||
|
|
expect(ok).toBe(false);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('version <= 0 时直接退化', async () => {
|
|||
|
|
const sync = createSyncService();
|
|||
|
|
const ok1 = await sync.syncByVersion(0);
|
|||
|
|
const ok2 = await sync.syncByVersion(-1);
|
|||
|
|
expect(ok1).toBe(false);
|
|||
|
|
expect(ok2).toBe(false);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('有会话变更时按需同步会话详情', async () => {
|
|||
|
|
const serviceMock = messageService as any;
|
|||
|
|
// 先在 store 放一个会话,让 fetchConversationDetail 有上下文
|
|||
|
|
useMessageStore.getState().setConversationsWithUnread(
|
|||
|
|
new Map([['c1', { id: 'c1', last_seq: 5, unread_count: 0 } as any]]),
|
|||
|
|
0, 0
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
let detailCalled = false;
|
|||
|
|
serviceMock.__setSyncByVersionHandler((version: number) => ({
|
|||
|
|
current_version: version + 5,
|
|||
|
|
changes: [
|
|||
|
|
{ conversation_id: 'c1', change_type: 'new_message', max_seq: 10, version: version + 1 },
|
|||
|
|
],
|
|||
|
|
full_sync: false,
|
|||
|
|
has_more: false,
|
|||
|
|
}));
|
|||
|
|
// fetchConversationDetail 内部调 getConversationById
|
|||
|
|
serviceMock.getConversationById = async () => {
|
|||
|
|
detailCalled = true;
|
|||
|
|
return { id: 'c1', last_seq: 10 } as any;
|
|||
|
|
};
|
|||
|
|
serviceMock.getMessages = async () => ({ messages: [], total: 0, page: 1, page_size: 20 });
|
|||
|
|
|
|||
|
|
const sync = createSyncService();
|
|||
|
|
const ok = await sync.syncByVersion(100);
|
|||
|
|
|
|||
|
|
expect(ok).toBe(true);
|
|||
|
|
expect(detailCalled).toBe(true);
|
|||
|
|
expect(useMessageStore.getState().syncVersion).toBe(105);
|
|||
|
|
});
|
|||
|
|
});
|