'''
Faraday Penetration Test IDE
Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/)
See the file 'doc/LICENSE' for the license information
'''
"""Generic test mixins for APIs with pagination enabled when listing"""
import pytest
try:
from urllib import urlencode
except ImportError as e:
from urllib.parse import urlencode, urljoin
def with_0_and_n_objects(n=10):
return pytest.mark.parametrize('object_count', [0, n])
class PaginationTestsMixin:
@pytest.fixture
def delete_previously_created_objects(self, session):
for obj in self.objects:
session.delete(obj)
session.commit()
@pytest.fixture
def pagination_test_logic(self, delete_previously_created_objects,
mock_envelope_list):
# Load this two fixtures
pass
def create_many_objects(self, session, n):
objects = self.factory.create_batch(n)
session.commit()
return objects
def page_url(self, page_number=None, per_page=None):
parameters = {}
if page_number is not None:
parameters[
self.view_class.page_number_parameter_name] = page_number
if per_page is not None:
parameters[self.view_class.per_page_parameter_name] = per_page
return urljoin(self.url(), f'?{urlencode(parameters)}')
@pytest.mark.parametrize("page_number", [None, 1, 2])
@pytest.mark.usefixtures('pagination_test_logic')
@pytest.mark.pagination
def test_returns_all_with_no_per_page(self, test_client, session,
page_number):
self.create_many_objects(session, 100)
res = test_client.get(self.page_url(page_number,
per_page=None))
assert res.status_code == 200
assert len(res.json['data']) == 100
@pytest.mark.skip("TODO: Fix for sqlite and postgres")
@with_0_and_n_objects()
@pytest.mark.usefixtures('pagination_test_logic')
@pytest.mark.pagination
def test_does_not_allow_negative_per_page(self, session, test_client,
object_count):
self.create_many_objects(session, object_count)
res = test_client.get(self.page_url(1, -1))
assert res.status_code == 404
@pytest.mark.skip("TODO: Fix for sqlite and postgres")
@with_0_and_n_objects()
@pytest.mark.usefixtures('pagination_test_logic')
@pytest.mark.pagination
def test_does_not_allow_negative_page_number(self, session, test_client,
object_count):
self.create_many_objects(session, object_count)
res = test_client.get(self.page_url(-1, 10))
assert res.status_code == 200
assert res.json == {'data': []}
@pytest.mark.usefixtures('pagination_test_logic')
@pytest.mark.pagination
def test_pages_have_different_elements(self, session, test_client):
"""Test correct page size, correct IDs and that there are
no duplicate items in different pages"""
ids = {getattr(obj, self.pk_field)
for obj in self.create_many_objects(session, 95)}
for page_number in range(1, 11):
res = test_client.get(self.page_url(page_number, 10))
assert res.status_code == 200
new_ids = {obj.get(self.pk_field) for obj in res.json['data']}
assert len(new_ids) == (5 if page_number == 10 else 10)
assert new_ids.issubset(ids)
ids.difference_update(new_ids) # Remove the new ids
assert not ids
@pytest.mark.usefixtures('pagination_test_logic')
@pytest.mark.pagination
def test_404_on_page_with_no_elements(self, session, test_client):
self.create_many_objects(session, 5)
res = test_client.get(self.page_url(2, 5))
assert res.status_code == 200
assert res.json == {'data': []}
@pytest.mark.usefixtures('pagination_test_logic')
@pytest.mark.pagination
def test_succeed_on_first_page_with_no_elements(self, test_client):
res = test_client.get(self.page_url(1, 5))
assert res.status_code == 200
assert len(res.json['data']) == 0