""" Comprehensive tests for resource_service. Tests CRUD operations for ResearchResource. """ import pytest from unittest.mock import Mock, patch class TestGetResourcesForResearch: """Tests for get_resources_for_research function.""" def test_returns_list_of_resources( self, mock_db_session, mock_research_resource, sample_research_id ): """Test that function returns list of resources.""" from local_deep_research.web.services.resource_service import ( get_resources_for_research, ) mock_db_session.query.return_value.filter_by.return_value.order_by.return_value.all.return_value = [ mock_research_resource ] with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False result = get_resources_for_research(sample_research_id) assert isinstance(result, list) assert len(result) == 1 def test_returns_correct_fields( self, mock_db_session, mock_research_resource, sample_research_id ): """Test that returned resources have correct fields.""" from local_deep_research.web.services.resource_service import ( get_resources_for_research, ) mock_db_session.query.return_value.filter_by.return_value.order_by.return_value.all.return_value = [ mock_research_resource ] with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False result = get_resources_for_research(sample_research_id) resource = result[0] assert "id" in resource assert "research_id" in resource assert "title" in resource assert "url" in resource assert "content_preview" in resource assert "source_type" in resource assert "metadata" in resource def test_returns_empty_list_when_no_resources( self, mock_db_session, sample_research_id ): """Test that empty list is returned when no resources exist.""" from local_deep_research.web.services.resource_service import ( get_resources_for_research, ) mock_db_session.query.return_value.filter_by.return_value.order_by.return_value.all.return_value = [] with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False result = get_resources_for_research(sample_research_id) assert result == [] def test_filters_by_research_id(self, mock_db_session, sample_research_id): """Test that query filters by research_id.""" from local_deep_research.web.services.resource_service import ( get_resources_for_research, ) mock_db_session.query.return_value.filter_by.return_value.order_by.return_value.all.return_value = [] with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False get_resources_for_research(sample_research_id) mock_db_session.query.return_value.filter_by.assert_called_once_with( research_id=sample_research_id ) def test_handles_null_metadata(self, mock_db_session, sample_research_id): """Test handling of null resource_metadata.""" from local_deep_research.web.services.resource_service import ( get_resources_for_research, ) resource = Mock() resource.id = 1 resource.research_id = sample_research_id resource.title = "Test" resource.url = "https://test.com" resource.content_preview = "Preview" resource.source_type = "web" resource.resource_metadata = None mock_db_session.query.return_value.filter_by.return_value.order_by.return_value.all.return_value = [ resource ] with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False result = get_resources_for_research(sample_research_id) assert result[0]["metadata"] == {} def test_raises_on_database_error( self, mock_db_session, sample_research_id ): """Test that exceptions are raised on database error.""" from local_deep_research.web.services.resource_service import ( get_resources_for_research, ) mock_db_session.query.side_effect = Exception("DB error") with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False with pytest.raises(Exception): get_resources_for_research(sample_research_id) class TestAddResource: """Tests for add_resource function.""" def test_creates_resource(self, mock_db_session, sample_research_id): """Test that resource is created and added to session.""" from local_deep_research.web.services.resource_service import ( add_resource, ) with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False with patch( "local_deep_research.web.services.resource_service.ResearchResource" ): add_resource( sample_research_id, "Test Title", "https://example.com" ) mock_db_session.add.assert_called_once() mock_db_session.commit.assert_called_once() def test_returns_created_resource( self, mock_db_session, sample_research_id ): """Test that created resource is returned.""" from local_deep_research.web.services.resource_service import ( add_resource, ) with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False with patch( "local_deep_research.web.services.resource_service.ResearchResource" ) as mock_resource_class: mock_resource_class.return_value = Mock() result = add_resource( sample_research_id, "Test Title", "https://example.com" ) assert result is not None def test_uses_default_source_type( self, mock_db_session, sample_research_id ): """Test that default source_type is 'web'.""" from local_deep_research.web.services.resource_service import ( add_resource, ) with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False with patch( "local_deep_research.web.services.resource_service.ResearchResource" ) as mock_resource_class: add_resource( sample_research_id, "Test Title", "https://example.com" ) call_kwargs = mock_resource_class.call_args[1] assert call_kwargs["source_type"] == "web" def test_accepts_custom_source_type( self, mock_db_session, sample_research_id ): """Test that custom source_type is accepted.""" from local_deep_research.web.services.resource_service import ( add_resource, ) with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False with patch( "local_deep_research.web.services.resource_service.ResearchResource" ) as mock_resource_class: add_resource( sample_research_id, "Test Title", "https://example.com", source_type="pdf", ) call_kwargs = mock_resource_class.call_args[1] assert call_kwargs["source_type"] == "pdf" def test_accepts_metadata(self, mock_db_session, sample_research_id): """Test that metadata is passed to resource.""" from local_deep_research.web.services.resource_service import ( add_resource, ) metadata = {"key": "value", "extra": "data"} with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False with patch( "local_deep_research.web.services.resource_service.ResearchResource" ) as mock_resource_class: add_resource( sample_research_id, "Test Title", "https://example.com", metadata=metadata, ) call_kwargs = mock_resource_class.call_args[1] assert call_kwargs["resource_metadata"] == metadata def test_raises_on_database_error( self, mock_db_session, sample_research_id ): """Test that exceptions are raised on database error.""" from local_deep_research.web.services.resource_service import ( add_resource, ) mock_db_session.add.side_effect = Exception("DB error") with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False with pytest.raises(Exception): add_resource( sample_research_id, "Test Title", "https://example.com" ) class TestDeleteResource: """Tests for delete_resource function.""" def test_deletes_existing_resource(self, mock_db_session): """Test that existing resource is deleted.""" from local_deep_research.web.services.resource_service import ( delete_resource, ) mock_resource = Mock() mock_db_session.query.return_value.filter_by.return_value.first.return_value = mock_resource with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False result = delete_resource(1) mock_db_session.delete.assert_called_once_with(mock_resource) mock_db_session.commit.assert_called_once() assert result is True def test_raises_value_error_when_not_found(self, mock_db_session): """Test that ValueError is raised when resource not found.""" from local_deep_research.web.services.resource_service import ( delete_resource, ) mock_db_session.query.return_value.filter_by.return_value.first.return_value = None with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False with pytest.raises(ValueError) as exc_info: delete_resource(999) assert "not found" in str(exc_info.value) def test_logs_successful_deletion(self, mock_db_session): """Test that successful deletion is logged.""" from local_deep_research.web.services.resource_service import ( delete_resource, ) mock_resource = Mock() mock_db_session.query.return_value.filter_by.return_value.first.return_value = mock_resource with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False with patch( "local_deep_research.web.services.resource_service.logger" ) as mock_logger: delete_resource(1) mock_logger.info.assert_called_once() def test_raises_on_database_error(self, mock_db_session): """Test that database errors are propagated.""" from local_deep_research.web.services.resource_service import ( delete_resource, ) mock_db_session.query.side_effect = Exception("DB error") with patch( "local_deep_research.web.services.resource_service.get_user_db_session" ) as mock_get_session: mock_get_session.return_value.__enter__.return_value = ( mock_db_session ) mock_get_session.return_value.__exit__.return_value = False with pytest.raises(Exception): delete_resource(1)