import assert from 'node:assert/strict'; import {readFileSync} from 'node:fs'; import {join} from 'node:path'; import {hashAt,frozenSnapshot} from './boot-contract-report.mjs'; import {filesIn} from './entry-extension.mjs'; import {servicesInputs,inspectRunqueueGuestServicesHost} from './runqueue-guest-services-host-report.mjs'; import {threadWaitInputs,inspectThreadWaitHost} from './thread-wait-host-report.mjs'; import {waitGuestServicesRust} from './wait-guest-services-sources.mjs'; import {waitGuestServicesTestSources} from './wait-guest-services-fixture.mjs'; const p=n=>'scripts/os-acceptance/wait-guest-services-'+n; export const waitServicesTests=['actual_before_departure_keeps_prepared_for_retry_and_after_failure_quarantines_all_owners','cancellation_keeps_other_sleep_episode_and_deadline_wakes_only_that_wait','constructor_duplicate_member_returns_exact_three_owner_queue_and_source_authority','context_and_queue_gates_precede_actual_table_access','custody_refusal_after_real_landing_keeps_actual_wait_and_all_three_bindings','direct_bridge_gate_precedes_actual_table_observation_without_waitset_gate','early_signal_aborts_actual_three_member_prepared_without_sleep','failed_source_release_retains_original_pin_and_claim_after_one_actual_wake','genuine_sleep_has_pending_prepared_before_table_change_and_exact_wait_after_landing','mismatched_capture_is_refused_before_actual_preparation_and_source_pin_released','old_queued_event_cannot_wake_reused_same_source_generation','postwake_execution_gate_precedes_owner_reborrow_after_real_retirement','raw_irq_gate_precedes_pointer_loan_for_wrong_cpu_unmasked_and_non_irq','requested_target_must_be_actual_fifo_head_before_preparation','separate_irq_ingress_operates_while_every_task_owner_is_exclusively_borrowed','source_epoch_change_refuses_before_wake_and_keeps_true_sleep_wait','successful_source_release_drift_retains_logical_claim_and_queue_without_false_pin_claim','successful_table_wake_with_execution_drift_quarantines_without_fifo_publication','two_exact_sleep_waits_same_tick_signal_win_once_and_publish_fifo_once','wake_refusal_retains_exact_prepared_wait_and_retry_publishes_once','landing_current_requires_exact_departed_selection_target_before_owner_access','old_root_stack_nonce_or_landing_frame_refuses_unchanged_exact_prepared_and_sleep_wait']; export const waitServicesMutants=[ {id:'bridge-pure-gate-skipped',path:p('bridge.rs'),needle:'wait::context(0, e, wait::Operation::Service)?;',replacement:'',test:waitServicesTests[5]}, {id:'duplicate-member-admitted',path:p('bridge.rs'),needle:'if this.handles[..i].contains(&this.handles[i]) {',replacement:'if false {',test:waitServicesTests[2]}, {id:'capture-authority-skipped',path:p('bridge.rs'),needle:'if actual != capture {',replacement:'if false {',test:waitServicesTests[9]}, {id:'fifo-target-skipped',path:p('bridge.rs'),needle:'if self.queue.queue().ready_order()[0] != Some(target) {',replacement:'if false {',test:waitServicesTests[13]}, {id:'before-selection-dropped',path:p('bridge.rs'),needle:'p.selection = Some(token);',replacement:'let _discarded = token;',test:waitServicesTests[0]}, {id:'after-departure-relabeled-before',path:p('bridge.rs'),needle:'error: wait::Error::Quarantined,\n phase: wait::FailurePhase::After,',replacement:'error: wait::Error::Quarantined,\n phase: wait::FailurePhase::Before,',test:waitServicesTests[0]}, {id:'actual-sleep-custody-skipped',path:p('bridge.rs'),needle:'self.custody(p, false)',replacement:'Ok::<(),wait::Failure>(())',test:waitServicesTests[8]}, {id:'postlanding-before-relabeled',path:p('bridge.rs'),needle:'f.phase = wait::FailurePhase::After;',replacement:'f.phase = wait::FailurePhase::Before;',test:waitServicesTests[4]}, {id:'actual-wait-wake-skipped',path:p('bridge.rs'),needle:'self.custody(p, true)?;',replacement:'let _not_resolved = &p;',test:waitServicesTests[19]}, {id:'ready-fifo-publication-skipped',path:p('queue.rs'),needle:'self.ready[self.len] = i;',replacement:'let _not_published = i;',test:waitServicesTests[18]}, {id:'postwake-execution-gate-skipped',path:p('context.rs'),needle:'if bank.backend.execution() != execution {',replacement:'if false {',test:waitServicesTests[11]}, {id:'failed-source-pin-dropped',path:p('bridge.rs'),needle:'owned.pins.pin = Some(pin);',replacement:'let _discarded = pin;',test:waitServicesTests[7]}, {id:'source-release-drift-skipped',path:p('bridge.rs'),needle:'if self.authority.execution() != execution {',replacement:'if false {',test:waitServicesTests[16]}, {id:'released-member-claim-kept',path:p('bridge.rs'),needle:'self.claims[owned.pins.member] = None;',replacement:'let _kept = owned.pins.member;',test:waitServicesTests[18]}, {id:'irq-before-pointer-gate-skipped',path:p('ingress.rs'),needle:'wait::context(0, execution, wait::Operation::Produce)?;',replacement:'',test:waitServicesTests[12]}, {id:'physical-landing-callback-skipped',path:p('bridge.rs'),needle:'self.queue.queue().wait_guest_physical_landing(h)',replacement:'Ok::<_,queue::Error>(wait::Execution{current:self.departed_target,..e})',test:waitServicesTests[21]}, {id:'context-owner-gates-skipped',path:p('context.rs'),needle:'self.os_k1060_queue_gate().map_err(before)?;',replacement:'',extra:[{path:p('context.rs'),needle:'let execution = bank.execution(false).map_err(before)?;',replacement:'let execution = bank.backend.execution();'}],test:waitServicesTests[3]}, ]; export const waitServicesBoundary=readFileSync(new URL('./wait-guest-services-contract.md',import.meta.url),'utf8'); const own=[...waitGuestServicesRust,...['contract.md','sources.mjs','fixture.mjs','smoke.mjs','host.mjs','host-report.mjs','test-host-report.mjs'].map(p)]; export const waitServicesInputs=root=>[...new Set([...servicesInputs(root).map(r=>r.path),...threadWaitInputs(root).map(r=>r.path),...own])].sort().map(path=>({path,sha256:hashAt(root,path)})); const anchorSpecs=[ {path:'reports/os-implementation/K1061-K1079-preparation-LgafCx/report.json',sha256:'77c427207cc9810675c5308289688e8e99aca81dade0b1f7c1b753f261218227',inspect:inspectThreadWaitHost}, {path:'reports/os-implementation/K1060-services-preparation-zWiNPR/report.json',sha256:'881dccf686834aa7905cb26f56912b0c0a2f5687f813429a36302dc7ec825f6c',inspect:inspectRunqueueGuestServicesHost}, ]; export function waitServicesAnchors(root){return anchorSpecs.map(({path,sha256,inspect})=>{assert.equal(hashAt(root,path),sha256);const result=inspect(JSON.parse(readFileSync(join(root,path),'utf8')),root);return{path,sha256,result};});} const lock='# This file is automatically @generated by Cargo.\n# It is not intended for manual editing.\nversion = 4\n\n[[package]]\nname = "turkos-os-exceptions"\nversion = "0.1.0"\n\n[[package]]\nname = "turkos-os-thread-wait"\nversion = "0.1.0"\ndependencies = [\n "turkos-os-threads",\n]\n\n[[package]]\nname = "turkos-os-threads"\nversion = "0.1.0"\n\n[[package]]\nname = "turkos-os-wait-guest-services"\nversion = "0.1.0"\ndependencies = [\n "turkos-os-exceptions",\n "turkos-os-thread-wait",\n "turkos-os-threads",\n]\n'; export function waitServicesSources(root,spec=null){ const overrides=new Map();if(spec)for(const edit of[spec,...(spec.extra??[])]){let s=overrides.get(edit.path)??readFileSync(join(root,edit.path),'utf8');assert.equal(s.split(edit.needle).length,(edit.all??1)+1,spec.id);overrides.set(edit.path,edit.all?s.replaceAll(edit.needle,edit.replacement):s.replace(edit.needle,edit.replacement));} const map=new Map();for(const[p,s]of waitGuestServicesTestSources(root,overrides))map.set('os-wait-guest-services/'+p,Buffer.from(s)); map.set('os-wait-guest-services/Cargo.lock',Buffer.from(lock)); for(const dep of['os-threads','os-exceptions','os-thread-wait','os-context-handoff','os-context-switch'])for(const p of filesIn(root,dep))map.set(p,readFileSync(join(root,p))); map.set('.cargo/config.toml',readFileSync(join(root,'.cargo/config.toml'))); map.set('scripts/os-acceptance/k1040-context-handoff.rs',readFileSync(join(root,'scripts/os-acceptance/k1040-context-handoff.rs'))); for(const r of waitServicesInputs(root))map.set('bound-inputs/'+r.path,Buffer.from(overrides.get(r.path)??readFileSync(join(root,r.path)))); return new Map([...map].sort(([a],[b])=>a.localeCompare(b))); } export function inspectWaitGuestServicesHost(report,root){ assert.equal(report.schema,'turkos-wait-guest-services-host/v1');assert.equal(report.status,'HOST_PREPARED');assert.equal(report.measurementScope,'MODELED_ONLY');assert.equal(report.guestAccepted,false);assert.equal(report.kernelElfBound,false);assert.equal(report.arm64Status,'CHECK_ONLY');assert.equal(report.hostTests,22);assert.equal(report.boundary,waitServicesBoundary);assert.deepEqual(report.localMoves,[]);assert.deepEqual(report.pending,[1065,1070,1075,1080]);assert.deepEqual(report.anchors,waitServicesAnchors(root));assert.match(report.runDirectory,/^reports\/os-implementation\/K1080-wait-services-preparation-[A-Za-z0-9_-]+$/);assert.deepEqual(report.inputsBefore,waitServicesInputs(root));assert.deepEqual(report.inputsAfter,report.inputsBefore);assert.deepEqual(report.protectedBefore,frozenSnapshot(root));assert.deepEqual(report.protectedAfter,report.protectedBefore); const read=a=>{assert.ok(a.path.startsWith(report.runDirectory+'/')&&!a.path.split('/').some(p=>['.','..',''].includes(p)));assert.equal(hashAt(root,a.path),a.sha256);return readFileSync(join(root,a.path));}; const source=(actual,expected,prefix)=>{assert.deepEqual(actual.map(a=>a.originalPath),[...expected.keys()]);assert.deepEqual(filesIn(root,prefix).sort(),actual.map(a=>a.path).sort());for(const a of actual){assert.equal(a.path,prefix+'/'+a.originalPath);assert.deepEqual(read(a),expected.get(a.originalPath));}}; source(report.sources,waitServicesSources(root),report.runDirectory+'/sources');assert.deepEqual(report.commands.map(c=>c.id),['tests','arm64','format','clippy']); const args=prefix=>['--manifest-path',`/${prefix}/os-wait-guest-services/Cargo.toml`,'--locked','--offline']; const expected=[['test',...args(report.runDirectory+'/sources'),'--test','services','--target','aarch64-apple-darwin','--','--test-threads=1'],['check',...args(report.runDirectory+'/sources'),'--lib','--target','aarch64-unknown-none'],['--config','skip_children=true','--edition','2024','--check',...waitGuestServicesRust.map(p=>`/${report.runDirectory}/sources/bound-inputs/${p}`)],['clippy',...args(report.runDirectory+'/sources'),'--lib','--test','services','--target','aarch64-apple-darwin','--','-D','warnings']]; for(const[i,c]of report.commands.entries()){assert.equal(c.exitCode,0);assert.equal(c.executable,i===2?'rustfmt':'cargo');assert.equal(c.targetDirectory,`/${report.runDirectory}/target`);assert.deepEqual(c.argv,expected[i]);const log=read(c.log).toString();assert.doesNotMatch(log,/error\[E\d+\]|could not compile/);if(i===0){assert.match(log,/running 22 tests/);assert.match(log,/test result: ok\. 22 passed; 0 failed/);for(const n of waitServicesTests)assert.ok(log.includes(`test ${n} ... ok`),n);}else if(i!==2)assert.match(log,/Finished `dev` profile/);} assert.equal(report.mutants.length,waitServicesMutants.length);for(const[i,m]of report.mutants.entries()){const spec=waitServicesMutants[i];for(const[k,v]of Object.entries(spec))assert.deepEqual(m[k],v);const prefix=report.runDirectory+'/mutant-'+spec.id+'/sources';source(m.sources,waitServicesSources(root,spec),prefix);assert.equal(m.source.path,prefix+'/bound-inputs/'+spec.path);assert.deepEqual(read(m.source),waitServicesSources(root,spec).get('bound-inputs/'+spec.path));assert.equal(m.exitCode,101);assert.equal(m.executable,'cargo');assert.equal(m.targetDirectory,`/${report.runDirectory}/target`);assert.deepEqual(m.argv,['test',...args(prefix),'--test','services','--target','aarch64-apple-darwin',spec.test,'--','--exact','--test-threads=1']);const log=read(m.log).toString();assert.doesNotMatch(log,/error\[E\d+\]|could not compile|signal: \d/);assert.match(log,/running 1 test/);assert.match(log,/test result: FAILED\. 0 passed; 1 failed/);assert.ok(log.includes(`test ${spec.test} ... FAILED`));assert.ok(log.includes('panicked at'));} return{hostTests:22,compiledKilledMutants:waitServicesMutants.length,guestAccepted:false,measurementScope:'MODELED_ONLY',kernelElfBound:false,pending:report.pending,actualThreeMemberQueueAndCompletionBank:true,actualFrozenWaitSet:true}; }