Skip to content

Large diffs are not rendered by default.

139 changes: 139 additions & 0 deletions src/backend-api/src/tests/azure/test_app_configuration_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
"""Tests for app_configuration helper module."""
import os
from unittest.mock import Mock, patch, MagicMock
import pytest
from azure.identity import DefaultAzureCredential
from azure.appconfiguration import AzureAppConfigurationClient

from libs.azure.app_configuration import AppConfigurationHelper


def test_app_configuration_helper_initialization():
"""Test AppConfigurationHelper initialization."""
with patch("libs.azure.app_configuration.AzureAppConfigurationClient") as mock_client:
helper = AppConfigurationHelper(
app_configuration_url="https://test.azconfig.io", credential=None
)

assert helper.app_config_endpoint == "https://test.azconfig.io"
assert helper.credential is not None # DefaultAzureCredential created


def test_app_configuration_helper_with_provided_credential():
"""Test AppConfigurationHelper initialization with provided credential."""
with patch("libs.azure.app_configuration.AzureAppConfigurationClient") as mock_client:
credential = Mock(spec=DefaultAzureCredential)
helper = AppConfigurationHelper(
app_configuration_url="https://test.azconfig.io", credential=credential
)

assert helper.credential is credential


def test_app_configuration_helper_initialize_client_valid_endpoint():
"""Test client initialization with valid endpoint."""
with patch("libs.azure.app_configuration.AzureAppConfigurationClient") as mock_client:
helper = AppConfigurationHelper(
app_configuration_url="https://test.azconfig.io"
)

# Verify AzureAppConfigurationClient was called with correct parameters
assert mock_client.called


def test_app_configuration_helper_initialize_client_none_endpoint():
"""Test client initialization raises error with None endpoint."""
with pytest.raises(ValueError, match="App Configuration Endpoint is not set"):
# Should raise error during initialization
AppConfigurationHelper(app_configuration_url=None)


def test_app_configuration_helper_read_configuration():
"""Test reading configuration settings."""
mock_client = Mock(spec=AzureAppConfigurationClient)
mock_setting1 = Mock()
mock_setting1.key = "TEST_KEY1"
mock_setting1.value = "test_value1"

mock_setting2 = Mock()
mock_setting2.key = "TEST_KEY2"
mock_setting2.value = "test_value2"

mock_client.list_configuration_settings.return_value = [
mock_setting1,
mock_setting2,
]

with patch(
"libs.azure.app_configuration.AzureAppConfigurationClient",
return_value=mock_client,
):
helper = AppConfigurationHelper(app_configuration_url="https://test.azconfig.io")
settings = helper.read_configuration()

assert len(settings) == 2
assert settings[0].key == "TEST_KEY1"
assert settings[1].key == "TEST_KEY2"


def test_app_configuration_helper_read_and_set_environmental_variables():
"""Test reading configuration and setting environment variables."""
mock_client = Mock(spec=AzureAppConfigurationClient)
mock_setting1 = Mock()
mock_setting1.key = "TEST_ENV_VAR1"
mock_setting1.value = "env_value1"

mock_setting2 = Mock()
mock_setting2.key = "TEST_ENV_VAR2"
mock_setting2.value = "env_value2"

mock_client.list_configuration_settings.return_value = [
mock_setting1,
mock_setting2,
]

with patch(
"libs.azure.app_configuration.AzureAppConfigurationClient",
return_value=mock_client,
):
helper = AppConfigurationHelper(app_configuration_url="https://test.azconfig.io")

# Clear test env vars if they exist
if "TEST_ENV_VAR1" in os.environ:
del os.environ["TEST_ENV_VAR1"]
if "TEST_ENV_VAR2" in os.environ:
del os.environ["TEST_ENV_VAR2"]

result = helper.read_and_set_environmental_variables()

# Verify environment variables were set
assert "TEST_ENV_VAR1" in result
assert result["TEST_ENV_VAR1"] == "env_value1"
assert "TEST_ENV_VAR2" in result
assert result["TEST_ENV_VAR2"] == "env_value2"

# Clean up
del os.environ["TEST_ENV_VAR1"]
del os.environ["TEST_ENV_VAR2"]


