railiance-platform/tests/test_task_execution_native_budget.py
codex 76fdc0b861
All checks were successful
CI Smoke / host-smoke (push) Successful in 3s
CI Smoke / container-smoke (push) Successful in 5s
Bound task execution by absolute call and credential deadlines
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
2026-10-16 17:15:00 +02:00

167 lines
7.9 KiB
Python

"""Absolute native budgets/source pins; no actual-v2 positive admission claim."""
from datetime import datetime,timedelta,timezone
from pathlib import Path
import signal
import sys
import threading
import time
from types import SimpleNamespace
import pytest
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'scripts'))
from test_task_execution_native_fixture import owner,bao_dev,compiler
from task_execution_native_fixture import NativeFixtureAdapter,_absolute_budget
from task_execution_journal import Refused
def test_absolute_budget_interrupts_source_work_and_restores_timer():
before=signal.getitimer(signal.ITIMER_REAL)
started=time.monotonic()
with pytest.raises(Refused):
with _absolute_budget(.03):time.sleep(.5)
assert time.monotonic()-started<.3
assert signal.getitimer(signal.ITIMER_REAL)==before
def test_nested_budget_cannot_refresh_outer_deadline():
started=time.monotonic()
with pytest.raises(Refused):
with _absolute_budget(.05):
time.sleep(.02)
with _absolute_budget(1):time.sleep(.5)
assert time.monotonic()-started<.3
def test_absolute_budget_rejects_foreign_threads():
refused=[]
def run():
try:
with _absolute_budget(1):pass
except Refused:refused.append(True)
worker=threading.Thread(target=run);worker.start();worker.join(2)
assert refused==[True]
def test_slow_compiler_is_interrupted_before_native_effect():
native=object.__new__(NativeFixtureAdapter)
native.deadline=datetime.now(timezone.utc)+timedelta(seconds=5.05)
native.monotonic_deadline=time.monotonic()+5.05
native.binding='synthetic';native.plan=None;native.task=object();native._next_metadata=0
native.journal=SimpleNamespace(_held=True,_admission='synthetic',_consumed_admission='synthetic',observe=lambda binding:{'state':'applying'})
native.compiler=SimpleNamespace(pins=[],before_call=lambda *args:time.sleep(.5))
sent=[];native._business=lambda *args,**kwargs:sent.append(True)
with pytest.raises(Refused):native.metadata_call(0)
assert sent==[]
@pytest.mark.parametrize('phase',['headers','body','body-and-slow-close'])
def test_absolute_transport_budget_interrupts_drip(phase,monkeypatch):
from http.server import BaseHTTPRequestHandler,ThreadingHTTPServer
class Drip(BaseHTTPRequestHandler):
def log_message(self,*args):pass
def do_GET(self):
if phase=='headers':
try:
for value in b'HTTP/1.1 200 OK\r\nX-Drip: '+b' '*1000:
self.connection.sendall(bytes([value]));time.sleep(.05)
except (BrokenPipeError,ConnectionResetError):pass
return
self.send_response(200);self.send_header('Content-Type','application/json');self.send_header('Content-Length','1000');self.end_headers()
try:
for _ in range(1000):
self.wfile.write(b' ');self.wfile.flush();time.sleep(.05)
except (BrokenPipeError,ConnectionResetError):pass
server=ThreadingHTTPServer(('127.0.0.1',0),Drip)
server.daemon_threads=True
thread=threading.Thread(target=server.serve_forever,daemon=True);thread.start()
native=object.__new__(NativeFixtureAdapter);native.host='127.0.0.1';native.port=server.server_port
native.admission=SimpleNamespace(server_process=SimpleNamespace(poll=lambda:None))
if phase=='body-and-slow-close':
import http.client
original_close=http.client.HTTPConnection.close
def slow_close(connection):
original_close(connection);time.sleep(5)
monkeypatch.setattr(http.client.HTTPConnection,'close',slow_close)
start=time.monotonic()
try:
with pytest.raises(Refused):native._http('GET','drip','synthetic')
assert time.monotonic()-start<2.6
finally:server.shutdown();server.server_close();thread.join(2)
def test_cleanup_remains_independent_but_absolute_after_business_expiry(owner,monkeypatch):
from test_task_execution_native_fixture import admit
from task_execution_cleanup import run_cleanup
native,journal,binding,call,*_=owner
with journal.locked():
admit(native,journal,binding);native.materialize_grant()
original=native._http
def stalled(method,path,token,body=b''):
if path=='auth/token/revoke-self' and token==native.task.token:time.sleep(5)
return original(method,path,token,body)
monkeypatch.setattr(native,'_http',stalled)
native.monotonic_deadline=time.monotonic()-1
native._task_monotonic_deadline=time.monotonic()-1
started=time.monotonic();result=run_cleanup(journal,binding,native)
assert time.monotonic()-started<3
assert not result['confirmed']
assert [x['outcome'] for x in result['obligations']]==['unconfirmed','confirmed','confirmed']
assert journal.observe(binding)['external_outcome_unknown']
# Explicit independent synthetic owner recovery, never adapter retry.
assert call('POST','auth/token/revoke-accessor',{'accessor':native.task.accessor})[0] in {200,204}
def test_absolute_budget_invalid_input_and_conflicting_timer_refuse():
original_handler=signal.getsignal(signal.SIGALRM)
original_timer=signal.getitimer(signal.ITIMER_REAL)
for value in [True,None,0,-1,float('nan'),float('inf')]:
with pytest.raises(Refused):
with _absolute_budget(value):pass
assert signal.getsignal(signal.SIGALRM)==original_handler
assert signal.getitimer(signal.ITIMER_REAL)==original_timer
try:
signal.signal(signal.SIGALRM,lambda *args:None)
signal.setitimer(signal.ITIMER_REAL,1)
with pytest.raises(Refused):
with _absolute_budget(.1):pass
assert signal.getitimer(signal.ITIMER_REAL)[0]>0
finally:
signal.setitimer(signal.ITIMER_REAL,0)
signal.signal(signal.SIGALRM,original_handler)
def test_actual_credential_bound_interrupts_before_later_global_deadline():
native=object.__new__(NativeFixtureAdapter)
native.deadline=datetime.now(timezone.utc)+timedelta(minutes=10)
native.monotonic_deadline=time.monotonic()+600
native._task_wall_deadline=datetime.now(timezone.utc)+timedelta(seconds=5.05)
native._task_monotonic_deadline=time.monotonic()+5.05
native.binding='synthetic';native.plan=None;native.task=object();native._next_metadata=0
native.journal=SimpleNamespace(_held=True,_admission='synthetic',_consumed_admission='synthetic',observe=lambda binding:{'state':'applying'})
native.compiler=SimpleNamespace(pins=[],before_call=lambda *args:time.sleep(.5))
sent=[];native._business=lambda *args,**kwargs:sent.append(True)
started=time.monotonic()
with pytest.raises(Refused):native.metadata_call(0)
assert time.monotonic()-started<.3 and sent==[]
@pytest.mark.parametrize('case',['valid','drift','writable','symlink','fifo','oversize'])
def test_exact_owner_source_bundle_is_bounded_and_fails_closed(tmp_path,case):
import hashlib
import os
from task_execution_mediator import _source_bundle
source=tmp_path/'owner-source.py';source.write_bytes(b'# independently installed source\n');source.chmod(0o600)
roles=['engine_dispatcher','platform_mediator','typed_ccr','policy_auth']
item={'path':str(source),'sha256':'sha256:'+hashlib.sha256(source.read_bytes()).hexdigest()}
descriptor={'source_bundle':{role:dict(item) for role in roles}}
if case=='valid':_source_bundle(descriptor);return
if case=='drift':source.write_bytes(b'# drift\n')
elif case=='writable':source.chmod(0o666)
elif case=='symlink':
target=tmp_path/'target.py';source.rename(target);source.symlink_to(target)
elif case=='fifo':source.unlink();os.mkfifo(source,0o600)
elif case=='oversize':source.write_bytes(b'X'*1048577)
started=time.monotonic()
with pytest.raises(Refused):_source_bundle(descriptor)
assert time.monotonic()-started<.5