65 lines
3.5 KiB
Python
65 lines
3.5 KiB
Python
"""Actual isolated lock/cache failures; never opens a developer or production cache."""
|
|
from pathlib import Path
|
|
import importlib.metadata
|
|
import json
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
from filelock import FileLock, SoftFileLock
|
|
from huggingface_hub.utils._fixes import WeakFileLock
|
|
from verify import verify_fixture
|
|
|
|
HERE = Path(__file__).resolve().parent
|
|
manifest = json.loads((HERE / 'ARTIFACTS.json').read_text())['safetensors']
|
|
source = verify_fixture(Path(sys.argv[1]), manifest)
|
|
results = []
|
|
with tempfile.TemporaryDirectory(prefix='jt-model-cache-') as temporary:
|
|
root = Path(temporary)
|
|
assert root.stat().st_mode & 0o077 == 0
|
|
for kind in ['missing', 'corrupt-weights', 'corrupt-config', 'linked', 'extra-code']:
|
|
directory = root / kind
|
|
shutil.copytree(source, directory)
|
|
weights = directory / 'model.safetensors'
|
|
if kind == 'missing': weights.unlink()
|
|
elif kind == 'linked':
|
|
weights.unlink(); weights.symlink_to(source / 'model.safetensors')
|
|
elif kind == 'extra-code': (directory / 'modeling_unreviewed.py').write_text('raise RuntimeError()')
|
|
else:
|
|
file = weights if kind == 'corrupt-weights' else directory / 'config.json'
|
|
content = bytearray(file.read_bytes()); content[-1] ^= 1; file.write_bytes(content)
|
|
try: verify_fixture(directory, manifest)
|
|
except ValueError: results.append({'case': kind, 'rejectedBeforeLoad': True})
|
|
else: raise AssertionError(kind + ' was accepted')
|
|
|
|
child = '''import sys
|
|
from filelock import FileLock,SoftFileLock,Timeout
|
|
cls=FileLock if sys.argv[1]=='native' else SoftFileLock
|
|
try:
|
|
with cls(sys.argv[2],timeout=0.2): print('acquired')
|
|
except Timeout: print('timed-out')
|
|
'''
|
|
for kind, context in [('native', lambda p: FileLock(p, timeout=1)), ('soft', lambda p: SoftFileLock(p, timeout=1)), ('hub', lambda p: WeakFileLock(p, timeout=1))]:
|
|
file = root / (kind + '.lock')
|
|
command = [sys.executable, '-c', child, 'soft' if kind == 'soft' else 'native', str(file)]
|
|
with context(file):
|
|
result = subprocess.run(command, capture_output=True, text=True, timeout=5, check=True)
|
|
assert result.stdout.strip() == 'timed-out', result.stdout
|
|
result = subprocess.run(command, capture_output=True, text=True, timeout=5, check=True)
|
|
assert result.stdout.strip() == 'acquired', result.stdout
|
|
results.append({'case': kind + '-cross-process', 'finiteContentionTimeout': True, 'acquiredAfterRelease': True})
|
|
|
|
os.environ['AI_SERVICE_SKIP_MODEL_LOAD'] = '0'
|
|
sys.path.insert(0, '/app')
|
|
import app
|
|
from fastapi.testclient import TestClient
|
|
app.MODEL_NAME = str(root / 'missing-model')
|
|
assert app._ensure_runtime_loaded() is False
|
|
assert app.model is app.tokenizer is None and not app.MODEL_LOADED
|
|
response = TestClient(app.app).post('/summarize', json={'text': 'Synthetic unavailable model input.'})
|
|
assert response.status_code == 503 and response.json()['detail']
|
|
results.append({'case': 'missing-offline-model', 'availability503': True, 'noPartialLoadedState': True})
|
|
verify_fixture(source, manifest)
|
|
print(json.dumps({'status': 'PASS', 'filelock': importlib.metadata.version('filelock'), 'hub': importlib.metadata.version('huggingface-hub'), 'cases': results, 'freshPrivateCache': True, 'sourceUnchanged': True, 'limits': 'Linux native/soft/Hub locking in one library generation. No shared-cache migration, Windows fallback, full-model cancellation, GPU or live cache claim.'}), flush=True)
|