|
23 | 23 |
|
24 | 24 | @pytest.fixture
|
25 | 25 | def mock_secret_client(mocker: MockerFixture):
|
26 |
| - if not gcp_secret_manager: |
27 |
| - pytest.skip('pydantic-settings[gcp-secret-manager] is not installed') |
28 |
| - |
29 | 26 | client = mocker.Mock(spec=SecretManagerServiceClient)
|
30 | 27 |
|
31 | 28 | # Mock common_project_path
|
@@ -79,125 +76,130 @@ def mock_google_auth(mocker: MockerFixture):
|
79 | 76 | )
|
80 | 77 |
|
81 | 78 |
|
82 |
| -def test_secret_manager_mapping_init(secret_manager_mapping): |
83 |
| - assert secret_manager_mapping._project_id == 'test-project' |
84 |
| - assert len(secret_manager_mapping._loaded_secrets) == 0 |
85 |
| - |
86 |
| - |
87 |
| -def test_secret_manager_mapping_gcp_project_path(secret_manager_mapping, mock_secret_client): |
88 |
| - secret_manager_mapping._gcp_project_path |
89 |
| - mock_secret_client.common_project_path.assert_called_once_with('test-project') |
90 |
| - |
91 |
| - |
92 |
| -def test_secret_manager_mapping_secret_names(secret_manager_mapping): |
93 |
| - names = secret_manager_mapping._secret_names |
94 |
| - assert names == ['test-secret'] |
95 |
| - |
96 |
| - |
97 |
| -def test_secret_manager_mapping_getitem_success(secret_manager_mapping): |
98 |
| - value = secret_manager_mapping['test-secret'] |
99 |
| - assert value == 'test-value' |
100 |
| - |
101 |
| - |
102 |
| -def test_secret_manager_mapping_getitem_nonexistent_key(secret_manager_mapping): |
103 |
| - with pytest.raises(KeyError): |
104 |
| - _ = secret_manager_mapping['nonexistent-secret'] |
105 |
| - |
106 |
| - |
107 |
| -def test_secret_manager_mapping_getitem_access_error(secret_manager_mapping, mocker): |
108 |
| - secret_manager_mapping._secret_client.access_secret_version = mocker.Mock(side_effect=Exception('Access denied')) |
109 |
| - |
110 |
| - with pytest.raises(KeyError): |
111 |
| - _ = secret_manager_mapping['test-secret'] |
112 |
| - |
113 |
| - |
114 |
| -def test_secret_manager_mapping_iter(secret_manager_mapping): |
115 |
| - assert list(secret_manager_mapping) == ['test-secret'] |
116 |
| - |
117 |
| - |
118 |
| -def test_settings_source_init_with_defaults(mock_google_auth, test_settings): |
119 |
| - source = GoogleSecretManagerSettingsSource(test_settings) |
120 |
| - assert source._project_id == 'default-project' |
121 |
| - |
122 |
| - |
123 |
| -def test_settings_source_init_with_custom_values(mocker, test_settings): |
124 |
| - credentials = mocker.Mock() |
125 |
| - source = GoogleSecretManagerSettingsSource(test_settings, credentials=credentials, project_id='custom-project') |
126 |
| - assert source._project_id == 'custom-project' |
127 |
| - assert source._credentials == credentials |
128 |
| - |
129 |
| - |
130 |
| -def test_settings_source_init_with_custom_values_no_project_raises_error(mocker, test_settings): |
131 |
| - credentials = mocker.Mock() |
132 |
| - mocker.patch('pydantic_settings.sources.providers.gcp.google_auth_default', return_value=(mocker.Mock(), None)) |
133 |
| - |
134 |
| - with pytest.raises(AttributeError): |
135 |
| - _ = GoogleSecretManagerSettingsSource(test_settings, credentials=credentials) |
136 |
| - |
137 |
| - |
138 |
| -def test_settings_source_load_env_vars(mock_secret_client, mocker, test_settings): |
139 |
| - credentials = mocker.Mock() |
140 |
| - source = GoogleSecretManagerSettingsSource(test_settings, credentials=credentials, project_id='test-project') |
141 |
| - source._secret_client = mock_secret_client |
142 |
| - |
143 |
| - env_vars = source._load_env_vars() |
144 |
| - assert isinstance(env_vars, GoogleSecretManagerMapping) |
145 |
| - assert env_vars.get('test-secret') == 'test-value' |
146 |
| - assert env_vars.get('another_secret') is None |
147 |
| - |
148 |
| - |
149 |
| -def test_settings_source_repr(test_settings): |
150 |
| - source = GoogleSecretManagerSettingsSource(test_settings, project_id='test-project') |
151 |
| - assert 'test-project' in repr(source) |
152 |
| - assert 'GoogleSecretManagerSettingsSource' in repr(source) |
153 |
| - |
154 |
| - |
155 |
| -def test_pydantic_base_settings(mock_secret_client, monkeypatch, mocker): |
156 |
| - monkeypatch.setenv('ANOTHER_SECRET', 'yep_this_one') |
157 |
| - |
158 |
| - class Settings(BaseSettings, case_sensitive=False): |
159 |
| - test_secret: str = Field(..., alias='test-secret') |
160 |
| - another_secret: str = Field(..., alias='ANOTHER_SECRET') |
161 |
| - |
162 |
| - @classmethod |
163 |
| - def settings_customise_sources( |
164 |
| - cls, |
165 |
| - settings_cls: type[BaseSettings], |
166 |
| - init_settings: PydanticBaseSettingsSource, |
167 |
| - env_settings: PydanticBaseSettingsSource, |
168 |
| - dotenv_settings: PydanticBaseSettingsSource, |
169 |
| - file_secret_settings: PydanticBaseSettingsSource, |
170 |
| - ) -> tuple[PydanticBaseSettingsSource, ...]: |
171 |
| - google_secret_manager_settings = GoogleSecretManagerSettingsSource( |
172 |
| - settings_cls, secret_client=mock_secret_client |
173 |
| - ) |
174 |
| - return (init_settings, env_settings, dotenv_settings, file_secret_settings, google_secret_manager_settings) |
175 |
| - |
176 |
| - settings = Settings() # type: ignore |
177 |
| - assert settings.another_secret == 'yep_this_one' |
178 |
| - assert settings.test_secret == 'test-value' |
179 |
| - |
180 |
| - |
181 |
| -def test_pydantic_base_settings_with_unknown_attribute(mock_secret_client, monkeypatch, mocker): |
182 |
| - from pydantic_core._pydantic_core import ValidationError |
183 |
| - |
184 |
| - class Settings(BaseSettings, case_sensitive=False): |
185 |
| - test_secret: str = Field(..., alias='test-secret') |
186 |
| - another_secret: str = Field(..., alias='ANOTHER_SECRET') |
187 |
| - |
188 |
| - @classmethod |
189 |
| - def settings_customise_sources( |
190 |
| - cls, |
191 |
| - settings_cls: type[BaseSettings], |
192 |
| - init_settings: PydanticBaseSettingsSource, |
193 |
| - env_settings: PydanticBaseSettingsSource, |
194 |
| - dotenv_settings: PydanticBaseSettingsSource, |
195 |
| - file_secret_settings: PydanticBaseSettingsSource, |
196 |
| - ) -> tuple[PydanticBaseSettingsSource, ...]: |
197 |
| - google_secret_manager_settings = GoogleSecretManagerSettingsSource( |
198 |
| - settings_cls, secret_client=mock_secret_client |
199 |
| - ) |
200 |
| - return (init_settings, env_settings, dotenv_settings, file_secret_settings, google_secret_manager_settings) |
201 |
| - |
202 |
| - with pytest.raises(ValidationError): |
203 |
| - _ = Settings() |
| 79 | +@pytest.mark.skipif(not gcp_secret_manager, reason='pydantic-settings[gcp-secret-manager] is not installed') |
| 80 | +class TestGoogleSecretManagerSettingsSource: |
| 81 | + """Test GoogleSecretManagerSettingsSource.""" |
| 82 | + |
| 83 | + def test_secret_manager_mapping_init(self, secret_manager_mapping): |
| 84 | + assert secret_manager_mapping._project_id == 'test-project' |
| 85 | + assert len(secret_manager_mapping._loaded_secrets) == 0 |
| 86 | + |
| 87 | + def test_secret_manager_mapping_gcp_project_path(self, secret_manager_mapping, mock_secret_client): |
| 88 | + secret_manager_mapping._gcp_project_path |
| 89 | + mock_secret_client.common_project_path.assert_called_once_with('test-project') |
| 90 | + |
| 91 | + def test_secret_manager_mapping_secret_names(self, secret_manager_mapping): |
| 92 | + names = secret_manager_mapping._secret_names |
| 93 | + assert names == ['test-secret'] |
| 94 | + |
| 95 | + def test_secret_manager_mapping_getitem_success(self, secret_manager_mapping): |
| 96 | + value = secret_manager_mapping['test-secret'] |
| 97 | + assert value == 'test-value' |
| 98 | + |
| 99 | + def test_secret_manager_mapping_getitem_nonexistent_key(self, secret_manager_mapping): |
| 100 | + with pytest.raises(KeyError): |
| 101 | + _ = secret_manager_mapping['nonexistent-secret'] |
| 102 | + |
| 103 | + def test_secret_manager_mapping_getitem_access_error(self, secret_manager_mapping, mocker): |
| 104 | + secret_manager_mapping._secret_client.access_secret_version = mocker.Mock( |
| 105 | + side_effect=Exception('Access denied') |
| 106 | + ) |
| 107 | + |
| 108 | + with pytest.raises(KeyError): |
| 109 | + _ = secret_manager_mapping['test-secret'] |
| 110 | + |
| 111 | + def test_secret_manager_mapping_iter(self, secret_manager_mapping): |
| 112 | + assert list(secret_manager_mapping) == ['test-secret'] |
| 113 | + |
| 114 | + def test_settings_source_init_with_defaults(self, mock_google_auth, test_settings): |
| 115 | + source = GoogleSecretManagerSettingsSource(test_settings) |
| 116 | + assert source._project_id == 'default-project' |
| 117 | + |
| 118 | + def test_settings_source_init_with_custom_values(self, mocker, test_settings): |
| 119 | + credentials = mocker.Mock() |
| 120 | + source = GoogleSecretManagerSettingsSource(test_settings, credentials=credentials, project_id='custom-project') |
| 121 | + assert source._project_id == 'custom-project' |
| 122 | + assert source._credentials == credentials |
| 123 | + |
| 124 | + def test_settings_source_init_with_custom_values_no_project_raises_error(self, mocker, test_settings): |
| 125 | + credentials = mocker.Mock() |
| 126 | + mocker.patch('pydantic_settings.sources.providers.gcp.google_auth_default', return_value=(mocker.Mock(), None)) |
| 127 | + |
| 128 | + with pytest.raises(AttributeError): |
| 129 | + _ = GoogleSecretManagerSettingsSource(test_settings, credentials=credentials) |
| 130 | + |
| 131 | + def test_settings_source_load_env_vars(self, mock_secret_client, mocker, test_settings): |
| 132 | + credentials = mocker.Mock() |
| 133 | + source = GoogleSecretManagerSettingsSource(test_settings, credentials=credentials, project_id='test-project') |
| 134 | + source._secret_client = mock_secret_client |
| 135 | + |
| 136 | + env_vars = source._load_env_vars() |
| 137 | + assert isinstance(env_vars, GoogleSecretManagerMapping) |
| 138 | + assert env_vars.get('test-secret') == 'test-value' |
| 139 | + assert env_vars.get('another_secret') is None |
| 140 | + |
| 141 | + def test_settings_source_repr(self, test_settings): |
| 142 | + source = GoogleSecretManagerSettingsSource(test_settings, project_id='test-project') |
| 143 | + assert 'test-project' in repr(source) |
| 144 | + assert 'GoogleSecretManagerSettingsSource' in repr(source) |
| 145 | + |
| 146 | + def test_pydantic_base_settings(self, mock_secret_client, monkeypatch, mocker): |
| 147 | + monkeypatch.setenv('ANOTHER_SECRET', 'yep_this_one') |
| 148 | + |
| 149 | + class Settings(BaseSettings, case_sensitive=False): |
| 150 | + test_secret: str = Field(..., alias='test-secret') |
| 151 | + another_secret: str = Field(..., alias='ANOTHER_SECRET') |
| 152 | + |
| 153 | + @classmethod |
| 154 | + def settings_customise_sources( |
| 155 | + cls, |
| 156 | + settings_cls: type[BaseSettings], |
| 157 | + init_settings: PydanticBaseSettingsSource, |
| 158 | + env_settings: PydanticBaseSettingsSource, |
| 159 | + dotenv_settings: PydanticBaseSettingsSource, |
| 160 | + file_secret_settings: PydanticBaseSettingsSource, |
| 161 | + ) -> tuple[PydanticBaseSettingsSource, ...]: |
| 162 | + google_secret_manager_settings = GoogleSecretManagerSettingsSource( |
| 163 | + settings_cls, secret_client=mock_secret_client |
| 164 | + ) |
| 165 | + return ( |
| 166 | + init_settings, |
| 167 | + env_settings, |
| 168 | + dotenv_settings, |
| 169 | + file_secret_settings, |
| 170 | + google_secret_manager_settings, |
| 171 | + ) |
| 172 | + |
| 173 | + settings = Settings() # type: ignore |
| 174 | + assert settings.another_secret == 'yep_this_one' |
| 175 | + assert settings.test_secret == 'test-value' |
| 176 | + |
| 177 | + def test_pydantic_base_settings_with_unknown_attribute(self, mock_secret_client, monkeypatch, mocker): |
| 178 | + from pydantic_core._pydantic_core import ValidationError |
| 179 | + |
| 180 | + class Settings(BaseSettings, case_sensitive=False): |
| 181 | + test_secret: str = Field(..., alias='test-secret') |
| 182 | + another_secret: str = Field(..., alias='ANOTHER_SECRET') |
| 183 | + |
| 184 | + @classmethod |
| 185 | + def settings_customise_sources( |
| 186 | + cls, |
| 187 | + settings_cls: type[BaseSettings], |
| 188 | + init_settings: PydanticBaseSettingsSource, |
| 189 | + env_settings: PydanticBaseSettingsSource, |
| 190 | + dotenv_settings: PydanticBaseSettingsSource, |
| 191 | + file_secret_settings: PydanticBaseSettingsSource, |
| 192 | + ) -> tuple[PydanticBaseSettingsSource, ...]: |
| 193 | + google_secret_manager_settings = GoogleSecretManagerSettingsSource( |
| 194 | + settings_cls, secret_client=mock_secret_client |
| 195 | + ) |
| 196 | + return ( |
| 197 | + init_settings, |
| 198 | + env_settings, |
| 199 | + dotenv_settings, |
| 200 | + file_secret_settings, |
| 201 | + google_secret_manager_settings, |
| 202 | + ) |
| 203 | + |
| 204 | + with pytest.raises(ValidationError): |
| 205 | + _ = Settings() |
0 commit comments