DevPlace CI / test (push) Failing after 44m45s
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>
192 lines
5.2 KiB
Python
192 lines
5.2 KiB
Python
# retoor <retoor@molodetz.nl>
|
|
|
|
import time
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
from devplacepy.database import get_setting, get_table, set_setting
|
|
from devplacepy.main import app
|
|
from devplacepy.utils import register_account
|
|
|
|
_counter = [0]
|
|
|
|
|
|
def unique(prefix: str) -> str:
|
|
_counter[0] += 1
|
|
return f"{prefix}{int(time.time() * 1000)}{_counter[0]}"
|
|
|
|
|
|
def make_account(role: str = "Member") -> dict:
|
|
name = unique("syncmb")
|
|
uid, _, _ = register_account(
|
|
name, f"{name}@t.dev", "secret123", age_band="adult", accepted_terms=True
|
|
)
|
|
if role != "Member":
|
|
get_table("users").update({"uid": uid, "role": role}, ["uid"])
|
|
row = get_table("users").find_one(uid=uid)
|
|
return {
|
|
"uid": uid,
|
|
"username": name,
|
|
"headers": {"X-API-KEY": row["api_key"], "Accept": "application/json"},
|
|
}
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def client():
|
|
previous = {key: get_setting(key, "") for key in ("sync_enabled", "sync_origins")}
|
|
set_setting("sync_enabled", "1")
|
|
set_setting("sync_origins", "")
|
|
with TestClient(app) as test_client:
|
|
yield test_client
|
|
for key, value in previous.items():
|
|
set_setting(key, value)
|
|
|
|
|
|
@pytest.fixture
|
|
def admin(client):
|
|
return make_account("Admin")
|
|
|
|
|
|
@pytest.fixture
|
|
def origin():
|
|
return f"{unique('o')}.example.org"
|
|
|
|
|
|
def sync(client, admin, kind, origin, records, **extra):
|
|
response = client.post(
|
|
f"/sync/{kind}",
|
|
json={"origin": origin, "records": records, **extra},
|
|
headers=admin["headers"],
|
|
)
|
|
return response
|
|
|
|
|
|
def sync_ok(client, admin, kind, origin, records, **extra) -> dict:
|
|
response = sync(client, admin, kind, origin, records, **extra)
|
|
assert response.status_code == 200, response.text
|
|
return response.json()
|
|
|
|
|
|
def user_record(uid="u1", username="syncuser", **extra) -> dict:
|
|
return {
|
|
"origin_uid": uid,
|
|
"username": username,
|
|
"created_at": "2025-01-01T00:00:00Z",
|
|
**extra,
|
|
}
|
|
|
|
|
|
def post_record(uid="p1", author="u1", **extra) -> dict:
|
|
return {
|
|
"origin_uid": uid,
|
|
"author_uid": author,
|
|
"content": "a synced post with enough content",
|
|
"created_at": "2025-01-02T00:00:00Z",
|
|
**extra,
|
|
}
|
|
|
|
|
|
def comment_record(uid="c1", post="p1", author="u1", **extra) -> dict:
|
|
return {
|
|
"origin_uid": uid,
|
|
"post_uid": post,
|
|
"author_uid": author,
|
|
"content": "a synced comment",
|
|
"created_at": "2025-01-03T00:00:00Z",
|
|
**extra,
|
|
}
|
|
|
|
|
|
def project_record(uid="pr1", author="u1", **extra) -> dict:
|
|
return {
|
|
"origin_uid": uid,
|
|
"author_uid": author,
|
|
"title": "Synced project",
|
|
"description": "A project that came in from another community",
|
|
"created_at": "2025-01-02T00:00:00Z",
|
|
**extra,
|
|
}
|
|
|
|
|
|
def poll_record(uid="po1", post="p1", author="u1", **extra) -> dict:
|
|
return {
|
|
"origin_uid": uid,
|
|
"post_uid": post,
|
|
"author_uid": author,
|
|
"question": "Tabs or spaces?",
|
|
"options": [{"origin_uid": "a", "label": "Tabs"}, {"origin_uid": "b", "label": "Spaces"}],
|
|
"created_at": "2025-01-03T00:00:00Z",
|
|
**extra,
|
|
}
|
|
|
|
|
|
def vote_record(uid="v1", voter="u2", target="p1", kind="post", value=1, **extra) -> dict:
|
|
return {
|
|
"origin_uid": uid,
|
|
"voter_uid": voter,
|
|
"target_kind": kind,
|
|
"target_uid": target,
|
|
"value": value,
|
|
"created_at": "2025-01-04T00:00:00Z",
|
|
**extra,
|
|
}
|
|
|
|
|
|
def reaction_record(uid="r1", author="u2", target="p1", kind="post", emoji="🔥", **extra) -> dict:
|
|
return {
|
|
"origin_uid": uid,
|
|
"author_uid": author,
|
|
"target_kind": kind,
|
|
"target_uid": target,
|
|
"emoji": emoji,
|
|
"created_at": "2025-01-04T00:00:00Z",
|
|
**extra,
|
|
}
|
|
|
|
|
|
def follow_record(uid="f1", follower="u2", following="u1", **extra) -> dict:
|
|
return {
|
|
"origin_uid": uid,
|
|
"follower_uid": follower,
|
|
"following_uid": following,
|
|
"created_at": "2025-01-04T00:00:00Z",
|
|
**extra,
|
|
}
|
|
|
|
|
|
def poll_vote_record(uid="pv1", voter="u2", poll="po1", option="a", **extra) -> dict:
|
|
return {
|
|
"origin_uid": uid,
|
|
"voter_uid": voter,
|
|
"poll_uid": poll,
|
|
"option_uid": option,
|
|
"created_at": "2025-01-05T00:00:00Z",
|
|
**extra,
|
|
}
|
|
|
|
|
|
PNG_1X1 = (
|
|
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
|
|
)
|
|
|
|
|
|
def attachment_record(uid="at1", author="u1", target="p1", kind="post", filename="pixel.png", content=PNG_1X1, **extra) -> dict:
|
|
return {
|
|
"origin_uid": uid,
|
|
"author_uid": author,
|
|
"target_kind": kind,
|
|
"target_uid": target,
|
|
"filename": filename,
|
|
"content_b64": content,
|
|
"created_at": "2025-01-05T00:00:00Z",
|
|
**extra,
|
|
}
|
|
|
|
|
|
def seed_world(client, admin, origin):
|
|
sync_ok(client, admin, "users", origin, [user_record("u1", unique("wu1")), user_record("u2", unique("wu2")), user_record("u3", unique("wu3"))])
|
|
sync_ok(client, admin, "projects", origin, [project_record("pr1", "u1")])
|
|
sync_ok(client, admin, "posts", origin, [post_record("p1", "u1", project_uid="pr1")])
|
|
sync_ok(client, admin, "comments", origin, [comment_record("c1", "p1", "u2")])
|