Fix Zotero table models for Zotero 9:
- Remove stale Annotations/Highlights/Transaction* models
- Add ItemAnnotations, RetractedItems, DeletedCollections,
DeletedSearches, DbDebug1
- Fix ItemAttachments, Libraries, Users column mismatches
New test files covering all major modules:
- cli/{bib,prisma,rec,zot,mail,run} deep exercising tests
- mail/{droplet,postmark,resend,cloudflare} lifecycle tests
- bib/{iom,oig,pincite,sync,regulations_gov,email_ingest,format,store}
- prisma/{vpn,fetch,export,llm,screen,eligibility,extract,project,ingest,flow}
- aco/lake/{unity,quality,deploy} + api/aco coverage gaps
- zot/{ops,db,extract,duck} + rec/{report,engine,base,pricers}
- pfs/{pipe,rules,eq,files}
Add pytest-xdist for parallel test execution.
Tracks #353
112 lines
3.4 KiB
Python
112 lines
3.4 KiB
Python
"""Deep tests for prisma.vpn — exercises all lifecycle functions."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
from prisma.vpn import (
|
|
_cloud_init,
|
|
_delete_account_ssh_key,
|
|
_ensure_account_ssh_key,
|
|
_gen_ssh_key,
|
|
_tunnel_running,
|
|
down,
|
|
status,
|
|
up,
|
|
)
|
|
|
|
|
|
class TestCloudInit:
|
|
def test_generates_config(self):
|
|
result = _cloud_init("ssh-ed25519 AAAA test")
|
|
assert "#cloud-config" in result
|
|
assert "dante-server" in result
|
|
assert "ssh-ed25519" in result
|
|
|
|
|
|
class TestGenSshKey:
|
|
@patch("prisma.vpn.subprocess.run")
|
|
def test_generates_key(self, mock_run, tmp_path):
|
|
key_path = tmp_path / "id_ed25519"
|
|
|
|
# _gen_ssh_key unlinks existing then runs ssh-keygen, which creates the file
|
|
# Mock the subprocess but also create the pubkey file it would produce
|
|
def fake_keygen(*a, **kw):
|
|
key_path.write_text("private")
|
|
key_path.with_suffix(".pub").write_text("ssh-ed25519 AAAA test")
|
|
return MagicMock(returncode=0)
|
|
|
|
mock_run.side_effect = fake_keygen
|
|
result = _gen_ssh_key(key_path)
|
|
assert "ssh-ed25519" in result
|
|
|
|
|
|
class TestEnsureAccountSshKey:
|
|
def test_reuses_existing(self):
|
|
client = MagicMock()
|
|
client.ssh_keys.list.return_value = {
|
|
"ssh_keys": [{"id": 42, "public_key": "ssh-ed25519 AAAA test"}]
|
|
}
|
|
result = _ensure_account_ssh_key(client, "ssh-ed25519 AAAA test", "name")
|
|
assert result == 42
|
|
|
|
def test_creates_new(self):
|
|
client = MagicMock()
|
|
client.ssh_keys.list.return_value = {"ssh_keys": []}
|
|
client.ssh_keys.create.return_value = {"ssh_key": {"id": 99}}
|
|
result = _ensure_account_ssh_key(client, "ssh-ed25519 BBBB new", "name")
|
|
assert result == 99
|
|
|
|
|
|
class TestDeleteAccountSshKey:
|
|
def test_deletes(self):
|
|
client = MagicMock()
|
|
_delete_account_ssh_key(client, 42)
|
|
client.ssh_keys.delete.assert_called_once()
|
|
|
|
def test_handles_error(self):
|
|
client = MagicMock()
|
|
client.ssh_keys.delete.side_effect = Exception("gone")
|
|
_delete_account_ssh_key(client, 42) # should not raise
|
|
|
|
|
|
class TestTunnelRunning:
|
|
def test_no_pid_file(self):
|
|
with patch("prisma.vpn._TUNNEL_PID") as mock_path:
|
|
mock_path.is_file.return_value = False
|
|
assert _tunnel_running() is False
|
|
|
|
|
|
class TestUp:
|
|
@patch("prisma.vpn._do_client")
|
|
@patch("prisma.vpn._gen_ssh_key", return_value="ssh-ed25519 AAAA")
|
|
@patch("prisma.vpn._ensure_account_ssh_key", return_value=1)
|
|
@patch("prisma.vpn._DROPLET_JSON")
|
|
@patch("prisma.vpn._STATE_DIR")
|
|
def test_raises_if_tracked(
|
|
self, mock_state, mock_json, mock_key_id, mock_gen, mock_client
|
|
):
|
|
mock_json.exists.return_value = True
|
|
with pytest.raises(RuntimeError, match="already tracked"):
|
|
up()
|
|
|
|
|
|
class TestDown:
|
|
@patch("prisma.vpn.detach_zotero_proxy")
|
|
@patch("prisma.vpn._tunnel_stop")
|
|
@patch("prisma.vpn._DROPLET_JSON")
|
|
def test_noop_if_not_tracked(self, mock_json, mock_stop, mock_detach):
|
|
mock_json.exists.return_value = False
|
|
result = down()
|
|
assert result == {"status": "nothing-to-do"}
|
|
|
|
|
|
class TestStatus:
|
|
@patch("prisma.vpn._DROPLET_JSON")
|
|
def test_down_if_not_tracked(self, mock_json):
|
|
mock_json.exists.return_value = False
|
|
result = status()
|
|
assert result["status"] == "down"
|