def test_app_configuration_helper_multiple_calls():
"""Test multiple calls to read configuration."""
mock_client = Mock(spec=AzureAppConfigurationClient)
mock_setting = Mock()
mock_setting.key = "TEST_KEY"
mock_setting.value = "test_value"

mock_client.list_configuration_settings.return_value = [mock_setting]

with patch(
"libs.azure.app_configuration.AzureAppConfigurationClient",
return_value=mock_client,
):
helper = AppConfigurationHelper(app_configuration_url="https://test.azconfig.io")

settings1 = helper.read_configuration()
settings2 = helper.read_configuration()

assert len(settings1) == len(settings2)
assert mock_client.list_configuration_settings.call_count == 2
191 changes: 191 additions & 0 deletions src/backend-api/src/tests/base/test_application_base_extra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
"""Additional tests for Application_Base class to improve coverage."""
import os
import logging
from unittest.mock import Mock, patch, MagicMock
import pytest
import tempfile

from libs.base.application_base import Application_Base
from libs.application.application_context import AppContext


class ConcreteApplication(Application_Base):
"""Concrete implementation for testing."""

def run(self):
return "run_result"

def initialize(self):
return "initialize_result"


def test_application_base_with_env_file():
"""Test Application_Base with a provided .env file."""
with tempfile.TemporaryDirectory() as tmpdir:
env_file = os.path.join(tmpdir, ".env")
with open(env_file, "w") as f:
f.write("TEST_VAR=test_value\n")

app = ConcreteApplication(env_file_path=env_file)

assert app.application_context is not None
assert app.application_context.configuration is not None


def test_application_base_initialization_calls_initialize():
"""Test that __init__ calls the initialize method."""

class TrackingApplication(Application_Base):
def __init__(self, **kwargs):
self.initialize_called = False
super().__init__(**kwargs)

def run(self):
pass

def initialize(self):
self.initialize_called = True

app = TrackingApplication(env_file_path=None)
assert app.initialize_called is True


def test_application_base_sets_default_azure_credential():
"""Test that Application_Base sets DefaultAzureCredential."""
app = ConcreteApplication(env_file_path=None)

assert app.application_context.credential is not None


def test_application_base_logging_disabled_by_default():
"""Test that logging is disabled by default."""
app = ConcreteApplication(env_file_path=None)

# Default logging should be disabled
assert app.application_context.configuration.app_logging_enable is False


def test_application_base_logging_enabled():
"""Test Application_Base with logging enabled."""
with tempfile.TemporaryDirectory() as tmpdir:
env_file = os.path.join(tmpdir, ".env")
with open(env_file, "w") as f:
f.write("APP_LOGGING_ENABLE=true\n")
f.write("APP_LOGGING_LEVEL=DEBUG\n")

with patch.dict(os.environ, {"APP_LOGGING_ENABLE": "true"}):
app = ConcreteApplication(env_file_path=env_file)
assert app.application_context is not None


def test_application_base_load_env_with_none_path():
"""Test _load_env with None path."""
app = ConcreteApplication(env_file_path=None)

# Should call _get_derived_class_location if env_file_path is None
result = app._load_env(env_file_path=None)

# Should return a path to .env
assert isinstance(result, str)
assert ".env" in result


def test_application_base_load_env_returns_path():
"""Test that _load_env returns the path."""
with tempfile.TemporaryDirectory() as tmpdir:
env_file = os.path.join(tmpdir, ".env")
with open(env_file, "w") as f:
f.write("TEST=value\n")

result = ConcreteApplication(env_file_path=None)._load_env(env_file_path=env_file)

assert result == env_file


def test_application_base_load_env_creates_app_context():
"""Test that application context is created even if .env is missing."""
app = ConcreteApplication(env_file_path=None)

# Even if .env doesn't exist, app context should be created
assert app.application_context is not None
assert isinstance(app.application_context, AppContext)


def test_application_base_run_method():
"""Test that run method can be called."""
app = ConcreteApplication(env_file_path=None)

result = app.run()
assert result == "run_result"


