"""Tests for feature flags connector.""" from dataclasses import dataclass from typing import Any, Dict, Optional from unittest.mock import MagicMock, patch import pytest from pdp import config from pdp.connectors.features import splitio_client_factory from pdp.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("pdp.connectors.features.client.get_factory") @patch("pdp.connectors.features.client.build_split_io_config") def test_splitio_client_factory( mock_build_split_io_config: MagicMock, mock_get_factory: MagicMock, monkeypatch: Any, 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( "description,test_config,should_fetch_from_sm,api_key_from_sm,expected_config", [ ( "Dev environment and localhost split.io key", 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, }, ), ( "Dev environment and null split.io key", 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, }, ), ( "Qa environment and null split.io key", 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", }, ), ( "Prod environment and null split.io key", 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", }, ), ( "QA environment and 'test_api_key' split.io key", 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", }, ), ( "QA environment and 'test_api_key' split.io 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("pdp.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, description: str, 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 ret = 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 ret == expected_config @patch("pdp.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 ret = fetch_api_key_from_secrets_manager() secrets_manager_client.get_cred.assert_called_with(API_KEY_SECRET) assert ret == "api_key"