feat(mcp): подготовить сервер и доступ к приёмке
This commit is contained in:
commit
bf3d50e1ff
3835 files changed
+537122
No files matched your search
@@ -0,0 +1,31 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { test } from 'node:test'
|
||||
import { evaluateObservedInstallationBudget as evaluate } from './installation-memory-budget.mjs'
|
||||
const MiB=1024*1024
|
||||
function fixture() {
|
||||
const containers=['backend','postgres','frontend','portal'].map((role,index)=>({id:String(index+1).repeat(64),role,running:true,imageId:'sha256:'+'a'.repeat(64),startedAt:'2026-10-28T12:00:00Z',memoryLimitBytes:0,reportedLimitBytes:2*1024*MiB}))
|
||||
const roleById=Object.fromEntries(containers.map(row=>[row.id,row.role]))
|
||||
return {inventory:{readOnly:true,containerSetStable:true,environmentRead:false,serviceChanges:false,newFixtureStarted:false,hostMemTotalBytes:2021212*1024,containers},roleById}
|
||||
}
|
||||
test('observed zero configured caps stay unbounded despite positive Docker reported host limits',()=>{
|
||||
const f=fixture(), result=evaluate(f.inventory,f.roleById)
|
||||
assert.equal(result.budgetFits,false);assert(result.reasons.includes('UNBOUNDED_CONTAINER'));assert.equal(result.configuredContainerBytes,0)
|
||||
assert.equal(result.wholeInstallation2GbAccepted,false);assert.equal(result.roleLabelsAuthenticated,false);assert.equal(result.inventoryFreshnessProven,false)
|
||||
})
|
||||
test('complete explicit configured caps can fit arithmetic without becoming runtime acceptance',()=>{
|
||||
const f=fixture();[512,384,160,192].forEach((limit,index)=>{f.inventory.containers[index].memoryLimitBytes=limit*MiB})
|
||||
const result=evaluate(f.inventory,f.roleById);assert(result.budgetFits);assert.equal(result.plannedBytes,1760*MiB);assert.equal(result.changesAuthorized,false)
|
||||
})
|
||||
test('uncertain snapshots, started fixtures and missing limit/identity fields refuse',()=>{
|
||||
for(const mutate of [f=>{f.inventory.containerSetStable=false},f=>{f.inventory.serviceChanges=true},f=>{f.inventory.newFixtureStarted=true},f=>{delete f.inventory.containers[0].memoryLimitBytes},f=>{f.inventory.containers[0].running=false},f=>{f.inventory.containers[0].imageId='unknown'},f=>{f.inventory.containers[0].startedAt='invalid'}]){const f=fixture();mutate(f);assert.throws(()=>evaluate(f.inventory,f.roleById))}
|
||||
})
|
||||
test('missing, foreign, inherited and accessor role labels cannot silently classify a service',()=>{
|
||||
for(const mode of ['missing','foreign','inherited','accessor']){
|
||||
const f=fixture(),key=f.inventory.containers[0].id
|
||||
if(mode==='missing')delete f.roleById[key]
|
||||
if(mode==='foreign')f.roleById['f'.repeat(64)]='other'
|
||||
if(mode==='inherited'){const labels=Object.create({[key]:'backend'});for(const [id,role]of Object.entries(f.roleById))if(id!==key)labels[id]=role;f.roleById=labels}
|
||||
if(mode==='accessor')Object.defineProperty(f.roleById,key,{enumerable:true,get(){assert.fail('Role getter must not execute')}})
|
||||
assert.throws(()=>evaluate(f.inventory,f.roleById))
|
||||
}
|
||||
})
|
||||
Reference in new issue
Block a user