def test_application_base_initialize_method():
"""Test that initialize method can be called."""
app = ConcreteApplication(env_file_path=None)

result = app.initialize()
assert result == "initialize_result"


def test_application_base_get_derived_class_location_returns_string():
"""Test that _get_derived_class_location returns a string path."""
app = ConcreteApplication(env_file_path=None)

location = app._get_derived_class_location()

assert isinstance(location, str)
assert len(location) > 0
assert os.path.exists(os.path.dirname(location))


def test_application_base_app_context_not_none():
"""Test that application_context is always set."""
app = ConcreteApplication(env_file_path=None)

assert app.application_context is not None
assert isinstance(app.application_context, AppContext)


def test_application_base_configuration_not_none():
"""Test that configuration is set in app context."""
app = ConcreteApplication(env_file_path=None)

assert app.application_context.configuration is not None


def test_application_base_abstract_methods():
"""Test that run and initialize must be implemented."""

with pytest.raises(TypeError):
# Cannot instantiate Application_Base with unimplemented abstract methods
Application_Base(env_file_path=None)


def test_application_base_azure_logging_packages_not_set():
"""Test with no azure logging packages configured."""
app = ConcreteApplication(env_file_path=None)

# Azure logging packages should be None or empty by default
assert (
app.application_context.configuration.azure_logging_packages is None
or app.application_context.configuration.azure_logging_packages == ""
)


def test_application_base_with_azure_logging():
"""Test Application_Base with Azure logging packages configured."""
with tempfile.TemporaryDirectory() as tmpdir:
env_file = os.path.join(tmpdir, ".env")
with open(env_file, "w") as f:
f.write("APP_LOGGING_ENABLE=true\n")
f.write("AZURE_LOGGING_PACKAGES=azure.core,azure.identity\n")

with patch.dict(
os.environ,
{
"APP_LOGGING_ENABLE": "true",
"AZURE_LOGGING_PACKAGES": "azure.core,azure.identity",
},
):
app = ConcreteApplication(env_file_path=env_file)
assert app.application_context is not None
67 changes: 67 additions & 0 deletions src/backend-api/src/tests/base/test_fastapi_protocol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""Tests for fastapi_protocol module."""
import pytest
from fastapi import FastAPI
from libs.application.application_context import AppContext
from libs.base.fastapi_protocol import add_app_context_to_fastapi, FastAPIWithContext


def test_fastapi_with_context_protocol_definition():
"""Test that FastAPIWithContext is a Protocol with expected attributes."""
# Just verify the protocol exists and has the expected structure
assert hasattr(FastAPIWithContext, "__protocol_attrs__") or hasattr(
FastAPIWithContext, "__mro__"
)


def test_add_app_context_to_fastapi_basic():
"""Test adding app context to FastAPI instance."""
app = FastAPI()
app_context = AppContext()

result = add_app_context_to_fastapi(app, app_context)

assert result is app
assert hasattr(app, "app_context")
assert app.app_context is app_context


def test_add_app_context_to_fastapi_with_configured_context():
"""Test adding a configured app context to FastAPI."""
from libs.application.application_configuration import Configuration

app = FastAPI()
app_context = AppContext()
config = Configuration()
app_context.set_configuration(config)

result = add_app_context_to_fastapi(app, app_context)

assert result.app_context.configuration is not None
assert result.app_context.configuration.app_sample_variable == "Hello World!"


def test_add_app_context_to_fastapi_returns_typed_app():
"""Test that returned value is properly typed for use as FastAPIWithContext."""
app = FastAPI()
app_context = AppContext()

result = add_app_context_to_fastapi(app, app_context)

# Should have app_context attribute
assert hasattr(result, "app_context")
# Should have FastAPI methods like include_router
assert hasattr(result, "include_router")
assert callable(result.include_router)


def test_add_app_context_to_fastapi_multiple_contexts():
"""Test that we can replace app context on same FastAPI instance."""
app = FastAPI()
app_context1 = AppContext()
app_context2 = AppContext()

add_app_context_to_fastapi(app, app_context1)
assert app.app_context is app_context1

add_app_context_to_fastapi(app, app_context2)
assert app.app_context is app_context2
Loading
Loading