import assert from "node:assert/strict" import {test} from "node:test" import {downloadSystemDatabaseBackup,restoreSystemDatabaseBackup} from "./system-database" const dump=new File(["PGDMPfixture"],"fixture.dump") test("export requires PGDMP bytes and a safe filename; fallback is dump, not db",async()=>{ const original=globalThis.fetch;try{ globalThis.fetch=async()=>new Response("PGDMPfixture",{headers:{"Content-Disposition":"attachment; filename*=UTF-8''backup%20fixture.dump"}}) const result=await downloadSystemDatabaseBackup("https://backend.test");assert.equal(result.filename,"backup fixture.dump");assert.equal(await result.blob.text(),"PGDMPfixture") globalThis.fetch=async()=>new Response("PGDMPfixture");assert.equal((await downloadSystemDatabaseBackup("https://backend.test")).filename,"mikrotik-manager.dump") for(const bytes of ["", "{}", "proxy"]){globalThis.fetch=async()=>new Response(bytes);await assert.rejects(downloadSystemDatabaseBackup("https://backend.test"),/PGDMP/)} for(const filename of ["../backup.dump","a/b.dump","a\\b.dump"]){globalThis.fetch=async()=>new Response("PGDMPfixture",{headers:{"Content-Disposition":`attachment; filename="${filename}"`}});await assert.rejects(downloadSystemDatabaseBackup("https://backend.test"),/Имя файла/)} }finally{globalThis.fetch=original} }) test("restore validates empty/invalid/oversized file and abort before any POST",async()=>{ const original=globalThis.fetch;let calls=0;try{globalThis.fetch=async()=>{calls++;return Response.json({ok:true})};for(const bytes of ["", "sqlite", ""]){await assert.rejects(restoreSystemDatabaseBackup("https://backend.test",new File([bytes],"wrong.dump")),/PGDMP/)} const huge=new File(["PGDMP"],"huge.dump");Object.defineProperty(huge,"size",{value:512*1024*1024+1});await assert.rejects(restoreSystemDatabaseBackup("https://backend.test",huge),/512 МБ/) const controller=new AbortController();controller.abort();await assert.rejects(restoreSystemDatabaseBackup("https://backend.test",dump,{signal:controller.signal}));assert.equal(calls,0) }finally{globalThis.fetch=original} }) test("restore needs literal receipt; malformed/false/204/HTTP error never retry",async()=>{ const original=globalThis.fetch;try{ let calls=0;globalThis.fetch=async(_url,init)=>{calls++;assert.equal(init?.body,dump);assert.equal(new Headers(init?.headers).get("Content-Type"),"application/octet-stream");assert.ok(init?.signal);return Response.json({ok:true,eventError:"audit unavailable"})} assert.deepEqual(await restoreSystemDatabaseBackup("https://backend.test",dump),{ok:true,eventError:"audit unavailable"});assert.equal(calls,1) for(const raw of [{},{ok:false},{ok:"true"},{ok:true,eventError:5},{ok:true,error:"restore failed"}]){calls=0;globalThis.fetch=async()=>{calls++;return Response.json(raw)};await assert.rejects(restoreSystemDatabaseBackup("https://backend.test",dump),/не подтверждено/);assert.equal(calls,1)} calls=0;globalThis.fetch=async()=>{calls++;return new Response(null,{status:204})};await assert.rejects(restoreSystemDatabaseBackup("https://backend.test",dump),/не подтверждено/);assert.equal(calls,1) calls=0;globalThis.fetch=async()=>{calls++;return Response.json({error:"restore unknown"},{status:503})};await assert.rejects(restoreSystemDatabaseBackup("https://backend.test",dump),/restore unknown/);assert.equal(calls,1) }finally{globalThis.fetch=original} })