| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 |
- import json
- from pathlib import Path
- import shutil
- import subprocess
- import sys
- import tempfile
- import unittest
- ROOT = Path(__file__).resolve().parents[1]
- SCRIPT = ROOT / 'scripts/install-unified-skills.py'
- class UnifiedSkillInstallerTests(unittest.TestCase):
- def setUp(self):
- self.tmp = tempfile.TemporaryDirectory();self.addCleanup(self.tmp.cleanup)
- self.root = Path(self.tmp.name)
- def run_cmd(self, command, skill, target, out, plan=None):
- selection = ['--component', 'research-runtime'] if skill == 'ksf-voc-library' else ['--skill', skill]
- argv = [sys.executable, '-B', '-X', 'utf8', str(SCRIPT), command, *selection, '--target', str(target), '--out', str(out)]
- if plan:
- argv += ['--plan', str(plan)]
- result = subprocess.run(argv, capture_output=True, encoding='utf-8')
- return result.returncode, json.loads(result.stdout)
- def target(self, skill):
- dest = self.root / skill
- shutil.copytree(ROOT / 'skills' / skill, dest)
- (dest / 'SKILL.md').write_text('previous-entry', encoding='utf-8')
- (dest / 'extra-local-file').write_text('preserve', encoding='utf-8')
- return dest
- def test_plan_apply_verify_preserve_other_files_and_business_code(self):
- for skill in ('ksf-voc-library', 'ksf-workshop-runtime'):
- target = self.target(skill)
- plans, applied = self.root / (skill + '-plan'), self.root / (skill + '-apply')
- self.assertEqual(self.run_cmd('plan', skill, target, plans)[0], 0)
- self.assertEqual((target / 'SKILL.md').read_text(), 'previous-entry')
- self.assertEqual(self.run_cmd('apply', skill, target, applied, plans / 'plan.json')[0], 0)
- self.assertEqual((applied / 'before/SKILL.md').read_text(), 'previous-entry')
- self.assertEqual((target / 'extra-local-file').read_text(), 'preserve')
- self.assertEqual(self.run_cmd('verify', skill, target, self.root / (skill + '-verify'))[0], 0)
- if skill == 'ksf-voc-library':
- self.assertFalse((target / 'SKILL.md').exists())
- self.assertNotIn('SKILL.md', (target / 'FILES.sha256').read_text())
- else:
- self.assertTrue((target / 'SKILL.md').exists())
- def test_already_merged_research_runtime_needs_no_skill_entry(self):
- skill = 'ksf-voc-library';target = self.target(skill)
- (target / 'SKILL.md').unlink()
- plans, applied = self.root / 'runtime-plan', self.root / 'runtime-apply'
- self.assertEqual(self.run_cmd('plan', skill, target, plans)[0], 0)
- self.assertEqual(self.run_cmd('apply', skill, target, applied, plans / 'plan.json')[0], 0)
- self.assertFalse((target / 'SKILL.md').exists())
- self.assertEqual(self.run_cmd('verify', skill, target, self.root / 'runtime-verify')[0], 0)
- def test_concurrent_change_and_protected_runtime_mismatch_stop_before_mutation(self):
- skill = 'ksf-workshop-runtime';target = self.target(skill)
- plans = self.root / 'plan'
- self.assertEqual(self.run_cmd('plan', skill, target, plans)[0], 0)
- (target / 'SKILL.md').write_text('concurrent-change', encoding='utf-8')
- self.assertNotEqual(self.run_cmd('apply', skill, target, self.root / 'apply', plans / 'plan.json')[0], 0)
- self.assertEqual((target / 'SKILL.md').read_text(), 'concurrent-change')
- protected = target / 'scripts/ksf-secure.mjs'
- protected.write_text('changed-runtime', encoding='utf-8')
- code, result = self.run_cmd('plan', skill, target, self.root / 'plan-bad-runtime')
- self.assertNotEqual(code, 0)
- self.assertEqual(result['error']['code'], 'PROTECTED_BUSINESS_RUNTIME_MISMATCH')
- if __name__ == '__main__':
- unittest.main()
|