personal memory agent
1# SPDX-License-Identifier: AGPL-3.0-only
2# Copyright (c) 2026 sol pbc
3
4from __future__ import annotations
5
6import json
7import os
8from pathlib import Path
9
10import pytest
11from cryptography.hazmat.primitives import serialization
12
13import solstone.observe.peer_lookup as peer_lookup
14import solstone.think.utils as think_utils
15from solstone.think.link.ca import cert_fingerprint, generate_ca
16
17
18def _set_journal(monkeypatch: pytest.MonkeyPatch, journal: Path) -> None:
19 monkeypatch.setenv("SOLSTONE_JOURNAL", str(journal))
20 think_utils._journal_path_cache = None
21 peer_lookup._cache.clear()
22
23
24def _write_peer(
25 journal: Path,
26 instance_id: str,
27 label: str,
28 *,
29 endpoints: list[dict[str, object]] | None = None,
30) -> Path:
31 peer_dir = journal / "peers" / instance_id
32 peer_dir.mkdir(parents=True)
33 ca = generate_ca(peer_dir / "ca")
34 cert_pem = ca.cert.public_bytes(serialization.Encoding.PEM).decode("ascii")
35 (peer_dir / "cert.pem").write_text(cert_pem, encoding="utf-8")
36 (peer_dir / "private.pem").write_text("private", encoding="utf-8")
37 (peer_dir / "chain.pem").write_text(cert_pem, encoding="utf-8")
38 (peer_dir / "home_attestation.jwt").write_text("jwt", encoding="utf-8")
39 (peer_dir / "peer.json").write_text(
40 json.dumps(
41 {
42 "label": label,
43 "instance_id": instance_id,
44 "home_label": "solstone",
45 "local_endpoints": endpoints or [{"ip": "127.0.0.1", "port": 7657}],
46 }
47 ),
48 encoding="utf-8",
49 )
50 return peer_dir
51
52
53def test_resolve_peer_happy_path(
54 tmp_path: Path, monkeypatch: pytest.MonkeyPatch
55) -> None:
56 journal = tmp_path / "journal"
57 _set_journal(monkeypatch, journal)
58 peer_dir = _write_peer(
59 journal,
60 "12345678-1234-1234-1234-123456789abc",
61 "host-a",
62 )
63
64 info = peer_lookup.resolve_peer("host-a")
65
66 assert info.dir == peer_dir
67 assert info.instance_id == "12345678-1234-1234-1234-123456789abc"
68 assert info.label == "host-a"
69 assert info.local_endpoints == [{"ip": "127.0.0.1", "port": 7657}]
70 expected = cert_fingerprint((peer_dir / "cert.pem").read_text(encoding="utf-8"))
71 assert info.cert_fingerprint == expected
72 assert info.cert_fingerprint.startswith("sha256:")
73
74
75def test_resolve_peer_no_match_lists_available(
76 tmp_path: Path,
77 monkeypatch: pytest.MonkeyPatch,
78) -> None:
79 journal = tmp_path / "journal"
80 _set_journal(monkeypatch, journal)
81 (journal / "peers").mkdir(parents=True)
82
83 with pytest.raises(peer_lookup.PeerLookupError, match="available: none"):
84 peer_lookup.resolve_peer("missing")
85
86 _write_peer(journal, "iid-a", "host-a")
87 _write_peer(journal, "iid-b", "host-b")
88
89 with pytest.raises(peer_lookup.PeerLookupError) as exc_info:
90 peer_lookup.resolve_peer("missing")
91
92 message = str(exc_info.value)
93 assert 'no peer with label "missing"' in message
94 assert "available: host-a, host-b" in message
95
96
97def test_resolve_peer_multiple_matches(
98 tmp_path: Path,
99 monkeypatch: pytest.MonkeyPatch,
100) -> None:
101 journal = tmp_path / "journal"
102 _set_journal(monkeypatch, journal)
103 _write_peer(journal, "iid-a", "host-a")
104 _write_peer(journal, "iid-b", "host-a")
105
106 with pytest.raises(peer_lookup.PeerLookupError) as exc_info:
107 peer_lookup.resolve_peer("host-a")
108
109 message = str(exc_info.value)
110 assert 'multiple peers with label "host-a"' in message
111 assert "iid-a" in message
112 assert "iid-b" in message
113 assert "use <journal_root>/peers/<instance_id>" in message
114
115
116def test_resolve_peer_cache_invalidates_on_peers_dir_mtime(
117 tmp_path: Path,
118 monkeypatch: pytest.MonkeyPatch,
119) -> None:
120 journal = tmp_path / "journal"
121 _set_journal(monkeypatch, journal)
122 _write_peer(journal, "iid-a", "host-a")
123
124 assert peer_lookup.resolve_peer("host-a").instance_id == "iid-a"
125
126 peers_dir = journal / "peers"
127 _write_peer(journal, "iid-b", "host-b")
128 stat = peers_dir.stat()
129 os.utime(peers_dir, ns=(stat.st_atime_ns, stat.st_mtime_ns + 1_000_000_000))
130
131 assert peer_lookup.resolve_peer("host-b").instance_id == "iid-b"