Skip to content

Commit 0b38569

Browse files
committed
feat: Add integration tests for uploaded file state restoration
- Introduced a new test class `TestUploadedFileStateRestoration` to validate the behavior of uploaded files regarding state management. - Added tests to ensure uploaded files start without a state hash, receive a state hash after execution, and correctly handle state restoration. - Verified that the `update_file_state_hash` function works as expected for uploaded files, including proper interaction with Redis. - Documented expected behavior for state restoration when state hashes are not set.
1 parent 5eca3ab commit 0b38569

1 file changed

Lines changed: 138 additions & 0 deletions

File tree

tests/integration/test_new_features.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,3 +336,141 @@ def test_exec_request_args_defaults_none(self):
336336
lang="py",
337337
)
338338
assert request.args is None
339+
340+
341+
class TestUploadedFileStateRestoration:
342+
"""Tests for uploaded file state restoration behavior.
343+
344+
Uploaded files should share the same behavior as generated files:
345+
- After first use in execution, they get a state_hash
346+
- On subsequent use with restore_state=true, that state is restored
347+
"""
348+
349+
def test_uploaded_file_no_initial_state_hash(self):
350+
"""Test that uploaded file has no state_hash initially."""
351+
file_info = FileInfo(
352+
file_id="uploaded-file-123",
353+
filename="data.csv",
354+
size=1024,
355+
content_type="text/csv",
356+
created_at=datetime.now(timezone.utc),
357+
path="/data.csv",
358+
# No state_hash, execution_id, or last_used_at
359+
)
360+
assert file_info.state_hash is None
361+
assert file_info.execution_id is None
362+
assert file_info.last_used_at is None
363+
364+
def test_uploaded_file_gets_state_hash_after_use(self):
365+
"""Test that uploaded file gets state_hash after being used in execution."""
366+
now = datetime.now(timezone.utc)
367+
368+
# Simulate file before use
369+
file_before = FileInfo(
370+
file_id="uploaded-file-123",
371+
filename="data.csv",
372+
size=1024,
373+
content_type="text/csv",
374+
created_at=now,
375+
path="/data.csv",
376+
)
377+
assert file_before.state_hash is None
378+
379+
# Simulate file after use (update_file_state_hash was called)
380+
file_after = FileInfo(
381+
file_id="uploaded-file-123",
382+
filename="data.csv",
383+
size=1024,
384+
content_type="text/csv",
385+
created_at=now,
386+
path="/data.csv",
387+
state_hash="abc123def456",
388+
execution_id="exec-789",
389+
last_used_at=now,
390+
)
391+
assert file_after.state_hash == "abc123def456"
392+
assert file_after.execution_id == "exec-789"
393+
assert file_after.last_used_at == now
394+
395+
@pytest.mark.asyncio
396+
async def test_update_file_state_hash_works_for_uploaded_files(self):
397+
"""Test that update_file_state_hash works on uploaded files."""
398+
from src.services.file import FileService
399+
from unittest.mock import AsyncMock, MagicMock
400+
401+
mock_redis = AsyncMock()
402+
mock_redis.hset = AsyncMock()
403+
404+
mock_minio = MagicMock()
405+
406+
service = FileService.__new__(FileService)
407+
service.redis_client = mock_redis
408+
service.minio_client = mock_minio
409+
service.bucket_name = "test-bucket"
410+
411+
# Call update_file_state_hash (simulating what happens after execution)
412+
result = await service.update_file_state_hash(
413+
session_id="session-123",
414+
file_id="uploaded-file-456", # This is an uploaded file
415+
state_hash="statehash789",
416+
execution_id="exec-abc",
417+
)
418+
419+
assert result is True
420+
mock_redis.hset.assert_called_once()
421+
422+
# Verify the updates include all state fields
423+
call_args = mock_redis.hset.call_args
424+
mapping = call_args[1]["mapping"]
425+
assert mapping["state_hash"] == "statehash789"
426+
assert mapping["execution_id"] == "exec-abc"
427+
assert "last_used_at" in mapping
428+
429+
def test_restore_state_flag_works_with_state_hash(self):
430+
"""Test that RequestFile with restore_state=True works when file has state_hash."""
431+
from src.models.exec import RequestFile
432+
433+
# Uploaded file reference with restore_state flag
434+
file_ref = RequestFile(
435+
id="uploaded-file-123",
436+
session_id="session-456",
437+
name="data.csv",
438+
restore_state=True, # Request state restoration
439+
)
440+
assert file_ref.restore_state is True
441+
442+
def test_restore_state_requires_state_hash_to_be_set(self):
443+
"""Test that state restoration requires file to have state_hash.
444+
445+
This documents expected behavior: if an uploaded file hasn't been used
446+
yet (no state_hash), restore_state=True is effectively ignored until
447+
the file is used in an execution.
448+
"""
449+
# File with no state_hash (never used in execution)
450+
file_info_no_state = FileInfo(
451+
file_id="uploaded-file-123",
452+
filename="data.csv",
453+
size=1024,
454+
content_type="text/csv",
455+
created_at=datetime.now(timezone.utc),
456+
path="/data.csv",
457+
)
458+
459+
# The mount logic checks: file_info.state_hash is truthy
460+
# For uploaded files that haven't been used, this will be None/False
461+
can_restore = bool(file_info_no_state.state_hash)
462+
assert can_restore is False
463+
464+
# After first use, file has state_hash
465+
file_info_with_state = FileInfo(
466+
file_id="uploaded-file-123",
467+
filename="data.csv",
468+
size=1024,
469+
content_type="text/csv",
470+
created_at=datetime.now(timezone.utc),
471+
path="/data.csv",
472+
state_hash="abc123def456",
473+
)
474+
475+
can_restore_now = bool(file_info_with_state.state_hash)
476+
assert can_restore_now is True

0 commit comments

Comments
 (0)