"""Unit tests for scripts/bootstrap_db.py with a fake Mongo at the leaf. The $jsonSchema validator's runtime behavior is server-side and is not covered here; it is verified against the live cluster when the script runs. """ import json import sys from pathlib import Path import pytest sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) import bootstrap_db # noqa: E402 class FakeCollection: def __init__(self, name): self.name = name self.docs = {} self.indexes = [] def find_one(self, query, projection=None): return self.docs.get(query["_id"]) def update_one(self, query, update, upsert=False): class Result: upserted_id = None result = Result() if query["_id"] not in self.docs and upsert: self.docs[query["_id"]] = {"_id": query["_id"], **update["$setOnInsert"]} result.upserted_id = query["_id"] return result def create_index(self, keys, **options): self.indexes.append((keys, options)) return "_".join(f"{field}_{direction}" for field, direction in keys) class FakeDatabase: def __init__(self, existing=()): self.collections = {name: FakeCollection(name) for name in existing} self.options = {name: {} for name in existing} self.created = [] self.commands = [] def list_collection_names(self): return list(self.collections) def list_collections(self, filter=None): names = [filter["name"]] if filter else list(self.collections) return [ {"name": n, "options": self.options[n]} for n in names if n in self.collections ] def create_collection(self, name, **options): self.collections[name] = FakeCollection(name) self.options[name] = options self.created.append((name, options)) def command(self, name, collection, **kwargs): self.commands.append((name, collection, kwargs)) self.options[collection].update(kwargs) def __getitem__(self, name): return self.collections.setdefault(name, FakeCollection(name)) @pytest.fixture def seed_root(tmp_path): for mode in ("production", "testing"): (tmp_path / mode).mkdir() (tmp_path / mode / "woot.json").write_text( json.dumps({"categories": ["tech"], "channels": {"50-60": "1"}}) ) (tmp_path / "production" / "bestbuy.json").write_text( json.dumps( { "categories": {"a": "categoryid$a"}, "channels": {"60-70": "2"}, "extra": "ignored", } ) ) (tmp_path / "control.json").write_text( json.dumps({"monitors": {"names": ["woot"], "settings": {}}}) ) return tmp_path def test_ensure_collection_creates_absent_with_options(): db = FakeDatabase() assert bootstrap_db.ensure_collection(db, "configs", validator={"x": 1}) is True assert db.created == [("configs", {"validator": {"x": 1}})] def test_ensure_collection_skips_existing(): db = FakeDatabase(existing=["configs"]) assert bootstrap_db.ensure_collection(db, "configs") is False assert db.created == [] def test_ensure_collection_dry_run_writes_nothing(): db = FakeDatabase() assert bootstrap_db.ensure_collection(db, "configs", dry_run=True) is True assert db.created == [] def test_ensure_config_validator_applies_collmod_once(): db = FakeDatabase(existing=["configs"]) assert bootstrap_db.ensure_config_validator(db, "configs") is True assert db.commands == [ ("collMod", "configs", {"validator": bootstrap_db.CONFIG_VALIDATOR}) ] assert bootstrap_db.ensure_config_validator(db, "configs") is False assert len(db.commands) == 1 def test_ensure_config_validator_dry_run_and_missing_collection(): db = FakeDatabase(existing=["configs"]) assert bootstrap_db.ensure_config_validator(db, "configs", dry_run=True) is True assert db.commands == [] assert bootstrap_db.ensure_config_validator(db, "nope") is False def test_load_seed_configs_rejects_list_channels(tmp_path): (tmp_path / "woot.json").write_text( json.dumps({"categories": [], "channels": {"50-60": ["1", "2"]}}) ) with pytest.raises(ValueError, match="single id strings"): bootstrap_db.load_seed_configs(tmp_path) def test_alert_indexes_match_consumer_spec(): alerts = FakeCollection("alerts") bootstrap_db.ensure_alert_indexes(alerts) assert alerts.indexes == [ ([("claimed", 1), ("priority", -1), ("createdAt", 1)], {}), ( [("product_id", 1)], {"unique": True, "partialFilterExpression": {"claimed": False}}, ), ] def test_load_seed_configs_keys_by_stem_and_drops_extra_fields(seed_root): docs = bootstrap_db.load_seed_configs(seed_root / "production") assert set(docs) == {"bestbuy", "woot"} assert docs["bestbuy"] == { "categories": {"a": "categoryid$a"}, "channels": {"60-70": "2"}, } def test_load_seed_configs_rejects_missing_keys(tmp_path): (tmp_path / "bad.json").write_text(json.dumps({"categories": []})) with pytest.raises(ValueError, match="channels"): bootstrap_db.load_seed_configs(tmp_path) def test_load_seed_configs_rejects_wrong_shape_for_monitor(tmp_path): (tmp_path / "bestbuy.json").write_text( json.dumps({"categories": ["abcat0"], "channels": {}}) ) with pytest.raises(ValueError, match="categories must be dict for bestbuy"): bootstrap_db.load_seed_configs(tmp_path) (tmp_path / "bestbuy.json").unlink() (tmp_path / "woot.json").write_text( json.dumps({"categories": {"tech": "tech"}, "channels": {}}) ) with pytest.raises(ValueError, match="categories must be list for woot"): bootstrap_db.load_seed_configs(tmp_path) def test_load_seed_configs_empty_dir(tmp_path): assert bootstrap_db.load_seed_configs(tmp_path) == {} def test_seed_configs_inserts_absent_and_preserves_existing(): configs = FakeCollection("configs") configs.docs["woot"] = {"_id": "woot", "categories": ["edited"], "channels": {}} docs = { "woot": {"categories": ["tech"], "channels": {}}, "hp": {"categories": [], "channels": {}}, } assert bootstrap_db.seed_configs(configs, docs) == ["hp"] assert configs.docs["woot"]["categories"] == ["edited"] assert configs.docs["hp"] == {"_id": "hp", "categories": [], "channels": {}} def test_seed_configs_dry_run_reports_without_writing(): configs = FakeCollection("configs") docs = {"hp": {"categories": [], "channels": {}}} assert bootstrap_db.seed_configs(configs, docs, dry_run=True) == ["hp"] assert configs.docs == {} def test_load_control_seed_keys_by_id(seed_root): docs = bootstrap_db.load_control_seed(seed_root / "control.json") assert docs == {"monitors": {"names": ["woot"], "settings": {}}} def test_load_control_seed_rejects_non_object_doc(tmp_path): path = tmp_path / "control.json" path.write_text(json.dumps({"monitors": ["woot"]})) with pytest.raises(ValueError, match="monitors"): bootstrap_db.load_control_seed(path) def test_seed_control_inserts_absent_and_preserves_existing(): control = FakeCollection("control") control.docs["monitors"] = {"_id": "monitors", "names": ["edited"]} docs = {"monitors": {"names": ["woot"]}, "other": {"x": 1}} assert bootstrap_db.seed_control(control, docs) == ["other"] assert control.docs["monitors"]["names"] == ["edited"] assert control.docs["other"] == {"_id": "other", "x": 1} def test_seed_control_dry_run_reports_without_writing(): control = FakeCollection("control") assert bootstrap_db.seed_control(control, {"monitors": {}}, dry_run=True) == [ "monitors" ] assert control.docs == {} def test_bootstrap_builds_both_modes(seed_root): db = FakeDatabase() summary = bootstrap_db.bootstrap(db, seed_root=seed_root) created = dict(db.created) for suffix in ("", "_testing"): assert created[f"configs{suffix}"] == { "validator": bootstrap_db.CONFIG_VALIDATOR } assert f"alerts{suffix}" in created assert f"control{suffix}" in created for monitor in bootstrap_db.MONITORS: assert f"{monitor}{suffix}" in created assert len(db[f"alerts{suffix}"].indexes) == 2 assert summary["seeded"]["configs"] == ["bestbuy", "woot"] assert summary["seeded"]["configs_testing"] == ["woot"] assert summary["seeded"]["control"] == ["monitors"] assert summary["seeded"]["control_testing"] == ["monitors"] assert db["control"].docs["monitors"]["names"] == ["woot"] assert len(summary["created"]) == 2 * (3 + len(bootstrap_db.MONITORS)) def test_bootstrap_rerun_is_noop(seed_root): db = FakeDatabase() bootstrap_db.bootstrap(db, seed_root=seed_root) db.created.clear() summary = bootstrap_db.bootstrap(db, seed_root=seed_root) assert db.created == [] assert db.commands == [] assert summary["created"] == [] assert summary["validators"] == [] assert summary["seeded"] == { "configs": [], "configs_testing": [], "control": [], "control_testing": [], } def test_shipped_control_seed_matches_registry_shape(): """monitors doc: names list and per-name {min_percentage, ping_threshold}""" docs = bootstrap_db.load_control_seed(bootstrap_db.CONTROL_SEED) monitors = docs["monitors"] assert set(monitors["settings"]) == set(monitors["names"]) for name, settings in monitors["settings"].items(): assert set(settings) == {"min_percentage", "ping_threshold"}, name assert isinstance(settings["min_percentage"], int), name assert 40 <= settings["min_percentage"] <= 100, name assert settings["ping_threshold"] is None or isinstance( settings["ping_threshold"], int ), name def test_shipped_seed_files_load_and_match_validator_shape(): """every checked-in seed doc has the shape the validator and setup_config want""" for mode in ("production", "testing"): docs = bootstrap_db.load_seed_configs(bootstrap_db.SEED_ROOT / mode) assert docs, mode for name, doc in docs.items(): categories, channels = doc["categories"], doc["channels"] assert isinstance(categories, bootstrap_db.CATEGORY_SHAPES[name]), name if isinstance(categories, dict): assert all(isinstance(v, str) for v in categories.values()), name else: assert all(isinstance(v, str) for v in categories), name for value in channels.values(): assert isinstance(value, str) and value.isdigit(), (name, value)