import assert from 'node:assert/strict' import { mkdtempSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import path from 'node:path' import test, { after } from 'node:test' const testDataDir = mkdtempSync(path.join(tmpdir(), 'music-together-tencent-refresh-')) process.env.DATABASE_URL = `file:${path.join(testDataDir, 'test.db')}` process.env.LOG_LEVEL = 'silent' const { db } = await import('../src/repositories/database.js') const { platformAuthRepo } = await import('../src/repositories/platformAuthRepository.js') const authService = await import('../src/services/authService.js') const tencentAuth = await import('../src/services/tencentAuthService.js') const { refreshDueTencentCredentials, TENCENT_CREDENTIAL_REFRESH_INTERVAL_MS } = await import('../src/services/tencentCredentialRefreshService.js') const now = 1_800_000_000_000 for (const userId of ['qq-refresh-success', 'qq-refresh-failure']) { db.prepare('INSERT INTO users (id, nickname, created_at, updated_at, last_seen_at) VALUES (?, ?, ?, ?, ?)').run( userId, userId, now, now, now, ) } function credential(musicid: number, musickey: string) { return tencentAuth.buildTencentCredentialCookie('', { musicid, musickey, refresh_token: `refresh-token-${musicid}`, refresh_key: `refresh-key-${musicid}`, loginType: 2, }) } const successCookie = credential(101, 'old-success-key') const failureCookie = credential(202, 'old-failure-key') for (const [userId, cookie] of [ ['qq-refresh-success', successCookie], ['qq-refresh-failure', failureCookie], ] as const) { platformAuthRepo.save({ userId, platform: 'tencent', cookie, nickname: userId, vipType: 1, credentialRefreshAttemptedAt: now - TENCENT_CREDENTIAL_REFRESH_INTERVAL_MS, }) authService.restoreUserCookies('refresh-room', userId) } after(() => { authService.cleanupRoom('refresh-room') db.close() rmSync(testDataDir, { recursive: true, force: true }) }) test('refreshes due credentials every 24 hours and updates active room copies', async () => { const summary = await refreshDueTencentCredentials(now, async (cookie) => { if (cookie === failureCookie) throw new Error('provider unavailable') return tencentAuth.buildTencentCredentialCookie(cookie, { musicid: 101, musickey: 'new-success-key', refresh_token: 'rotated-refresh-token', refresh_key: 'rotated-refresh-key', loginType: 2, }) }) assert.deepEqual(summary, { checked: 2, refreshed: 1, failed: 1, skipped: 0 }) const persistedSuccess = platformAuthRepo.loadUser('qq-refresh-success')[0] const persistedFailure = platformAuthRepo.loadUser('qq-refresh-failure')[0] assert.equal(tencentAuth.parseTencentCredential(persistedSuccess.cookie)?.musickey, 'new-success-key') assert.equal(tencentAuth.parseTencentCredential(persistedSuccess.cookie)?.refreshToken, 'rotated-refresh-token') assert.equal(persistedSuccess.credentialRefreshAttemptedAt, now) assert.equal(persistedFailure.cookie, failureCookie) assert.equal(persistedFailure.credentialRefreshAttemptedAt, now) assert.equal( tencentAuth.parseTencentCredential(authService.getUserCookie('qq-refresh-success', 'tencent', 'refresh-room')!) ?.musickey, 'new-success-key', ) assert.equal(authService.getUserCookie('qq-refresh-failure', 'tencent', 'refresh-room'), failureCookie) assert.equal(platformAuthRepo.loadDueTencent(now - 1).length, 0) assert.equal(platformAuthRepo.loadDueTencent(now).length, 2) })