dsh-im-ops/test/channels/dingtalk/connection-error.test.mjs

80 lines
3.2 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import {
describeDingtalkConnectionFailure,
dingtalkPublicConnectionError,
dingtalkRuntimeStartError,
installedDingtalkConnectionDependencies,
} from '../../../src/channels/dingtalk/connection-error.mjs';
const FIXED_REFERENCE = 'DT-CONN-DEADBEEF';
test('connection diagnostics identify the pnpm mirror proxy dependency failure without leaking values', () => {
const cause = new Error(
'request for client-id-private failed via https://name:password@proxy.example because clientSecret=secret-private',
);
cause.name = 'AxiosError';
cause.code = 'ECONNRESET';
cause.response = { status: 502, data: { code: 'GatewayFailure' } };
const error = dingtalkRuntimeStartError('dingtalk-stream-connect-failed', cause);
const failure = describeDingtalkConnectionFailure(error, {
clientId: 'client-id-private',
clientSecret: 'secret-private',
environment: { HTTPS_PROXY: 'https://name:password@proxy.example' },
dependencies: {
dingtalkStream: '2.1.4',
axios: '1.19.0',
httpsProxyAgent: '5.0.1',
agentBase: '6.0.0',
},
nodeVersion: '24.19.0',
referenceId: FIXED_REFERENCE,
});
assert.deepEqual(failure.publicError, {
code: 'stream-proxy-dependency-incompatible',
message: '钉钉 Stream 连接失败:检测到代理依赖 agent-base 6.0.0。',
hint: '请将 DSH profile 中的 agent-base@6 固定为 6.0.2 后重新安装依赖,或升级 pnpm 后重新解析 lockfile。',
referenceId: FIXED_REFERENCE,
});
assert.equal(failure.diagnostic.stage, 'dingtalk-stream-connect-failed');
assert.deepEqual(failure.diagnostic.proxy, {
configured: true,
variables: ['HTTPS_PROXY'],
});
assert.equal(failure.diagnostic.dependencies.agentBase, '6.0.0');
assert.equal(failure.diagnostic.errors.at(-1).providerCode, 'GatewayFailure');
assert.doesNotMatch(
JSON.stringify(failure.diagnostic),
/client-id-private|secret-private|name:password/,
);
});
test('connection diagnostics classify common stages and keep a public-only RPC projection', () => {
const cause = Object.assign(new Error('getaddrinfo ENOTFOUND api.dingtalk.com'), {
code: 'ENOTFOUND',
});
const staged = dingtalkRuntimeStartError('dingtalk-stream-connect-failed', cause);
const failure = describeDingtalkConnectionFailure(staged, {
environment: {},
dependencies: { agentBase: '6.0.2' },
referenceId: FIXED_REFERENCE,
});
assert.equal(failure.publicError.code, 'stream-dns-failed');
assert.match(failure.publicError.message, /无法解析/);
const outward = dingtalkPublicConnectionError(failure.publicError, staged);
assert.equal(outward.name, 'DingtalkPublicConnectionError');
assert.deepEqual(outward.publicError, failure.publicError);
assert.equal(outward.cause, staged);
});
test('installed connection diagnostics follow the DingTalk dependency chain', () => {
const versions = installedDingtalkConnectionDependencies();
assert.match(versions.dingtalkStream, /^\d+\.\d+\.\d+/);
assert.match(versions.axios, /^\d+\.\d+\.\d+/);
assert.match(versions.httpsProxyAgent, /^\d+\.\d+\.\d+/);
assert.match(versions.agentBase, /^6\./);
});