Skip to content

Commit 76d5f94

Browse files
test: update test_settings.py for unified stores configuration
- Replace config.external tests with stores credential tests - Update template test to check for stores structure instead of object_storage - Update get_store_spec tests for new default behavior (None instead of DEFAULT_SUBFOLDING) - Add tests for default store lookup (store=None) - Add tests for loading per-store credentials from .secrets/ - Verify partition_pattern and token_length defaults
1 parent 90d6d55 commit 76d5f94

File tree

1 file changed

+90
-7
lines changed

1 file changed

+90
-7
lines changed

tests/unit/test_settings.py

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,15 @@ def test_dict_access_unwraps_secret(self):
145145
assert not isinstance(value, SecretStr)
146146
dj.config.database.password = None
147147

148-
def test_aws_secret_key_is_secret_str(self):
149-
"""AWS secret key uses SecretStr type."""
150-
dj.config.external.aws_secret_access_key = "aws_secret"
151-
assert isinstance(dj.config.external.aws_secret_access_key, SecretStr)
152-
dj.config.external.aws_secret_access_key = None
148+
def test_store_secret_key_is_secret_str(self):
149+
"""Store secret key uses SecretStr type when set."""
150+
original_stores = dj.config.stores.copy()
151+
try:
152+
dj.config.stores["test_store"] = {"secret_key": "aws_secret"}
153+
# SecretStr is handled by pydantic if defined, but stores dict doesn't enforce it
154+
assert dj.config.stores["test_store"]["secret_key"] == "aws_secret"
155+
finally:
156+
dj.config.stores = original_stores
153157

154158

155159
class TestSettingsAccess:
@@ -325,7 +329,10 @@ def test_get_store_spec_file_protocol(self):
325329
spec = dj.config.get_store_spec("test_file")
326330
assert spec["protocol"] == "file"
327331
assert spec["location"] == "/tmp/test"
328-
assert spec["subfolding"] == settings.DEFAULT_SUBFOLDING
332+
# Default is now None (no subfolding) instead of DEFAULT_SUBFOLDING
333+
assert spec["subfolding"] is None
334+
assert spec["partition_pattern"] is None
335+
assert spec["token_length"] == 8
329336
finally:
330337
dj.config.stores = original_stores
331338

@@ -342,6 +349,78 @@ def test_get_store_spec_missing_required(self):
342349
finally:
343350
dj.config.stores = original_stores
344351

352+
def test_get_store_spec_default_store(self):
353+
"""Test getting default store when store=None."""
354+
original_stores = dj.config.stores.copy()
355+
try:
356+
dj.config.stores["default"] = "my_default"
357+
dj.config.stores["my_default"] = {
358+
"protocol": "file",
359+
"location": "/tmp/default",
360+
}
361+
# Calling with None should use stores.default
362+
spec = dj.config.get_store_spec(None)
363+
assert spec["protocol"] == "file"
364+
assert spec["location"] == "/tmp/default"
365+
finally:
366+
dj.config.stores = original_stores
367+
368+
def test_get_store_spec_no_default_configured(self):
369+
"""Test error when stores.default is not configured."""
370+
original_stores = dj.config.stores.copy()
371+
try:
372+
dj.config.stores = {} # Clear stores
373+
with pytest.raises(DataJointError, match="stores.default is not configured"):
374+
dj.config.get_store_spec(None)
375+
finally:
376+
dj.config.stores = original_stores
377+
378+
379+
class TestStoreSecrets:
380+
"""Test loading store credentials from secrets directory."""
381+
382+
def test_load_store_credentials_from_secrets(self, tmp_path):
383+
"""Test loading per-store credentials from .secrets/ directory."""
384+
# Create secrets directory with store credentials
385+
secrets_dir = tmp_path / SECRETS_DIRNAME
386+
secrets_dir.mkdir()
387+
(secrets_dir / "stores.main.access_key").write_text("test_access_key")
388+
(secrets_dir / "stores.main.secret_key").write_text("test_secret_key")
389+
390+
# Create a fresh config instance
391+
cfg = settings.Config()
392+
original_stores = cfg.stores.copy()
393+
try:
394+
# Load secrets
395+
cfg._load_secrets(secrets_dir)
396+
397+
# Verify credentials were loaded
398+
assert "main" in cfg.stores
399+
assert cfg.stores["main"]["access_key"] == "test_access_key"
400+
assert cfg.stores["main"]["secret_key"] == "test_secret_key"
401+
finally:
402+
cfg.stores = original_stores
403+
404+
def test_secrets_do_not_override_existing(self, tmp_path):
405+
"""Test that secrets don't override already-configured store settings."""
406+
secrets_dir = tmp_path / SECRETS_DIRNAME
407+
secrets_dir.mkdir()
408+
(secrets_dir / "stores.main.access_key").write_text("secret_key")
409+
410+
cfg = settings.Config()
411+
original_stores = cfg.stores.copy()
412+
try:
413+
# Pre-configure the store with a key
414+
cfg.stores["main"] = {"access_key": "existing_key"}
415+
416+
# Load secrets - should not override
417+
cfg._load_secrets(secrets_dir)
418+
419+
# Existing key should be preserved
420+
assert cfg.stores["main"]["access_key"] == "existing_key"
421+
finally:
422+
cfg.stores = original_stores
423+
345424

346425
class TestDisplaySettings:
347426
"""Test display-related settings."""
@@ -418,10 +497,14 @@ def test_save_full_template(self, tmp_path):
418497
assert "database" in content
419498
assert "connection" in content
420499
assert "display" in content
421-
assert "object_storage" in content
422500
assert "stores" in content
423501
assert "loglevel" in content
424502
assert "safemode" in content
503+
# Verify stores structure
504+
assert "default" in content["stores"]
505+
assert "main" in content["stores"]
506+
assert content["stores"]["default"] == "main"
507+
assert content["stores"]["main"]["protocol"] == "file"
425508
# But still no credentials
426509
assert "password" not in content["database"]
427510
assert "user" not in content["database"]

0 commit comments

Comments
 (0)