coulomb-social/tests/test_import_tree.py
tegwick 8447943dc0 Import Bubble export trees into PageOps and finish CSOC-WP-0001
Add import_content_tree management command and import_tree helper for
ADR-0004 sample trees. Document reichelag rehearsal lossiness; mark T02/T04
and the bubble exit workplan finished.
2026-08-13 12:48:55 +02:00

121 lines
3.9 KiB
Python

"""Import ADR-0004 tree into content plane (CSOC-WP-0001-T04 rehearsal path)."""
from pathlib import Path
import pytest
from django.core.management import call_command
from coulomb_social.apps.members.models import Member, User
from coulomb_social.apps.spaces import pageops
from coulomb_social.apps.spaces.content import load_space_page
from coulomb_social.apps.spaces.import_tree import import_space_tree
from coulomb_social.apps.spaces.models import Space, SpaceMembership
@pytest.fixture
def content_root(tmp_path, settings):
root = tmp_path / "content"
settings.CONTENT_ROOT = str(root)
return root
def _write_sample_tree(root: Path) -> Path:
tree = root / "sample-space"
pages = tree / "pages"
assets = tree / "assets"
pages.mkdir(parents=True)
assets.mkdir(parents=True)
(pages / "index.md").write_text(
"---\n"
'title: "Sample Space"\n'
'abstractor: "From export"\n'
'visual: ""\n'
'space: "sample-space"\n'
"bubble_type: space\n"
"---\n\n"
"# Sample Space\n\nLanding.\n",
encoding="utf-8",
)
(pages / "notes.md").write_text(
"---\n"
'title: "Notes"\n'
'abstractor: "Scratch"\n'
'visual: "assets/notes-visual.png"\n'
'space: "sample-space"\n'
"bubble_type: article\n"
"---\n\n"
"# Notes\n\nBody text.\n",
encoding="utf-8",
)
(assets / "notes-visual.png").write_bytes(b"\x89PNG\r\n")
return tree
@pytest.mark.django_db
def test_import_space_tree(content_root, tmp_path):
tree = _write_sample_tree(tmp_path / "export")
user = User.objects.create_user(username="imp")
member = Member.objects.create(
tenant_id="tenant:a",
user=user,
user_engine_user_id="usr_imp",
issuer="https://local.dev/issuer",
subject="imp-sub",
display_name="Importer",
)
report = import_space_tree(
tree,
tenant_id="tenant:a",
member=member,
)
assert report.pages_copied == 2
assert report.assets_copied == 1
assert report.space_created
space = Space.objects.get(tenant_id="tenant:a", slug="sample-space")
assert space.title == "Sample Space"
assert space.description == "From export"
assert SpaceMembership.objects.filter(space=space, member=member).exists()
notes = pageops.read_page("sample-space", "notes")
assert notes.exists
assert notes.title == "Notes"
assert "Body text" in notes.body
assert (pageops.space_dir("sample-space") / "assets" / "notes-visual.png").is_file()
rendered = load_space_page(space, "notes")
assert rendered.error is None
assert rendered.source == "content-plane"
assert "Body text" in rendered.html
@pytest.mark.django_db
def test_import_refuses_overwrite_without_replace(content_root, tmp_path):
tree = _write_sample_tree(tmp_path / "export")
import_space_tree(tree, tenant_id="tenant:a")
with pytest.raises(pageops.PageOpsError):
import_space_tree(tree, tenant_id="tenant:a", replace=False)
report = import_space_tree(tree, tenant_id="tenant:a", replace=True)
assert report.space_updated or report.space_created
assert report.pages_copied == 2
@pytest.mark.django_db
def test_import_content_tree_command(content_root, tmp_path, capsys):
tree = _write_sample_tree(tmp_path / "export")
call_command("import_content_tree", str(tree), "--tenant", "tenant:cmd", "--dry-run")
out = capsys.readouterr().out
assert "Dry run" in out
assert not Space.objects.filter(slug="sample-space").exists()
call_command(
"import_content_tree",
str(tree),
"--tenant",
"tenant:cmd",
"--slug",
"cmd-space",
)
space = Space.objects.get(slug="cmd-space", tenant_id="tenant:cmd")
assert space.title == "Sample Space"
assert pageops.read_page("cmd-space", "index").exists