import pytest from mltrail_verifiable_provenance_ledger_for.ledger import Ledger, delta_sync from mltrail_verifiable_provenance_ledger_for.contracts import Experiment, Run, Dataset, Model, Environment, EvaluationMetric, Policy def test_ledger_append_and_chain(): ledger = Ledger() e = Experiment(id="exp1", name="Demo", version=1, description="test", metadata={"owner": "alice"}) ledger.add_record("Experiment", e.to_dict()) head1 = ledger.head assert head1.index == 1 assert head1.previous_hash == "0" * 64 assert len(head1.data) == 1 # Add a Run in a new block r = Run(id="run1", experiment_id="exp1", parameters={"lr": 0.01}, metrics={"acc": 0.9}, environment_hash="abc123") ledger.add_record("Run", r.to_dict()) head2 = ledger.head assert head2.index == 2 assert head2.previous_hash == head1.hash assert len(head2.data) == 1 def test_delta_sync_basic(): a = Ledger() b = Ledger() # A has two blocks now a.add_record("Experiment", Experiment(id="exp1", name="Demo", version=1, description="test", metadata={}).to_dict()) a.add_record("Run", Run(id="run1", experiment_id="exp1", parameters={}, metrics={}, environment_hash="e1").to_dict()) # B only has genesis and first block (simulate partition) b.add_record("Experiment", Experiment(id="exp1", name="Demo", version=1, description="test", metadata={}).to_dict()) delta = delta_sync(a, b.head_hash()) assert isinstance(delta, list) assert len(delta) == 1 or len(delta) == 2 # depending on whether b's head matches a's first block def test_environment_hash_reproducibility(): from mltrail_verifiable_provenance_ledger_for.util import environment_hash deps1 = {"numpy": "1.26.0", "pandas": "2.0.0"} deps2 = {"pandas": "2.0.0", "numpy": "1.26.0"} assert environment_hash(deps1) == environment_hash(deps2)