import json import pytest from unittest.mock import patch, MagicMock from openvpncertupdate import create_note, CryptgeonError def mock_response(body: bytes): resp = MagicMock() resp.read.return_value = body resp.__enter__ = lambda s: s resp.__exit__ = MagicMock(return_value=False) return resp @patch("openvpncertupdate.urllib.request.urlopen") def test_returns_url_with_id(mock_open): mock_open.return_value = mock_response(b'{"id":"abc-123"}') url = create_note("secret", "https://cg.example.com") assert "abc-123" in url assert url.startswith("https://cg.example.com/#/note/abc-123/") @patch("openvpncertupdate.urllib.request.urlopen") def test_posts_to_correct_endpoint(mock_open): mock_open.return_value = mock_response(b'{"id":"x"}') create_note("hello", "https://cg.example.com") req = mock_open.call_args[0][0] assert req.full_url == "https://cg.example.com/api/notes/" body = json.loads(req.data) assert isinstance(body["contents"], list) assert body["views"] == 1 assert body["type"] == "text" @patch("openvpncertupdate.urllib.request.urlopen") def test_raises_on_http_error(mock_open): import urllib.error mock_open.side_effect = urllib.error.HTTPError("", 500, "Error", None, None) with pytest.raises(CryptgeonError, match="500"): create_note("secret", "https://cg.example.com") @patch("openvpncertupdate.urllib.request.urlopen") def test_different_passwords_give_different_urls(mock_open): mock_open.return_value = mock_response(b'{"id":"same"}') url1 = create_note("pass1", "https://cg.example.com") url2 = create_note("pass2", "https://cg.example.com") assert url1 != url2