"""Tests for contributor feature flags connector.""" from dataclasses import dataclass from typing import Any, Dict, Optional from unittest.mock import MagicMock, patch import pytest from contributor import config from contributor.connectors.features import splitio_client_factory from contributor.connectors.features.client import ( API_KEY_SECRET, SPLITIO_CONFIG_API_KEY, build_split_io_config, fetch_api_key_from_secrets_manager, ) @dataclass class SplitioTestConfig: """Test configs for split.io.""" environment: str api_key: Optional[str] = None impressions_mode: str = "optimized" prefork_enabled: bool = False split_file_path: Optional[str] = None @pytest.mark.parametrize("api_key, expect_error", [("testKey", False), (None, True)]) @patch("contributor.connectors.features.client.get_factory") @patch("contributor.connectors.features.client.build_split_io_config") def test_splitio_client_factory( mock_build_split_io_config: MagicMock, mock_get_factory: MagicMock, api_key: str, expect_error: bool, ) -> None: """Verify the splitio client factory method.""" expected_config = {SPLITIO_CONFIG_API_KEY: api_key} mock_factory = MagicMock() mock_get_factory.return_value = mock_factory mock_build_split_io_config.return_value = expected_config if expect_error: with pytest.raises(AssertionError): splitio_client_factory() else: splitio_client_factory() mock_get_factory.assert_called_with(api_key=api_key, config=expected_config) mock_factory.block_until_ready.assert_called_once() mock_factory.client.assert_called_once() @pytest.mark.parametrize( "test_config,should_fetch_from_sm,api_key_from_sm,expected_config", [ ( SplitioTestConfig( environment=config.DEV_ENVIRONMENT, impressions_mode="optimized", prefork_enabled=True, split_file_path=config.DEFAULT_SPLIT_FILE_PATH, api_key=config.SPLITIO_LOCALHOST_ENV, ), False, None, { "impressionsMode": "optimized", "preforkedInitialization": True, "splitFile": config.DEFAULT_SPLIT_FILE_PATH, SPLITIO_CONFIG_API_KEY: config.SPLITIO_LOCALHOST_ENV, }, ), ( SplitioTestConfig( environment=config.DEV_ENVIRONMENT, impressions_mode="optimized", prefork_enabled=True, split_file_path=config.DEFAULT_SPLIT_FILE_PATH, api_key=None, ), True, None, { "impressionsMode": "optimized", "preforkedInitialization": True, "splitFile": config.DEFAULT_SPLIT_FILE_PATH, SPLITIO_CONFIG_API_KEY: config.SPLITIO_LOCALHOST_ENV, }, ), ( SplitioTestConfig( environment=config.QA_ENVIRONMENT, impressions_mode="optimized", prefork_enabled=False, split_file_path=config.DEFAULT_SPLIT_FILE_PATH, api_key=None, ), True, "api_key_from_secrets_manager", { "impressionsMode": "optimized", "preforkedInitialization": False, SPLITIO_CONFIG_API_KEY: "api_key_from_secrets_manager", }, ), ( SplitioTestConfig( environment=config.PROD_ENVIRONMENT, impressions_mode="optimized", prefork_enabled=False, split_file_path=config.DEFAULT_SPLIT_FILE_PATH, api_key=None, ), True, "api_key_from_secrets_manager", { "impressionsMode": "optimized", "preforkedInitialization": False, SPLITIO_CONFIG_API_KEY: "api_key_from_secrets_manager", }, ), ( SplitioTestConfig( environment=config.QA_ENVIRONMENT, impressions_mode="optimized", prefork_enabled=False, split_file_path=config.DEFAULT_SPLIT_FILE_PATH, api_key="test_api_key", ), False, None, { "impressionsMode": "optimized", "preforkedInitialization": False, SPLITIO_CONFIG_API_KEY: "test_api_key", }, ), ( SplitioTestConfig( environment=config.PROD_ENVIRONMENT, impressions_mode="optimized", prefork_enabled=False, split_file_path=config.DEFAULT_SPLIT_FILE_PATH, api_key="test_api_key", ), False, None, { "impressionsMode": "optimized", "preforkedInitialization": False, SPLITIO_CONFIG_API_KEY: "test_api_key", }, ), ], ) @patch("contributor.connectors.features.client.fetch_api_key_from_secrets_manager") def test_build_split_io_config( mock_fetch_api_key_from_secrets_manager: MagicMock, monkeypatch: Any, test_config: SplitioTestConfig, should_fetch_from_sm: bool, api_key_from_sm: Optional[str], expected_config: Dict[str, Any], ) -> None: """Verify the splitio configuration method.""" monkeypatch.setattr(config, "ENVIRONMENT", test_config.environment) monkeypatch.setattr(config, "SPLIT_FILE_PATH", test_config.split_file_path) monkeypatch.setattr(config, "SPLITIO_API_KEY", test_config.api_key) monkeypatch.setattr( config, "SPLITIO_IMPRESSIONS_MODE", test_config.impressions_mode, ) monkeypatch.setattr(config, "SPLITIO_PREFORKED_INIT", test_config.prefork_enabled) mock_fetch_api_key_from_secrets_manager.return_value = api_key_from_sm result = build_split_io_config() if should_fetch_from_sm: mock_fetch_api_key_from_secrets_manager.assert_called_once() else: mock_fetch_api_key_from_secrets_manager.assert_not_called() assert result == expected_config @patch("contributor.connectors.features.client.PythonSecretsManager") def test_fetch_api_key_from_secrets_manager( mock_python_secrets_manager: MagicMock, ) -> None: """Verify the method to fetch api key from secrets manager.""" secrets_manager_client = MagicMock() secrets_manager_client.get_cred.return_value = "api_key" mock_python_secrets_manager.return_value = secrets_manager_client result = fetch_api_key_from_secrets_manager() secrets_manager_client.get_cred.assert_called_with(API_KEY_SECRET) assert result == "api_key"