const test = require('node:test'); const assert = require('node:assert/strict'); const { TelegramImportService, publicError } = require('../src/services/telegramImportService'); const { TelegramSource } = require('../src/services/telegramSource'); const { getTelegramConfig } = require('../src/config/telegram'); const config = { enabled: true, autoPublish: true, apiId: 123, apiHash: 'a'.repeat(32), sessionFile: '/tmp/private/account.session', channel: 'avp2Polotsk', citySlug: 'polotsk', intervalMs: 60_000 }; function setup(source, overrides = {}) { return new TelegramImportService({ config: { ...config, ...overrides }, source, pool: { query: async () => ({ rows: [{ id: 1 }] }) }, logger: { warn() {} }, now: () => new Date('2026-10-02T12:00:00Z') }); } test('disabled or incomplete setup never connects to Telegram and never reveals credentials in status', async () => { let calls = 0; const source = { fetchMessages: async () => { calls++; } }; const disabled = setup(source, { enabled: false }); await assert.rejects(disabled.sync(), /выключен/); const missing = setup(source, { apiHash: '' }); assert.equal(missing.getStatus().connection, 'configuration_required'); await assert.rejects(missing.sync(), /Укажите/); assert.equal(calls, 0); assert.equal(JSON.stringify(disabled.getStatus()).includes(config.apiHash), false); assert.equal(JSON.stringify(disabled.getStatus()).includes(config.sessionFile), false); assert.equal(getTelegramConfig({}).enabled, false); }); test('worker polls a bounded three-day window, processes sequentially, and reports success', async () => { const processed = []; const source = { async fetchMessages(since) { assert.equal(since.toISOString(), '2026-09-29T21:00:00.000Z'); return [{ id: 1 }, { id: 2 }]; } }; const service = setup(source); service.processMessage = async (message, cityId) => { processed.push([message.id, cityId]); return { status: 'published' }; }; const counts = await service.sync(); assert.equal(counts.published, 2); assert.deepEqual(processed, [[1, 1], [2, 1]]); assert.equal(service.getStatus().connection, 'ready'); }); test('overlapping worker requests do not start two channel readers', async () => { let finish; const service = setup({ fetchMessages: () => new Promise(resolve => { finish = resolve; }) }); const running = service.sync(); await new Promise(resolve => setImmediate(resolve)); await assert.rejects(service.sync(), /уже выполняется/); finish([]); await running; }); test('FloodWait backs off and only a sanitized error code is exposed or logged', async () => { const logs = []; let attempts = 0; const service = setup({ async fetchMessages() { attempts++; throw Object.assign(new Error('private-session-secret'), { seconds: 120 }); }, async close() {} }); service.logger = { warn: (...args) => logs.push(args) }; await assert.rejects(service.sync(), /FLOOD_WAIT/); assert.equal(service.getStatus().retryAt, '2026-10-02T12:02:00.000Z'); await assert.rejects(service.sync(), /частоту запросов/); assert.equal(attempts, 1); assert.equal(JSON.stringify([logs, service.getStatus()]).includes('private-session-secret'), false); assert.equal(publicError(new Error('some sensitive content')), 'IMPORT_FAILED'); }); test('source stops reading old history and keeps original publication and edit timestamps', async () => { const source = new TelegramSource(config); source.channel = { id: { toString: () => '1234567' }, username: config.channel }; source.connect = async () => {}; let iterations = 0; source.client = { async *iterMessages() { for (const entry of [ { className: 'Message', id: 7, date: Date.parse('2026-10-02T10:00Z') / 1000, editDate: Date.parse('2026-10-02T11:00Z') / 1000, message: 'Отмена', media: null }, { className: 'MessageService', id: 6, date: Date.parse('2026-10-02T09:00Z') / 1000 }, { className: 'Message', id: 5, date: Date.parse('2026-09-01T10:00Z') / 1000 }, { className: 'Message', id: 4, date: Date.parse('2026-08-01T10:00Z') / 1000 } ]) { iterations++; yield entry; } } }; const messages = await source.fetchMessages(new Date('2026-10-01T21:00Z')); assert.equal(iterations, 3); assert.equal(messages.length, 1); assert.equal(messages[0].publishedAt, '2026-10-02T10:00:00.000Z'); assert.equal(messages[0].editedAt, '2026-10-02T11:00:00.000Z'); });