Integrate delivered Code navigation and Yuxi channel recovery into Canvas trial source
This commit is contained in:
1 parent
2ca6e3199d
commit
3fe3fdb1c0
38 files changed
+1602
-198
No files matched your search
@@ -596,10 +596,15 @@ describe('Main cloud Agents boundary', () => {
|
||||
const plan = operationPlan({ operation: 'unbindChannelAccount', input: {
|
||||
channel_account_id: 'wechat-1', operation_id: input.operation_id, expected_revision: 2,
|
||||
target_agent_slug: draft.slug, access_token: 'private',
|
||||
expected_provider_generation: 'forged-generation', expected_binding_id: 'forged-binding',
|
||||
expected_route_revision: 999, source_route_operation_id: 'forged-route',
|
||||
provider_generation: 'forged-generation', provider_unbind: { status: 'completed', token: 'private' },
|
||||
cookie: 'private',
|
||||
} });
|
||||
expect(plan.path).toBe('/api/makelore/channel-accounts/wechat-1/unbind');
|
||||
expect(plan.method).toBe('POST');
|
||||
expect(plan.body).toEqual({ operation_id: input.operation_id, expected_revision: 2 });
|
||||
expect(plan.input).toEqual({ channel_account_id: 'wechat-1', operation_id: input.operation_id, expected_revision: 2 });
|
||||
expect(plan.project({ channel: { id: 'wechat-1', desired_state: 'paused', sync_state: 'ready', access_token: 'private' },
|
||||
unbound: true, disconnected: true, wechat: { status: 'empty', token: 'private' } })).toEqual({
|
||||
channel: { id: 'wechat-1', desired_state: 'paused', sync_state: 'ready' },
|
||||
@@ -654,6 +659,67 @@ describe('Main cloud Agents boundary', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it.each([
|
||||
['channel_operation_legacy', '这次旧微信操作无法安全恢复,请联系管理员核对后再操作'],
|
||||
['identity_conflict', '当前账号关系不一致,请刷新状态并核对账号后再操作'],
|
||||
['target_agent_unavailable', '当前智能体暂不可用,请刷新状态并重新选择智能体'],
|
||||
])('keeps the original uncertain channel request after the safe %s recovery error', async (code, message) => {
|
||||
const channel = { id: 'wechat-1', enabled: true, target_agent_slug: draft.slug, revision: 3, health: 'connected' };
|
||||
const fetchImpl = vi.fn().mockResolvedValueOnce(session()).mockRejectedValueOnce(new Error('lost response'))
|
||||
.mockResolvedValueOnce(json({ detail: { code, message: 'private Core owner and provider credentials' } }, 409))
|
||||
.mockResolvedValueOnce(json({ channel }));
|
||||
const module = moduleFor(fetchImpl);
|
||||
const original = { channel_account_id: 'wechat-1', operation_id: input.operation_id, expected_revision: 2 };
|
||||
await expect(module.execute({ operation: 'enableChannelAccount', input: original })).rejects.toMatchObject({
|
||||
commandOutcome: 'unknown',
|
||||
});
|
||||
const pending = (await module.recovery()).pending[0];
|
||||
expect(pending).toMatchObject({ operation: 'enableChannelAccount', input: original });
|
||||
await expect(module.resolvePending({ id: pending.id })).rejects.toMatchObject({
|
||||
status: 409, code, message, commandOutcome: 'unknown',
|
||||
});
|
||||
expect((await module.recovery()).pending).toEqual([pending]);
|
||||
expect(await module.resolvePending({ id: pending.id })).toMatchObject({
|
||||
operation: 'enableChannelAccount', input: original, result: { channel },
|
||||
});
|
||||
expect((await module.recovery()).pending).toEqual([]);
|
||||
expect(fetchImpl.mock.calls.slice(1).map(call => [call[0], JSON.parse(call[1].body)])).toEqual(
|
||||
Array.from({ length: 3 }, () => ['https://agents.example.test/api/makelore/channel-accounts/wechat-1/enable', {
|
||||
operation_id: input.operation_id, expected_revision: 2,
|
||||
}]),
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ blockers: ['wechat_disconnect_pending'] },
|
||||
{ sync_state: 'degraded' },
|
||||
{ sync_state: 'pending' },
|
||||
{ sync_state: 'unknown' },
|
||||
{ desired_state: 'enabled' },
|
||||
])('recovers the same unbind request after a flagged success still has unfinished logout state %o', async unfinished => {
|
||||
const channel = { id: 'wechat-1', enabled: false, target_agent_slug: null, health: 'login_required',
|
||||
desired_state: 'paused', sync_state: 'ready', blockers: [] };
|
||||
const fetchImpl = vi.fn().mockResolvedValueOnce(session())
|
||||
.mockResolvedValueOnce(json({ channel: { ...channel, ...unfinished }, unbound: true, disconnected: true }))
|
||||
.mockResolvedValueOnce(json({ channel, unbound: true, disconnected: true }));
|
||||
const module = moduleFor(fetchImpl);
|
||||
const original = { channel_account_id: 'wechat-1', operation_id: input.operation_id, expected_revision: 2 };
|
||||
await expect(module.execute({ operation: 'unbindChannelAccount', input: original })).rejects.toMatchObject({
|
||||
status: 503, code: 'channel_operation_unconfirmed', commandOutcome: 'unknown',
|
||||
});
|
||||
const pending = (await module.recovery()).pending[0];
|
||||
expect(pending).toMatchObject({ operation: 'unbindChannelAccount', input: original });
|
||||
expect(await module.resolvePending({ id: pending.id })).toMatchObject({
|
||||
operation: 'unbindChannelAccount', input: original, result: { channel, unbound: true, disconnected: true },
|
||||
});
|
||||
expect((await module.recovery()).pending).toEqual([]);
|
||||
expect(fetchImpl.mock.calls.slice(1).map(call => [call[0], JSON.parse(call[1].body)])).toEqual(
|
||||
Array.from({ length: 2 }, () => ['https://agents.example.test/api/makelore/channel-accounts/wechat-1/unbind', {
|
||||
operation_id: input.operation_id, expected_revision: 2,
|
||||
}]),
|
||||
);
|
||||
});
|
||||
|
||||
it('recovers a completed WeChat verification from its receipt without replaying the code', async () => {
|
||||
const fetchImpl = vi.fn().mockResolvedValueOnce(session()).mockRejectedValueOnce(new Error('lost response'))
|
||||
.mockResolvedValueOnce(json({ operation_id: input.operation_id, status: 'completed', result: { channel: { id: 'channel-1' } } }));
|
||||
|
||||
Reference in new issue
Block a user