Content is user-generated and unverified.
import os import tempfile import pytest from unittest.mock import Mock, patch, mock_open from secretsmith.vault.client import from_config, resolve_token, resolve_namespace, login_with_approle class TestFromConfig: """Test the from_config method""" @patch('secretsmith.vault.client.Client') @patch('secretsmith.vault.client.login_with_approle') def test_from_config_approle_method(self, mock_login_approle, mock_client): """Test that approle authentication calls the login method""" # Arrange config = { "server": {"url": "https://vault.example.com"}, "auth": { "method": "approle", "role_id": "test-role-id", "secret_id": "test-secret-id" } } mock_client_instance = Mock() mock_client.return_value = mock_client_instance # Act result = from_config(config) # Assert mock_client.assert_called_once_with( url="https://vault.example.com", token=None, verify=None, namespace=None ) mock_login_approle.assert_called_once_with(mock_client_instance, config["auth"]) assert result == mock_client_instance @patch('secretsmith.vault.client.Client') def test_from_config_token_method(self, mock_client): """Test that token authentication works without calling approle login""" # Arrange config = { "server": {"url": "https://vault.example.com"}, "auth": { "method": "token", "token": "s.test-token" } } mock_client_instance = Mock() mock_client.return_value = mock_client_instance # Act result = from_config(config) # Assert mock_client.assert_called_once_with( url="https://vault.example.com", token="s.test-token", verify=None, namespace=None ) assert result == mock_client_instance @patch('secretsmith.vault.client.Client') def test_from_config_unknown_method_raises_error(self, mock_client): """Test that unknown authentication method raises ValueError""" # Arrange config = { "auth": { "method": "notexisting" } } mock_client_instance = Mock() mock_client.return_value = mock_client_instance # Act & Assert with pytest.raises(ValueError, match="Unknown auth method: notexisting"): from_config(config) class TestResolveToken: """Test the resolve_token function""" def test_resolve_token_no_config_returns_none(self): """Test that empty config returns None""" # Arrange config_auth = {} # Act result = resolve_token(config_auth) # Assert assert result is None def test_resolve_token_from_file(self): """Test reading token from file""" # Arrange token_content = "s.test-file-token" with tempfile.NamedTemporaryFile(mode='w', delete=False, dir='tests') as temp_file: temp_file.write(token_content + "\n ") # Add whitespace to test strip() temp_file_path = temp_file.name try: config_auth = {"tokenfile": temp_file_path} # Act result = resolve_token(config_auth) # Assert assert result == token_content finally: os.unlink(temp_file_path) def test_resolve_token_from_config(self): """Test reading token directly from config""" # Arrange config_auth = {"token": "s.0000"} # Act result = resolve_token(config_auth) # Assert assert result == "s.0000" def test_resolve_token_tokenfile_takes_precedence(self): """Test that tokenfile takes precedence over direct token config""" # Arrange token_from_file = "s.file-token" with tempfile.NamedTemporaryFile(mode='w', delete=False, dir='tests') as temp_file: temp_file.write(token_from_file) temp_file_path = temp_file.name try: config_auth = { "tokenfile": temp_file_path, "token": "s.config-token" } # Act result = resolve_token(config_auth) # Assert assert result == token_from_file finally: os.unlink(temp_file_path) class TestResolveNamespace: """Test the resolve_namespace function""" def test_resolve_namespace_from_config(self): """Test resolving namespace from config""" # Arrange config = {"namespace": "quux"} # Act result = resolve_namespace(config) # Assert assert result == "quux" def test_resolve_namespace_from_environment(self): """Test resolving namespace from environment variable""" # Arrange config = {} # Act & Assert with patch.dict(os.environ, {"VAULT_NAMESPACE": "quux"}): result = resolve_namespace(config) assert result == "quux" def test_resolve_namespace_config_overrides_environment(self): """Test that config value takes precedence over environment variable""" # Arrange config = {"namespace": "config-namespace"} # Act & Assert with patch.dict(os.environ, {"VAULT_NAMESPACE": "env-namespace"}): result = resolve_namespace(config) assert result == "config-namespace" def test_resolve_namespace_no_config_no_env_returns_none(self): """Test that missing config and env var returns None""" # Arrange config = {} # Act & Assert with patch.dict(os.environ, {}, clear=True): result = resolve_namespace(config) assert result is None class TestLoginWithApprole: """Test the login_with_approle function""" def test_login_with_approle_success(self): """Test successful approle login""" # Arrange mock_client = Mock() config_auth = { "role_id": "test-role-id", "secret_id": "test-secret-id" } # Act login_with_approle(mock_client, config_auth) # Assert mock_client.auth.approle.login.assert_called_once_with( role_id="test-role-id", secret_id="test-secret-id" ) def test_login_with_approle_no_secret_id(self): """Test approle login without secret_id (should pass None)""" # Arrange mock_client = Mock() config_auth = {"role_id": "test-role-id"} # Act login_with_approle(mock_client, config_auth) # Assert mock_client.auth.approle.login.assert_called_once_with( role_id="test-role-id", secret_id=None ) def test_login_with_approle_missing_role_id_raises_error(self): """Test that missing role_id raises ValueError""" # Arrange mock_client = Mock() config_auth = {"secret_id": "test-secret-id"} # Act & Assert with pytest.raises(ValueError, match="Missing role_id in auth configuration"): login_with_approle(mock_client, config_auth) # Additional integration-style tests class TestIntegration: """Integration tests combining multiple functions""" @patch('secretsmith.vault.client.Client') def test_full_config_with_all_options(self, mock_client): """Test complete configuration with all options""" # Arrange config = { "server": { "url": "https://vault.example.com", "verify": "/path/to/ca.crt", "namespace": "test-namespace" }, "auth": { "method": "token", "token": "s.full-test-token" } } mock_client_instance = Mock() mock_client.return_value = mock_client_instance # Act result = from_config(config) # Assert mock_client.assert_called_once_with( url="https://vault.example.com", token="s.full-test-token", verify="/path/to/ca.crt", namespace="test-namespace" ) assert result == mock_client_instance @patch('secretsmith.vault.client.Client') def test_minimal_config(self, mock_client): """Test minimal configuration""" # Arrange config = {} mock_client_instance = Mock() mock_client.return_value = mock_client_instance # Act result = from_config(config) # Assert mock_client.assert_called_once_with( url=None, token=None, verify=None, namespace=None ) assert result == mock_client_instance
Content is user-generated and unverified.
    Test Suite for secretsmith client.py | Claude