test-board-deployment.mjs 2.9 KB

1234567891011121314151617181920212223242526272829303132333435
  1. import fs from 'node:fs';
  2. import path from 'node:path';
  3. import crypto from 'node:crypto';
  4. import assert from 'node:assert/strict';
  5. import { publishFiles } from '../work/board-deploy-20261106-r1/package/scripts/publish-board.mjs';
  6. const base=path.resolve('work/board-deploy-20261106-r1');
  7. const pkg=path.join(base,'package'),sourceDir=path.join(pkg,'payload'),manifestPath=path.join(pkg,'deploy/board-files.json');
  8. const manifest=JSON.parse(fs.readFileSync(manifestPath));
  9. const targetDir=fs.mkdtempSync(path.join(base,'static-publish-test-'));
  10. for(const f of manifest.files){const p=path.join(targetDir,f.path);fs.mkdirSync(path.dirname(p),{recursive:true});fs.copyFileSync(path.join(sourceDir,f.path),p);}
  11. fs.copyFileSync(path.join(base,'production-index.html'),path.join(targetDir,'index.html'));
  12. const nav=path.join(targetDir,'src/layout/kf-nav.js');
  13. fs.copyFileSync(path.join(base,'production-before/src/layout/kf-nav.js'),nav);
  14. fs.unlinkSync(path.join(targetDir,'src/core/library.js'));
  15. const snapshot=()=>Object.fromEntries(['index.html',...manifest.files.map(f=>f.path)].map(p=>{const f=path.join(targetDir,p);return[p,fs.existsSync(f)?crypto.createHash('sha256').update(fs.readFileSync(f)).digest('hex'):null];}));
  16. const options={sourceDir,manifestPath,targetDir},before=snapshot();
  17. const plan=publishFiles(options);
  18. assert.equal(plan.readOnly,true);assert.equal(plan.filesChecked,71);assert.equal(plan.changes.length,2);assert.deepEqual(snapshot(),before);
  19. let thrown;
  20. try{publishFiles({...options,apply:true},{beforeWrite:p=>{if(p==='src/layout/kf-nav.js')throw Error('simulated filesystem failure');}});}catch(e){thrown=e;}
  21. assert.equal(thrown?.rollbackComplete,true);assert.deepEqual(snapshot(),before);
  22. fs.writeFileSync(nav,'unknown concurrent revision');
  23. assert.throws(()=>publishFiles({...options,apply:true}),{code:'UNKNOWN_TARGET_CONTENT'});
  24. assert.equal(fs.readFileSync(nav,'utf8'),'unknown concurrent revision');
  25. fs.copyFileSync(path.join(base,'production-before/src/layout/kf-nav.js'),nav);
  26. const applied=publishFiles({...options,apply:true});
  27. assert.equal(applied.filesystemVerified,true);assert.equal(applied.homepageModified,false);assert.ok(!applied.backup.startsWith(targetDir+path.sep));
  28. const stamp=fs.statSync(nav).mtimeMs,after=snapshot();
  29. assert.equal(publishFiles({...options,apply:true}).changes.length,0);assert.equal(fs.statSync(nav).mtimeMs,stamp);assert.deepEqual(snapshot(),after);
  30. fs.writeFileSync(path.join(targetDir,'index.html'),'changed homepage');
  31. assert.throws(()=>publishFiles(options),{code:'HOMEPAGE_MISMATCH'});
  32. const result={ok:true,checks:['dry run writes nothing','failure restores changed and newly created files','unknown target revision is preserved','apply verifies all 71 files and preserves homepage','repeat is a no-op preserving mtime','changed homepage is refused'],productionWrites:0};
  33. fs.writeFileSync(path.join(base,'static-publisher-validation.json'),JSON.stringify(result,null,2));
  34. console.log(JSON.stringify(result));