learningcircuit--local-deep-research
7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
747 行
25 KiB
Python
747 行
25 KiB
Python
"""
|
|
Comprehensive tests for BackgroundJobScheduler class.
|
|
Tests scheduling, user sessions, document processing, and configuration.
|
|
"""
|
|
|
|
import pytest
|
|
from unittest.mock import MagicMock, Mock, patch
|
|
from datetime import datetime
|
|
import threading
|
|
|
|
|
|
class TestNewsSchedulerSingleton:
|
|
"""Tests for BackgroundJobScheduler singleton pattern."""
|
|
|
|
def test_returns_same_instance(self):
|
|
"""Test returns same instance on multiple calls."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
# Reset singleton for test
|
|
BackgroundJobScheduler._instance = None
|
|
|
|
s1 = BackgroundJobScheduler()
|
|
s2 = BackgroundJobScheduler()
|
|
assert s1 is s2
|
|
|
|
def test_thread_safe_singleton(self):
|
|
"""Test singleton is thread-safe."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
instances = []
|
|
|
|
def create_instance():
|
|
instances.append(BackgroundJobScheduler())
|
|
|
|
threads = [threading.Thread(target=create_instance) for _ in range(10)]
|
|
for t in threads:
|
|
t.start()
|
|
for t in threads:
|
|
t.join()
|
|
|
|
# All instances should be the same
|
|
assert all(i is instances[0] for i in instances)
|
|
|
|
|
|
class TestNewsSchedulerInit:
|
|
"""Tests for BackgroundJobScheduler initialization."""
|
|
|
|
def test_initializes_user_sessions_dict(self):
|
|
"""Test user_sessions initialized as empty dict."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
assert scheduler.user_sessions == {}
|
|
|
|
def test_initializes_lock(self):
|
|
"""Test lock is initialized."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
assert isinstance(scheduler.lock, type(threading.Lock()))
|
|
|
|
def test_initializes_background_scheduler(self):
|
|
"""Test BackgroundScheduler is initialized."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
from apscheduler.schedulers.background import BackgroundScheduler
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
assert isinstance(scheduler.scheduler, BackgroundScheduler)
|
|
|
|
def test_is_running_initially_false(self):
|
|
"""Test is_running is False initially."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
assert scheduler.is_running is False
|
|
|
|
|
|
class TestLoadDefaultConfig:
|
|
"""Tests for _load_default_config method."""
|
|
|
|
def test_returns_dict(self):
|
|
"""Test returns a dictionary."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
config = scheduler._load_default_config()
|
|
assert isinstance(config, dict)
|
|
|
|
def test_includes_enabled_key(self):
|
|
"""Test config includes enabled key."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
config = scheduler._load_default_config()
|
|
assert "enabled" in config
|
|
|
|
def test_includes_retention_hours(self):
|
|
"""Test config includes retention_hours."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
config = scheduler._load_default_config()
|
|
assert "retention_hours" in config
|
|
assert config["retention_hours"] == 48
|
|
|
|
def test_includes_max_jitter_seconds(self):
|
|
"""Test config includes max_jitter_seconds."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
config = scheduler._load_default_config()
|
|
assert "max_jitter_seconds" in config
|
|
|
|
|
|
class TestInitializeWithSettings:
|
|
"""Tests for initialize_with_settings method."""
|
|
|
|
def test_stores_settings_manager(self):
|
|
"""Test stores settings manager reference."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
mock_settings = Mock()
|
|
mock_settings.get_setting.return_value = True
|
|
|
|
scheduler.initialize_with_settings(mock_settings)
|
|
assert scheduler.settings_manager is mock_settings
|
|
|
|
def test_loads_config_from_settings(self):
|
|
"""Test loads config from settings manager."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
mock_settings = Mock()
|
|
mock_settings.get_setting.side_effect = lambda k, default: {
|
|
"news.scheduler.enabled": False,
|
|
"news.scheduler.retention_hours": 24,
|
|
}.get(k, default)
|
|
|
|
scheduler.initialize_with_settings(mock_settings)
|
|
assert scheduler.config["enabled"] is False
|
|
assert scheduler.config["retention_hours"] == 24
|
|
|
|
def test_handles_settings_exception(self):
|
|
"""Test handles exception during settings load."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
mock_settings = Mock()
|
|
mock_settings.get_setting.side_effect = Exception("Settings error")
|
|
|
|
# Should not raise
|
|
scheduler.initialize_with_settings(mock_settings)
|
|
|
|
|
|
class TestGetSetting:
|
|
"""Tests for _get_setting method."""
|
|
|
|
def test_returns_default_without_settings_manager(self):
|
|
"""Test returns default when no settings manager."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
result = scheduler._get_setting("some.key", default=42)
|
|
assert result == 42
|
|
|
|
def test_calls_settings_manager(self):
|
|
"""Test calls settings manager get_setting."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
mock_settings = Mock()
|
|
mock_settings.get_setting.return_value = 100
|
|
scheduler.settings_manager = mock_settings
|
|
|
|
_ = scheduler._get_setting("some.key", default=42)
|
|
mock_settings.get_setting.assert_called_with("some.key", default=42)
|
|
|
|
|
|
class TestDocumentSchedulerSettings:
|
|
"""Tests for DocumentSchedulerSettings dataclass."""
|
|
|
|
def test_is_frozen(self):
|
|
"""Test dataclass is frozen (immutable)."""
|
|
from local_deep_research.scheduler.background import (
|
|
DocumentSchedulerSettings,
|
|
)
|
|
|
|
settings = DocumentSchedulerSettings()
|
|
with pytest.raises(Exception): # FrozenInstanceError
|
|
settings.enabled = False
|
|
|
|
def test_default_enabled_is_true(self):
|
|
"""Test default enabled is True."""
|
|
from local_deep_research.scheduler.background import (
|
|
DocumentSchedulerSettings,
|
|
)
|
|
|
|
settings = DocumentSchedulerSettings()
|
|
assert settings.enabled is True
|
|
|
|
def test_default_interval_seconds(self):
|
|
"""Test default interval_seconds is 1800."""
|
|
from local_deep_research.scheduler.background import (
|
|
DocumentSchedulerSettings,
|
|
)
|
|
|
|
settings = DocumentSchedulerSettings()
|
|
assert settings.interval_seconds == 1800
|
|
|
|
def test_defaults_factory_method(self):
|
|
"""Test defaults() factory method."""
|
|
from local_deep_research.scheduler.background import (
|
|
DocumentSchedulerSettings,
|
|
)
|
|
|
|
defaults = DocumentSchedulerSettings.defaults()
|
|
assert defaults.enabled is True
|
|
assert defaults.interval_seconds == 1800
|
|
|
|
|
|
class TestGetDocumentSchedulerSettings:
|
|
"""Tests for _get_document_scheduler_settings method."""
|
|
|
|
def test_returns_cached_value(self):
|
|
"""Test returns cached value when available."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
DocumentSchedulerSettings,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
cached_settings = DocumentSchedulerSettings(
|
|
enabled=False, interval_seconds=600
|
|
)
|
|
scheduler._settings_cache["testuser"] = cached_settings
|
|
|
|
result = scheduler._get_document_scheduler_settings("testuser")
|
|
assert result is cached_settings
|
|
|
|
def test_returns_defaults_without_session(self):
|
|
"""Test returns defaults when no user session."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
DocumentSchedulerSettings,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
result = scheduler._get_document_scheduler_settings("unknown_user")
|
|
defaults = DocumentSchedulerSettings.defaults()
|
|
assert result.enabled == defaults.enabled
|
|
|
|
def test_force_refresh_bypasses_cache(self):
|
|
"""Test force_refresh bypasses cache."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
DocumentSchedulerSettings,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
cached_settings = DocumentSchedulerSettings(enabled=False)
|
|
scheduler._settings_cache["testuser"] = cached_settings
|
|
|
|
# Without session, should return defaults even with cache
|
|
result = scheduler._get_document_scheduler_settings(
|
|
"testuser", force_refresh=True
|
|
)
|
|
# Returns defaults since no session
|
|
assert result.enabled is True
|
|
|
|
|
|
class TestInvalidateUserSettingsCache:
|
|
"""Tests for invalidate_user_settings_cache method."""
|
|
|
|
def test_removes_user_from_cache(self):
|
|
"""Test removes user from cache."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
DocumentSchedulerSettings,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
scheduler._settings_cache["testuser"] = DocumentSchedulerSettings()
|
|
scheduler.invalidate_user_settings_cache("testuser")
|
|
|
|
assert "testuser" not in scheduler._settings_cache
|
|
|
|
def test_returns_true_if_found(self):
|
|
"""Test returns True when user was in cache."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
DocumentSchedulerSettings,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
scheduler._settings_cache["testuser"] = DocumentSchedulerSettings()
|
|
result = scheduler.invalidate_user_settings_cache("testuser")
|
|
|
|
assert result is True
|
|
|
|
def test_returns_false_if_not_found(self):
|
|
"""Test returns False when user not in cache."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
result = scheduler.invalidate_user_settings_cache("unknown_user")
|
|
assert result is False
|
|
|
|
|
|
class TestInvalidateAllSettingsCache:
|
|
"""Tests for invalidate_all_settings_cache method."""
|
|
|
|
def test_clears_all_entries(self):
|
|
"""Test clears all cache entries."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
DocumentSchedulerSettings,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
scheduler._settings_cache["user1"] = DocumentSchedulerSettings()
|
|
scheduler._settings_cache["user2"] = DocumentSchedulerSettings()
|
|
|
|
scheduler.invalidate_all_settings_cache()
|
|
|
|
assert len(scheduler._settings_cache) == 0
|
|
|
|
def test_returns_count_cleared(self):
|
|
"""Test returns count of cleared entries."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
DocumentSchedulerSettings,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
scheduler._settings_cache["user1"] = DocumentSchedulerSettings()
|
|
scheduler._settings_cache["user2"] = DocumentSchedulerSettings()
|
|
scheduler._settings_cache["user3"] = DocumentSchedulerSettings()
|
|
|
|
count = scheduler.invalidate_all_settings_cache()
|
|
assert count == 3
|
|
|
|
|
|
class TestStartScheduler:
|
|
"""Tests for start method."""
|
|
|
|
def test_sets_is_running_true(self):
|
|
"""Test sets is_running to True."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
scheduler.set_app(MagicMock())
|
|
|
|
with patch.object(scheduler.scheduler, "start"):
|
|
scheduler.start()
|
|
assert scheduler.is_running is True
|
|
|
|
def test_starts_background_scheduler(self):
|
|
"""Test starts the background scheduler."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
scheduler.set_app(MagicMock())
|
|
|
|
with patch.object(scheduler.scheduler, "start") as mock_start:
|
|
scheduler.start()
|
|
mock_start.assert_called_once()
|
|
|
|
def test_does_not_start_if_already_running(self):
|
|
"""Test does not start if already running."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
scheduler.is_running = True
|
|
|
|
with patch.object(scheduler.scheduler, "start") as mock_start:
|
|
scheduler.start()
|
|
mock_start.assert_not_called()
|
|
|
|
|
|
class TestStopScheduler:
|
|
"""Tests for stop method."""
|
|
|
|
def test_sets_is_running_false(self):
|
|
"""Test sets is_running to False."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
scheduler.is_running = True
|
|
|
|
with patch.object(scheduler.scheduler, "shutdown"):
|
|
scheduler.stop()
|
|
assert scheduler.is_running is False
|
|
|
|
def test_shuts_down_scheduler(self):
|
|
"""Test shuts down the background scheduler."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
scheduler.is_running = True
|
|
|
|
with patch.object(scheduler.scheduler, "shutdown") as mock_shutdown:
|
|
scheduler.stop()
|
|
mock_shutdown.assert_called_once()
|
|
|
|
|
|
class TestUpdateUserInfo:
|
|
"""Tests for update_user_info method."""
|
|
|
|
def test_creates_new_session(self):
|
|
"""Test creates new session for new user."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
scheduler.is_running = True # Enable scheduler
|
|
|
|
with patch.object(scheduler, "_schedule_user_subscriptions"):
|
|
scheduler.update_user_info("newuser", "password123")
|
|
|
|
assert "newuser" in scheduler.user_sessions
|
|
assert "password" not in scheduler.user_sessions["newuser"]
|
|
assert scheduler._credential_store.retrieve("newuser") == "password123"
|
|
|
|
def test_updates_last_activity(self):
|
|
"""Test updates last_activity timestamp."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
from datetime import timezone
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
scheduler.is_running = True
|
|
|
|
before = datetime.now(timezone.utc)
|
|
with patch.object(scheduler, "_schedule_user_subscriptions"):
|
|
scheduler.update_user_info("testuser", "password")
|
|
after = datetime.now(timezone.utc)
|
|
|
|
last_activity = scheduler.user_sessions["testuser"]["last_activity"]
|
|
assert before <= last_activity <= after
|
|
|
|
def test_initializes_scheduled_jobs_set(self):
|
|
"""Test initializes empty scheduled_jobs set."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
scheduler.is_running = True
|
|
|
|
with patch.object(scheduler, "_schedule_user_subscriptions"):
|
|
scheduler.update_user_info("testuser", "password")
|
|
|
|
assert scheduler.user_sessions["testuser"]["scheduled_jobs"] == set()
|
|
|
|
|
|
class TestUnregisterUser:
|
|
"""Tests for unregister_user method."""
|
|
|
|
def test_removes_user_from_sessions(self):
|
|
"""Test removes user from sessions."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
scheduler.user_sessions["testuser"] = {
|
|
"last_activity": datetime.now(),
|
|
"scheduled_jobs": set(),
|
|
}
|
|
scheduler._credential_store.store("testuser", "test")
|
|
|
|
scheduler.unregister_user("testuser")
|
|
|
|
assert "testuser" not in scheduler.user_sessions
|
|
|
|
def test_invalidates_settings_cache(self):
|
|
"""Test invalidates settings cache for user."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
DocumentSchedulerSettings,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
scheduler.user_sessions["testuser"] = {
|
|
"last_activity": datetime.now(),
|
|
"scheduled_jobs": set(),
|
|
}
|
|
scheduler._credential_store.store("testuser", "test")
|
|
scheduler._settings_cache["testuser"] = DocumentSchedulerSettings()
|
|
|
|
scheduler.unregister_user("testuser")
|
|
|
|
assert "testuser" not in scheduler._settings_cache
|
|
|
|
def test_handles_nonexistent_user(self):
|
|
"""Test handles unregistering nonexistent user."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
# Should not raise
|
|
scheduler.unregister_user("nonexistent_user")
|
|
|
|
|
|
class TestGetDocumentSchedulerStatus:
|
|
"""Tests for get_document_scheduler_status method."""
|
|
|
|
def test_returns_dict(self):
|
|
"""Test returns a dictionary."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
result = scheduler.get_document_scheduler_status("testuser")
|
|
assert isinstance(result, dict)
|
|
|
|
def test_includes_enabled_flag(self):
|
|
"""Test includes enabled flag."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
result = scheduler.get_document_scheduler_status("testuser")
|
|
assert "enabled" in result
|
|
|
|
def test_returns_disabled_for_unknown_user(self):
|
|
"""Test returns disabled for unknown user."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
result = scheduler.get_document_scheduler_status("unknown")
|
|
# Default settings should have enabled=True
|
|
assert "enabled" in result
|
|
|
|
|
|
class TestTriggerDocumentProcessing:
|
|
"""Tests for trigger_document_processing method."""
|
|
|
|
def test_returns_false_if_no_session(self):
|
|
"""Test returns False if no user session."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
result = scheduler.trigger_document_processing("unknown_user")
|
|
assert result is False
|
|
|
|
def test_returns_false_if_not_running(self):
|
|
"""Test returns False if scheduler not running."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
scheduler.is_running = False
|
|
scheduler.user_sessions["testuser"] = {
|
|
"last_activity": datetime.now(),
|
|
"scheduled_jobs": set(),
|
|
}
|
|
scheduler._credential_store.store("testuser", "test")
|
|
|
|
result = scheduler.trigger_document_processing("testuser")
|
|
assert result is False
|
|
|
|
|
|
class TestSchedulerThreadSafety:
|
|
"""Tests for scheduler thread safety."""
|
|
|
|
def test_lock_used_for_user_sessions(self):
|
|
"""Test lock is used when modifying user_sessions."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
# The lock should be accessible
|
|
assert hasattr(scheduler, "lock")
|
|
assert isinstance(scheduler.lock, type(threading.Lock()))
|
|
|
|
def test_settings_cache_lock_exists(self):
|
|
"""Test settings cache lock exists."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
assert hasattr(scheduler, "_settings_cache_lock")
|
|
assert isinstance(
|
|
scheduler._settings_cache_lock, type(threading.Lock())
|
|
)
|
|
|
|
|
|
class TestSchedulerConfigDefaults:
|
|
"""Tests for scheduler configuration defaults."""
|
|
|
|
def test_default_retention_hours_is_48(self):
|
|
"""Test default retention_hours is 48."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
assert scheduler.config["retention_hours"] == 48
|
|
|
|
def test_default_cleanup_interval_is_1_hour(self):
|
|
"""Test default cleanup_interval_hours is 1."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
assert scheduler.config["cleanup_interval_hours"] == 1
|
|
|
|
def test_default_max_jitter_is_300_seconds(self):
|
|
"""Test default max_jitter_seconds is 300."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
assert scheduler.config["max_jitter_seconds"] == 300
|
|
|
|
def test_default_max_concurrent_jobs_is_10(self):
|
|
"""Test default max_concurrent_jobs is 10."""
|
|
from local_deep_research.scheduler.background import (
|
|
BackgroundJobScheduler,
|
|
)
|
|
|
|
BackgroundJobScheduler._instance = None
|
|
scheduler = BackgroundJobScheduler()
|
|
|
|
assert scheduler.config["max_concurrent_jobs"] == 10
|