coordinator / test (push) Waiting to run
python / test (push) Waiting to run
release / binaries (amd64, darwin) (push) Waiting to run
release / binaries (amd64, linux) (push) Waiting to run
release / binaries (amd64, windows) (push) Waiting to run
release / binaries (arm64, darwin) (push) Waiting to run
release / binaries (arm64, linux) (push) Waiting to run
release / binaries (arm64, windows) (push) Waiting to run
release / wheel (push) Waiting to run
release / release (push) Blocked by required conditions
release / image (push) Waiting to run
users / test (push) Waiting to run
688 lines
23 KiB
Python
688 lines
23 KiB
Python
"""Compatibility tests for the built-in SDK bridge and scientific reference."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import csv
|
|
from dataclasses import replace
|
|
from pathlib import Path
|
|
from uuid import uuid4
|
|
|
|
import pytest
|
|
|
|
from scimesh.chemistry.dataset import find_molecule_by_id
|
|
from scimesh.sdk import (
|
|
ArtifactCollection,
|
|
WorkloadManifest,
|
|
ArtifactSchema,
|
|
CheckpointPolicy,
|
|
CompatibilityError,
|
|
ComponentRef,
|
|
DeterminismProfile,
|
|
FeatureRequirement,
|
|
GangSpec,
|
|
JobRequest,
|
|
LocalArtifactStore,
|
|
LocalCoreBatchExecutor,
|
|
LocalPlanningContext,
|
|
NetworkPolicy,
|
|
PortRef,
|
|
ProcessModel,
|
|
RetryPolicy,
|
|
SchemaRef,
|
|
StageKind,
|
|
TrustMode,
|
|
VerificationDecision,
|
|
VerificationStatus,
|
|
VersionRange,
|
|
WorkloadDefinition,
|
|
WorkloadRegistry,
|
|
assert_manifest_round_trip,
|
|
)
|
|
from scimesh.workloads.library import default_sdk_registry, default_sdk_runtime
|
|
from scimesh.workloads.search import similarity_search_sdk_definition
|
|
from scimesh.workloads.similarity_search import search_similar, write_search_results
|
|
|
|
|
|
def _write_tiny_dataset(path: Path) -> None:
|
|
path.write_text(
|
|
"chembl_id\tcanonical_smiles\textra\n"
|
|
"QUERY\tCCO\tquery\n"
|
|
"ALCOHOL\tCCCO\talcohol\n"
|
|
"ALKANE\tCCCC\talkane\n"
|
|
"BROKEN\tnot-a-smiles\tinvalid\n"
|
|
"DUPLICATE\tCCO\tduplicate\n"
|
|
"AMINE\tCCN\tamine\n",
|
|
encoding="utf-8",
|
|
)
|
|
|
|
|
|
def _registered_similarity_search(shard_rows: int = 2):
|
|
registry = default_sdk_registry(shard_rows=shard_rows)
|
|
runtime = default_sdk_runtime()
|
|
descriptions = registry.descriptions()
|
|
assert len(descriptions) == 5
|
|
description = next(
|
|
item for item in descriptions if item.workload.name == "similarity-search"
|
|
)
|
|
definition, negotiated = registry.require(
|
|
description.workload.name,
|
|
description.workload.version,
|
|
description.package_digest,
|
|
runtime=runtime,
|
|
)
|
|
return registry, runtime, description, definition, negotiated
|
|
|
|
|
|
def _request_for(
|
|
dataset: Path,
|
|
artifact_store: LocalArtifactStore,
|
|
definition: WorkloadDefinition,
|
|
) -> JobRequest:
|
|
input_port = definition.manifest.inputs["input"]
|
|
dataset_artifact = artifact_store.import_file(
|
|
dataset,
|
|
declaration=input_port.schema,
|
|
)
|
|
return JobRequest(
|
|
workload=definition.manifest.workload,
|
|
parameters={"query_id": "QUERY", "top_k": 3, "progress_every": 0},
|
|
inputs={"input": ArtifactCollection.single(dataset_artifact)},
|
|
)
|
|
|
|
|
|
def test_builtin_similarity_search_manifest_is_registered_and_negotiable() -> None:
|
|
_, _, description, definition, negotiated = _registered_similarity_search()
|
|
manifest = definition.manifest
|
|
|
|
assert description.enabled is True
|
|
assert manifest.workload.name == "similarity-search"
|
|
assert manifest.workload.version == "1.0.0"
|
|
assert manifest.determinism is DeterminismProfile.BYTE_EXACT
|
|
assert manifest.conformance_profiles == ("core-batch-v1",)
|
|
assert [stage.kind for stage in manifest.workflow.stages] == [
|
|
StageKind.MAP,
|
|
StageKind.REDUCE,
|
|
]
|
|
assert set(definition.runners) == {manifest.workflow.stages[0].entry_point}
|
|
assert set(definition.reducers) == {manifest.workflow.stages[1].entry_point}
|
|
assert negotiated is not None
|
|
assert negotiated.manifest == manifest
|
|
assert_manifest_round_trip(manifest)
|
|
|
|
|
|
def test_local_sdk_executor_matches_similarity_search_reference(tmp_path: Path) -> None:
|
|
dataset = tmp_path / "molecules.tsv"
|
|
_write_tiny_dataset(dataset)
|
|
registry, runtime, description, definition, _ = _registered_similarity_search()
|
|
artifact_store = LocalArtifactStore(tmp_path / "artifacts")
|
|
request = _request_for(dataset, artifact_store, definition)
|
|
|
|
result = LocalCoreBatchExecutor(
|
|
registry,
|
|
runtime,
|
|
artifact_store,
|
|
tmp_path / "sdk-work",
|
|
).execute(request, description.package_digest)
|
|
result_artifact = result.outputs["result"].items[0].artifact
|
|
|
|
reference_path = tmp_path / "reference.csv"
|
|
query = find_molecule_by_id(dataset, "QUERY")
|
|
reference = search_similar(dataset, query, top_k=3, progress_every=0)
|
|
write_search_results(reference_path, reference.matches)
|
|
|
|
assert (
|
|
artifact_store.materialize(result_artifact).read_bytes()
|
|
== reference_path.read_bytes()
|
|
)
|
|
assert result.task_key == "reduce/final"
|
|
assert result.metrics == {"matches_emitted": 3, "partial_count": 3}
|
|
|
|
|
|
def test_legacy_adapter_planning_is_deterministic_ordered_and_path_free(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
dataset = tmp_path / "molecules.tsv"
|
|
_write_tiny_dataset(dataset)
|
|
registry, runtime, description, definition, _ = _registered_similarity_search()
|
|
artifact_store = LocalArtifactStore(tmp_path / "artifacts")
|
|
request = _request_for(dataset, artifact_store, definition)
|
|
input_artifact = request.inputs["input"].items[0].artifact
|
|
|
|
first = registry.plan(
|
|
request,
|
|
description.package_digest,
|
|
runtime,
|
|
LocalPlanningContext(
|
|
artifact_store,
|
|
artifact_store,
|
|
tmp_path / "first-plan",
|
|
allowed_artifacts=(input_artifact,),
|
|
),
|
|
)
|
|
second = registry.plan(
|
|
request,
|
|
description.package_digest,
|
|
runtime,
|
|
LocalPlanningContext(
|
|
artifact_store,
|
|
artifact_store,
|
|
tmp_path / "second-plan",
|
|
allowed_artifacts=(input_artifact,),
|
|
),
|
|
)
|
|
|
|
assert first.to_json() == second.to_json()
|
|
assert first.digest == second.digest
|
|
assert first.package_digest == definition.manifest.package.digest
|
|
assert first.manifest_digest == definition.manifest.digest
|
|
assert first.trust_mode is request.trust_mode
|
|
assert JobRequest.from_json(request.to_json()) == request
|
|
assert [task.task_key for task in first.tasks] == [
|
|
"map/00000000",
|
|
"map/00000001",
|
|
"map/00000002",
|
|
]
|
|
assert all(task.stage_id == "map" for task in first.tasks)
|
|
assert all(task.package_digest == first.package_digest for task in first.tasks)
|
|
assert all(task.manifest_digest == first.manifest_digest for task in first.tasks)
|
|
assert all(task.trust_mode is first.trust_mode for task in first.tasks)
|
|
assert all("query_id" not in task.parameters for task in first.tasks)
|
|
assert all(task.parameters["query_smiles"] == "CCO" for task in first.tasks)
|
|
|
|
shard_ids: list[list[str]] = []
|
|
for task in first.tasks:
|
|
artifact = task.inputs["input"].items[0].artifact
|
|
with artifact_store.materialize(artifact).open(
|
|
encoding="utf-8", newline=""
|
|
) as source:
|
|
shard_ids.append(
|
|
[row["chembl_id"] for row in csv.DictReader(source, delimiter="\t")]
|
|
)
|
|
assert set(artifact.to_dict()) == {
|
|
"artifact_id",
|
|
"sha256",
|
|
"schema",
|
|
"media_type",
|
|
"size_bytes",
|
|
"records",
|
|
"dimensions",
|
|
}
|
|
assert shard_ids == [
|
|
["QUERY", "ALCOHOL"],
|
|
["ALKANE", "BROKEN"],
|
|
["DUPLICATE", "AMINE"],
|
|
]
|
|
|
|
wire_payload = first.to_json()
|
|
assert str(tmp_path) not in wire_payload
|
|
assert "file://" not in wire_payload
|
|
assert "worker://" not in wire_payload
|
|
assert "workspace" not in wire_payload
|
|
|
|
|
|
def test_local_context_sink_cannot_seal_files_outside_the_attempt(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
_, _, _, definition, _ = _registered_similarity_search()
|
|
artifact_store = LocalArtifactStore(tmp_path / "artifacts")
|
|
workspace = tmp_path / "attempt"
|
|
context = LocalPlanningContext(artifact_store, artifact_store, workspace)
|
|
outside = tmp_path / "private.txt"
|
|
outside.write_text("private", encoding="utf-8")
|
|
schema = definition.manifest.inputs["input"].schema
|
|
|
|
with pytest.raises(ValueError, match="inside its workspace"):
|
|
context.sink.seal(outside, declaration=schema)
|
|
|
|
workspace.mkdir(parents=True, exist_ok=True)
|
|
link = workspace / "result"
|
|
link.symlink_to(outside)
|
|
with pytest.raises(ValueError, match="real workspace directories"):
|
|
context.sink.seal(link, declaration=schema)
|
|
|
|
|
|
def test_local_store_rejects_malformed_content_before_publishing(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
malformed = tmp_path / "malformed.json"
|
|
malformed.write_text('{"unfinished":', encoding="utf-8")
|
|
declaration = ArtifactSchema(
|
|
SchemaRef("json-result", 1),
|
|
"application/json",
|
|
"utf-8",
|
|
max_bytes=1_024,
|
|
validator=ComponentRef("json-document", 1),
|
|
)
|
|
store = LocalArtifactStore(tmp_path / "artifacts")
|
|
|
|
with pytest.raises(ValueError, match="not a valid bounded document"):
|
|
store.import_file(malformed, declaration=declaration)
|
|
assert (
|
|
tuple(
|
|
path for path in store.root.iterdir() if not path.name.startswith(".seal-")
|
|
)
|
|
== ()
|
|
)
|
|
|
|
|
|
def test_delimited_validator_rejects_headerless_data_and_enforces_record_limit(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
declaration = ArtifactSchema(
|
|
SchemaRef("bounded-table", 1),
|
|
"text/csv",
|
|
"utf-8",
|
|
max_bytes=1_024,
|
|
validator=ComponentRef("delimited-table", 1),
|
|
validator_configuration={"columns": ["value"]},
|
|
max_records=1,
|
|
)
|
|
store = LocalArtifactStore(tmp_path / "artifacts")
|
|
headerless = tmp_path / "headerless.csv"
|
|
headerless.write_text("1\n2\n", encoding="utf-8")
|
|
oversized = tmp_path / "oversized.csv"
|
|
oversized.write_text("value\n1\n2\n", encoding="utf-8")
|
|
|
|
with pytest.raises(ValueError, match="header does not match"):
|
|
store.import_file(headerless, declaration=declaration)
|
|
with pytest.raises(ValueError, match="record limit"):
|
|
store.import_file(oversized, declaration=declaration)
|
|
|
|
|
|
def test_custom_artifact_inspector_is_bound_to_schema_and_validator_identity(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
schema_ref = SchemaRef("matrix-result", 1)
|
|
validator = ComponentRef("matrix-inspector", 1)
|
|
declaration = ArtifactSchema(
|
|
schema_ref,
|
|
"application/x-matrix",
|
|
None,
|
|
max_bytes=1_024,
|
|
validator=validator,
|
|
validator_configuration={"layout": "row-major"},
|
|
max_records=1,
|
|
max_dimensions=(2, 2),
|
|
)
|
|
source = tmp_path / "matrix.bin"
|
|
source.write_bytes(b"matrix")
|
|
wrong = LocalArtifactStore(
|
|
tmp_path / "wrong-store",
|
|
inspectors={
|
|
schema_ref.canonical: (
|
|
ComponentRef("other-inspector", 1),
|
|
lambda _path, _configuration: (1, (2, 2)),
|
|
)
|
|
},
|
|
)
|
|
with pytest.raises(ValueError, match="no matching registered validator"):
|
|
wrong.import_file(source, declaration=declaration)
|
|
|
|
def inspect(_path: Path, configuration):
|
|
assert dict(configuration) == {"layout": "row-major"}
|
|
return 1, (2, 2)
|
|
|
|
store = LocalArtifactStore(
|
|
tmp_path / "store",
|
|
inspectors={schema_ref.canonical: (validator, inspect)},
|
|
)
|
|
artifact = store.import_file(source, declaration=declaration)
|
|
assert artifact.records == 1
|
|
assert artifact.dimensions == (2, 2)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("forgery", "message"),
|
|
(
|
|
("artifact", "artifacts sealed by its attempt"),
|
|
("provenance", "provenance does not match"),
|
|
),
|
|
)
|
|
def test_local_executor_rejects_handler_forged_outputs(
|
|
tmp_path: Path,
|
|
forgery: str,
|
|
message: str,
|
|
) -> None:
|
|
dataset = tmp_path / "molecules.tsv"
|
|
_write_tiny_dataset(dataset)
|
|
_, runtime, description, original, _ = _registered_similarity_search()
|
|
map_stage = next(
|
|
stage
|
|
for stage in original.manifest.workflow.stages
|
|
if stage.kind is StageKind.MAP
|
|
)
|
|
inner = original.runners[map_stage.entry_point]
|
|
|
|
class ForgingRunner:
|
|
def run(self, context):
|
|
result = inner.run(context)
|
|
if forgery == "provenance":
|
|
forged = replace(
|
|
result.provenance,
|
|
worker_runtime={"kind": "forged-runtime"},
|
|
)
|
|
return replace(result, provenance=forged)
|
|
original_ref = result.outputs["partial"].items[0].artifact
|
|
forged_ref = replace(original_ref, artifact_id=str(uuid4()))
|
|
return replace(
|
|
result,
|
|
outputs={"partial": ArtifactCollection.single(forged_ref)},
|
|
)
|
|
|
|
definition = WorkloadDefinition(
|
|
original.manifest,
|
|
original.planner,
|
|
{map_stage.entry_point: ForgingRunner()},
|
|
original.reducers,
|
|
original.verifiers,
|
|
)
|
|
registry = WorkloadRegistry()
|
|
registry.register(definition, enabled=True)
|
|
store = LocalArtifactStore(tmp_path / "artifacts")
|
|
request = _request_for(dataset, store, definition)
|
|
|
|
with pytest.raises(ValueError, match=message):
|
|
LocalCoreBatchExecutor(registry, runtime, store, tmp_path / "work").execute(
|
|
request,
|
|
description.package_digest,
|
|
)
|
|
|
|
|
|
def test_local_executor_rejects_profiles_that_claim_network_isolation(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
dataset = tmp_path / "molecules.tsv"
|
|
_write_tiny_dataset(dataset)
|
|
_, runtime, description, original, _ = _registered_similarity_search()
|
|
stages = tuple(
|
|
replace(stage, execution=replace(stage.execution, network=NetworkPolicy.NONE))
|
|
for stage in original.manifest.workflow.stages
|
|
)
|
|
workflow = replace(original.manifest.workflow, stages=stages)
|
|
manifest = replace(original.manifest, workflow=workflow)
|
|
definition = WorkloadDefinition(
|
|
manifest,
|
|
original.planner,
|
|
original.runners,
|
|
original.reducers,
|
|
original.verifiers,
|
|
)
|
|
registry = WorkloadRegistry()
|
|
registry.register(definition, enabled=True)
|
|
store = LocalArtifactStore(tmp_path / "artifacts")
|
|
request = _request_for(dataset, store, definition)
|
|
|
|
with pytest.raises(CompatibilityError) as raised:
|
|
LocalCoreBatchExecutor(registry, runtime, store, tmp_path / "work").execute(
|
|
request,
|
|
description.package_digest,
|
|
)
|
|
assert raised.value.code == "feature-undeclared"
|
|
|
|
|
|
def test_local_executor_rejects_aliased_terminal_outputs_before_planning(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
dataset = tmp_path / "molecules.tsv"
|
|
_write_tiny_dataset(dataset)
|
|
_, runtime, description, original, _ = _registered_similarity_search()
|
|
reducer = next(
|
|
stage
|
|
for stage in original.manifest.workflow.stages
|
|
if stage.kind is StageKind.REDUCE
|
|
)
|
|
internal_name = next(iter(reducer.outputs))
|
|
workflow = replace(
|
|
original.manifest.workflow,
|
|
outputs={"aliased": PortRef(internal_name, reducer.stage_id)},
|
|
)
|
|
manifest = replace(
|
|
original.manifest,
|
|
workflow=workflow,
|
|
outputs={"aliased": reducer.outputs[internal_name]},
|
|
)
|
|
definition = WorkloadDefinition(
|
|
manifest,
|
|
original.planner,
|
|
original.runners,
|
|
original.reducers,
|
|
original.verifiers,
|
|
)
|
|
registry = WorkloadRegistry()
|
|
registry.register(definition, enabled=True)
|
|
store = LocalArtifactStore(tmp_path / "artifacts")
|
|
request = _request_for(dataset, store, definition)
|
|
|
|
with pytest.raises(ValueError, match="identity-mapped reducer outputs"):
|
|
LocalCoreBatchExecutor(registry, runtime, store, tmp_path / "work").execute(
|
|
request,
|
|
description.package_digest,
|
|
)
|
|
|
|
|
|
def test_local_executor_rejects_non_trusted_trust_modes(tmp_path: Path) -> None:
|
|
dataset = tmp_path / "molecules.tsv"
|
|
_write_tiny_dataset(dataset)
|
|
_, runtime, _, original, _ = _registered_similarity_search()
|
|
stages = tuple(
|
|
replace(stage, trust_modes=("trusted", "verified"))
|
|
for stage in original.manifest.workflow.stages
|
|
)
|
|
manifest = replace(
|
|
original.manifest,
|
|
workflow=replace(original.manifest.workflow, stages=stages),
|
|
trust_modes=(TrustMode.TRUSTED, TrustMode.VERIFIED),
|
|
)
|
|
definition = WorkloadDefinition(
|
|
manifest,
|
|
original.planner,
|
|
original.runners,
|
|
original.reducers,
|
|
original.verifiers,
|
|
)
|
|
registry = WorkloadRegistry()
|
|
registry.register(definition, enabled=True)
|
|
store = LocalArtifactStore(tmp_path / "artifacts")
|
|
request = replace(
|
|
_request_for(dataset, store, definition),
|
|
trust_mode=TrustMode.VERIFIED,
|
|
)
|
|
runtime = replace(runtime, trust_modes=(TrustMode.TRUSTED, TrustMode.VERIFIED))
|
|
|
|
with pytest.raises(ValueError, match="supports only trusted workloads"):
|
|
LocalCoreBatchExecutor(registry, runtime, store, tmp_path / "work").execute(
|
|
request,
|
|
manifest.package.digest,
|
|
)
|
|
|
|
|
|
def _advanced_execution_manifest(
|
|
original: WorkloadDefinition,
|
|
case: str,
|
|
) -> tuple[tuple[str, ...], WorkloadManifest]:
|
|
"""Declare one negotiable advanced profile the local executor cannot enforce."""
|
|
stages = original.manifest.workflow.stages
|
|
if case == "process-pool":
|
|
features = ("process-pools", "multi-process")
|
|
changed = tuple(
|
|
replace(
|
|
stage,
|
|
resources=replace(stage.resources, cpu_cores=2),
|
|
execution=replace(
|
|
stage.execution,
|
|
process_model=ProcessModel.PROCESS_POOL,
|
|
max_processes=2,
|
|
),
|
|
)
|
|
for stage in stages
|
|
)
|
|
elif case == "checkpoints":
|
|
features = ("checkpoints",)
|
|
changed = tuple(
|
|
replace(
|
|
stage,
|
|
execution=replace(
|
|
stage.execution,
|
|
checkpoint=CheckpointPolicy(
|
|
enabled=True,
|
|
schema=SchemaRef("task-state", 1),
|
|
compatibility_version=1,
|
|
),
|
|
),
|
|
)
|
|
for stage in stages
|
|
)
|
|
elif case == "retries":
|
|
features = ("retries",)
|
|
changed = tuple(
|
|
replace(stage, retry=RetryPolicy(max_attempts=2)) for stage in stages
|
|
)
|
|
elif case == "secrets":
|
|
features = ("secret-injection",)
|
|
changed = tuple(
|
|
replace(
|
|
stage,
|
|
execution=replace(stage.execution, secret_handles=("db-credential",)),
|
|
)
|
|
for stage in stages
|
|
)
|
|
elif case == "gang":
|
|
features = ("gang-leases",)
|
|
changed = tuple(
|
|
replace(
|
|
stage,
|
|
gang=GangSpec(replicas=2, per_replica_resources=stage.resources),
|
|
)
|
|
for stage in stages
|
|
)
|
|
elif case == "network-isolation":
|
|
features = ("network-isolation",)
|
|
changed = tuple(
|
|
replace(
|
|
stage,
|
|
execution=replace(stage.execution, network=NetworkPolicy.NONE),
|
|
)
|
|
for stage in stages
|
|
)
|
|
else:
|
|
assert case == "service-stage"
|
|
features = ("services",)
|
|
changed = (replace(stages[0], kind=StageKind.SERVICE),) + stages[1:]
|
|
manifest = replace(
|
|
original.manifest,
|
|
workflow=replace(original.manifest.workflow, stages=changed),
|
|
required_features=original.manifest.required_features
|
|
+ tuple(
|
|
FeatureRequirement(feature, VersionRange(">=1,<2")) for feature in features
|
|
),
|
|
)
|
|
return features, manifest
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("case", "message"),
|
|
(
|
|
("process-pool", "one non-nested host thread"),
|
|
("checkpoints", "cannot enforce this stage profile"),
|
|
("retries", "does not implement retries"),
|
|
("secrets", "cannot enforce this stage profile"),
|
|
("gang", "cannot enforce this stage profile"),
|
|
("network-isolation", "cannot enforce a restricted network policy"),
|
|
("service-stage", "does not implement advanced stages"),
|
|
),
|
|
)
|
|
def test_local_executor_rejects_profiles_it_cannot_enforce(
|
|
tmp_path: Path,
|
|
case: str,
|
|
message: str,
|
|
) -> None:
|
|
dataset = tmp_path / "molecules.tsv"
|
|
_write_tiny_dataset(dataset)
|
|
_, runtime, _, original, _ = _registered_similarity_search()
|
|
features, manifest = _advanced_execution_manifest(original, case)
|
|
definition = WorkloadDefinition(
|
|
manifest,
|
|
original.planner,
|
|
original.runners,
|
|
original.reducers,
|
|
original.verifiers,
|
|
)
|
|
registry = WorkloadRegistry()
|
|
registry.register(definition, enabled=True)
|
|
store = LocalArtifactStore(tmp_path / "artifacts")
|
|
request = _request_for(dataset, store, definition)
|
|
runtime = replace(
|
|
runtime,
|
|
features={**runtime.features, **{feature: "1.0.0" for feature in features}},
|
|
)
|
|
|
|
with pytest.raises(ValueError, match=message):
|
|
LocalCoreBatchExecutor(registry, runtime, store, tmp_path / "work").execute(
|
|
request,
|
|
manifest.package.digest,
|
|
)
|
|
|
|
|
|
def test_local_executor_fails_when_the_declared_verifier_rejects(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
dataset = tmp_path / "molecules.tsv"
|
|
_write_tiny_dataset(dataset)
|
|
_, runtime, _, original, _ = _registered_similarity_search()
|
|
|
|
class RejectingVerifier:
|
|
identity = ComponentRef("exact-artifact", 1)
|
|
|
|
def verify(self, context, candidates):
|
|
return VerificationDecision(
|
|
VerificationStatus.REJECTED,
|
|
self.identity,
|
|
"forced-rejection",
|
|
{},
|
|
)
|
|
|
|
definition = WorkloadDefinition(
|
|
original.manifest,
|
|
original.planner,
|
|
original.runners,
|
|
original.reducers,
|
|
{ComponentRef("exact-artifact", 1).canonical: RejectingVerifier()},
|
|
)
|
|
registry = WorkloadRegistry()
|
|
registry.register(definition, enabled=True)
|
|
store = LocalArtifactStore(tmp_path / "artifacts")
|
|
request = _request_for(dataset, store, definition)
|
|
|
|
with pytest.raises(ValueError, match="did not pass its declared verifier"):
|
|
LocalCoreBatchExecutor(registry, runtime, store, tmp_path / "work").execute(
|
|
request,
|
|
original.manifest.package.digest,
|
|
)
|
|
|
|
|
|
def test_local_executor_enforces_the_declared_output_byte_budget(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
dataset = tmp_path / "molecules.tsv"
|
|
_write_tiny_dataset(dataset)
|
|
runtime = default_sdk_runtime()
|
|
workload = similarity_search_sdk_definition(shard_rows=2)
|
|
# The planner pins its own manifest into every task, so the budget cut must
|
|
# be applied to the workload's manifest for plan and definition to agree.
|
|
workload.manifest = replace(
|
|
workload.manifest,
|
|
workflow=replace(workload.manifest.workflow, max_output_bytes=256),
|
|
limits=replace(workload.manifest.limits, max_output_bytes=256),
|
|
)
|
|
definition = workload.definition()
|
|
registry = WorkloadRegistry()
|
|
registry.register(definition, enabled=True)
|
|
store = LocalArtifactStore(tmp_path / "artifacts")
|
|
request = _request_for(dataset, store, definition)
|
|
|
|
with pytest.raises(ValueError, match="bytes exceed their sink limit"):
|
|
LocalCoreBatchExecutor(registry, runtime, store, tmp_path / "work").execute(
|
|
request,
|
|
definition.manifest.package.digest,
|
|
)
|