adobe-to-docusign-migrator/tests/test_upload_upsert.py

128 lines
4.5 KiB
Python

"""
tests/test_upload_upsert.py
---------------------------
Tests for idempotent (upsert) upload logic in upload_docusign_template.py.
All DocuSign API calls are mocked with responses; no live account needed.
"""
import json
import os
import sys
import tempfile
from unittest.mock import patch
import pytest
import responses as rsps_lib
# Ensure src/ is importable before import
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
# Patch get_access_token at import time so the module never tries to load a private key
with patch("docusign_auth.get_access_token", return_value="fake-token"):
import upload_docusign_template
BASE_URL = "https://demo.docusign.net/restapi"
ACCOUNT_ID = "test-account-id"
TEMPLATE_NAME = "My NDA Template"
@pytest.fixture(autouse=True)
def env_vars(monkeypatch):
monkeypatch.setenv("DOCUSIGN_ACCOUNT_ID", ACCOUNT_ID)
monkeypatch.setenv("DOCUSIGN_BASE_URL", BASE_URL)
@pytest.fixture()
def template_file():
"""Write a minimal template JSON to a temp file."""
template = {"name": TEMPLATE_NAME, "description": "test template"}
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
json.dump(template, f)
path = f.name
yield path
os.unlink(path)
def _list_url():
return f"{BASE_URL}/v2.1/accounts/{ACCOUNT_ID}/templates"
def _update_url(template_id):
return f"{BASE_URL}/v2.1/accounts/{ACCOUNT_ID}/templates/{template_id}"
@rsps_lib.activate
def test_creates_when_no_match(template_file):
"""No existing templates with this name → POST called, new ID returned."""
new_id = "new-template-abc"
rsps_lib.add(rsps_lib.GET, _list_url(), json={"envelopeTemplates": []}, status=200)
rsps_lib.add(rsps_lib.POST, _list_url(), json={"templateId": new_id}, status=201)
with patch.object(upload_docusign_template, "get_access_token", return_value="fake-token"):
result = upload_docusign_template.upload_template(template_file)
assert result == new_id
methods = [c.request.method for c in rsps_lib.calls]
assert methods == ["GET", "POST"]
@rsps_lib.activate
def test_updates_most_recent_when_match(template_file):
"""Two exact-name matches → PUT called on the most recently modified one."""
older_id = "template-older"
newer_id = "template-newer"
existing = [
{"templateId": older_id, "name": TEMPLATE_NAME, "lastModified": "2026-04-10T10:00:00.000Z"},
{"templateId": newer_id, "name": TEMPLATE_NAME, "lastModified": "2026-04-15T10:00:00.000Z"},
]
rsps_lib.add(rsps_lib.GET, _list_url(), json={"envelopeTemplates": existing}, status=200)
rsps_lib.add(rsps_lib.PUT, _update_url(newer_id), json={}, status=200)
with patch.object(upload_docusign_template, "get_access_token", return_value="fake-token"):
result = upload_docusign_template.upload_template(template_file)
assert result == newer_id
put_calls = [c for c in rsps_lib.calls if c.request.method == "PUT"]
assert len(put_calls) == 1
assert newer_id in put_calls[0].request.url
@rsps_lib.activate
def test_force_create_bypasses_upsert(template_file):
"""force_create=True → always POST, no GET for existing templates."""
new_id = "force-created-id"
rsps_lib.add(rsps_lib.POST, _list_url(), json={"templateId": new_id}, status=201)
with patch.object(upload_docusign_template, "get_access_token", return_value="fake-token"):
result = upload_docusign_template.upload_template(template_file, force_create=True)
assert result == new_id
get_calls = [c for c in rsps_lib.calls if c.request.method == "GET"]
assert len(get_calls) == 0
post_calls = [c for c in rsps_lib.calls if c.request.method == "POST"]
assert len(post_calls) == 1
@rsps_lib.activate
def test_partial_name_match_ignored(template_file):
"""DocuSign search_text is substring; we must reject partial-name results and POST."""
partial_id = "partial-match-id"
existing = [
{"templateId": partial_id, "name": "My NDA Template (Copy)", "lastModified": "2026-04-15T10:00:00.000Z"},
]
rsps_lib.add(rsps_lib.GET, _list_url(), json={"envelopeTemplates": existing}, status=200)
new_id = "created-new-id"
rsps_lib.add(rsps_lib.POST, _list_url(), json={"templateId": new_id}, status=201)
with patch.object(upload_docusign_template, "get_access_token", return_value="fake-token"):
result = upload_docusign_template.upload_template(template_file)
assert result == new_id
put_calls = [c for c in rsps_lib.calls if c.request.method == "PUT"]
assert len(put_calls) == 0