fix: keep Langflow flow names in sync files, write them world-readable

This commit is contained in:
Jonas Miederer 2026-09-25 10:44:13 +02:00
parent 95a1c1afb7
commit 3ee997cb72
8 changed files with 58 additions and 769 deletions

View file

@ -5,11 +5,15 @@ import json
from app.flows import export
def test_slugify():
assert export.slugify("Dachsanierung 200k") == "dachsanierung-200k"
assert export.slugify(" A/B\\C ") == "a-b-c"
assert export.slugify("simple_rule") == "simple-rule"
assert export.slugify("") == "flow"
def test_filename_stem_keeps_original_names():
assert export.filename_stem("simple_rule") == "simple_rule"
assert export.filename_stem("test_flow") == "test_flow"
assert export.filename_stem("Gehaltserhöhung") == "Gehaltserhöhung"
assert export.filename_stem("Dachsanierung 200k") == "Dachsanierung 200k"
assert export.filename_stem(" A/B\\C ") == "A-B-C"
assert export.filename_stem('a:b*c?d"e<f>g|h') == "a-b-c-d-e-f-g-h"
assert export.filename_stem("trailing...") == "trailing"
assert export.filename_stem("") == "flow"
def test_canonical_bytes_stable_under_key_reorder():
@ -22,7 +26,7 @@ def test_canonical_bytes_stable_under_key_reorder():
def test_write_and_read_roundtrip_is_byte_stable(tmp_path):
doc = {"name": "My Flow", "data": {"nodes": [], "edges": []}}
path = export.write_flow_file(tmp_path, doc)
assert path == tmp_path / "my-flow.json"
assert path == tmp_path / "My Flow.json"
assert json.loads(path.read_text()) == doc
# Rewriting identical content is byte-identical (no phantom git diffs).
before = path.read_bytes()
@ -64,3 +68,15 @@ def test_find_reuse_path_no_match_and_missing_dir(tmp_path):
def test_find_reuse_path_skips_unreadable_files(tmp_path):
(tmp_path / "kaputt.json").write_text("{kein json")
assert export.find_reuse_path(tmp_path, {"name": "Neu"}) == (None, False)
def test_write_flow_file_is_world_readable(tmp_path):
import os
import stat
doc = {"name": "Lesbar", "data": {"nodes": [], "edges": []}}
path = export.write_flow_file(tmp_path, doc)
mode = stat.S_IMODE(os.stat(path).st_mode)
# Read bits for user/group/other (mkstemp defaults to 0o600; on Windows
# chmod maps to 0o666, so only assert the read bits, not the exact mode).
assert mode & 0o444 == 0o444, f"expected world-readable, got {oct(mode)}"

View file

@ -163,17 +163,17 @@ async def test_sync_endpoint_pulls_from_langflow_then_syncs(
response = await client.post("/api/flows/sync")
assert response.status_code == 200, response.text
body = response.json()
assert body["pulled"] == ["gehaltserh-hung"]
assert body["added"] == ["gehaltserh-hung"]
assert body["pulled"] == ["Gehaltserhöhung"]
assert body["added"] == ["Gehaltserhöhung"]
assert body["errors"] == {}
assert (tmp_path / "gehaltserh-hung.json").is_file()
assert (tmp_path / "Gehaltserhöhung.json").is_file()
# Second pass: same content pulls again but syncs nothing new.
response = await client.post("/api/flows/sync")
assert response.status_code == 200, response.text
body = response.json()
assert body["pulled"] == ["gehaltserh-hung"]
assert body["skipped"] == ["gehaltserh-hung"]
assert body["pulled"] == ["Gehaltserhöhung"]
assert body["skipped"] == ["Gehaltserhöhung"]
async def test_sync_endpoint_pull_reuses_same_named_file(
@ -214,8 +214,8 @@ async def test_sync_endpoint_pull_error_continues(
response = await client.post("/api/flows/sync")
assert response.status_code == 200, response.text
body = response.json()
assert body["pulled"] == ["gut"]
assert body["added"] == ["gut"]
assert body["pulled"] == ["Gut"]
assert body["added"] == ["Gut"]
assert "kaputt-id" in body["errors"]