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:
@@ -107,3 +107,73 @@ def test_clear_empties_everything():
|
||||
cache.put("GET", "u", 200, {}, b"x", False)
|
||||
cache.clear()
|
||||
assert len(cache) == 0 and cache.size_bytes == 0
|
||||
|
||||
|
||||
def test_age_moves_the_expiry_forward():
|
||||
cache, clock = make(ttl_seconds=100)
|
||||
cache.put("GET", "https://r/x", 200, {}, b"x", False, age_seconds=90)
|
||||
clock.now = 105
|
||||
assert cache.get("GET", "https://r/x") is not None
|
||||
clock.now = 111
|
||||
assert cache.get("GET", "https://r/x") is None
|
||||
|
||||
|
||||
def shared(local_db, **kwargs):
|
||||
from devplacepy.database import nodes as store
|
||||
from devplacepy.services.nodes.cache import SharedResultCache
|
||||
|
||||
store.cache_clear()
|
||||
clock = Clock()
|
||||
return SharedResultCache(clock=clock, **kwargs), clock, store
|
||||
|
||||
|
||||
def test_a_second_process_sees_what_the_first_stored(local_db):
|
||||
first, _, store = shared(local_db, ttl_seconds=60)
|
||||
assert first.put("GET", "https://r/a", 200, {"content-type": "text/plain"}, b"payload", False)
|
||||
from devplacepy.services.nodes.cache import SharedResultCache
|
||||
|
||||
second = SharedResultCache(ttl_seconds=60)
|
||||
hit = second.get("GET", "https://r/a")
|
||||
assert hit is not None and hit.body == b"payload" and hit.headers == {"content-type": "text/plain"}
|
||||
assert (second.hits, second.misses) == (1, 0)
|
||||
again = second.get("GET", "https://r/a")
|
||||
assert again is not None and second.hits == 2
|
||||
store.cache_clear()
|
||||
|
||||
|
||||
def test_the_shared_layer_honours_ttl_truncation_and_server_errors(local_db):
|
||||
cache, _, store = shared(local_db, ttl_seconds=60)
|
||||
assert not cache.put("GET", "https://r/b", 500, {}, b"x", False)
|
||||
assert not cache.put("GET", "https://r/b", 200, {}, b"x", True)
|
||||
assert store.cache_stats()["entries"] == 0
|
||||
cache.put("GET", "https://r/c", 200, {}, b"x", False)
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
assert store.cache_get("k-not-there") is None
|
||||
key = cache_key("GET", "https://r/c")
|
||||
assert store.cache_get(key) is not None
|
||||
assert store.cache_get(key, datetime.now(timezone.utc) + timedelta(seconds=120)) is None
|
||||
store.cache_clear()
|
||||
|
||||
|
||||
def test_clear_empties_both_layers(local_db):
|
||||
cache, _, store = shared(local_db, ttl_seconds=60)
|
||||
cache.put("GET", "https://r/d", 200, {}, b"x", False)
|
||||
cache.clear()
|
||||
assert len(cache) == 0 and store.cache_stats()["entries"] == 0
|
||||
|
||||
|
||||
def test_the_shared_layer_prunes_expired_rows_and_evicts_oldest_over_the_cap(local_db):
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
cache, _, store = shared(local_db, ttl_seconds=60)
|
||||
now = datetime.now(timezone.utc)
|
||||
for index in range(4):
|
||||
store.cache_put(f"k{index}", "GET", f"https://r/{index}", 200, "{}", "AAAA", 1000, 60, now + timedelta(seconds=index))
|
||||
store.cache_put("old", "GET", "https://r/old", 200, "{}", "AAAA", 10, 60, now - timedelta(seconds=300))
|
||||
removed = store.cache_prune(2500)
|
||||
assert removed["expired"] == 1 and removed["evicted"] == 2 and removed["bytes"] == 2000
|
||||
left = store.cache_stats()
|
||||
assert left["entries"] == 2
|
||||
assert store.cache_get("k0") is None and store.cache_get("k3") is not None
|
||||
store.cache_clear()
|
||||
|
||||
Reference in New Issue
Block a user