import { test, after } from 'node:test'; import assert from 'node:assert/strict'; import { mkdtempSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { DatabaseSync } from 'node:sqlite'; const dir = mkdtempSync(join(tmpdir(), 'ihaleist-store-')); process.env.IHALEIST_USER_DATA_DIR = dir; const legacy = new DatabaseSync(join(dir, 'users.sqlite')); legacy.exec(`CREATE TABLE belgeler (id TEXT PRIMARY KEY,email TEXT NOT NULL,ad TEXT NOT NULL,kategori TEXT,boyut INTEGER NOT NULL,mime TEXT,dosya TEXT NOT NULL,olusturma TEXT); INSERT INTO belgeler VALUES ('old','a@example.test','Eski belge','Yasal',5,'text/plain','old.txt','2026-09-01');`); legacy.close(); const store = await import('../server/user-store.mjs'); after(() => rmSync(dir, { recursive: true, force: true })); test('old volume migrates before indexing, preserves files and migration is repeatable', () => { for (let i = 0; i < 2; i++) { const db = store.openDb(); assert.equal(db.prepare('SELECT COUNT(*) n FROM schema_migrations').get().n, 2); assert.ok(db.prepare('PRAGMA table_info(belgeler)').all().some(c => c.name === 'ikn')); db.close(); } assert.equal(store.listDocuments('a@example.test')[0].ad, 'Eski belge'); assert.equal(store.listDocuments('a@example.test')[0].tur, 'firma'); assert.deepEqual(store.listDocuments('b@example.test'), []); }); test('five preparation records persist across DB close/reopen and stay account scoped', () => { const records = Object.fromEntries(['1573235','1582991','1523851','1499061','1534665'].map(id => ['2026/'+id, { takipte: true, gorev: { kontrolListesi: [{ad:'ÜTS',tamam:false}] }, kanbanStatus:'teklif_hazirlaniyor' }])); assert.equal(store.setData('a@example.test', 'gorevler', records), true); assert.deepEqual(store.getAllData('a@example.test').gorevler, records); assert.equal(store.getData('b@example.test', 'gorevler'), null); }); test('document and API key ownership enforced', () => { const id = store.addDocument('a@example.test', {ad:'Şartname',boyut:10,dosya:'spec.pdf',ikn:'2026/1582991'}); assert.equal(store.listDocuments('a@example.test', {ikn:'2026/1582991'}).length, 1); assert.equal(store.getDocument('b@example.test', id), null); const key = store.createApiKey('a@example.test', 'Test'); assert.equal(store.verifyApiKey(key.anahtar).email, 'a@example.test'); assert.equal(store.revokeApiKey('b@example.test', key.id), false); store.revokeApiKey('a@example.test', key.id); assert.equal(store.verifyApiKey(key.anahtar), null); }); test('database write failure propagates instead of pretending success', () => { const db = store.openDb(); db.exec(`CREATE TRIGGER reject_write BEFORE INSERT ON kullanici_verisi BEGIN SELECT RAISE(FAIL,'test write failure'); END;`); db.close(); assert.throws(() => store.setData('a@example.test','takip',[]), /test write failure/); }); test('per-tender versions prevent stale updates; five tasks persist', () => { for (const id of ['1573235','1582991','1523851','1499061','1534665']) { const key = '2026/'+id; const saved = store.saveTenderState('c@example.test', key, {takipte:true,gorev:{kontrolListesi:[]}}, {id:key,ikn:key}, 0); assert.equal(saved.version,1); assert.throws(() => store.saveTenderState('c@example.test', key, {takipte:false}, {}, 0), e => e.kod === 'VERSION_CONFLICT'); assert.equal(store.saveTenderState('c@example.test', key, {notes:[{text:'test'}]}, {}, 1).version,2); } assert.equal(Object.keys(store.getTenderStates('c@example.test')).length,5); assert.deepEqual(store.getTenderStates('d@example.test'),{}); });