1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
"""
A video in a photo folder (a phone's clips, backed up beside its photos,
docs/MESHBAY_DESIGN.md §9.12) is probed and thumbnailed by the video enricher,
so the Photos app can show it in its album; one outside every photo folder
and every video folder is left alone, as before.
"""
import asyncio
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_common.crypto import generate_gek
from meshbay_node.config import Config, GroupConfig, HubConfig, KeystoreConfig, NodeConfig
from meshbay_node.daemon import NodeDaemon
from meshbay_node.indexer import DirectoryIndexer
from meshbay_node.indexer.enrich import Enricher
from meshbay_node.indexer.enrich_photo import PhotoEnricher
from meshbay_node.media_cache import MediaCache
from meshbay_node.roster import Roster
from conftest import one_root
pytestmark = pytest.mark.asyncio
def _free_port() -> int:
import socket
with socket.socket() as s:
s.bind(("127.0.0.1", 0))
return s.getsockname()[1]
async def _make_daemon(tmp_path, shared, group_id):
config = Config(
hub=HubConfig(url="http://localhost:9999", username="testuser"),
node=NodeConfig(quic_port=_free_port(), ui_port=_free_port()),
groups=[GroupConfig(
id=group_id, name="test-group", shared_dir=str(shared),
visibility="private", quic_port=29015,
)],
keystore=KeystoreConfig(path=tmp_path / "keystore.enc"),
data_dir=tmp_path / "data",
)
daemon = NodeDaemon(config)
daemon._broadcast_coalesce_secs = 0.01
daemon._media_cache = MediaCache(db_path=tmp_path / "media_cache.db")
await daemon._media_cache.open()
daemon._enricher = Enricher(daemon._media_cache)
daemon._photo_enricher = PhotoEnricher(daemon._media_cache)
daemon._roster = Roster(db_path=tmp_path / "roster.db")
await daemon._roster.open()
return daemon
async def test_a_video_in_a_photo_folder_goes_to_the_video_enricher(tmp_path):
group_id = "b" * 32
shared = tmp_path / "shared"
(shared / "Photos" / "bob-photos").mkdir(parents=True)
(shared / "Photos" / "bob-photos" / "clip.mp4").write_bytes(b"a clip")
(shared / "Photos" / "bob-photos" / "shot.jpg").write_bytes(b"a photo")
(shared / "elsewhere.mp4").write_bytes(b"not in any app folder")
daemon = await _make_daemon(tmp_path, shared, group_id)
video_spawned, photo_spawned = [], []
daemon._enricher.spawn = lambda entry, path, on_done: video_spawned.append(entry.name)
daemon._photo_enricher.spawn = lambda entry, path, on_done: photo_spawned.append(entry.name)
try:
await daemon._roster.set_app_directories(group_id, "photo", ["shared/Photos"], set_by="op")
indexer = DirectoryIndexer(
roots=one_root(shared), group_id=group_id,
sk_node=Ed25519PrivateKey.generate(), gek=generate_gek())
await indexer.initial_scan()
await daemon._on_index_change(indexer)
await asyncio.sleep(0.05)
assert video_spawned == ["clip.mp4"]
assert photo_spawned == ["shot.jpg"]
finally:
await daemon._media_cache.close()
await daemon._roster.close()
|