mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-09 05:20:46 +08:00
80 lines
3.2 KiB
JavaScript
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\./);
|
|
});
|