conservancy_beancount/tests/test_rtutil.py
Brett Smith a8407c7b6a rtutil: Add RTLinkCache class to cache links to disk.
This will greatly reduce RT requests across multiple runs
and speed up link checking/conversion.
2020-03-27 07:35:45 -04:00

181 lines
6.2 KiB
Python

"""Test RT integration"""
# Copyright © 2020 Brett Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import contextlib
import pytest
from . import testutil
from conservancy_beancount import rtutil
DEFAULT_RT_URL = testutil.RTClient.DEFAULT_URL[:-9]
EXPECTED_URLS = [
(1, None, 'Ticket/Display.html?id=1'),
(1, 2, 'Ticket/Display.html?id=1#txn-1'),
(1, 4, 'Ticket/Attachment/1/4/Forwarded%20Message.eml'),
(1, 99, None),
(2, 1, None),
(2, 10, 'Ticket/Attachment/7/10/screenshot.png'),
(2, 13, 'Ticket/Display.html?id=2#txn-11'),
(2, 14, 'Ticket/Display.html?id=2#txn-11'), # statement.txt
(3, None, 'Ticket/Display.html?id=3'),
(9, None, None),
]
@pytest.fixture(scope='module')
def rt():
client = testutil.RTClient()
return rtutil.RT(client)
@pytest.fixture
def new_client():
class RTClient(testutil.RTClient):
TICKET_DATA = testutil.RTClient.TICKET_DATA.copy()
return RTClient()
def new_cache(database=':memory:'):
db = rtutil.RTLinkCache.setup(database)
if db is None:
print("NOTE: did not set up database cache at {}".format(database))
return contextlib.nullcontext(db)
else:
return contextlib.closing(db)
@pytest.mark.parametrize('ticket_id,attachment_id,expected', EXPECTED_URLS)
def test_url(rt, ticket_id, attachment_id, expected):
if expected is not None:
expected = DEFAULT_RT_URL + expected
assert rt.url(ticket_id, attachment_id) == expected
@pytest.mark.parametrize('attachment_id', [
13,
None,
])
def test_url_caches(new_client, attachment_id):
if attachment_id is None:
fragment = ''
else:
fragment = '#txn-11'
expected = '{}Ticket/Display.html?id=2{}'.format(DEFAULT_RT_URL, fragment)
rt = rtutil.RT(new_client)
assert rt.url(2, attachment_id) == expected
new_client.TICKET_DATA.clear()
assert rt.url(2, attachment_id) == expected
@pytest.mark.parametrize('mimetype,extension', [
('application/pdf', 'pdf'),
('image/png', 'png'),
('message/rfc822', 'eml'),
('x-test/x-unknown', 'bin'),
])
def test_url_default_filename(new_client, mimetype, extension):
new_client.TICKET_DATA['1'] = [('9', '(Unnamed)', mimetype, '50.5k')]
rt = rtutil.RT(new_client)
expected = '{}Ticket/Attachment/9/9/RT1%20attachment%209.{}'.format(DEFAULT_RT_URL, extension)
assert rt.url(1, 9) == expected
@pytest.mark.parametrize('ticket_id,attachment_id,expected', EXPECTED_URLS)
def test_exists(rt, ticket_id, attachment_id, expected):
expected = False if expected is None else True
assert rt.exists(ticket_id, attachment_id) is expected
def test_exists_caches(new_client):
rt = rtutil.RT(new_client)
assert rt.exists(1, 3)
assert rt.exists(2)
assert not rt.exists(1, 99)
assert not rt.exists(9)
new_client.TICKET_DATA.clear()
assert rt.exists(1, 3)
assert rt.exists(2)
assert not rt.exists(1, 99)
assert not rt.exists(9)
@pytest.mark.parametrize('link,expected', [
('rt:1/2', ('1', '2')),
('rt:123/456', ('123', '456')),
('rt:12345', ('12345', None)),
('rt:12346/', ('12346', None)),
('rt:12346/789', ('12346', '789')),
('rt:12346/780/', ('12346', '780')),
('rt://ticket/1', ('1', None)),
('rt://ticket/1/', ('1', None)),
('rt://ticket/1234/attachments/5678', ('1234', '5678')),
('rt://ticket/1234/attachments/5678/', ('1234', '5678')),
('rt://ticket/1234/attachment/5678', ('1234', '5678')),
('rt://ticket/1234/attachment/5678/', ('1234', '5678')),
('rt:', None),
('rt://', None),
('rt:example.org', None),
('rt:example.org/1', None),
('rt://example.org', None),
('rt://example.org/1', None),
('https://example.org/rt/Ticket/Display.html?id=123', None),
])
def test_parse(rt, link, expected):
assert rt.parse(link) == expected
def test_uncommon_server_url_parsing():
url = 'https://example.org/REST/1.0/'
client = testutil.RTClient(url + 'REST/1.0/')
rt = rtutil.RT(client)
assert rt.url(1).startswith(url)
def test_shared_cache(new_client):
ticket_id, _, expected = EXPECTED_URLS[0]
expected = DEFAULT_RT_URL + expected
with new_cache() as cachedb:
rt1 = rtutil.RT(new_client, cachedb)
assert rt1.url(ticket_id) == expected
new_client.TICKET_DATA.clear()
rt2 = rtutil.RT(new_client, cachedb)
assert rt2.url(ticket_id) == expected
assert not rt2.exists(ticket_id + 1)
assert rt1 is not rt2
def test_no_shared_cache(new_client):
with new_cache() as cache1, new_cache() as cache2:
rt1 = rtutil.RT(new_client, cache1)
rt2 = rtutil.RT(new_client, cache2)
assert rt1.exists(1)
new_client.TICKET_DATA.clear()
assert not rt2.exists(1)
assert rt1.exists(1)
def test_read_only_cache(new_client, tmp_path):
db_path = tmp_path / 'test.db'
ticket_id, _, expected = EXPECTED_URLS[0]
expected = DEFAULT_RT_URL + expected
with new_cache(db_path) as cache1:
rt1 = rtutil.RT(new_client, cache1)
assert rt1.url(ticket_id) == expected
new_client.TICKET_DATA.clear()
db_path.chmod(0o400)
with new_cache(db_path) as cache2:
rt2 = rtutil.RT(new_client, cache2)
assert rt2.url(ticket_id) == expected
assert rt2.url(ticket_id + 1) is None
def test_results_not_found_only_in_transient_cache(new_client):
with new_cache() as cache:
rt1 = rtutil.RT(new_client, cache)
rt2 = rtutil.RT(new_client, cache)
assert not rt1.exists(9)
new_client.TICKET_DATA['9'] = [('99', '(Unnamed)', 'text/plain', '0b')]
assert not rt1.exists(9)
assert rt2.exists(9)