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.
109 lines
3.6 KiB
TypeScript
109 lines
3.6 KiB
TypeScript
import { Database } from 'bun:sqlite';
|
|
import { beforeAll, beforeEach, afterAll, describe, expect, test } from 'bun:test';
|
|
import { initializeDatabase } from '../../../src/db';
|
|
import { GroupSyncService } from '../../../src/services/group-sync';
|
|
|
|
describe('GroupSyncService - reconcileGroupMembers', () => {
|
|
let memdb: Database;
|
|
|
|
beforeAll(() => {
|
|
memdb = new Database(':memory:');
|
|
memdb.exec('PRAGMA foreign_keys = ON;');
|
|
initializeDatabase(memdb);
|
|
// Inyectar DB en el servicio
|
|
GroupSyncService.dbInstance = memdb as any;
|
|
});
|
|
|
|
afterAll(() => {
|
|
memdb.close();
|
|
});
|
|
|
|
beforeEach(() => {
|
|
// Limpiar tablas relevantes entre tests
|
|
memdb.exec('DELETE FROM group_members');
|
|
memdb.exec('DELETE FROM users');
|
|
memdb.exec('DELETE FROM groups');
|
|
|
|
// Crear grupo base activo
|
|
memdb.prepare(`INSERT INTO groups (id, community_id, name) VALUES (?, ?, ?)`)
|
|
.run('123@g.us', 'community-1', 'Grupo 123');
|
|
});
|
|
|
|
function getMember(userId: string) {
|
|
return memdb.prepare(`
|
|
SELECT group_id, user_id, is_admin, is_active, first_seen_at, last_seen_at, last_role_change_at
|
|
FROM group_members
|
|
WHERE group_id = ? AND user_id = ?
|
|
`).get('123@g.us', userId) as any;
|
|
}
|
|
|
|
test('inserta miembros y marca activos en la primera reconciliación', () => {
|
|
const res = GroupSyncService.reconcileGroupMembers('123@g.us', [
|
|
{ userId: '111', isAdmin: true },
|
|
{ userId: '222', isAdmin: false }
|
|
], '2025-01-01 00:00:00.000');
|
|
|
|
expect(res).toEqual({ added: 2, updated: 0, deactivated: 0 });
|
|
|
|
const m1 = getMember('111');
|
|
const m2 = getMember('222');
|
|
|
|
expect(m1).toBeDefined();
|
|
expect(m1.is_active).toBe(1);
|
|
expect(m1.is_admin).toBe(1);
|
|
expect(m1.first_seen_at).toBe('2025-01-01 00:00:00.000');
|
|
expect(m1.last_seen_at).toBe('2025-01-01 00:00:00.000');
|
|
|
|
expect(m2).toBeDefined();
|
|
expect(m2.is_active).toBe(1);
|
|
expect(m2.is_admin).toBe(0);
|
|
});
|
|
|
|
test('actualiza roles, desactiva ausentes y añade nuevos en reconciliaciones posteriores', () => {
|
|
// Primera pasada
|
|
GroupSyncService.reconcileGroupMembers('123@g.us', [
|
|
{ userId: '111', isAdmin: true },
|
|
{ userId: '222', isAdmin: false }
|
|
], '2025-01-01 00:00:00.000');
|
|
|
|
// Segunda pasada con cambios: 111 pierde admin, 222 desaparece, 333 aparece
|
|
const res2 = GroupSyncService.reconcileGroupMembers('123@g.us', [
|
|
{ userId: '111', isAdmin: false },
|
|
{ userId: '333', isAdmin: false }
|
|
], '2025-01-02 00:00:00.000');
|
|
|
|
expect(res2).toEqual({ added: 1, updated: 1, deactivated: 1 });
|
|
|
|
const m111 = getMember('111');
|
|
const m222 = getMember('222');
|
|
const m333 = getMember('333');
|
|
|
|
expect(m111.is_active).toBe(1);
|
|
expect(m111.is_admin).toBe(0);
|
|
expect(m111.last_role_change_at).toBe('2025-01-02 00:00:00.000');
|
|
expect(m222.is_active).toBe(0);
|
|
expect(m333.is_active).toBe(1);
|
|
expect(m333.is_admin).toBe(0);
|
|
});
|
|
|
|
test('idempotencia: aplicar mismo snapshot no altera contadores y actualiza last_seen_at', () => {
|
|
GroupSyncService.reconcileGroupMembers('123@g.us', [
|
|
{ userId: '111', isAdmin: false },
|
|
{ userId: '333', isAdmin: false }
|
|
], '2025-01-02 00:00:00.000');
|
|
|
|
const res3 = GroupSyncService.reconcileGroupMembers('123@g.us', [
|
|
{ userId: '111', isAdmin: false },
|
|
{ userId: '333', isAdmin: false }
|
|
], '2025-01-03 00:00:00.000');
|
|
|
|
expect(res3).toEqual({ added: 0, updated: 0, deactivated: 0 });
|
|
|
|
const m111 = getMember('111');
|
|
const m333 = getMember('333');
|
|
|
|
expect(m111.last_seen_at).toBe('2025-01-03 00:00:00.000');
|
|
expect(m333.last_seen_at).toBe('2025-01-03 00:00:00.000');
|
|
});
|
|
});
|