105 lines
5.1 KiB
Python
105 lines
5.1 KiB
Python
import io
|
|
import json
|
|
|
|
from test_upload import AUTH, git, publisher, service
|
|
from posts import content_similarity, title_id
|
|
|
|
|
|
BODY = "\n\n".join(f"Paragraph {i}: I walked beside the river and considered how memory changes our understanding of a place. The details matter more than the names we give them." for i in range(12))
|
|
|
|
|
|
def send(client, text, filename="essay.md"):
|
|
return client.post("/api/posts", headers=AUTH, data={"file": (io.BytesIO(text.encode()), filename)})
|
|
|
|
|
|
def test_post_validation(service):
|
|
_, client, _ = service
|
|
assert client.post("/api/posts").status_code == 401
|
|
assert client.post("/api/posts", headers=AUTH).status_code == 400
|
|
assert send(client, BODY, "../escape.md").status_code == 400
|
|
assert send(client, BODY, "essay.pdf").status_code == 400
|
|
assert send(client, "---\ntitle: [bad\n---\nBody").status_code == 400
|
|
assert send(client, "---\npost_id: ../../escape\n---\nBody").status_code == 400
|
|
assert send(client, " ").status_code == 400
|
|
assert send(client, "x" * (1024 * 1024 + 1)).status_code == 400
|
|
|
|
|
|
def test_content_update_preserves_url_date_and_no_duplicate(publisher, service, monkeypatch, tmp_path):
|
|
run, remote, client = publisher
|
|
first_text = "---\ntitle: My walk\ndate: 2020-01-02\npermalink: /my-walk/\n---\n\n" + BODY
|
|
first = send(client, first_text)
|
|
assert first.status_code == 202
|
|
assert run().returncode == 0
|
|
status = client.get(first.json["status_url"], headers=AUTH).json
|
|
assert status["action"] == "created" and status["url"] == "/my-walk/"
|
|
assert status["post_id"] == "my-walk"
|
|
second = send(client, "# My revised walk\n\n" + BODY.replace("beside the river", "along the river", 1), "renamed.md")
|
|
result = run()
|
|
assert result.returncode == 0, result.stderr
|
|
status2 = client.get(second.json["status_url"], headers=AUTH).json
|
|
assert status2["action"] == "updated"
|
|
assert status2["url"] == status["url"]
|
|
assert status2["post_id"] == status["post_id"]
|
|
paths = [p for p in git(remote, "ls-tree", "-r", "--name-only", "master").splitlines() if p.startswith("_posts/")]
|
|
assert len(paths) == 1
|
|
saved = git(remote, "show", "master:" + paths[0])
|
|
assert "2020-01-02" in saved and "along the river" in saved
|
|
assert "render_with_liquid: false" in saved
|
|
assert client.get(first.json["status_url"], headers=AUTH).json["status"] == "superseded"
|
|
receipt = tmp_path / "deployed.json"
|
|
monkeypatch.setenv("PHOTO_DEPLOYMENT_FILE", str(receipt))
|
|
receipt.write_text(json.dumps({"posts": [second.json["id"]]}))
|
|
assert client.get(second.json["status_url"], headers=AUTH).json["status"] == "published"
|
|
assert send(client, first_text).status_code == 200
|
|
|
|
|
|
def test_unrelated_same_filename_creates_new_post(publisher):
|
|
run, remote, client = publisher
|
|
send(client, BODY)
|
|
assert run().returncode == 0
|
|
response = send(client, "# Another subject\n\n" + "Astronomy explores stars, galaxies and planetary orbits. " * 20)
|
|
assert run().returncode == 0
|
|
assert client.get(response.json["status_url"], headers=AUTH).json["action"] == "created"
|
|
assert len([p for p in git(remote, "ls-tree", "-r", "--name-only", "master").splitlines() if p.startswith("_posts/")]) == 2
|
|
|
|
|
|
def test_ambiguous_matches_fail_without_pushing(publisher):
|
|
run, remote, client = publisher
|
|
for identity in ("one", "two"):
|
|
send(client, f"---\npost_id: {identity}\ntitle: {identity}\n---\n" + BODY, identity + ".md")
|
|
assert run().returncode == 0
|
|
head = git(remote, "rev-parse", "master")
|
|
response = send(client, BODY.replace("details", "small details", 1))
|
|
assert run().returncode != 0
|
|
state = client.get(response.json["status_url"], headers=AUTH).json
|
|
assert state["status"] == "failed" and "Multiple posts" in state["error"]
|
|
assert git(remote, "rev-parse", "master") == head
|
|
|
|
|
|
def test_similarity_requires_substantial_unambiguous_content():
|
|
assert content_similarity("short shared title", "short shared title") == 0
|
|
assert content_similarity(BODY, BODY.replace("river", "lake", 1)) >= 0.92
|
|
assert content_similarity(BODY, "Completely unrelated writing.") == 0
|
|
|
|
|
|
def test_title_derived_id_and_permalink(publisher):
|
|
run, _, client = publisher
|
|
response = send(client, "# My New_Post: Hello, World!\n\n" + BODY)
|
|
assert run().returncode == 0
|
|
state = client.get(response.json["status_url"], headers=AUTH).json
|
|
assert state["post_id"] == "my-new-post-hello-world"
|
|
assert state["url"] == "/my-new-post-hello-world/"
|
|
assert title_id(" سفر به تهران! ") == "سفر-به-تهران"
|
|
assert len(title_id("漢" * 100).encode()) <= 160
|
|
|
|
|
|
def test_same_title_does_not_overwrite_unrelated_content(publisher):
|
|
run, remote, client = publisher
|
|
send(client, "# Shared title\n\n" + BODY)
|
|
assert run().returncode == 0
|
|
head = git(remote, "rev-parse", "master")
|
|
response = send(client, "# Shared title\n\n" + "An unrelated essay about distant stars. " * 20)
|
|
assert run().returncode != 0
|
|
assert client.get(response.json["status_url"], headers=AUTH).json["status"] == "failed"
|
|
assert git(remote, "rev-parse", "master") == head
|