from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.test import TestCase, Client, override_settings from django.urls import reverse from galerie.models import Galerie, Soubor from soustredeni.models import Soustredeni import django.contrib.auth.models as auth import personalni.models as pers import tvorba.models as tv from contextlib import ExitStack from pathlib import Path import shutil import tempfile # NOTE: Existují metody, jak si pořídit kontext: https://docs.python.org/3/library/unittest.html#unittest.TestCase.enterClassContext # Nepoužíváme je, protože jsem nepřišlo na to, jak je pak použít v `@override_settings(MEDIA_ROOT=media_dir)` # Ref: https://stackoverflow.com/a/2269295 tempdir = tempfile.TemporaryDirectory(prefix='mamweb_test') media_dir = Path(tempdir.name) / 'media' class GalerieTests(TestCase): @classmethod def setUpTestData(cls): org_perm = auth.Permission.objects.get(content_type=ContentType.objects.get_for_model(auth.User), codename='org') resitel_perm = auth.Permission.objects.get(content_type=ContentType.objects.get_for_model(auth.User), codename='resitel') r = tv.Rocnik.objects.create(rocnik=42, prvni_rok=1970) cls.sous_a = Soustredeni.objects.create(rocnik=r) cls.sous_b = Soustredeni.objects.create(rocnik=r) cls.neucastnik = pers.Resitel.objects.create(osoba=pers.Osoba.objects.create(user=auth.User.objects.create_user(username='ne'))) cls.neucastnik.osoba.user.user_permissions.add(resitel_perm) cls.ucastnik_a = pers.Resitel.objects.create(osoba=pers.Osoba.objects.create(user=auth.User.objects.create_user(username='ua'))) cls.ucastnik_a.osoba.user.user_permissions.add(resitel_perm) cls.sous_a.ucastnici.add(cls.ucastnik_a) cls.ucastnik_b = pers.Resitel.objects.create(osoba=pers.Osoba.objects.create(user=auth.User.objects.create_user(username='ub'))) cls.ucastnik_b.osoba.user.user_permissions.add(resitel_perm) cls.sous_b.ucastnici.add(cls.ucastnik_b) cls.org = pers.Organizator.objects.create(osoba=pers.Osoba.objects.create(user=auth.User.objects.create_user(username='o', is_staff=True))) cls.org.osoba.user.user_permissions.add(org_perm) def setUp(self): media_dir.mkdir() def tearDown(self): shutil.rmtree(media_dir) @classmethod def tearDownClass(cls): super().tearDownClass() tempdir.cleanup() # TODO: tohle není moc unit test. Správnější by bylo mít polopřipravené # věci (sous s galerií, sous bez galerie, sous se špatně uspořádanými # galeriemi ap.) a dedikované testy na jednotlivé úkony. Ale teď jsem to # začalo psát takhle a chci to nejdřív dopsat a commitnout, takže pokud to # zapomenu rozstřelit na menší, tak to takhle zůstane… @override_settings(MEDIA_ROOT=media_dir) def test_vyrobeni_galerii_k_sousu(self): """Vyrobí strukturu galerií odpovídající sousové běžné struktuře pomocí příslušných views""" org_client = Client() org_client.force_login(self.org.osoba.user) resp = org_client.get(reverse('galerie_nova', kwargs={'soustredeni': self.sous_a.id, 'galerie': 0})) self.assertEqual(resp.status_code, 200) tf = Path(settings.BASE_DIR) / 'galerie' / 'testfiles' filenames_pa = [ tf / 'kod_emoji.jpg', tf / 'metal.jpg', tf / 'ohno_small.jpg', ] filenames_so = [ tf / 'pf2020_small.jpg', ] resp = org_client.post( reverse('galerie_nova', kwargs={'soustredeni': self.sous_a.id, 'galerie': 0}), data={'nazev': 'Top galerie k sousu A'}, follow=True, ) self.assertEqual(resp.status_code, 200) # Teď je kind-of těžké kliknout na „přidat novou podgalerii“, protože ten odkaz je někde v HTML vyrenderovaný templatem. # Ale můžeme vytáhnout pk galerie z kontextu top_gal = resp.context['galerie'] self.assertIsInstance(top_gal, Galerie) # Záměrně vyrobíme nejdřív sobotní a pak páteční galerii, ať je pak můžeme prohodit with ExitStack() as stack: files = [stack.enter_context(open(fn, 'rb')) for fn in filenames_so] resp = org_client.post( reverse('galerie_nova', kwargs={'soustredeni': self.sous_a.id, 'galerie': top_gal.pk}), data={'nazev': 'Sobota', 'obr': files}, follow=True, ) self.assertEqual(resp.status_code, 200) so_gal = resp.context['galerie'] self.assertIsInstance(so_gal, Galerie) with ExitStack() as stack: files = [stack.enter_context(open(fn, 'rb')) for fn in filenames_pa] resp = org_client.post( reverse('galerie_nova', kwargs={'soustredeni': self.sous_a.id, 'galerie': top_gal.pk}), data={'nazev': 'Pátek', 'obr': files}, follow=True, ) self.assertEqual(resp.status_code, 200) pa_gal = resp.context['galerie'] self.assertIsInstance(pa_gal, Galerie) self.assertGreater(pa_gal.poradi, so_gal.poradi) # Dokonce i tušíme, jaká ta pořadí jsou # NOTE: pokud tohle začne failovat, tak je asi safe to smazat. self.assertEqual(pa_gal.poradi, 2) self.assertEqual(so_gal.poradi, 1) # Teď je prohodíme: # NOTE: použití metody PATCH by tady prošlo, protože nekontrolujeme, # jaká metoda se používá. Ale dokud simulujeme orga na webu s odkazy # (``), tak použijeme GET. resp = org_client.get( reverse('galerie_doleva', kwargs={'soustredeni': self.sous_a.id, 'galerie': top_gal.pk, 'subgalerie': pa_gal.pk}), follow=True, ) self.assertEqual(resp.status_code, 200) resp = org_client.get( reverse('galerie_doprava', kwargs={'soustredeni': self.sous_a.id, 'galerie': top_gal.pk, 'subgalerie': so_gal.pk}), follow=True, ) self.assertEqual(resp.status_code, 200) # Změnil se stav pa_gal.refresh_from_db() so_gal.refresh_from_db() self.assertLess(pa_gal.poradi, so_gal.poradi) self.assertEqual(pa_gal.poradi, 1) self.assertEqual(so_gal.poradi, 2)