"""Integration tests for the snapshot REST API (commit / list / content).""" import json import pytest SAMPLE_NB = { "cells": [ { "cell_type": "code", "id": "c1", "source": "print('hi')", "outputs": [{"output_type": "stream", "text": "hi"}], "execution_count": 1, "metadata": {}, }, { "cell_type": "markdown", "id": "c2", "source": "# title", "metadata": {}, }, ], "metadata": {}, "nbformat": 4, "nbformat_minor": 5, } def _post_commit(jp_fetch, path: str, name: str, description: str = ""): body = json.dumps( { "path": path, "content": SAMPLE_NB, "name": name, "description": description, } ).encode() return jp_fetch( "snapshot", "notebook-version", "commit", method="POST", body=body, ) async def test_commit_creates_entry(jp_fetch): response = await _post_commit(jp_fetch, "api_a.ipynb", "v1", "first") assert response.code == 200 payload = json.loads(response.body) assert payload["entry"]["name"] == "v1" assert payload["entry"]["description"] == "first" assert payload["entry"]["id"].startswith("v_") assert payload["entry"]["size"] > 0 assert payload["entry"]["hash"] async def test_list_contains_committed_entry(jp_fetch): await _post_commit(jp_fetch, "api_b.ipynb", "v1", "desc") response = await jp_fetch( "snapshot", "notebook-version", "list", params={"path": "api_b.ipynb"}, ) assert response.code == 200 payload = json.loads(response.body) assert len(payload["versions"]) == 1 assert payload["versions"][0]["name"] == "v1" assert payload["versions"][0]["description"] == "desc" async def test_content_returns_stripped_notebook(jp_fetch): commit_resp = await _post_commit(jp_fetch, "api_c.ipynb", "v1") entry = json.loads(commit_resp.body)["entry"] response = await jp_fetch( "snapshot", "notebook-version", "content", params={"path": "api_c.ipynb", "id": entry["id"]}, ) assert response.code == 200 notebook = json.loads(response.body) code = next(c for c in notebook["cells"] if c["cell_type"] == "code") assert code["outputs"] == [] assert code["execution_count"] is None assert notebook["nbformat"] == 4 async def test_commit_missing_name_returns_400(jp_fetch): body = json.dumps( {"path": "api_d.ipynb", "content": SAMPLE_NB} ).encode() response = await jp_fetch( "snapshot", "notebook-version", "commit", method="POST", body=body, raise_error=False, ) assert response.code == 400 async def test_list_unknown_path_returns_empty(jp_fetch): response = await jp_fetch( "snapshot", "notebook-version", "list", params={"path": "never_committed_unique.ipynb"}, ) assert response.code == 200 payload = json.loads(response.body) assert payload["versions"] == [] async def test_commit_duplicate_returns_skipped(jp_fetch): """Second commit with identical content must NOT save; response is {skipped: True}.""" r1 = await _post_commit(jp_fetch, "api_dup.ipynb", "v1") assert r1.code == 200 first = json.loads(r1.body) assert first.get("entry") is not None assert first.get("skipped") in (None, False) r2 = await _post_commit(jp_fetch, "api_dup.ipynb", "v2") assert r2.code == 200 # not an error — just a warning second = json.loads(r2.body) assert second.get("skipped") is True assert second.get("reason") == "unchanged" assert "未变更" in second.get("message", "") or "unchanged" in second.get("message", "").lower() assert second.get("entry") is None # And the manifest still has exactly one entry. list_resp = await jp_fetch( "snapshot", "notebook-version", "list", params={"path": "api_dup.ipynb"}, ) assert json.loads(list_resp.body)["versions"].__len__() == 1 async def test_content_unknown_id_returns_404(jp_fetch): response = await jp_fetch( "snapshot", "notebook-version", "content", params={"path": "api_e.ipynb", "id": "v_0_doesnotexist"}, raise_error=False, ) assert response.code == 404