You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
3.6 KiB
TypeScript

import { beforeEach, describe, expect, it } from 'bun:test';
import Database from 'bun:sqlite';
import { initializeDatabase } from '../../../src/db';
import { MaintenanceService } from '../../../src/services/maintenance';
import { toIsoSqlUTC } from '../../../src/utils/datetime';
function makeMem(): any {
const db = new Database(':memory:');
initializeDatabase(db);
return db;
}
describe('MaintenanceService', () => {
let memdb: any;
beforeEach(() => {
memdb = makeMem();
});
it('cleanupInactiveMembersOnce elimina miembros inactivos más antiguos que el umbral', async () => {
// Grupo y usuarios
memdb.exec(`INSERT OR IGNORE INTO groups (id, community_id, name, active) VALUES ('g1@g.us','comm','G',1);`);
memdb.exec(`INSERT OR IGNORE INTO users (id) VALUES ('111');`);
memdb.exec(`INSERT OR IGNORE INTO users (id) VALUES ('222');`);
// last_seen_at muy antiguo → debe borrarse
memdb.exec(`
INSERT INTO group_members (group_id, user_id, is_admin, is_active, first_seen_at, last_seen_at)
VALUES ('g1@g.us','111',0,0,'2020-01-01 00:00:00','2020-01-01 00:00:00');
`);
// last_seen_at reciente → no debe borrarse
const recent = toIsoSqlUTC(new Date(Date.now() - 12 * 60 * 60 * 1000));
memdb.exec(`
INSERT INTO group_members (group_id, user_id, is_admin, is_active, first_seen_at, last_seen_at)
VALUES ('g1@g.us','222',0,0,'${recent}','${recent}');
`);
const deleted = await MaintenanceService.cleanupInactiveMembersOnce(memdb, 1);
expect(deleted).toBe(1);
const rows = memdb.prepare(`SELECT user_id FROM group_members ORDER BY user_id`).all() as any[];
const remaining = rows.map(r => r.user_id);
expect(remaining).toEqual(['222']);
});
it('cleanupInactiveMembersOnce no hace nada si retención <= 0', async () => {
const deleted = await MaintenanceService.cleanupInactiveMembersOnce(memdb, 0);
expect(deleted).toBe(0);
});
it('reconcileAliasUsersOnce fusiona alias a usuario real en tablas principales', async () => {
// Sembrar usuarios
memdb.exec(`INSERT OR IGNORE INTO users (id) VALUES ('alias-1');`);
memdb.exec(`INSERT OR IGNORE INTO users (id) VALUES ('real-1');`);
// Tarea creada por alias y asignaciones usando alias
const res = memdb.prepare(`
INSERT INTO tasks (description, due_date, group_id, created_by, completed, completed_at)
VALUES ('T1', NULL, NULL, 'alias-1', 0, NULL)
`).run() as any;
const taskId = Number(res.lastInsertRowid);
memdb.exec(`
INSERT OR IGNORE INTO task_assignments (task_id, user_id, assigned_by)
VALUES (${taskId}, 'alias-1', 'alias-1');
`);
// Tabla de alias
memdb.exec(`
INSERT OR IGNORE INTO user_aliases (alias, user_id, source)
VALUES ('alias-1', 'real-1', 'test');
`);
const merged = await MaintenanceService.reconcileAliasUsersOnce(memdb);
expect(merged).toBeGreaterThanOrEqual(1);
const tRow = memdb.prepare(`SELECT created_by FROM tasks WHERE id = ?`).get(taskId) as any;
expect(String(tRow.created_by)).toBe('real-1');
const aRows = memdb.prepare(`SELECT user_id, assigned_by FROM task_assignments WHERE task_id = ?`).all(taskId) as any[];
expect(aRows.length).toBe(1);
expect(String(aRows[0].user_id)).toBe('real-1');
expect(String(aRows[0].assigned_by)).toBe('real-1');
});
it('reconcileAliasUsersOnce retorna 0 si no existe la tabla user_aliases', async () => {
try {
memdb.exec(`DROP TABLE IF EXISTS user_aliases;`);
} catch {}
const merged = await MaintenanceService.reconcileAliasUsersOnce(memdb);
expect(merged).toBe(0);
});
});