import datetime from unittest import mock from bx_django_utils.test_utils.datetime import MockDatetimeGenerator from bx_django_utils.test_utils.html_assertion import HtmlAssertionMixin, assert_html_response_snapshot from bx_py_utils.test_utils.snapshot import assert_html_snapshot from django.template.defaulttags import CsrfTokenNode, NowNode from django.test import TestCase, override_settings from django.utils import timezone from django_tools.unittest_utils.mockup import ImageDummy from reversion.models import Revision from inventory import __version__ from inventory.models import ItemImageModel, ItemModel from inventory_project.tests.fixtures import get_normal_user ITEM_FORM_DEFAULTS = { 'version': 0, # VersionProtectBaseModel field 'kind': 'kind', 'name': 'name', 'itemimagemodel_set-TOTAL_FORMS': '0', 'itemimagemodel_set-INITIAL_FORMS': '0', 'itemimagemodel_set-MIN_NUM_FORMS': '0', 'itemimagemodel_set-MAX_NUM_FORMS': '1000', 'itemimagemodel_set-__prefix__-position': '0', 'itemfilemodel_set-TOTAL_FORMS': '0', 'itemfilemodel_set-INITIAL_FORMS': '0', 'itemfilemodel_set-MIN_NUM_FORMS': '0', 'itemfilemodel_set-MAX_NUM_FORMS': '1000', 'itemfilemodel_set-__prefix__-position': '0', 'itemlinkmodel_set-TOTAL_FORMS': '0', 'itemlinkmodel_set-INITIAL_FORMS': '0', 'itemlinkmodel_set-MIN_NUM_FORMS': '0', 'itemlinkmodel_set-MAX_NUM_FORMS': '1000', 'itemlinkmodel_set-__prefix__-position': '0', '_save': 'Save', } ITEM_FORM_DEFAULTS = tuple(ITEM_FORM_DEFAULTS.items()) @override_settings(SECURE_SSL_REDIRECT=True) class AdminAnonymousTests(HtmlAssertionMixin, TestCase): def test_login(self): # HTTP -> HTTPS redirect: response = self.client.get('/admin/', HTTP_ACCEPT_LANGUAGE='en') self.assertRedirects( response, expected_url='https://testserver/admin/', status_code=301, # Permanent redirect fetch_redirect_response=False ) response = self.client.get( path='/admin/inventory/itemmodel/add/', secure=True, HTTP_ACCEPT_LANGUAGE='en' ) self.assertRedirects( response, expected_url='/admin/login/?next=/admin/inventory/itemmodel/add/', fetch_redirect_response=False ) with mock.patch.object(CsrfTokenNode, 'render', return_value='MockedCsrfTokenNode'): response = self.client.get( path='/admin/login/', secure=True, HTTP_ACCEPT_LANGUAGE='en' ) self.assert_html_parts(response, parts=( f'Log in | PyInventory v{__version__}', '', '', )) assert_html_response_snapshot(response, validate=False) @override_settings(SECURE_SSL_REDIRECT=False) class AdminTestCase(HtmlAssertionMixin, TestCase): @classmethod def setUpTestData(cls): cls.normaluser = get_normal_user() def test_normal_user_create_minimal_item(self): offset = datetime.timedelta(minutes=1) with mock.patch.object(timezone, 'now', MockDatetimeGenerator(offset=offset)),\ mock.patch.object(NowNode, 'render', return_value='MockedNowNode'), \ mock.patch.object(CsrfTokenNode, 'render', return_value='MockedCsrfTokenNode'): self.client.force_login(self.normaluser) response = self.client.get('/admin/inventory/itemmodel/add/') assert response.status_code == 200 self.assert_html_parts(response, parts=( f'Add Item | PyInventory v{__version__}', )) assert_html_response_snapshot(response=response, validate=False) assert ItemModel.objects.count() == 0 post_data = dict(ITEM_FORM_DEFAULTS) response = self.client.post( path='/admin/inventory/itemmodel/add/', data=post_data, ) assert response.status_code == 302, response.content.decode('utf-8') # Form error? self.assertRedirects(response, expected_url='/admin/inventory/itemmodel/') data = list(ItemModel.objects.values_list('kind__name', 'name', 'version')) assert data == [('kind', 'name', 2)] # FIXME: Save call done two times! item = ItemModel.objects.first() self.assert_messages( response, expected_messages=[ f'The Item “name”' ' was added successfully.' ], ) assert item.user_id == self.normaluser.pk # Test django-tools VersionProtectBaseModel integration: assert item.version == 2 # current Version in DB post_data['version'] = 1 # Try to overwrite with older version post_data['name'] = 'A new Name!' response = self.client.post( path=f'/admin/inventory/itemmodel/{item.pk}/change/', data=post_data, ) self.assert_html_parts(response, parts=( f'Change Item | PyInventory v{__version__}', '
  • Version error: Overwrite version 2 with 1 is forbidden!
  • ', '
    - "name"\n+ "A new Name!"
    ' )) html = response.content.decode('utf-8') html = html.replace(str(item.pk), '') assert_html_snapshot(got=html, validate=False) # django-revision integration: comments = list(Revision.objects.order_by('date_created').values_list('comment', flat=True)) self.assertEqual(comments, ['Added.']) def test_new_item_with_image(self): """ https://github.com/jedie/PyInventory/issues/33 """ self.client.force_login(self.normaluser) img = ImageDummy(width=1, height=1, format='png').in_memory_image_file(filename='test.png') post_data = dict(ITEM_FORM_DEFAULTS) post_data.update({ 'itemimagemodel_set-TOTAL_FORMS': '1', 'itemimagemodel_set-0-position': '0', 'itemimagemodel_set-0-image': img, }) response = self.client.post( path='/admin/inventory/itemmodel/add/', data=post_data, ) self.assertRedirects(response, expected_url='/admin/inventory/itemmodel/') data = list(ItemModel.objects.values_list('kind__name', 'name')) assert data == [('kind', 'name')] item = ItemModel.objects.first() self.assert_messages( response, expected_messages=[ f'The Item “name”' ' was added successfully.' ], ) assert item.user_id == self.normaluser.pk assert ItemImageModel.objects.count() == 1 image = ItemImageModel.objects.first() assert image.name == 'test.png' assert image.item == item assert image.user_id == self.normaluser.pk def test_auto_group_items(self): self.client.force_login(self.normaluser) offset = datetime.timedelta(minutes=1) with mock.patch.object(timezone, 'now', MockDatetimeGenerator(offset=offset)): for main_item_no in range(1, 3): main_item = ItemModel.objects.create( id=f'00000000-000{main_item_no}-0000-0000-000000000000', user=self.normaluser, name=f'main item {main_item_no}' ) main_item.full_clean() for sub_item_no in range(1, 3): sub_item = ItemModel.objects.create( id=f'00000000-000{main_item_no}-000{sub_item_no}-0000-000000000000', user=self.normaluser, parent=main_item, name=f'sub item {main_item_no}.{sub_item_no}' ) sub_item.full_clean() names = list(ItemModel.objects.order_by('id').values_list('name', flat=True)) assert names == [ 'main item 1', 'sub item 1.1', 'sub item 1.2', 'main item 2', 'sub item 2.1', 'sub item 2.2', ] with mock.patch.object(NowNode, 'render', return_value='MockedNowNode'), mock.patch.object( CsrfTokenNode, 'render', return_value='MockedCsrfTokenNode' ): response = self.client.get( path='/admin/inventory/itemmodel/', ) assert response.status_code == 200 self.assert_html_parts( response, parts=( f'Select Item to change | PyInventory v{__version__}', '' 'main item 1', '' 'main item 1 › sub item 1.1', ), ) assert_html_response_snapshot(response=response, validate=False)