Changeset View
Changeset View
Standalone View
Standalone View
swh/web/tests/api/views/test_origin.py
# Copyright (C) 2015-2019 The Software Heritage developers | # Copyright (C) 2015-2019 The Software Heritage developers | ||||
# See the AUTHORS file at the top-level directory of this distribution | # See the AUTHORS file at the top-level directory of this distribution | ||||
# License: GNU Affero General Public License version 3, or any later version | # License: GNU Affero General Public License version 3, or any later version | ||||
# See top-level LICENSE file for more information | # See top-level LICENSE file for more information | ||||
from unittest.mock import patch | from hypothesis import given | ||||
from hypothesis import given, strategies | |||||
import pytest | |||||
from requests.utils import parse_header_links | from requests.utils import parse_header_links | ||||
from rest_framework.test import APITestCase | |||||
from swh.storage.exc import StorageDBError, StorageAPIError | from swh.storage.exc import StorageDBError, StorageAPIError | ||||
from swh.web.common.exc import BadInputExc | from swh.web.common.exc import BadInputExc | ||||
from swh.web.common.utils import reverse | from swh.web.common.utils import reverse | ||||
from swh.web.common.origin_visits import get_origin_visits | from swh.web.common.origin_visits import get_origin_visits | ||||
from swh.web.tests.strategies import ( | from swh.web.tests.strategies import ( | ||||
origin, new_origin, visit_dates, new_snapshots | origin, new_origin, visit_dates, new_snapshots | ||||
) | ) | ||||
from swh.web.tests.testcase import WebTestCase | |||||
from swh.web.tests.data import get_tests_data | |||||
class OriginApiTestCase(WebTestCase, APITestCase): | def _scroll_results(api_client, url): | ||||
def _scroll_results(self, url): | |||||
"""Iterates through pages of results, and returns them all.""" | """Iterates through pages of results, and returns them all.""" | ||||
results = [] | results = [] | ||||
while True: | while True: | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
self.assertEqual(rv.status_code, 200, rv.data) | assert rv.status_code == 200, rv.data | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | assert rv['Content-Type'] == 'application/json' | ||||
results.extend(rv.data) | results.extend(rv.data) | ||||
if 'Link' in rv: | if 'Link' in rv: | ||||
for link in parse_header_links(rv['Link']): | for link in parse_header_links(rv['Link']): | ||||
if link['rel'] == 'next': | if link['rel'] == 'next': | ||||
# Found link to next page of results | # Found link to next page of results | ||||
url = link['url'] | url = link['url'] | ||||
break | break | ||||
else: | else: | ||||
# No link with 'rel=next' | # No link with 'rel=next' | ||||
break | break | ||||
else: | else: | ||||
# No Link header | # No Link header | ||||
break | break | ||||
return results | return results | ||||
@patch('swh.web.api.views.origin.get_origin_visits') | |||||
def test_api_lookup_origin_visits_raise_error( | |||||
self, mock_get_origin_visits, | |||||
): | |||||
def test_api_lookup_origin_visits_raise_error(api_client, mocker): | |||||
mock_get_origin_visits = mocker.patch( | |||||
'swh.web.api.views.origin.get_origin_visits') | |||||
err_msg = 'voluntary error to check the bad request middleware.' | err_msg = 'voluntary error to check the bad request middleware.' | ||||
mock_get_origin_visits.side_effect = BadInputExc(err_msg) | mock_get_origin_visits.side_effect = BadInputExc(err_msg) | ||||
url = reverse( | url = reverse('api-1-origin-visits', url_args={'origin_url': 'http://foo'}) | ||||
'api-1-origin-visits', url_args={'origin_url': 'http://foo'}) | rv = api_client.get(url) | ||||
rv = self.client.get(url) | |||||
self.assertEqual(rv.status_code, 400, rv.data) | assert rv.status_code == 400, rv.data | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | assert rv['Content-Type'] == 'application/json' | ||||
self.assertEqual(rv.data, { | assert rv.data == { | ||||
'exception': 'BadInputExc', | 'exception': 'BadInputExc', | ||||
'reason': err_msg}) | 'reason': err_msg | ||||
} | |||||
@patch('swh.web.api.views.origin.get_origin_visits') | |||||
def test_api_lookup_origin_visits_raise_swh_storage_error_db( | |||||
self, mock_get_origin_visits): | |||||
def test_api_lookup_origin_visits_raise_swh_storage_error_db(api_client, | |||||
mocker): | |||||
mock_get_origin_visits = mocker.patch( | |||||
'swh.web.api.views.origin.get_origin_visits') | |||||
err_msg = 'Storage exploded! Will be back online shortly!' | err_msg = 'Storage exploded! Will be back online shortly!' | ||||
mock_get_origin_visits.side_effect = StorageDBError(err_msg) | mock_get_origin_visits.side_effect = StorageDBError(err_msg) | ||||
url = reverse( | url = reverse('api-1-origin-visits', url_args={'origin_url': 'http://foo'}) | ||||
'api-1-origin-visits', url_args={'origin_url': 'http://foo'}) | rv = api_client.get(url) | ||||
rv = self.client.get(url) | |||||
self.assertEqual(rv.status_code, 503, rv.data) | assert rv.status_code == 503, rv.data | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | assert rv['Content-Type'] == 'application/json' | ||||
self.assertEqual(rv.data, { | assert rv.data == { | ||||
'exception': 'StorageDBError', | 'exception': 'StorageDBError', | ||||
'reason': | 'reason': | ||||
'An unexpected error occurred in the backend: %s' % err_msg}) | 'An unexpected error occurred in the backend: %s' % err_msg | ||||
} | |||||
@patch('swh.web.api.views.origin.get_origin_visits') | |||||
def test_api_lookup_origin_visits_raise_swh_storage_error_api( | |||||
self, mock_get_origin_visits): | |||||
def test_api_lookup_origin_visits_raise_swh_storage_error_api(api_client, | |||||
mocker): | |||||
mock_get_origin_visits = mocker.patch( | |||||
'swh.web.api.views.origin.get_origin_visits') | |||||
err_msg = 'Storage API dropped dead! Will resurrect asap!' | err_msg = 'Storage API dropped dead! Will resurrect asap!' | ||||
mock_get_origin_visits.side_effect = StorageAPIError(err_msg) | mock_get_origin_visits.side_effect = StorageAPIError(err_msg) | ||||
url = reverse( | url = reverse( | ||||
'api-1-origin-visits', url_args={'origin_url': 'http://foo'}) | 'api-1-origin-visits', url_args={'origin_url': 'http://foo'}) | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
self.assertEqual(rv.status_code, 503, rv.data) | assert rv.status_code == 503, rv.data | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | assert rv['Content-Type'] == 'application/json' | ||||
self.assertEqual(rv.data, { | assert rv.data == { | ||||
'exception': 'StorageAPIError', | 'exception': 'StorageAPIError', | ||||
'reason': | 'reason': | ||||
'An unexpected error occurred in the api backend: %s' % err_msg | 'An unexpected error occurred in the api backend: %s' % err_msg | ||||
}) | } | ||||
@given(new_origin(), visit_dates(3), new_snapshots(3)) | |||||
def test_api_lookup_origin_visits(self, new_origin, visit_dates, | |||||
new_snapshots): | |||||
self.storage.origin_add_one(new_origin) | @given(new_origin(), visit_dates(3), new_snapshots(3)) | ||||
def test_api_lookup_origin_visits(api_client, test_archive, new_origin, | |||||
visit_dates, new_snapshots): | |||||
test_archive.storage.origin_add_one(new_origin) | |||||
for i, visit_date in enumerate(visit_dates): | for i, visit_date in enumerate(visit_dates): | ||||
origin_visit = self.storage.origin_visit_add( | origin_visit = test_archive.storage.origin_visit_add( | ||||
new_origin['url'], visit_date, type='git') | new_origin['url'], visit_date, type='git') | ||||
self.storage.snapshot_add([new_snapshots[i]]) | test_archive.storage.snapshot_add([new_snapshots[i]]) | ||||
self.storage.origin_visit_update( | test_archive.storage.origin_visit_update( | ||||
new_origin['url'], origin_visit['visit'], | new_origin['url'], origin_visit['visit'], | ||||
snapshot=new_snapshots[i]['id']) | snapshot=new_snapshots[i]['id']) | ||||
all_visits = list(reversed(get_origin_visits(new_origin))) | all_visits = list(reversed(get_origin_visits(new_origin))) | ||||
for last_visit, expected_visits in ( | for last_visit, expected_visits in ( | ||||
(None, all_visits[:2]), | (None, all_visits[:2]), | ||||
(all_visits[1]['visit'], all_visits[2:4])): | (all_visits[1]['visit'], all_visits[2:4])): | ||||
url = reverse('api-1-origin-visits', | url = reverse('api-1-origin-visits', | ||||
url_args={'origin_url': new_origin['url']}, | url_args={'origin_url': new_origin['url']}, | ||||
query_params={'per_page': 2, | query_params={'per_page': 2, | ||||
'last_visit': last_visit}) | 'last_visit': last_visit}) | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
self.assertEqual(rv.status_code, 200, rv.data) | assert rv.status_code == 200, rv.data | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | assert rv['Content-Type'] == 'application/json' | ||||
for expected_visit in expected_visits: | for expected_visit in expected_visits: | ||||
origin_visit_url = reverse( | origin_visit_url = reverse( | ||||
'api-1-origin-visit', | 'api-1-origin-visit', | ||||
url_args={'origin_url': new_origin['url'], | url_args={'origin_url': new_origin['url'], | ||||
'visit_id': expected_visit['visit']}) | 'visit_id': expected_visit['visit']}) | ||||
snapshot_url = reverse( | snapshot_url = reverse( | ||||
'api-1-snapshot', | 'api-1-snapshot', | ||||
url_args={'snapshot_id': expected_visit['snapshot']}) | url_args={'snapshot_id': expected_visit['snapshot']}) | ||||
expected_visit['origin'] = new_origin['url'] | expected_visit['origin'] = new_origin['url'] | ||||
expected_visit['origin_visit_url'] = origin_visit_url | expected_visit['origin_visit_url'] = origin_visit_url | ||||
expected_visit['snapshot_url'] = snapshot_url | expected_visit['snapshot_url'] = snapshot_url | ||||
self.assertEqual(rv.data, expected_visits) | assert rv.data == expected_visits | ||||
@given(new_origin(), visit_dates(3), new_snapshots(3)) | |||||
def test_api_lookup_origin_visits_by_id(self, new_origin, visit_dates, | |||||
new_snapshots): | |||||
self.storage.origin_add_one(new_origin) | @given(new_origin(), visit_dates(3), new_snapshots(3)) | ||||
def test_api_lookup_origin_visits_by_id(api_client, test_archive, new_origin, | |||||
visit_dates, new_snapshots): | |||||
test_archive.storage.origin_add_one(new_origin) | |||||
for i, visit_date in enumerate(visit_dates): | for i, visit_date in enumerate(visit_dates): | ||||
origin_visit = self.storage.origin_visit_add( | origin_visit = test_archive.storage.origin_visit_add( | ||||
new_origin['url'], visit_date, type='git') | new_origin['url'], visit_date, type='git') | ||||
self.storage.snapshot_add([new_snapshots[i]]) | test_archive.storage.snapshot_add([new_snapshots[i]]) | ||||
self.storage.origin_visit_update( | test_archive.storage.origin_visit_update( | ||||
new_origin['url'], origin_visit['visit'], | new_origin['url'], origin_visit['visit'], | ||||
snapshot=new_snapshots[i]['id']) | snapshot=new_snapshots[i]['id']) | ||||
all_visits = list(reversed(get_origin_visits(new_origin))) | all_visits = list(reversed(get_origin_visits(new_origin))) | ||||
for last_visit, expected_visits in ( | for last_visit, expected_visits in ( | ||||
(None, all_visits[:2]), | (None, all_visits[:2]), | ||||
(all_visits[1]['visit'], all_visits[2:4])): | (all_visits[1]['visit'], all_visits[2:4])): | ||||
url = reverse('api-1-origin-visits', | url = reverse('api-1-origin-visits', | ||||
url_args={'origin_url': new_origin['url']}, | url_args={'origin_url': new_origin['url']}, | ||||
query_params={'per_page': 2, | query_params={'per_page': 2, | ||||
'last_visit': last_visit}) | 'last_visit': last_visit}) | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
self.assertEqual(rv.status_code, 200, rv.data) | assert rv.status_code == 200, rv.data | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | assert rv['Content-Type'] == 'application/json' | ||||
for expected_visit in expected_visits: | for expected_visit in expected_visits: | ||||
origin_visit_url = reverse( | origin_visit_url = reverse( | ||||
'api-1-origin-visit', | 'api-1-origin-visit', | ||||
url_args={'origin_url': new_origin['url'], | url_args={'origin_url': new_origin['url'], | ||||
'visit_id': expected_visit['visit']}) | 'visit_id': expected_visit['visit']}) | ||||
snapshot_url = reverse( | snapshot_url = reverse( | ||||
'api-1-snapshot', | 'api-1-snapshot', | ||||
url_args={'snapshot_id': expected_visit['snapshot']}) | url_args={'snapshot_id': expected_visit['snapshot']}) | ||||
expected_visit['origin'] = new_origin['url'] | expected_visit['origin'] = new_origin['url'] | ||||
expected_visit['origin_visit_url'] = origin_visit_url | expected_visit['origin_visit_url'] = origin_visit_url | ||||
expected_visit['snapshot_url'] = snapshot_url | expected_visit['snapshot_url'] = snapshot_url | ||||
self.assertEqual(rv.data, expected_visits) | assert rv.data == expected_visits | ||||
@given(new_origin(), visit_dates(3), new_snapshots(3)) | |||||
def test_api_lookup_origin_visit(self, new_origin, visit_dates, | |||||
new_snapshots): | |||||
self.storage.origin_add_one(new_origin) | @given(new_origin(), visit_dates(3), new_snapshots(3)) | ||||
def test_api_lookup_origin_visit(api_client, test_archive, new_origin, | |||||
visit_dates, new_snapshots): | |||||
test_archive.storage.origin_add_one(new_origin) | |||||
for i, visit_date in enumerate(visit_dates): | for i, visit_date in enumerate(visit_dates): | ||||
origin_visit = self.storage.origin_visit_add( | origin_visit = test_archive.storage.origin_visit_add( | ||||
new_origin['url'], visit_date, type='git') | new_origin['url'], visit_date, type='git') | ||||
visit_id = origin_visit['visit'] | visit_id = origin_visit['visit'] | ||||
self.storage.snapshot_add([new_snapshots[i]]) | test_archive.storage.snapshot_add([new_snapshots[i]]) | ||||
self.storage.origin_visit_update( | test_archive.storage.origin_visit_update( | ||||
new_origin['url'], origin_visit['visit'], | new_origin['url'], origin_visit['visit'], | ||||
snapshot=new_snapshots[i]['id']) | snapshot=new_snapshots[i]['id']) | ||||
url = reverse('api-1-origin-visit', | url = reverse('api-1-origin-visit', | ||||
url_args={'origin_url': new_origin['url'], | url_args={'origin_url': new_origin['url'], | ||||
'visit_id': visit_id}) | 'visit_id': visit_id}) | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
self.assertEqual(rv.status_code, 200, rv.data) | assert rv.status_code == 200, rv.data | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | assert rv['Content-Type'] == 'application/json' | ||||
expected_visit = self.origin_visit_get_by( | expected_visit = test_archive.origin_visit_get_by( | ||||
new_origin['url'], visit_id) | new_origin['url'], visit_id) | ||||
origin_url = reverse('api-1-origin', | origin_url = reverse('api-1-origin', | ||||
url_args={'origin_url': new_origin['url']}) | url_args={'origin_url': new_origin['url']}) | ||||
snapshot_url = reverse( | snapshot_url = reverse( | ||||
'api-1-snapshot', | 'api-1-snapshot', | ||||
url_args={'snapshot_id': expected_visit['snapshot']}) | url_args={'snapshot_id': expected_visit['snapshot']}) | ||||
expected_visit['origin'] = new_origin['url'] | expected_visit['origin'] = new_origin['url'] | ||||
expected_visit['origin_url'] = origin_url | expected_visit['origin_url'] = origin_url | ||||
expected_visit['snapshot_url'] = snapshot_url | expected_visit['snapshot_url'] = snapshot_url | ||||
self.assertEqual(rv.data, expected_visit) | assert rv.data == expected_visit | ||||
@given(new_origin()) | |||||
def test_api_lookup_origin_visit_latest_no_visit(self, new_origin): | |||||
self.storage.origin_add_one(new_origin) | @given(new_origin()) | ||||
def test_api_lookup_origin_visit_latest_no_visit(api_client, test_archive, | |||||
new_origin): | |||||
test_archive.storage.origin_add_one(new_origin) | |||||
url = reverse('api-1-origin-visit-latest', | url = reverse('api-1-origin-visit-latest', | ||||
url_args={'origin_url': new_origin['url']}) | url_args={'origin_url': new_origin['url']}) | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
self.assertEqual(rv.status_code, 404, rv.data) | assert rv.status_code == 404, rv.data | ||||
self.assertEqual(rv.data, { | assert rv.data == { | ||||
'exception': 'NotFoundExc', | 'exception': 'NotFoundExc', | ||||
'reason': 'No visit for origin %s found' % new_origin['url'] | 'reason': 'No visit for origin %s found' % new_origin['url'] | ||||
}) | } | ||||
@given(new_origin(), visit_dates(2), new_snapshots(1)) | |||||
def test_api_lookup_origin_visit_latest( | |||||
self, new_origin, visit_dates, new_snapshots): | |||||
self.storage.origin_add_one(new_origin) | |||||
@given(new_origin(), visit_dates(2), new_snapshots(1)) | |||||
def test_api_lookup_origin_visit_latest(api_client, test_archive, new_origin, | |||||
visit_dates, new_snapshots): | |||||
test_archive.storage.origin_add_one(new_origin) | |||||
visit_dates.sort() | visit_dates.sort() | ||||
visit_ids = [] | visit_ids = [] | ||||
for i, visit_date in enumerate(visit_dates): | for i, visit_date in enumerate(visit_dates): | ||||
origin_visit = self.storage.origin_visit_add( | origin_visit = test_archive.storage.origin_visit_add( | ||||
new_origin['url'], visit_date, type='git') | new_origin['url'], visit_date, type='git') | ||||
visit_ids.append(origin_visit['visit']) | visit_ids.append(origin_visit['visit']) | ||||
self.storage.snapshot_add([new_snapshots[0]]) | test_archive.storage.snapshot_add([new_snapshots[0]]) | ||||
self.storage.origin_visit_update( | test_archive.storage.origin_visit_update( | ||||
new_origin['url'], visit_ids[0], | new_origin['url'], visit_ids[0], | ||||
snapshot=new_snapshots[0]['id']) | snapshot=new_snapshots[0]['id']) | ||||
url = reverse('api-1-origin-visit-latest', | url = reverse('api-1-origin-visit-latest', | ||||
url_args={'origin_url': new_origin['url']}) | url_args={'origin_url': new_origin['url']}) | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
self.assertEqual(rv.status_code, 200, rv.data) | assert rv.status_code == 200, rv.data | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | assert rv['Content-Type'] == 'application/json' | ||||
expected_visit = self.origin_visit_get_by( | expected_visit = test_archive.origin_visit_get_by( | ||||
new_origin['url'], visit_ids[1]) | new_origin['url'], visit_ids[1]) | ||||
origin_url = reverse('api-1-origin', | origin_url = reverse('api-1-origin', | ||||
url_args={'origin_url': new_origin['url']}) | url_args={'origin_url': new_origin['url']}) | ||||
expected_visit['origin'] = new_origin['url'] | expected_visit['origin'] = new_origin['url'] | ||||
expected_visit['origin_url'] = origin_url | expected_visit['origin_url'] = origin_url | ||||
expected_visit['snapshot_url'] = None | expected_visit['snapshot_url'] = None | ||||
self.assertEqual(rv.data, expected_visit) | assert rv.data == expected_visit | ||||
@given(new_origin(), visit_dates(2), new_snapshots(1)) | @given(new_origin(), visit_dates(2), new_snapshots(1)) | ||||
def test_api_lookup_origin_visit_latest_with_snapshot( | def test_api_lookup_origin_visit_latest_with_snapshot(api_client, test_archive, | ||||
self, new_origin, visit_dates, new_snapshots): | new_origin, visit_dates, | ||||
self.storage.origin_add_one(new_origin) | new_snapshots): | ||||
test_archive.storage.origin_add_one(new_origin) | |||||
visit_dates.sort() | visit_dates.sort() | ||||
visit_ids = [] | visit_ids = [] | ||||
for i, visit_date in enumerate(visit_dates): | for i, visit_date in enumerate(visit_dates): | ||||
origin_visit = self.storage.origin_visit_add( | origin_visit = test_archive.storage.origin_visit_add( | ||||
new_origin['url'], visit_date, type='git') | new_origin['url'], visit_date, type='git') | ||||
visit_ids.append(origin_visit['visit']) | visit_ids.append(origin_visit['visit']) | ||||
self.storage.snapshot_add([new_snapshots[0]]) | test_archive.storage.snapshot_add([new_snapshots[0]]) | ||||
self.storage.origin_visit_update( | test_archive.storage.origin_visit_update( | ||||
new_origin['url'], visit_ids[0], | new_origin['url'], visit_ids[0], | ||||
snapshot=new_snapshots[0]['id']) | snapshot=new_snapshots[0]['id']) | ||||
url = reverse('api-1-origin-visit-latest', | url = reverse('api-1-origin-visit-latest', | ||||
url_args={'origin_url': new_origin['url']}) | url_args={'origin_url': new_origin['url']}) | ||||
url += '?require_snapshot=true' | url += '?require_snapshot=true' | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
self.assertEqual(rv.status_code, 200, rv.data) | assert rv.status_code == 200, rv.data | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | assert rv['Content-Type'] == 'application/json' | ||||
expected_visit = self.origin_visit_get_by( | expected_visit = test_archive.origin_visit_get_by( | ||||
new_origin['url'], visit_ids[0]) | new_origin['url'], visit_ids[0]) | ||||
origin_url = reverse('api-1-origin', | origin_url = reverse('api-1-origin', | ||||
url_args={'origin_url': new_origin['url']}) | url_args={'origin_url': new_origin['url']}) | ||||
snapshot_url = reverse( | snapshot_url = reverse( | ||||
'api-1-snapshot', | 'api-1-snapshot', | ||||
url_args={'snapshot_id': expected_visit['snapshot']}) | url_args={'snapshot_id': expected_visit['snapshot']}) | ||||
expected_visit['origin'] = new_origin['url'] | expected_visit['origin'] = new_origin['url'] | ||||
expected_visit['origin_url'] = origin_url | expected_visit['origin_url'] = origin_url | ||||
expected_visit['snapshot_url'] = snapshot_url | expected_visit['snapshot_url'] = snapshot_url | ||||
self.assertEqual(rv.data, expected_visit) | assert rv.data == expected_visit | ||||
@given(origin()) | @given(origin()) | ||||
def test_api_lookup_origin_visit_not_found(self, origin): | def test_api_lookup_origin_visit_not_found(api_client, origin): | ||||
all_visits = list(reversed(get_origin_visits(origin))) | all_visits = list(reversed(get_origin_visits(origin))) | ||||
max_visit_id = max([v['visit'] for v in all_visits]) | max_visit_id = max([v['visit'] for v in all_visits]) | ||||
url = reverse('api-1-origin-visit', | url = reverse('api-1-origin-visit', | ||||
url_args={'origin_url': origin['url'], | url_args={'origin_url': origin['url'], | ||||
'visit_id': max_visit_id + 1}) | 'visit_id': max_visit_id + 1}) | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
self.assertEqual(rv.status_code, 404, rv.data) | assert rv.status_code == 404, rv.data | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | assert rv['Content-Type'] == 'application/json' | ||||
self.assertEqual(rv.data, { | assert rv.data == { | ||||
'exception': 'NotFoundExc', | 'exception': 'NotFoundExc', | ||||
'reason': 'Origin %s or its visit with id %s not found!' % | 'reason': 'Origin %s or its visit with id %s not found!' % | ||||
(origin['url'], max_visit_id+1) | (origin['url'], max_visit_id+1) | ||||
}) | |||||
@pytest.mark.origin_id | |||||
def test_api_origins(self): | |||||
origins = get_tests_data()['origins'] | |||||
origin_urls = {origin['url'] for origin in origins} | |||||
# Get only one | |||||
url = reverse('api-1-origins', | |||||
query_params={'origin_count': 1}) | |||||
rv = self.client.get(url) | |||||
self.assertEqual(rv.status_code, 200, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual(len(rv.data), 1) | |||||
self.assertLess({origin['url'] for origin in rv.data}, origin_urls) | |||||
# Get all | |||||
url = reverse('api-1-origins', | |||||
query_params={'origin_count': len(origins)}) | |||||
rv = self.client.get(url) | |||||
self.assertEqual(rv.status_code, 200, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual(len(rv.data), len(origins)) | |||||
self.assertEqual({origin['url'] for origin in rv.data}, origin_urls) | |||||
# Get "all + 10" | |||||
url = reverse('api-1-origins', | |||||
query_params={'origin_count': len(origins)+10}) | |||||
rv = self.client.get(url) | |||||
self.assertEqual(rv.status_code, 200, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual(len(rv.data), len(origins)) | |||||
self.assertEqual({origin['url'] for origin in rv.data}, origin_urls) | |||||
@pytest.mark.origin_id | |||||
@given(strategies.integers(min_value=1)) | |||||
def test_api_origins_scroll(self, origin_count): | |||||
origins = get_tests_data()['origins'] | |||||
origin_urls = {origin['url'] for origin in origins} | |||||
url = reverse('api-1-origins', | |||||
query_params={'origin_count': origin_count}) | |||||
results = self._scroll_results(url) | |||||
self.assertEqual(len(results), len(origins)) | |||||
self.assertEqual({origin['url'] for origin in results}, origin_urls) | |||||
@given(origin()) | |||||
def test_api_origin_by_url(self, origin): | |||||
url = reverse('api-1-origin', | |||||
url_args={'origin_url': origin['url']}) | |||||
rv = self.client.get(url) | |||||
expected_origin = self.origin_get(origin) | |||||
origin_visits_url = reverse('api-1-origin-visits', | |||||
url_args={'origin_url': origin['url']}) | |||||
expected_origin['origin_visits_url'] = origin_visits_url | |||||
self.assertEqual(rv.status_code, 200, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual(rv.data, expected_origin) | |||||
@given(new_origin()) | |||||
def test_api_origin_not_found(self, new_origin): | |||||
url = reverse('api-1-origin', | |||||
url_args={'origin_url': new_origin['url']}) | |||||
rv = self.client.get(url) | |||||
self.assertEqual(rv.status_code, 404, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual(rv.data, { | |||||
'exception': 'NotFoundExc', | |||||
'reason': 'Origin with url %s not found!' % new_origin['url'] | |||||
}) | |||||
@pytest.mark.origin_id | |||||
def test_api_origin_search(self): | |||||
expected_origins = { | |||||
'https://github.com/wcoder/highlightjs-line-numbers.js', | |||||
'https://github.com/memononen/libtess2', | |||||
} | |||||
# Search for 'github.com', get only one | |||||
url = reverse('api-1-origin-search', | |||||
url_args={'url_pattern': 'github.com'}, | |||||
query_params={'limit': 1}) | |||||
rv = self.client.get(url) | |||||
self.assertEqual(rv.status_code, 200, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual(len(rv.data), 1) | |||||
self.assertLess({origin['url'] for origin in rv.data}, | |||||
expected_origins) | |||||
# Search for 'github.com', get all | |||||
url = reverse('api-1-origin-search', | |||||
url_args={'url_pattern': 'github.com'}, | |||||
query_params={'limit': 2}) | |||||
rv = self.client.get(url) | |||||
self.assertEqual(rv.status_code, 200, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual({origin['url'] for origin in rv.data}, | |||||
expected_origins) | |||||
# Search for 'github.com', get more than available | |||||
url = reverse('api-1-origin-search', | |||||
url_args={'url_pattern': 'github.com'}, | |||||
query_params={'limit': 10}) | |||||
rv = self.client.get(url) | |||||
self.assertEqual(rv.status_code, 200, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual({origin['url'] for origin in rv.data}, | |||||
expected_origins) | |||||
@pytest.mark.origin_id | |||||
def test_api_origin_search_regexp(self): | |||||
expected_origins = { | |||||
'https://github.com/memononen/libtess2', | |||||
'repo_with_submodules' | |||||
} | |||||
url = reverse('api-1-origin-search', | |||||
url_args={'url_pattern': '(repo|libtess)'}, | |||||
query_params={'limit': 10, | |||||
'regexp': True}) | |||||
rv = self.client.get(url) | |||||
self.assertEqual(rv.status_code, 200, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual({origin['url'] for origin in rv.data}, | |||||
expected_origins) | |||||
@pytest.mark.origin_id | |||||
@given(strategies.integers(min_value=1)) | |||||
def test_api_origin_search_scroll(self, limit): | |||||
expected_origins = { | |||||
'https://github.com/wcoder/highlightjs-line-numbers.js', | |||||
'https://github.com/memononen/libtess2', | |||||
} | } | ||||
url = reverse('api-1-origin-search', | |||||
url_args={'url_pattern': 'github.com'}, | |||||
query_params={'limit': limit}) | |||||
results = self._scroll_results(url) | |||||
self.assertEqual({origin['url'] for origin in results}, | def test_api_origin_search_limit(api_client, test_archive): | ||||
expected_origins) | test_archive.storage.origin_add([ | ||||
def test_api_origin_search_limit(self): | |||||
self.storage.origin_add([ | |||||
{'url': 'http://foobar/{}'.format(i)} | {'url': 'http://foobar/{}'.format(i)} | ||||
for i in range(2000) | for i in range(2000) | ||||
]) | ]) | ||||
url = reverse('api-1-origin-search', | url = reverse('api-1-origin-search', | ||||
url_args={'url_pattern': 'foobar'}, | url_args={'url_pattern': 'foobar'}, | ||||
query_params={'limit': 1050}) | query_params={'limit': 1050}) | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
self.assertEqual(rv.status_code, 200, rv.data) | assert rv.status_code == 200, rv.data | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | assert rv['Content-Type'] == 'application/json' | ||||
self.assertEqual(len(rv.data), 1000) | assert len(rv.data) == 1000 | ||||
@given(origin()) | @given(origin()) | ||||
def test_api_origin_metadata_search(self, origin): | def test_api_origin_metadata_search(api_client, mocker, origin): | ||||
with patch('swh.web.common.service.idx_storage') as mock_idx_storage: | mock_idx_storage = mocker.patch('swh.web.common.service.idx_storage') | ||||
mock_idx_storage.origin_intrinsic_metadata_search_fulltext \ | oimsft = mock_idx_storage.origin_intrinsic_metadata_search_fulltext | ||||
.side_effect = lambda conjunction, limit: [{ | oimsft.side_effect = lambda conjunction, limit: [{ | ||||
'from_revision': ( | 'from_revision': ( | ||||
b'p&\xb7\xc1\xa2\xafVR\x1e\x95\x1c\x01\xed ' | b'p&\xb7\xc1\xa2\xafVR\x1e\x95\x1c\x01\xed ' | ||||
b'\xf2U\xfa\x05B8'), | b'\xf2U\xfa\x05B8'), | ||||
'metadata': {'author': 'Jane Doe'}, | 'metadata': {'author': 'Jane Doe'}, | ||||
'id': origin['url'], | 'id': origin['url'], | ||||
'tool': { | 'tool': { | ||||
'configuration': { | 'configuration': { | ||||
'context': ['NpmMapping', 'CodemetaMapping'], | 'context': ['NpmMapping', 'CodemetaMapping'], | ||||
'type': 'local' | 'type': 'local' | ||||
}, | }, | ||||
'id': 3, | 'id': 3, | ||||
'name': 'swh-metadata-detector', | 'name': 'swh-metadata-detector', | ||||
'version': '0.0.1' | 'version': '0.0.1' | ||||
} | } | ||||
}] | }] | ||||
url = reverse('api-1-origin-metadata-search', | url = reverse('api-1-origin-metadata-search', | ||||
query_params={'fulltext': 'Jane Doe'}) | query_params={'fulltext': 'Jane Doe'}) | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
self.assertEqual(rv.status_code, 200, rv.content) | assert rv.status_code == 200, rv.content | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | assert rv['Content-Type'] == 'application/json' | ||||
expected_data = [{ | expected_data = [{ | ||||
'url': origin['url'], | 'url': origin['url'], | ||||
'metadata': { | 'metadata': { | ||||
'metadata': {'author': 'Jane Doe'}, | 'metadata': {'author': 'Jane Doe'}, | ||||
'from_revision': ( | 'from_revision': ( | ||||
'7026b7c1a2af56521e951c01ed20f255fa054238'), | '7026b7c1a2af56521e951c01ed20f255fa054238'), | ||||
'tool': { | 'tool': { | ||||
'configuration': { | 'configuration': { | ||||
'context': ['NpmMapping', 'CodemetaMapping'], | 'context': ['NpmMapping', 'CodemetaMapping'], | ||||
'type': 'local' | 'type': 'local' | ||||
}, | }, | ||||
'id': 3, | 'id': 3, | ||||
'name': 'swh-metadata-detector', | 'name': 'swh-metadata-detector', | ||||
'version': '0.0.1', | 'version': '0.0.1', | ||||
} | } | ||||
} | } | ||||
}] | }] | ||||
self.assertEqual(rv.data, expected_data) | |||||
mock_idx_storage.origin_intrinsic_metadata_search_fulltext \ | assert rv.data == expected_data | ||||
.assert_called_with(conjunction=['Jane Doe'], limit=70) | oimsft.assert_called_with(conjunction=['Jane Doe'], limit=70) | ||||
@given(origin()) | @given(origin()) | ||||
def test_api_origin_metadata_search_limit(self, origin): | def test_api_origin_metadata_search_limit(api_client, mocker, origin): | ||||
with patch('swh.web.common.service.idx_storage') as mock_idx_storage: | mock_idx_storage = mocker.patch('swh.web.common.service.idx_storage') | ||||
mock_idx_storage.origin_intrinsic_metadata_search_fulltext \ | oimsft = mock_idx_storage.origin_intrinsic_metadata_search_fulltext | ||||
.side_effect = lambda conjunction, limit: [{ | |||||
oimsft.side_effect = lambda conjunction, limit: [{ | |||||
'from_revision': ( | 'from_revision': ( | ||||
b'p&\xb7\xc1\xa2\xafVR\x1e\x95\x1c\x01\xed ' | b'p&\xb7\xc1\xa2\xafVR\x1e\x95\x1c\x01\xed ' | ||||
b'\xf2U\xfa\x05B8'), | b'\xf2U\xfa\x05B8'), | ||||
'metadata': {'author': 'Jane Doe'}, | 'metadata': {'author': 'Jane Doe'}, | ||||
'id': origin['url'], | 'id': origin['url'], | ||||
'tool': { | 'tool': { | ||||
'configuration': { | 'configuration': { | ||||
'context': ['NpmMapping', 'CodemetaMapping'], | 'context': ['NpmMapping', 'CodemetaMapping'], | ||||
'type': 'local' | 'type': 'local' | ||||
}, | }, | ||||
'id': 3, | 'id': 3, | ||||
'name': 'swh-metadata-detector', | 'name': 'swh-metadata-detector', | ||||
'version': '0.0.1' | 'version': '0.0.1' | ||||
} | } | ||||
}] | }] | ||||
url = reverse('api-1-origin-metadata-search', | url = reverse('api-1-origin-metadata-search', | ||||
query_params={'fulltext': 'Jane Doe'}) | query_params={'fulltext': 'Jane Doe'}) | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
self.assertEqual(rv.status_code, 200, rv.content) | assert rv.status_code == 200, rv.content | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | assert rv['Content-Type'] == 'application/json' | ||||
self.assertEqual(len(rv.data), 1) | assert len(rv.data) == 1 | ||||
mock_idx_storage.origin_intrinsic_metadata_search_fulltext \ | oimsft.assert_called_with(conjunction=['Jane Doe'], limit=70) | ||||
.assert_called_with(conjunction=['Jane Doe'], limit=70) | |||||
url = reverse('api-1-origin-metadata-search', | url = reverse('api-1-origin-metadata-search', | ||||
query_params={'fulltext': 'Jane Doe', | query_params={'fulltext': 'Jane Doe', | ||||
'limit': 10}) | 'limit': 10}) | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
self.assertEqual(rv.status_code, 200, rv.content) | assert rv.status_code == 200, rv.content | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | assert rv['Content-Type'] == 'application/json' | ||||
self.assertEqual(len(rv.data), 1) | assert len(rv.data) == 1 | ||||
mock_idx_storage.origin_intrinsic_metadata_search_fulltext \ | oimsft.assert_called_with(conjunction=['Jane Doe'], limit=10) | ||||
.assert_called_with(conjunction=['Jane Doe'], limit=10) | |||||
url = reverse('api-1-origin-metadata-search', | url = reverse('api-1-origin-metadata-search', | ||||
query_params={'fulltext': 'Jane Doe', | query_params={'fulltext': 'Jane Doe', | ||||
'limit': 987}) | 'limit': 987}) | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
assert rv.status_code == 200, rv.content | |||||
assert rv['Content-Type'] == 'application/json' | |||||
assert len(rv.data) == 1 | |||||
oimsft.assert_called_with(conjunction=['Jane Doe'], limit=100) | |||||
self.assertEqual(rv.status_code, 200, rv.content) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual(len(rv.data), 1) | |||||
mock_idx_storage.origin_intrinsic_metadata_search_fulltext \ | |||||
.assert_called_with(conjunction=['Jane Doe'], limit=100) | |||||
@given(origin()) | @given(origin()) | ||||
def test_api_origin_intrinsic_metadata(self, origin): | def test_api_origin_intrinsic_metadata(api_client, mocker, origin): | ||||
with patch('swh.web.common.service.idx_storage') as mock_idx_storage: | mock_idx_storage = mocker.patch('swh.web.common.service.idx_storage') | ||||
mock_idx_storage.origin_intrinsic_metadata_get \ | oimg = mock_idx_storage.origin_intrinsic_metadata_get | ||||
.side_effect = lambda origin_urls: [{ | oimg.side_effect = lambda origin_urls: [{ | ||||
'from_revision': ( | 'from_revision': ( | ||||
b'p&\xb7\xc1\xa2\xafVR\x1e\x95\x1c\x01\xed ' | b'p&\xb7\xc1\xa2\xafVR\x1e\x95\x1c\x01\xed ' | ||||
b'\xf2U\xfa\x05B8'), | b'\xf2U\xfa\x05B8'), | ||||
'metadata': {'author': 'Jane Doe'}, | 'metadata': {'author': 'Jane Doe'}, | ||||
'id': origin['url'], | 'id': origin['url'], | ||||
'tool': { | 'tool': { | ||||
'configuration': { | 'configuration': { | ||||
'context': ['NpmMapping', 'CodemetaMapping'], | 'context': ['NpmMapping', 'CodemetaMapping'], | ||||
'type': 'local' | 'type': 'local' | ||||
}, | }, | ||||
'id': 3, | 'id': 3, | ||||
'name': 'swh-metadata-detector', | 'name': 'swh-metadata-detector', | ||||
'version': '0.0.1' | 'version': '0.0.1' | ||||
} | } | ||||
}] | }] | ||||
url = reverse('api-origin-intrinsic-metadata', | url = reverse('api-origin-intrinsic-metadata', | ||||
url_args={'origin_url': origin['url']}) | url_args={'origin_url': origin['url']}) | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
mock_idx_storage.origin_intrinsic_metadata_get \ | oimg.assert_called_once_with([origin['url']]) | ||||
.assert_called_once_with([origin['url']]) | assert rv.status_code == 200, rv.content | ||||
self.assertEqual(rv.status_code, 200, rv.content) | assert rv['Content-Type'] == 'application/json' | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
expected_data = {'author': 'Jane Doe'} | expected_data = {'author': 'Jane Doe'} | ||||
self.assertEqual(rv.data, expected_data) | assert rv.data == expected_data | ||||
@patch('swh.web.common.service.idx_storage') | |||||
def test_api_origin_metadata_search_invalid(self, mock_idx_storage): | |||||
def test_api_origin_metadata_search_invalid(api_client, mocker): | |||||
mock_idx_storage = mocker.patch('swh.web.common.service.idx_storage') | |||||
url = reverse('api-1-origin-metadata-search') | url = reverse('api-1-origin-metadata-search') | ||||
rv = self.client.get(url) | rv = api_client.get(url) | ||||
self.assertEqual(rv.status_code, 400, rv.content) | assert rv.status_code == 400, rv.content | ||||
mock_idx_storage.assert_not_called() | mock_idx_storage.assert_not_called() |