diff --git a/apps/report-execution/pytest.toml b/apps/report-execution/pytest.toml index 031d3e55ac..932f56312a 100644 --- a/apps/report-execution/pytest.toml +++ b/apps/report-execution/pytest.toml @@ -1,6 +1,7 @@ [pytest] pythonpath = ["."] testpaths = ["tests"] +norecursedirs = ["assets"] python_files = ["*.py"] python_classes = ["Test*"] python_functions = ["test_*"] @@ -10,4 +11,4 @@ addopts = [ "--strict-config", "--showlocals", "--import-mode=importlib" -] \ No newline at end of file +] diff --git a/apps/report-execution/src/execute_report.py b/apps/report-execution/src/execute_report.py index 1dc7c732d7..59ab99a88f 100644 --- a/apps/report-execution/src/execute_report.py +++ b/apps/report-execution/src/execute_report.py @@ -62,7 +62,7 @@ def get_library(library_name: str, is_builtin: bool): if is_builtin: return import_module(f'src.libraries.{library_name}') else: - raise errors.ToDoError('support custom libraries') + return import_module(f'src.libraries.custom.{library_name}') except ModuleNotFoundError: # Initial error not helpful for debugging raise errors.MissingLibraryError(library_name, is_builtin) from None diff --git a/apps/report-execution/src/libraries/custom/__init__.py b/apps/report-execution/src/libraries/custom/__init__.py new file mode 100644 index 0000000000..6d8099d70f --- /dev/null +++ b/apps/report-execution/src/libraries/custom/__init__.py @@ -0,0 +1,2 @@ +# This module contains libraries that deployments mount into this location, but will be +# empty in the base product diff --git a/apps/report-execution/tests/integration/assets/custom_library.py b/apps/report-execution/tests/integration/assets/custom_library.py new file mode 100644 index 0000000000..5626147f13 --- /dev/null +++ b/apps/report-execution/tests/integration/assets/custom_library.py @@ -0,0 +1,17 @@ +from src.db_transaction import Transaction +from src.models import ReportResult, TimeRange + + +def execute( + trx: Transaction, + subset_query: str, + data_source_name: str, + time_range: TimeRange | None = None, + **kwargs, +): + """This is a stub custom library just to start to get the interface hooked up.""" + content = trx.execute(subset_query) + + return ReportResult( + content_type='table', content=content, description='Custom pass through query' + ) diff --git a/apps/report-execution/tests/integration/docker-compose.yml b/apps/report-execution/tests/integration/docker-compose.yml index 7c9dd6dd04..a0faca53dc 100644 --- a/apps/report-execution/tests/integration/docker-compose.yml +++ b/apps/report-execution/tests/integration/docker-compose.yml @@ -3,3 +3,9 @@ services: report-execution: # allows using localhost db conn for easy access to db container directly or via report-execution container network_mode: host + # Tests external client library mounting into container works + volumes: + - type: bind + source: ../apps/report-execution/tests/integration/assets/custom_library.py + target: /usr/report-execution/src/libraries/custom/custom_library.py + read_only: true diff --git a/apps/report-execution/tests/integration/libraries/custom_library.py b/apps/report-execution/tests/integration/libraries/custom_library.py new file mode 100644 index 0000000000..8e4a295fba --- /dev/null +++ b/apps/report-execution/tests/integration/libraries/custom_library.py @@ -0,0 +1,35 @@ +import http.client +import json + +import pytest + + +@pytest.mark.usefixtures('setup_containers') +@pytest.mark.integration +class TestCustomLibrary: + """Integration tests for custom library execution.""" + + def test_custom_library_runs(self): + report_spec = { + 'version': 1, + 'is_export': True, + 'is_builtin': False, + 'report_title': 'Test Report', + 'library_name': 'custom_library', + # Filter code is used here as it is a stable, small table + 'data_source_name': '[NBS_ODSE].[dbo].[Filter_code]', + 'subset_query': 'SELECT * FROM [NBS_ODSE].[dbo].[Filter_code]', + } + + connection = http.client.HTTPConnection('localhost:8001') + + headers = {'Content-type': 'application/json'} + body = json.dumps(report_spec) + + connection.request('POST', '/report/execute', body, headers) + + response = connection.getresponse() + assert response.status == 200 + + result = json.loads(response.read()) + assert result['description'] == 'Custom pass through query' diff --git a/apps/report-execution/tests/integration/main.py b/apps/report-execution/tests/integration/main.py index f5bb6beadd..22338e181f 100644 --- a/apps/report-execution/tests/integration/main.py +++ b/apps/report-execution/tests/integration/main.py @@ -36,6 +36,6 @@ def test_report_runs(self): result = json.loads(response.read()) assert ( - result['description'] + result['header'] == 'Custom Report For Table: [NBS_ODSE].[dbo].[Filter_code]' )