from __future__ import annotations
import json
import sys
import urllib.error
from pathlib import Path
import pytest
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from dev_harness import mobile_fixtures as mf
from dev_harness.session_evidence import EvidenceError
class TestFixtureLoading:
def test_v1_fixture_loads_deterministically(self) -> None:
fixture = mf.load_fixture("v1")
assert fixture.version == "v1"
user = fixture.default_user
assert user.uid == "omi-fixture-v1-user-1"
assert user.email.endswith("@local.test")
assert mf.load_fixture("v1").default_user == user
def test_unknown_version_names_available_fixtures(self) -> None:
with pytest.raises(mf.FixtureError, match="available: \\['v1'\\]"):
mf.load_fixture("v99")
def test_fixture_declaring_the_wrong_version_is_rejected(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
directory = tmp_path / "fixtures"
directory.mkdir()
(directory / "v2.json").write_text(json.dumps({"fixture_version": "v3", "auth": {"users": []}}), "utf-8")
monkeypatch.setattr(mf, "FIXTURES_DIR", directory)
with pytest.raises(mf.FixtureError, match="declares version 'v3'"):
mf.load_fixture("v2")
def test_non_reserved_domain_email_is_rejected(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
directory = tmp_path / "fixtures"
directory.mkdir()
(directory / "v5.json").write_text(
json.dumps(
{
"fixture_version": "v5",
"auth": {"users": [{"uid": "real-ish", "email": "someone@gmail.com"}]},
}
),
"utf-8",
)
monkeypatch.setattr(mf, "FIXTURES_DIR", directory)
with pytest.raises(mf.FixtureError, match="@local.test"):
mf.load_fixture("v5")
class TestEgressFailClosed:
@pytest.mark.parametrize(
"base_url",
["https://api.omi.me/", "https://api.omiapi.com/", "http://api.omi.me/", "https://10.0.2.2:8000/"],
)
def test_off_loopback_backends_are_refused_before_any_request(self, base_url: str) -> None:
def _must_not_request(url: str, form: dict) -> dict:
raise AssertionError(f"request escaped to {url}")
with pytest.raises((mf.FixtureError, Exception)) as excinfo:
mf.seed_synthetic_user(base_url, mf.load_fixture("v1"), post=_must_not_request)
message = str(excinfo.value)
assert "loopback" in message or "production host" in message or "plain http" in message
def test_production_host_is_named_explicitly(self) -> None:
with pytest.raises(Exception, match="production host 'api.omi.me'"):
mf.backend_endpoint("https://api.omi.me/")
def test_https_loopback_is_refused(self) -> None:
with pytest.raises(Exception, match="plain http"):
mf.backend_endpoint("https://127.0.0.1:8000/")
def _ok_post(url: str, form: dict) -> dict:
assert url == "http://127.0.0.1:8300/v1/auth/local-dev/custom-token"
assert form["uid"] == "omi-fixture-v1-user-1"
return {"custom_token": "minted-token-value", "uid": form["uid"], "provider": "local_dev"}
class TestSeeding:
def test_happy_path_receipt_never_contains_the_token(self) -> None:
receipt = mf.seed_synthetic_user("http://127.0.0.1:8300/", mf.load_fixture("v1"), post=_ok_post)
serialized = json.dumps(receipt)
assert "minted-token-value" not in serialized
assert receipt["token_minted"] is True
assert receipt["token_retained"] is False
assert receipt["fixture_version"] == "v1"
assert receipt["uid"] == "omi-fixture-v1-user-1"
def test_404_explains_the_emulator_gate(self) -> None:
def _not_found(url: str, form: dict) -> dict:
raise urllib.error.HTTPError(url, 404, "Not Found", None, None)
with pytest.raises(mf.FixtureError, match="Firebase Auth emulator"):
mf.seed_synthetic_user("http://127.0.0.1:8300/", mf.load_fixture("v1"), post=_not_found)
def test_unreachable_backend_fails_closed_with_reason(self) -> None:
def _down(url: str, form: dict) -> dict:
raise urllib.error.URLError("connection refused")
with pytest.raises(mf.FixtureError, match="unreachable"):
mf.seed_synthetic_user("http://127.0.0.1:8300/", mf.load_fixture("v1"), post=_down)
def test_token_for_the_wrong_uid_is_rejected(self) -> None:
def _wrong_uid(url: str, form: dict) -> dict:
return {"custom_token": "tok", "uid": "someone-else"}
with pytest.raises(mf.FixtureError, match="someone-else"):
mf.seed_synthetic_user("http://127.0.0.1:8300/", mf.load_fixture("v1"), post=_wrong_uid)
def test_missing_token_in_response_is_rejected(self) -> None:
with pytest.raises(mf.FixtureError, match="no custom_token"):
mf.seed_synthetic_user("http://127.0.0.1:8300/", mf.load_fixture("v1"), post=lambda url, form: {})
class TestSeedReceipts:
def test_receipt_with_credential_key_is_refused(self, tmp_path: Path) -> None:
receipt = mf.seed_synthetic_user("http://127.0.0.1:8300/", mf.load_fixture("v1"), post=_ok_post)
receipt["custom_token"] = "minted-token-value"
with pytest.raises(EvidenceError, match="credential-free"):
mf.write_seed_receipt(tmp_path / "seed.json", receipt)
def test_clean_receipt_roundtrips(self, tmp_path: Path) -> None:
receipt = mf.seed_synthetic_user("http://127.0.0.1:8300/", mf.load_fixture("v1"), post=_ok_post)
path = mf.write_seed_receipt(tmp_path / "seed.json", receipt)
assert mf.read_seed_receipt(path)["uid"] == receipt["uid"]