Changeset View
Changeset View
Standalone View
Standalone View
swh/web/tests/api/views/test_revision.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 | ||||
import random | |||||
from hypothesis import given | from hypothesis import given | ||||
import pytest | |||||
from rest_framework.test import APITestCase | from rest_framework.test import APITestCase | ||||
from unittest.mock import patch | from unittest.mock import patch | ||||
from swh.web.common.exc import NotFoundExc | from swh.web.common.exc import NotFoundExc | ||||
from swh.web.common.utils import reverse, parse_timestamp | from swh.web.common.utils import reverse | ||||
from swh.web.tests.data import random_sha1 | from swh.web.tests.data import random_sha1 | ||||
from swh.web.tests.strategies import ( | from swh.web.tests.strategies import revision | ||||
revision, origin, origin_with_multiple_visits | |||||
) | |||||
from swh.web.tests.testcase import WebTestCase | from swh.web.tests.testcase import WebTestCase | ||||
class RevisionApiTestCase(WebTestCase, APITestCase): | class RevisionApiTestCase(WebTestCase, APITestCase): | ||||
@given(revision()) | @given(revision()) | ||||
def test_api_revision(self, revision): | def test_api_revision(self, revision): | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | def test_api_revision_raw_ko_no_rev(self): | ||||
self.assertEqual(rv.status_code, 404, rv.data) | self.assertEqual(rv.status_code, 404, rv.data) | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | self.assertEqual(rv['Content-Type'], 'application/json') | ||||
self.assertEqual(rv.data, { | self.assertEqual(rv.data, { | ||||
'exception': 'NotFoundExc', | 'exception': 'NotFoundExc', | ||||
'reason': 'Revision with sha1_git %s not found.' % | 'reason': 'Revision with sha1_git %s not found.' % | ||||
unknown_revision_}) | unknown_revision_}) | ||||
@pytest.mark.origin_id | |||||
def test_api_revision_with_origin_id_not_found(self): | |||||
unknown_origin_id = random.randint(1000, 1000000) | |||||
url = reverse('api-1-revision-origin', | |||||
url_args={'origin_id': unknown_origin_id}) | |||||
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 %s not found!' % | |||||
unknown_origin_id}) | |||||
@pytest.mark.origin_id | |||||
@given(origin()) | |||||
def test_api_revision_with_origin_id(self, origin): | |||||
url = reverse('api-1-revision-origin', | |||||
url_args={'origin_id': origin['id']}) | |||||
rv = self.client.get(url) | |||||
snapshot = self.snapshot_get_latest(origin['url']) | |||||
expected_revision = self.revision_get( | |||||
snapshot['branches']['HEAD']['target']) | |||||
self._enrich_revision(expected_revision) | |||||
self.assertEqual(rv.status_code, 200, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual(rv.data, expected_revision) | |||||
@pytest.mark.origin_id | |||||
@given(origin()) | |||||
def test_api_revision_with_origin_id_and_branch_name(self, origin): | |||||
snapshot = self.snapshot_get_latest(origin['url']) | |||||
branch_name = random.choice( | |||||
list(b for b in snapshot['branches'].keys() | |||||
if snapshot['branches'][b]['target_type'] == 'revision')) | |||||
url = reverse('api-1-revision-origin', | |||||
url_args={'origin_id': origin['id'], | |||||
'branch_name': branch_name}) | |||||
rv = self.client.get(url) | |||||
expected_revision = self.revision_get( | |||||
snapshot['branches'][branch_name]['target']) | |||||
self._enrich_revision(expected_revision) | |||||
self.assertEqual(rv.status_code, 200, rv.data) | |||||
self.assertEqual(rv['content-type'], 'application/json') | |||||
self.assertEqual(rv.data, expected_revision) | |||||
@pytest.mark.origin_id | |||||
@given(origin_with_multiple_visits()) | |||||
def test_api_revision_with_origin_id_and_branch_name_and_ts(self, origin): | |||||
visit = random.choice(self.origin_visit_get(origin['url'])) | |||||
snapshot = self.snapshot_get(visit['snapshot']) | |||||
branch_name = random.choice( | |||||
list(b for b in snapshot['branches'].keys() | |||||
if snapshot['branches'][b]['target_type'] == 'revision')) | |||||
url = reverse('api-1-revision-origin', | |||||
url_args={'origin_id': origin['id'], | |||||
'branch_name': branch_name, | |||||
'ts': visit['date']}) | |||||
rv = self.client.get(url) | |||||
expected_revision = self.revision_get( | |||||
snapshot['branches'][branch_name]['target']) | |||||
self._enrich_revision(expected_revision) | |||||
self.assertEqual(rv.status_code, 200, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual(rv.data, expected_revision) | |||||
@pytest.mark.origin_id | |||||
@given(origin_with_multiple_visits()) | |||||
def test_api_revision_with_origin_id_and_branch_name_and_ts_escapes( | |||||
self, origin): | |||||
visit = random.choice(self.origin_visit_get(origin['url'])) | |||||
snapshot = self.snapshot_get(visit['snapshot']) | |||||
branch_name = random.choice( | |||||
list(b for b in snapshot['branches'].keys() | |||||
if snapshot['branches'][b]['target_type'] == 'revision')) | |||||
date = parse_timestamp(visit['date']) | |||||
formatted_date = date.strftime('Today is %B %d, %Y at %X') | |||||
url = reverse('api-1-revision-origin', | |||||
url_args={'origin_id': origin['id'], | |||||
'branch_name': branch_name, | |||||
'ts': formatted_date}) | |||||
rv = self.client.get(url) | |||||
expected_revision = self.revision_get( | |||||
snapshot['branches'][branch_name]['target']) | |||||
self._enrich_revision(expected_revision) | |||||
self.assertEqual(rv.status_code, 200, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual(rv.data, expected_revision) | |||||
@pytest.mark.origin_id | |||||
def test_api_directory_through_revision_origin_id_ko(self): | |||||
unknown_origin_id_ = random.randint(1000, 1000000) | |||||
url = reverse('api-1-revision-origin-directory', | |||||
url_args={'origin_id': unknown_origin_id_}) | |||||
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 %s not found!' % | |||||
unknown_origin_id_ | |||||
}) | |||||
@pytest.mark.origin_id | |||||
@given(origin()) | |||||
def test_api_directory_through_revision_origin_id(self, origin): | |||||
url = reverse('api-1-revision-origin-directory', | |||||
url_args={'origin_id': origin['id']}) | |||||
rv = self.client.get(url) | |||||
snapshot = self.snapshot_get_latest(origin['id']) | |||||
revision_id = snapshot['branches']['HEAD']['target'] | |||||
revision = self.revision_get(revision_id) | |||||
directory = self.directory_ls(revision['directory']) | |||||
for entry in directory: | |||||
if entry['type'] == 'dir': | |||||
entry['target_url'] = reverse( | |||||
'api-1-directory', | |||||
url_args={'sha1_git': entry['target']} | |||||
) | |||||
entry['dir_url'] = reverse( | |||||
'api-1-revision-origin-directory', | |||||
url_args={'origin_id': origin['id'], | |||||
'path': entry['name']}) | |||||
elif entry['type'] == 'file': | |||||
entry['target_url'] = reverse( | |||||
'api-1-content', | |||||
url_args={'q': 'sha1_git:%s' % entry['target']} | |||||
) | |||||
entry['file_url'] = reverse( | |||||
'api-1-revision-origin-directory', | |||||
url_args={'origin_id': origin['id'], | |||||
'path': entry['name']}) | |||||
elif entry['type'] == 'rev': | |||||
entry['target_url'] = reverse( | |||||
'api-1-revision', | |||||
url_args={'sha1_git': entry['target']} | |||||
) | |||||
entry['rev_url'] = reverse( | |||||
'api-1-revision-origin-directory', | |||||
url_args={'origin_id': origin['id'], | |||||
'path': entry['name']}) | |||||
expected_result = { | |||||
'content': directory, | |||||
'path': '.', | |||||
'revision': revision_id, | |||||
'type': 'dir' | |||||
} | |||||
self.assertEqual(rv.status_code, 200, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual(rv.data, expected_result) | |||||
@given(revision()) | @given(revision()) | ||||
def test_api_revision_log(self, revision): | def test_api_revision_log(self, revision): | ||||
per_page = 10 | per_page = 10 | ||||
url = reverse('api-1-revision-log', url_args={'sha1_git': revision}, | url = reverse('api-1-revision-log', url_args={'sha1_git': revision}, | ||||
query_params={'per_page': per_page}) | query_params={'per_page': per_page}) | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | def test_api_revision_log_context(self, revision): | ||||
prev_revision = self.revision_get(prev_rev) | prev_revision = self.revision_get(prev_rev) | ||||
expected_log.insert(0, prev_revision) | expected_log.insert(0, prev_revision) | ||||
expected_log = list(map(self._enrich_revision, expected_log)) | expected_log = list(map(self._enrich_revision, expected_log)) | ||||
self.assertEqual(rv.status_code, 200, rv.data) | self.assertEqual(rv.status_code, 200, rv.data) | ||||
self.assertEqual(rv['Content-Type'], 'application/json') | self.assertEqual(rv['Content-Type'], 'application/json') | ||||
self.assertEqual(rv.data, expected_log) | self.assertEqual(rv.data, expected_log) | ||||
@pytest.mark.origin_id | |||||
@given(origin()) | |||||
def test_api_revision_log_by_origin_id(self, origin): | |||||
per_page = 10 | |||||
url = reverse('api-1-revision-origin-log', | |||||
url_args={'origin_id': origin['id']}, | |||||
query_params={'per_page': per_page}) | |||||
rv = self.client.get(url) | |||||
snapshot = self.snapshot_get_latest(origin['url']) | |||||
expected_log = self.revision_log( | |||||
snapshot['branches']['HEAD']['target'], limit=per_page+1) | |||||
expected_log = list(map(self._enrich_revision, expected_log)) | |||||
has_next = len(expected_log) > per_page | |||||
self.assertEqual(rv.status_code, 200, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertEqual(rv.data, | |||||
expected_log[:-1] if has_next else expected_log) | |||||
if has_next: | |||||
self.assertIn('Link', rv) | |||||
next_log_url = reverse( | |||||
'api-1-revision-origin-log', | |||||
url_args={'origin_id': origin['id'], | |||||
'branch_name': 'HEAD'}, | |||||
query_params={'per_page': per_page, | |||||
'sha1_git': expected_log[-1]['id']}) | |||||
self.assertIn(next_log_url, rv['Link']) | |||||
@pytest.mark.origin_id | |||||
@given(origin()) | |||||
def test_api_revision_log_by_ko(self, origin): | |||||
invalid_branch_name = 'foobar' | |||||
url = reverse('api-1-revision-origin-log', | |||||
url_args={'origin_id': origin['id'], | |||||
'branch_name': invalid_branch_name}) | |||||
rv = self.client.get(url) | |||||
self.assertEqual(rv.status_code, 404, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertFalse(rv.has_header('Link')) | |||||
self.assertEqual( | |||||
rv.data, | |||||
{'exception': 'NotFoundExc', | |||||
'reason': 'Revision for origin %s and branch %s not found.' % | |||||
(origin['id'], invalid_branch_name)}) | |||||
@pytest.mark.origin_id | |||||
@given(origin()) | |||||
def test_api_revision_log_by_origin_id_ko(self, origin): | |||||
invalid_branch_name = 'foobar' | |||||
url = reverse('api-1-revision-origin-log', | |||||
url_args={'origin_id': origin['id'], | |||||
'branch_name': invalid_branch_name}) | |||||
rv = self.client.get(url) | |||||
self.assertEqual(rv.status_code, 404, rv.data) | |||||
self.assertEqual(rv['Content-Type'], 'application/json') | |||||
self.assertFalse(rv.has_header('Link')) | |||||
self.assertEqual( | |||||
rv.data, | |||||
{'exception': 'NotFoundExc', | |||||
'reason': 'Revision for origin %s and branch %s not found.' % | |||||
(origin['id'], invalid_branch_name)}) | |||||
@patch('swh.web.api.views.revision._revision_directory_by') | @patch('swh.web.api.views.revision._revision_directory_by') | ||||
def test_api_revision_directory_ko_not_found(self, mock_rev_dir): | def test_api_revision_directory_ko_not_found(self, mock_rev_dir): | ||||
# given | # given | ||||
mock_rev_dir.side_effect = NotFoundExc('Not found') | mock_rev_dir.side_effect = NotFoundExc('Not found') | ||||
# then | # then | ||||
rv = self.client.get('/api/1/revision/999/directory/some/path/to/dir/') | rv = self.client.get('/api/1/revision/999/directory/some/path/to/dir/') | ||||
▲ Show 20 Lines • Show All 117 Lines • Show Last 20 Lines |