BoilerWorks

boilerworks / tests / test_manifest.py
Source Blame History 146 lines
0cb4a5e… anonymous 1 """Tests for boilerworks.manifest."""
0cb4a5e… anonymous 2
0cb4a5e… anonymous 3 from __future__ import annotations
0cb4a5e… anonymous 4
0cb4a5e… anonymous 5 import pytest
0cb4a5e… anonymous 6 from pydantic import ValidationError
0cb4a5e… anonymous 7
0cb4a5e… anonymous 8 from boilerworks.manifest import BoilerworksManifest, DataConfig, ServicesConfig
0cb4a5e… anonymous 9 from boilerworks.manifest import TestingConfig as TestingCfg
0cb4a5e… anonymous 10
0cb4a5e… anonymous 11
0cb4a5e… anonymous 12 def _make_manifest(**kwargs) -> BoilerworksManifest:
0cb4a5e… anonymous 13 defaults = {
0cb4a5e… anonymous 14 "project": "my-app",
0cb4a5e… anonymous 15 "family": "django-nextjs",
0cb4a5e… anonymous 16 "size": "full",
0cb4a5e… anonymous 17 }
0cb4a5e… anonymous 18 defaults.update(kwargs)
0cb4a5e… anonymous 19 return BoilerworksManifest(**defaults)
0cb4a5e… anonymous 20
0cb4a5e… anonymous 21
0cb4a5e… anonymous 22 class TestValidManifest:
0cb4a5e… anonymous 23 def test_minimal_manifest_passes(self) -> None:
0cb4a5e… anonymous 24 m = _make_manifest()
0cb4a5e… anonymous 25 assert m.project == "my-app"
0cb4a5e… anonymous 26 assert m.family == "django-nextjs"
0cb4a5e… anonymous 27 assert m.size == "full"
0cb4a5e… anonymous 28
0cb4a5e… anonymous 29 def test_defaults_are_correct(self) -> None:
0cb4a5e… anonymous 30 m = _make_manifest()
0cb4a5e… anonymous 31 assert m.topology == "standard"
0cb4a5e… anonymous 32 assert m.cloud is None
0cb4a5e… anonymous 33 assert m.region is None
0cb4a5e… anonymous 34 assert m.domain is None
0cb4a5e… anonymous 35 assert m.mobile is False
0cb4a5e… anonymous 36 assert m.web_presence is False
0cb4a5e… anonymous 37 assert m.compliance == []
0cb4a5e… anonymous 38 assert m.template_versions == {}
0cb4a5e… anonymous 39
0cb4a5e… anonymous 40 def test_full_manifest_passes(self, valid_manifest: BoilerworksManifest) -> None:
0cb4a5e… anonymous 41 assert valid_manifest.project == "my-app"
0cb4a5e… anonymous 42 assert valid_manifest.cloud == "aws"
0cb4a5e… anonymous 43 assert valid_manifest.region == "us-east-1"
0cb4a5e… anonymous 44
0cb4a5e… anonymous 45 def test_micro_template(self) -> None:
0cb4a5e… anonymous 46 m = _make_manifest(family="fastapi-micro", size="micro")
0cb4a5e… anonymous 47 assert m.size == "micro"
0cb4a5e… anonymous 48
0cb4a5e… anonymous 49 def test_edge_template(self) -> None:
0cb4a5e… anonymous 50 m = _make_manifest(family="astro-site", size="edge")
0cb4a5e… anonymous 51 assert m.size == "edge"
0cb4a5e… anonymous 52
0cb4a5e… anonymous 53
0cb4a5e… anonymous 54 class TestProjectSlugValidation:
0cb4a5e… anonymous 55 def test_valid_slugs(self) -> None:
0cb4a5e… anonymous 56 for slug in ["my-app", "app", "my-app-v2", "a1b2c3"]:
0cb4a5e… anonymous 57 m = _make_manifest(project=slug)
0cb4a5e… anonymous 58 assert m.project == slug
0cb4a5e… anonymous 59
0cb4a5e… anonymous 60 def test_spaces_fail(self) -> None:
0cb4a5e… anonymous 61 with pytest.raises(ValidationError, match="project name"):
0cb4a5e… anonymous 62 _make_manifest(project="my app")
0cb4a5e… anonymous 63
0cb4a5e… anonymous 64 def test_uppercase_fails(self) -> None:
0cb4a5e… anonymous 65 with pytest.raises(ValidationError, match="project name"):
0cb4a5e… anonymous 66 _make_manifest(project="MyApp")
0cb4a5e… anonymous 67
0cb4a5e… anonymous 68 def test_leading_digit_fails(self) -> None:
0cb4a5e… anonymous 69 with pytest.raises(ValidationError, match="project name"):
0cb4a5e… anonymous 70 _make_manifest(project="1app")
0cb4a5e… anonymous 71
0cb4a5e… anonymous 72 def test_underscore_fails(self) -> None:
0cb4a5e… anonymous 73 with pytest.raises(ValidationError, match="project name"):
0cb4a5e… anonymous 74 _make_manifest(project="my_app")
0cb4a5e… anonymous 75
0cb4a5e… anonymous 76 def test_empty_fails(self) -> None:
0cb4a5e… anonymous 77 with pytest.raises(ValidationError):
0cb4a5e… anonymous 78 _make_manifest(project="")
0cb4a5e… anonymous 79
0cb4a5e… anonymous 80
0cb4a5e… anonymous 81 class TestFamilyValidation:
0cb4a5e… anonymous 82 def test_unknown_family_fails(self) -> None:
0cb4a5e… anonymous 83 with pytest.raises(ValidationError, match="unknown template family"):
0cb4a5e… anonymous 84 _make_manifest(family="not-a-real-template")
0cb4a5e… anonymous 85
0cb4a5e… anonymous 86 def test_all_known_families_pass(self) -> None:
0cb4a5e… anonymous 87 from boilerworks.registry import Registry
0cb4a5e… anonymous 88
0cb4a5e… anonymous 89 registry = Registry()
0cb4a5e… anonymous 90 for t in registry.list_all():
0cb4a5e… anonymous 91 m = _make_manifest(family=t.name, size=t.size)
0cb4a5e… anonymous 92 assert m.family == t.name
0cb4a5e… anonymous 93
0cb4a5e… anonymous 94
0cb4a5e… anonymous 95 class TestYamlRoundtrip:
0cb4a5e… anonymous 96 def test_to_yaml_and_back(self, valid_manifest: BoilerworksManifest) -> None:
0cb4a5e… anonymous 97 yaml_str = valid_manifest.to_yaml()
0cb4a5e… anonymous 98 assert "my-app" in yaml_str
0cb4a5e… anonymous 99 assert "django-nextjs" in yaml_str
0cb4a5e… anonymous 100
0cb4a5e… anonymous 101 restored = BoilerworksManifest.from_yaml(yaml_str)
0cb4a5e… anonymous 102 assert restored.project == valid_manifest.project
0cb4a5e… anonymous 103 assert restored.family == valid_manifest.family
0cb4a5e… anonymous 104 assert restored.size == valid_manifest.size
0cb4a5e… anonymous 105 assert restored.cloud == valid_manifest.cloud
0cb4a5e… anonymous 106 assert restored.region == valid_manifest.region
0cb4a5e… anonymous 107
0cb4a5e… anonymous 108 def test_to_yaml_is_valid_yaml(self, valid_manifest: BoilerworksManifest) -> None:
0cb4a5e… anonymous 109 import yaml
0cb4a5e… anonymous 110
0cb4a5e… anonymous 111 yaml_str = valid_manifest.to_yaml()
0cb4a5e… anonymous 112 parsed = yaml.safe_load(yaml_str)
0cb4a5e… anonymous 113 assert isinstance(parsed, dict)
0cb4a5e… anonymous 114 assert parsed["project"] == "my-app"
0cb4a5e… anonymous 115
0cb4a5e… anonymous 116 def test_from_file(self, valid_manifest: BoilerworksManifest, tmp_path) -> None:
0cb4a5e… anonymous 117 yaml_file = tmp_path / "boilerworks.yaml"
0cb4a5e… anonymous 118 valid_manifest.to_file(yaml_file)
0cb4a5e… anonymous 119
0cb4a5e… anonymous 120 loaded = BoilerworksManifest.from_file(yaml_file)
0cb4a5e… anonymous 121 assert loaded.project == valid_manifest.project
0cb4a5e… anonymous 122 assert loaded.family == valid_manifest.family
0cb4a5e… anonymous 123
0cb4a5e… anonymous 124
0cb4a5e… anonymous 125 class TestNestedModels:
0cb4a5e… anonymous 126 def test_services_config_defaults(self) -> None:
0cb4a5e… anonymous 127 s = ServicesConfig()
0cb4a5e… anonymous 128 assert s.email is None
0cb4a5e… anonymous 129 assert s.cache == "redis"
0cb4a5e… anonymous 130
0cb4a5e… anonymous 131 def test_data_config_defaults(self) -> None:
0cb4a5e… anonymous 132 d = DataConfig()
0cb4a5e… anonymous 133 assert d.database == "postgres"
0cb4a5e… anonymous 134 assert d.migrations is True
0cb4a5e… anonymous 135 assert d.seed_data is True
0cb4a5e… anonymous 136
0cb4a5e… anonymous 137 def test_testing_config_defaults(self) -> None:
0cb4a5e… anonymous 138 t = TestingCfg()
0cb4a5e… anonymous 139 assert t.e2e is None
0cb4a5e… anonymous 140 assert t.unit is True
0cb4a5e… anonymous 141 assert t.integration is True
0cb4a5e… anonymous 142
0cb4a5e… anonymous 143 def test_services_email_options(self) -> None:
0cb4a5e… anonymous 144 for provider in ("ses", "sendgrid", "mailgun"):
0cb4a5e… anonymous 145 s = ServicesConfig(email=provider)
0cb4a5e… anonymous 146 assert s.email == provider

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button