Skip to content

Commit a4443cb

Browse files
Alok SaldanhaAlok Saldanha
authored andcommitted
add create_entry backend cache tests
1 parent c92fe18 commit a4443cb

1 file changed

Lines changed: 130 additions & 0 deletions

File tree

tests/test_backend_cache.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import unittest
2+
import pytest
23
from http import HTTPStatus
34
from unittest.mock import MagicMock, Mock, patch, call
45
from freezegun import freeze_time
@@ -360,3 +361,132 @@ def test_GIVEN_empty_cache_THEN_prune_raises_value_error(self):
360361

361362
with self.assertRaises(ValueError):
362363
cache.prune(entry_mock)
364+
365+
366+
@pytest.fixture(autouse=True)
367+
def connect_mock():
368+
with patch("socket.socket") as socketMock:
369+
connectMock = socketMock()
370+
connectMock.__enter__.return_value = connectMock
371+
connectMock.connect_ex.return_value = 1 # Port not in use by default
372+
yield connectMock
373+
374+
375+
@pytest.fixture(autouse=True)
376+
def process_backend_mock():
377+
with patch("cellxgene_gateway.backend_cache.process_backend") as mock:
378+
yield mock
379+
380+
381+
@pytest.fixture(autouse=True)
382+
def sleep_mock():
383+
from time import sleep
384+
385+
with patch("cellxgene_gateway.backend_cache.time.sleep") as mock:
386+
mock.side_effect = lambda x: sleep(0.01) # short sleep
387+
yield mock
388+
389+
390+
@freeze_time("2025-12-01 10:00:00")
391+
def test_GIVEN_empty_cache_THEN_create_entry_uses_starting_port(process_backend_mock):
392+
"""create_entry should use port 8000 when cache is empty and port is free."""
393+
key = Mock()
394+
scripts = ["script1", "script2"]
395+
396+
cache = BackendCache()
397+
result = cache.create_entry(key, scripts)
398+
399+
# Verify port 8000 was used
400+
assert result.port == 8000
401+
402+
# Verify entry was added to list
403+
assert result in cache.entry_list
404+
# Verify thread was started
405+
process_backend_mock.launch.assert_called_once()
406+
407+
# Verify CacheEntry was created with correct key
408+
assert result.key is key
409+
assert result.status == CacheEntryStatus.loading
410+
411+
412+
@freeze_time("2025-12-01 10:00:00")
413+
def test_GIVEN_port_in_use_THEN_create_entry_finds_next_available_port(connect_mock):
414+
"""create_entry should increment port until finding one that's free."""
415+
# Ports 8000 and 8001 are in use, 8002 is free
416+
connect_mock.connect_ex.side_effect = [0, 0, 1]
417+
418+
key = Mock()
419+
scripts = []
420+
421+
cache = BackendCache()
422+
result = cache.create_entry(key, scripts)
423+
424+
# Verify port 8002 was used (after skipping 8000 and 8001)
425+
assert result.port == 8002
426+
427+
428+
@freeze_time("2025-12-01 10:00:00")
429+
def test_GIVEN_port_exists_in_cache_THEN_create_entry_skips_it():
430+
"""create_entry should skip ports already in the cache."""
431+
key = Mock()
432+
scripts = []
433+
434+
# Pre-populate cache with port 8000
435+
existing_entry = Mock()
436+
existing_entry.port = 8000
437+
438+
cache = BackendCache()
439+
cache.entry_list = [existing_entry]
440+
441+
result = cache.create_entry(key, scripts)
442+
443+
# Verify port 8001 was used (skipping the existing 8000)
444+
assert result.port == 8001
445+
446+
447+
@freeze_time("2025-12-01 10:00:00")
448+
def test_GIVEN_create_entry_THEN_background_thread_is_started(process_backend_mock):
449+
"""create_entry should start a background thread with correct args."""
450+
key = Mock()
451+
scripts = ["script1"]
452+
453+
with patch("cellxgene_gateway.backend_cache.env") as env_mock:
454+
env_mock.cellxgene_location = "/path/to/cellxgene"
455+
456+
cache = BackendCache()
457+
result = cache.create_entry(key, scripts)
458+
459+
# Verify Thread was created with correct target and args
460+
process_backend_mock.launch.assert_called_once()
461+
call_kwargs = process_backend_mock.launch.call_args[0]
462+
assert call_kwargs == ("/path/to/cellxgene", ["script1"], result)
463+
464+
465+
@freeze_time("2025-12-01 10:00:00")
466+
def test_GIVEN_create_entry_THEN_entry_is_added_to_cache():
467+
"""create_entry should add the created entry to the cache list."""
468+
key = Mock()
469+
scripts = []
470+
471+
cache = BackendCache()
472+
initial_count = len(cache.entry_list)
473+
474+
result = cache.create_entry(key, scripts)
475+
476+
# Verify entry was added
477+
assert len(cache.entry_list) == initial_count + 1
478+
assert result in cache.entry_list
479+
480+
481+
@freeze_time("2025-12-01 10:00:00")
482+
def test_GIVEN_create_entry_THEN_returns_created_entry():
483+
"""create_entry should return the created entry."""
484+
key = Mock()
485+
scripts = []
486+
487+
cache = BackendCache()
488+
result = cache.create_entry(key, scripts)
489+
490+
# Verify the result is a CacheEntry instance
491+
assert isinstance(result, CacheEntry)
492+
assert result.status == CacheEntryStatus.loading

0 commit comments

Comments
 (0)