forked from retoor/devplacepy
Code Farm: per-plot auto-replant pause and crop-lock check; community sync and node work
Continuous Delivery could never be turned off once a crop was planted. Add a one-shot per-plot "stop after harvest" flag (POST /game/plot/stop, Devii tool game_plot_stop, game_plots.stop_after_harvest), cleared by the next plant, autoreplant claim or Refactor. Autoreplant now also respects crop locks through the shared _crop_lock predicate. Plan and measurements in happyplanting.md. Also includes the pending community sync, node network and related work in the tree; the full suite passed (4999) with all of it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -83,3 +83,67 @@ def test_envelope_normalizes_origin_and_bounds_batch():
|
||||
SyncBatchForm(origin="other.org", records=[{}] * (LIMITS.max_batch_records + 1))
|
||||
with pytest.raises(ValidationError):
|
||||
SyncBatchForm(origin="bad origin", records=[{}])
|
||||
|
||||
|
||||
def test_new_kinds_have_models_and_a_published_schema():
|
||||
from devplacepy.services.sync.records import RECORD_MODELS
|
||||
from devplacepy.services.sync.spec import KINDS
|
||||
|
||||
assert set(RECORD_MODELS) == set(KINDS)
|
||||
for model in RECORD_MODELS.values():
|
||||
assert model.model_json_schema()["title"]
|
||||
|
||||
|
||||
def test_vote_value_and_target_kind_are_closed_sets():
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from devplacepy.services.sync.records import VoteRecord
|
||||
|
||||
base = {"origin_uid": "v", "voter_uid": "u", "target_kind": "post", "target_uid": "p", "value": 1, "created_at": "2025-01-01T00:00:00Z"}
|
||||
assert VoteRecord.model_validate(base).value == 1
|
||||
for change in ({"value": 0}, {"value": 2}, {"target_kind": "gist"}, {"voter_uid": "bad id"}):
|
||||
with pytest.raises(ValidationError):
|
||||
VoteRecord.model_validate({**base, **change})
|
||||
|
||||
|
||||
def test_attachment_fingerprint_ignores_the_blob_but_not_its_hash():
|
||||
import base64
|
||||
|
||||
from devplacepy.services.sync.records import AttachmentRecord
|
||||
|
||||
def make(data):
|
||||
return AttachmentRecord.model_validate({
|
||||
"origin_uid": "a", "author_uid": "u", "target_kind": "post", "target_uid": "p",
|
||||
"filename": "dir/evil\\name.png", "content_b64": base64.b64encode(data).decode(), "created_at": "2025-01-01T00:00:00Z",
|
||||
})
|
||||
|
||||
first, second = make(b"one"), make(b"two")
|
||||
assert first.filename == "name.png"
|
||||
assert "content_b64" not in first.content_fields() and first.content_fields()["sha256"] != second.content_fields()["sha256"]
|
||||
assert first.content_bytes() == b"one"
|
||||
|
||||
|
||||
def test_batch_byte_cap(monkeypatch):
|
||||
import pytest
|
||||
from dataclasses import replace
|
||||
from pydantic import ValidationError
|
||||
|
||||
from devplacepy.services.sync import records
|
||||
from devplacepy.services.sync.spec import LIMITS
|
||||
|
||||
monkeypatch.setattr(records, "LIMITS", replace(LIMITS, max_batch_bytes=100))
|
||||
with pytest.raises(ValidationError):
|
||||
records.SyncBatchForm(origin="a.b", records=[{"x": "y" * 200}])
|
||||
|
||||
|
||||
def test_ack_form_validates_kinds_and_ids():
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from devplacepy.services.sync.records import SyncAckForm
|
||||
|
||||
assert SyncAckForm(origin="A.B", items='[{"kind": "posts", "origin_uid": "p1"}]').items == [{"kind": "posts", "origin_uid": "p1"}]
|
||||
for items in ([], [{"kind": "gists", "origin_uid": "x"}], [{"kind": "posts", "origin_uid": ""}], "not json"):
|
||||
with pytest.raises(ValidationError):
|
||||
SyncAckForm(origin="a.b", items=items)
|
||||
|
||||
Reference in New Issue
Block a user