Skip to content

Commit 40595da

Browse files
committed
Test undeclared Dolt support as read-only and fail-closed [skip ci]
1 parent 3fb04c3 commit 40595da

1 file changed

Lines changed: 28 additions & 153 deletions

File tree

‎tests/test_sql_services.py‎

Lines changed: 28 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Real-service conformance checks for PostgreSQL, MySQL, MariaDB, and Dolt."""
1+
"""Real-service conformance checks plus Dolt fail-closed and candidate probes."""
22

33
import os
44
from uuid import uuid4
@@ -10,8 +10,8 @@
1010
from sqlalchemy.exc import DBAPIError
1111

1212
import openstatspec
13-
import openstatspec.sql.wide as wide
1413
from openstatspec.core import UnsupportedOperationError
14+
from openstatspec.sql.dolt_conformance import DoltConformanceSource
1515
from conformance import compare_sav_semantics, write_supported_semantics_fixture
1616

1717

@@ -37,7 +37,7 @@ def source_sav(tmp_path):
3737

3838
@pytest.mark.parametrize(
3939
("environment_name", "dataset_id"),
40-
[("OPENSTATSPEC_POSTGRES_URL", "profile_pg"), ("OPENSTATSPEC_MYSQL_URL", "profile_mysql"), ("OPENSTATSPEC_MARIADB_URL", "profile_mariadb"), ("OPENSTATSPEC_DOLT_URL", "profile_dolt")],
40+
[("OPENSTATSPEC_POSTGRES_URL", "profile_pg"), ("OPENSTATSPEC_MYSQL_URL", "profile_mysql"), ("OPENSTATSPEC_MARIADB_URL", "profile_mariadb")],
4141
)
4242
def test_live_profile_import_validate_and_export(environment_name, dataset_id, source_sav, tmp_path):
4343
database_url = os.environ.get(environment_name)
@@ -70,7 +70,7 @@ def test_live_profile_import_validate_and_export(environment_name, dataset_id, s
7070

7171
@pytest.mark.parametrize(
7272
("environment_name", "dataset_id"),
73-
[("OPENSTATSPEC_POSTGRES_URL", "semantics_pg"), ("OPENSTATSPEC_MYSQL_URL", "semantics_mysql"), ("OPENSTATSPEC_MARIADB_URL", "semantics_mariadb"), ("OPENSTATSPEC_DOLT_URL", "semantics_dolt")],
73+
[("OPENSTATSPEC_POSTGRES_URL", "semantics_pg"), ("OPENSTATSPEC_MYSQL_URL", "semantics_mysql"), ("OPENSTATSPEC_MARIADB_URL", "semantics_mariadb")],
7474
)
7575
@pytest.mark.parametrize("suffix", [".sav", ".zsav"])
7676
def test_live_profile_preserves_supported_sav_semantics(environment_name, dataset_id, suffix, tmp_path):
@@ -95,168 +95,43 @@ def test_live_profile_preserves_supported_sav_semantics(environment_name, datase
9595
)
9696
assert compare_sav_semantics(source, destination) == {"equivalent": True, "differences": []}
9797

98-
def test_live_dolt_conservative_source_width_envelope(tmp_path) -> None:
98+
def test_live_dolt_is_read_only_and_rejects_writes_without_declarations(
99+
tmp_path,
100+
) -> None:
99101
database_url = os.environ.get("OPENSTATSPEC_DOLT_URL")
100102
if not database_url:
101103
pytest.skip("OPENSTATSPEC_DOLT_URL is not configured")
102-
openstatspec.initialize_catalog(database_url=database_url)
103-
token = uuid4().hex[:8]
104-
accepted_id = f"dolt_width_accepted_{token}"
105-
rejected_id = f"dolt_width_rejected_{token}"
106-
accepted_source = tmp_path / f"{accepted_id}.sav"
107-
rejected_source = tmp_path / f"{rejected_id}.sav"
108-
accepted_columns = [f"v{ordinal:03d}" for ordinal in range(1, 306)]
109-
rejected_columns = [*accepted_columns, "v306"]
110-
pyspssio.write_sav(
111-
str(accepted_source),
112-
pd.DataFrame([[float(ordinal) for ordinal in range(1, 306)]],
113-
columns=accepted_columns),
114-
)
115-
pyspssio.write_sav(
116-
str(rejected_source),
117-
pd.DataFrame([[float(ordinal) for ordinal in range(1, 307)]],
118-
columns=rejected_columns),
119-
)
120-
121-
imported = openstatspec.import_sav(
122-
accepted_source, database_url=database_url, dataset_id=accepted_id,
123-
)
124-
assert imported["case_count"] == 1
125-
assert openstatspec.validate(
126-
database_url=database_url, dataset_id=accepted_id,
127-
)["variable_count"] == 305
128104

129-
with pytest.raises(UnsupportedOperationError, match="Target capability exceeded"):
130-
openstatspec.import_sav(
131-
rejected_source, database_url=database_url, dataset_id=rejected_id,
132-
)
105+
status = DoltConformanceSource.packaged().status()
106+
assert status["status"] == "blocked_no_concrete_declarations"
107+
assert status["declaration_count"] == 0
108+
assert status["write_enabled"] is False
133109

134-
engine = create_engine(database_url)
135-
with engine.connect() as connection:
136-
assert connection.execute(text(
137-
"select count(*) from dataset where dataset_name = :name"
138-
), {"name": rejected_id}).scalar_one() == 0
139-
assert connection.execute(text(
140-
"select count(*) from dataset_catalog where dataset_id = :name"
141-
), {"name": rejected_id}).scalar_one() == 0
142-
mirror_event = connection.execute(text("""
143-
select f.dataset_id, f.direction, f.severity, f.code
144-
from fidelity_event_catalog f
145-
join operation_catalog o on o.operation_id = f.operation_id
146-
where o.source = :source
147-
"""), {"source": rejected_source.name}).mappings().one()
148-
normative_event = connection.execute(text("""
149-
select f.dataset_id, f.direction, f.severity, f.event_code
150-
from fidelity_event f
151-
where f.source_item = :source
152-
"""), {"source": rejected_source.name}).mappings().one()
153-
assert tuple(mirror_event.values()) == (
154-
None, "import", "error", "target_capability_exceeded",
155-
)
156-
assert tuple(normative_event.values()) == (
157-
None, "import", "error", "target_capability_exceeded",
158-
)
159-
assert f"data_{rejected_id}" not in inspect_database(engine).get_table_names()
110+
before = openstatspec.dolt_state_snapshot(database_url=database_url)
111+
assert before["read_only"] is True
112+
assert before["operational_write_enabled"] is False
160113

114+
rejection = "no concrete declarations; write rejected before mutation"
115+
with pytest.raises(UnsupportedOperationError, match=rejection):
116+
openstatspec.initialize_catalog(database_url=database_url)
117+
after_initialize = openstatspec.dolt_state_snapshot(database_url=database_url)
161118

162-
def test_live_dolt_post_ddl_fault_has_complete_compensating_cleanup(
163-
tmp_path, monkeypatch,
164-
) -> None:
165-
database_url = os.environ.get("OPENSTATSPEC_DOLT_URL")
166-
if not database_url:
167-
pytest.skip("OPENSTATSPEC_DOLT_URL is not configured")
168-
openstatspec.initialize_catalog(database_url=database_url)
169-
dataset_id = f"dolt_cleanup_{uuid4().hex[:8]}"
170-
source = tmp_path / f"{dataset_id}.sav"
119+
source = tmp_path / "blocked-write.sav"
171120
pyspssio.write_sav(str(source), pd.DataFrame({"answer": [1.0]}))
172-
real_store = wide.store_normative_dataset
173-
174-
def fail_after_normative_write(*args, **kwargs):
175-
real_store(*args, **kwargs)
176-
raise RuntimeError("injected Dolt post-DDL fault")
177-
178-
monkeypatch.setattr(wide, "store_normative_dataset", fail_after_normative_write)
179-
180-
with pytest.raises(RuntimeError, match="injected Dolt post-DDL fault"):
121+
with pytest.raises(UnsupportedOperationError, match=rejection):
181122
openstatspec.import_sav(
182-
source, database_url=database_url, dataset_id=dataset_id,
123+
source, database_url=database_url, dataset_id="blocked_write",
183124
)
125+
after_import = openstatspec.dolt_state_snapshot(database_url=database_url)
184126

185-
engine = create_engine(database_url)
186-
with engine.connect() as connection:
187-
assert connection.execute(text(
188-
"select count(*) from dataset where dataset_name = :name"
189-
), {"name": dataset_id}).scalar_one() == 0
190-
assert connection.execute(text(
191-
"select count(*) from dataset_catalog where dataset_id = :name"
192-
), {"name": dataset_id}).scalar_one() == 0
193-
assert connection.execute(text(
194-
"select status, dataset_id from operation_catalog where source = :source"
195-
), {"source": source.name}).one() == ("failed", None)
196-
assert connection.execute(text("""
197-
select f.dataset_id, f.direction, f.severity, f.code
198-
from fidelity_event_catalog f
199-
join operation_catalog o on o.operation_id = f.operation_id
200-
where o.source = :source
201-
"""), {"source": source.name}).one() == (
202-
None, "import", "error", "import_failed",
203-
)
204-
assert f"data_{dataset_id}" not in inspect_database(engine).get_table_names()
205-
206-
207-
def test_live_dolt_adapter_value_boundary_is_atomic() -> None:
208-
database_url = os.environ.get("OPENSTATSPEC_DOLT_URL")
209-
if not database_url:
210-
pytest.skip("OPENSTATSPEC_DOLT_URL is not configured")
211-
openstatspec.initialize_catalog(database_url=database_url)
212-
token = uuid4().hex[:8]
213-
accepted_id = f"dolt_value_accepted_{token}"
214-
rejected_id = f"dolt_value_rejected_{token}"
215-
accepted_value = "é" * 32_752
216-
rejected_value = accepted_value + "x"
217-
assert len(accepted_value.encode("utf-8")) == 65_504
218-
assert len(rejected_value.encode("utf-8")) == 65_505
219-
variables = [{
220-
"ordinal": 1, "source_name": "value", "physical_name": "value",
221-
"storage_kind": "string", "string_width": 65_504, "label": "",
222-
"format": "A65504", "measure": "nominal", "alignment": "left",
223-
"display_width": 8, "value_labels": "{}", "missing_ranges": "[]",
224-
}]
225-
226-
imported = wide.create_wide_dataset(
227-
database_url=database_url, dataset_id=accepted_id,
228-
source_name="accepted.sav", source_format="SAV",
229-
rows=[{"value": accepted_value}], variables=variables,
230-
)
231-
assert imported["case_count"] == 1
232-
233-
with pytest.raises(UnsupportedOperationError) as caught:
234-
wide.create_wide_dataset(
235-
database_url=database_url, dataset_id=rejected_id,
236-
source_name="rejected.sav", source_format="SAV",
237-
rows=[{"value": rejected_value}], variables=variables,
238-
)
239-
assert caught.value.details["reason"] == "text_value_limit"
240-
241-
engine = create_engine(database_url)
242-
accepted_table = wide.data_table_name(accepted_id)
243-
rejected_table = wide.data_table_name(rejected_id)
244-
quote = engine.dialect.identifier_preparer.quote
245-
with engine.connect() as connection:
246-
assert connection.execute(text(
247-
f"SELECT OCTET_LENGTH(value) FROM {quote(accepted_table)}"
248-
)).scalar_one() == 65_504
249-
assert connection.execute(text(
250-
"SELECT COUNT(*) FROM dataset_catalog WHERE dataset_id = :dataset_id"
251-
), {"dataset_id": rejected_id}).scalar_one() == 0
252-
assert connection.execute(text(
253-
"SELECT COUNT(*) FROM dataset WHERE dataset_name = :dataset_id"
254-
), {"dataset_id": rejected_id}).scalar_one() == 0
255-
assert rejected_table not in inspect_database(engine).get_table_names()
256-
engine.dispose()
127+
assert after_initialize["working_set_binding"] == before["working_set_binding"]
128+
assert after_import["working_set_binding"] == before["working_set_binding"]
129+
assert after_initialize["state"] == before["state"]
130+
assert after_import["state"] == before["state"]
257131

258132

259-
def test_live_dolt_published_storage_and_identifier_evidence() -> None:
133+
@pytest.mark.candidate_evidence
134+
def test_live_dolt_candidate_limit_probe_smoke() -> None:
260135
database_url = os.environ.get("OPENSTATSPEC_DOLT_URL")
261136
if not database_url:
262137
pytest.skip("OPENSTATSPEC_DOLT_URL is not configured")

0 commit comments

Comments
 (0)