From 57bab53cec76f7cf84ae8ad4472073ff54e892b5 Mon Sep 17 00:00:00 2001 From: Philip Sargent Date: Thu, 4 Jul 2024 22:10:49 +0300 Subject: [PATCH] Nearly fixed test suite --- core/TESTS/test_caves.py | 75 +++++++++++----- core/TESTS/test_logins.py | 171 +++++++++++++++++-------------------- core/TESTS/test_parsers.py | 62 ++++++++------ core/utils.py | 2 +- 4 files changed, 170 insertions(+), 140 deletions(-) diff --git a/core/TESTS/test_caves.py b/core/TESTS/test_caves.py index 437648a..2fb3102 100644 --- a/core/TESTS/test_caves.py +++ b/core/TESTS/test_caves.py @@ -6,10 +6,24 @@ import re from http import HTTPStatus from django.test import Client, TestCase +from django.contrib.auth.models import User from troggle.core.models.caves import Cave -from troggle.core.models.troggle import Person, PersonExpedition +from troggle.core.models.troggle import Person, PersonExpedition, Expedition +from troggle.core.utils import current_expo +current_year = current_expo() + + +def create_user(name=None, last_name="Caver", is_superuser=False): + u = User() + u.username = name + u.email = f"philip.sargent+{name}@gmail.com" + u.first_name, u.last_name = name, last_name + u.set_password("secretword") # all test users have same password + u.save() + return u + # import troggle.settings as settings # FIXTURE_DIRS = settings.PYTHON_PATH / "core" /"fixtures" @@ -18,24 +32,52 @@ class FixtureTests(TestCase): They do not exercise the GET and url functions """ - fixtures = ["auth_users", "expo_caves", "expo_exped"] + fixtures = ["expo_caves", "expo_exped"] ph = r"and leads in 800m of tortuous going to" def setUp(self): - pass + create_user(name="expo") # needed for current_year() def tearDown(self): - pass + User.objects.all().delete() - def test_fix_person_loaded(self): + def test_fix_person_loaded_byname(self): p = Person.objects.get(fullname="Michael Sargent") self.assertEqual(str(p.first_name), "Michael") - def test_fix_person_loaded(self): + def test_fix_personexped_loaded_bypk(self): pe = PersonExpedition.objects.get(pk="681") self.assertEqual(str(pe.person.fullname), "Michael Sargent") self.assertEqual(str(pe.expedition.year), "2019") + def test_fix_expedition_loaded(self): + e = Expedition.objects.get(pk="44") + self.assertEqual(str(e.year), "2019") + + def test_page_person(self): + response = self.client.get("/person/michael-sargent") + content = response.content.decode() + # with open('testresponseperson.html','w') as tr: + # tr.writelines(content) + self.assertEqual(response.status_code, HTTPStatus.OK) + for ph in [r"Michael Sargent", r"has been on expo in the following years"]: + phmatch = re.search(ph, content) + self.assertIsNotNone(phmatch, "Failed to find expected text: '" + ph + "'") + + + def test_page_personexpedition(self): + # Not working despite all components present and correct + response = self.client.get("/personexpedition/michael-sargent/2019") + content = response.content.decode() + # with open('testresponse.html','w') as tr: + # tr.writelines(content) + self.assertEqual(response.status_code, HTTPStatus.OK) + for ph in [r"Michael Sargent", r"Table of all trips and surveys aligned by date"]: + phmatch = re.search(ph, content) + self.assertIsNotNone(phmatch, "Failed to find expected text: '" + ph + "'") + + # Need to add a fixture so that this actually has a logbook entry and a trip/svx in it. + def test_fix_cave_loaded115(self): c = Cave.objects.get(kataster_number="115") self.assertEqual(str(c.description_file), "1623/115.htm") @@ -43,9 +85,6 @@ class FixtureTests(TestCase): self.assertEqual(str(c.filename), "1623-115.html") self.assertEqual(str(c.areacode), "1623") - # c.area is a 'ManyRelatedManager' object and not iterable - # self.assertEqual(str(c.[0].short_name), "1623") - ph = self.ph phmatch = re.search(ph, c.underground_description) self.assertIsNotNone(phmatch, "In fixture-loaded cave, failed to find expected text: '" + ph + "'") @@ -60,16 +99,6 @@ class FixtureTests(TestCase): phmatch = re.search(ph, c.notes) self.assertIsNotNone(phmatch, "In fixture-loaded cave, failed to find expected text: '" + ph + "'") - def test_page_personexpedition(self): - response = self.client.get("/personexpedition/michael-sargent/2019") - content = response.content.decode() - # with open('testresponse.html','w') as tr: - # tr.writelines(content) - self.assertEqual(response.status_code, HTTPStatus.OK) - for ph in [r"Michael Sargent", r"Table of all trips and surveys aligned by date"]: - phmatch = re.search(ph, content) - self.assertIsNotNone(phmatch, "Failed to find expected text: '" + ph + "'") - # Need to add a fixture so that this actually has a logbook entry and a trip/svx in it. class FixturePageTests(TestCase): @@ -81,7 +110,7 @@ class FixturePageTests(TestCase): # The fixtures have a password hash which is compatible with plain-text password 'secretword' # The hash CHANGES whenever Django upgrades the encryption key length. Better to create the test uses # algorithmically and not via a fixture. - fixtures = ["auth_users", "expo_caves", "expo_exped"] + fixtures = ["expo_caves", "expo_exped"] ph = r"and leads in 800m of tortuous going to" @classmethod @@ -89,7 +118,9 @@ class FixturePageTests(TestCase): pass def setUp(self): - from django.contrib.auth.models import User + create_user(name="expo") + create_user(name="expotest") + create_user(name="expotestadmin", is_superuser = True) self.user = User.objects.get(username="expotest") @@ -97,7 +128,7 @@ class FixturePageTests(TestCase): self.client = Client() def tearDown(self): - pass + User.objects.all().delete() def test_fix_expedition(self): response = self.client.get("/expedition/2019") diff --git a/core/TESTS/test_logins.py b/core/TESTS/test_logins.py index 8596205..3954dba 100644 --- a/core/TESTS/test_logins.py +++ b/core/TESTS/test_logins.py @@ -14,56 +14,53 @@ from django.test import Client, TestCase import troggle.settings as settings from troggle.core.models.wallets import Wallet from troggle.core.models.troggle import Expedition +from django.contrib.auth.models import User +from troggle.core.utils import current_expo + +current_year = current_expo() +def create_user(name=None, last_name="Caver", is_superuser=False): + u = User() + u.username = name + u.email = f"philip.sargent+{name}@gmail.com" + u.first_name, u.last_name = name, last_name + u.set_password("secretword") # all test users have same password + u.save() + return u + + class DataTests(TestCase): - """These check that the NULL and NON-UNIQUE constraints are working in the database""" + """These check that the NULL and NON-UNIQUE constraints are working in the database + + no tests here... !""" @classmethod def setUpTestData(cls): pass def setUp(self): - from django.contrib.auth.models import User - - u = User() - u.pk = 9000 - u.user_id = 8000 - u.username, u.password = "stinker", "secretword" - u.email = "philip.sargent+SP@gmail.com" - u.first_name, u.last_name = "Stinker", "Pinker" - u.save() - self.user = u - + create_user(name="expo") + def tearDown(self): - # self.member.delete() # must delete member before user - # self.user.delete() # horrible crash, why? - pass + Users.objects.all().delete() -class FixturePageTests(TestCase): - # The fixtures have a password hash which is compatible with plain-text password 'secretword' - fixtures = ["auth_users"] +class LoginTests(TestCase): def setUp(self): - from django.contrib.auth.models import User - - self.user = User.objects.get(username="expotest") + create_user(name="expo") + create_user(name="expotest") + create_user(name="expotestadmin", is_superuser = True) def tearDown(self): - pass + User.objects.all().delete() def test_fix_admin_login_fail(self): c = self.client - from django.contrib.auth.models import User - u = User.objects.get(username="expotest") - self.assertTrue(u.is_active, "User '" + u.username + "' is INACTIVE") - - logged_in = c.login(username=u.username, password="secretword") # fails to work if password=u.password ! - self.assertTrue(logged_in, "FAILED to login as '" + u.username + "'") - + response = c.get("/admin/") content = response.content.decode() # with open('admin-op.html', 'w') as f: @@ -75,17 +72,16 @@ class FixturePageTests(TestCase): class PostTests(TestCase): """Tests walletedit form""" - fixtures = ["auth_users"] - @classmethod def setUpTestData(cls): pass def setUp(self): - from django.contrib.auth.models import User - - self.user = User.objects.get(username="expotest") - self.client = Client() + create_user(name="expo") + create_user(name="expotestadmin", is_superuser = True) + self.user = create_user(name="expotest") + + c = self.client testyear = "2022" wname = f"{testyear}:00" @@ -102,14 +98,17 @@ class PostTests(TestCase): e.save() self.expedition = e + def tearDown(self): + User.objects.all().delete() + Wallet.objects.all().delete() + Expedition.objects.all().delete() + def test_file_permissions(self): """Expect to be allowed to write to SCANS_ROOT, DRAWINGS_DATA, SURVEX_DATA, EXPOWEB Need to login first. """ c = self.client - from django.contrib.auth.models import User - - u = User.objects.get(username="expotest") + u = self.user testyear = self.testyear self.assertTrue(u.is_active, "User '" + u.username + "' is INACTIVE") @@ -173,14 +172,12 @@ class PostTests(TestCase): def test_photo_upload(self): """Expect photo upload to work on any file (contrary to msg on screen) - Upload into current default year. settings.PHOTOS_YEAR + Upload into current default year. Deletes file afterwards Need to login first. """ c = self.client - from django.contrib.auth.models import User - - u = User.objects.get(username="expotest") + u = self.user self.assertTrue(u.is_active, "User '" + u.username + "' is INACTIVE") c.login(username=u.username, password="secretword") @@ -192,11 +189,11 @@ class PostTests(TestCase): content = response.content.decode() self.assertEqual(response.status_code, HTTPStatus.OK) self.assertEqual(response.status_code, HTTPStatus.OK) - # with open('_test_response.html', 'w') as f: - # f.write(content) + with open('_test_response.html', 'w') as f: + f.write(content) for ph in [ r"test_upload_", - r"Upload photos into /photos/" + str(settings.PHOTOS_YEAR), + r"Upload photos into /photos/" + str(current_year), r" you can create a new folder in your name", r"Create new Photographer folder", r"only photo image files are accepted", @@ -206,19 +203,17 @@ class PostTests(TestCase): # Does not use the filename Django actually uses, assumes it is unchanged. Bug: accumulates one file with random name # added each time it is run. The name of the uploaded file is only available within the code where it happens - remove_file = pathlib.Path(settings.PHOTOS_ROOT, settings.PHOTOS_YEAR) / "test_upload_file.txt" + remove_file = pathlib.Path(settings.PHOTOS_ROOT, current_year) / "test_upload_file.txt" remove_file.unlink() def test_photo_upload_rename(self): """Expect photo upload to work on any file (contrary to msg on screen) - Upload into current default year. settings.PHOTOS_YEAR + Upload into current default year. Deletes file afterwards Need to login first. """ c = self.client - from django.contrib.auth.models import User - - u = User.objects.get(username="expotest") + u = self.user self.assertTrue(u.is_active, "User '" + u.username + "' is INACTIVE") c.login(username=u.username, password="secretword") @@ -239,19 +234,20 @@ class PostTests(TestCase): # Does not use the filename Django actually uses, assumes it is unchanged. Bug: accumulates one file with random name # added each time it is run. The name of the uploaded file is only available within the code where it happens - remove_file = pathlib.Path(settings.PHOTOS_ROOT, settings.PHOTOS_YEAR) / rename - remove_file.unlink() + remove_file = pathlib.Path(settings.PHOTOS_ROOT, current_year) / rename + if remove_file.is_file(): + remove_file.unlink() + + def test_photo_folder_create(self): """Create folder for new user - Create in current default year. settings.PHOTOS_YEAR + Create in current year. Deletes folder afterwards Need to login first. """ c = self.client - from django.contrib.auth.models import User - - u = User.objects.get(username="expotest") + u = self.user self.assertTrue(u.is_active, "User '" + u.username + "' is INACTIVE") c.login(username=u.username, password="secretword") @@ -268,17 +264,17 @@ class PostTests(TestCase): # Does not use the filename Django actually uses, assumes it is unchanged. Bug: accumulates one file with random name # added each time it is run. The name of the uploaded file is only available within the code where it happens - remove_dir = pathlib.Path(settings.PHOTOS_ROOT, settings.PHOTOS_YEAR) / "GussieFinkNottle" - remove_dir.rmdir() + remove_dir = pathlib.Path(settings.PHOTOS_ROOT, current_year) / "GussieFinkNottle" + if remove_dir.is_dir(): + remove_dir.rmdir() def test_dwg_upload_txt(self): """Expect .pdf file to be refused upload Need to login first. """ c = self.client - from django.contrib.auth.models import User + u = self.user - u = User.objects.get(username="expotest") self.assertTrue(u.is_active, "User '" + u.username + "' is INACTIVE") c.login(username=u.username, password="secretword") @@ -298,9 +294,8 @@ class PostTests(TestCase): Need to login first. """ c = self.client - from django.contrib.auth.models import User + u = self.user - u = User.objects.get(username="expotest") self.assertTrue(u.is_active, "User '" + u.username + "' is INACTIVE") c.login(username=u.username, password="secretword") @@ -327,7 +322,8 @@ class PostTests(TestCase): # added each time it is run. The name of the uploaded file is only available within the code where it happens # UploadedFile.name see https://docs.djangoproject.com/en/4.1/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile remove_file = pathlib.Path(settings.DRAWINGS_DATA) / "uploads" / "test_upload_nosuffix" - remove_file.unlink() + if remove_file.is_file(): + remove_file.unlink() class ComplexLoginTests(TestCase): @@ -335,27 +331,14 @@ class ComplexLoginTests(TestCase): def setUp(self): """setUp runs once for each test in this class""" - from django.contrib.auth.models import User - - u = User() - u.pk = 9000 - u.user_id = 8000 - u.username, u.password = "expotest", "secretword" - u.email = "philip.sargent+ET@gmail.com" - u.first_name, u.last_name = "ExpoTest", "Caver" - u.is_staff = True - u.is_superuser = True - - u.set_password(u.password) # This creates a new salt and thus a new key for EACH test - u.save() # vital that we save all this before attempting login - # print ('\n',u.password) - self.user = u + create_user(name="expo") + create_user(name="expotest") + create_user(name="expotestadmin", is_superuser = True) def tearDown(self): self.client.logout() # not needed as each test creates a new self.client - # self.member.delete() - ##self.user.delete() # id attribute set to None ! - pass + User.objects.all().delete() + # def test_login_redirect_for_non_logged_on_user(self): # need to fix this in real system # c = self.client @@ -365,11 +348,11 @@ class ComplexLoginTests(TestCase): def test_ordinary_login(self): c = self.client - u = self.user + u = User.objects.get(username="expotest") self.assertTrue(u.is_active, "User '" + u.username + "' is INACTIVE") - logged_in = c.login(username=u.username, password="secretword") # fails to work if password=u.password ! + logged_in = c.login(username=u.username, password="secretword") self.assertTrue(logged_in, "FAILED to login as '" + u.username + "'") response = c.get("/accounts/login/") # defined by auth system @@ -379,14 +362,14 @@ class ComplexLoginTests(TestCase): def test_authentication_login(self): c = self.client - u = self.user + u = User.objects.get(username="expotest") self.assertTrue(u.is_active, "User '" + u.username + "' is INACTIVE") # This is weird. I thought that the user had to login before she was in the authenticated state self.assertTrue(u.is_authenticated, "User '" + u.username + "' is NOT AUTHENTICATED before login") - logged_in = c.login(username=u.username, password="secretword") # fails to work if password=u.password ! + logged_in = c.login(username=u.username, password="secretword") self.assertTrue(logged_in, "FAILED to login as '" + u.username + "'") self.assertTrue(u.is_authenticated, "User '" + u.username + "' is NOT AUTHENTICATED after login") @@ -396,24 +379,26 @@ class ComplexLoginTests(TestCase): def test_admin_login(self): c = self.client - u = self.user + u = User.objects.get(username="expotestadmin") - logged_in = c.login(username=u.username, password="secretword") # fails to work if password=u.password ! + logged_in = c.login(username=u.username, password="secretword") self.assertTrue(logged_in, "FAILED to login as '" + u.username + "'") - response = c.get("/admin/") + response = c.get("/admin/login/") content = response.content.decode() - # with open('admin-op.html', 'w') as f: - # f.write(content) + # fn='admin-op.html' + # print(f"Writing {fn}") + # with open(fn, 'w') as f: + # f.write(content) t = re.search(r"Troggle database administration", content) self.assertIsNotNone(t, "Logged in as '" + u.username + "' but failed to get the Troggle Admin page") def test_noinfo_login(self): c = self.client # inherited from TestCase - u = self.user + u = User.objects.get(username="expotest") - logged_in = c.login(username=u.username, password="secretword") # fails if password=u.password ! + logged_in = c.login(username=u.username, password="secretword") self.assertTrue(logged_in, "FAILED to login as '" + u.username + "'") response = c.get("/stats") # a page with the Troggle menus content = response.content.decode() @@ -428,7 +413,7 @@ class ComplexLoginTests(TestCase): def test_user_force(self): c = self.client - u = self.user + u = User.objects.get(username="expotest") try: c.force_login(u) diff --git a/core/TESTS/test_parsers.py b/core/TESTS/test_parsers.py index 1c7b929..aaccff3 100644 --- a/core/TESTS/test_parsers.py +++ b/core/TESTS/test_parsers.py @@ -23,33 +23,45 @@ import unittest from http import HTTPStatus from django.test import Client, SimpleTestCase, TestCase +from django.contrib.auth.models import User from troggle.core.models.logbooks import LogbookEntry from troggle.core.models.troggle import Expedition, DataIssue, Person, PersonExpedition +from troggle.core.utils import current_expo import troggle.parsers.logbooks as lbp + +current_year = current_expo() + +def create_user(name=None, last_name="Caver", is_superuser=False): + u = User() + u.username = name + u.email = f"philip.sargent+{name}@gmail.com" + u.first_name, u.last_name = name, last_name + u.set_password("secretword") # all test users have same password + u.save() + return u + +def create_person(firstname, lastname, nickname=False, vfho=False, exped=None): + fullname = f"{firstname} {lastname}" + slug=f"{firstname.lower()}-{lastname.lower()}" + coUniqueAttribs = {"first_name": firstname, "last_name": (lastname or ""), "slug": slug,} + otherAttribs = {"is_vfho": vfho, "fullname": fullname, "nickname": nickname} + person = Person.objects.create(**otherAttribs, **coUniqueAttribs) + + coUniqueAttribs = {"person": person, "expedition": exped} + otherAttribs = {} + pe = PersonExpedition.objects.create(**otherAttribs, **coUniqueAttribs) + return person + TEST_YEAR = "1986" lbp.ENTRIES[TEST_YEAR] = 4 # number of entries in the test logbook class ImportTest(TestCase): # see test_logins.py for the tests to check that logged-in users work - fixtures = ["auth_users"] # contains user 'expotest' with a hash => password = 'secretword' @classmethod - def setUpTestData(cls): - def make_person(firstname, lastname, nickname=False, vfho=False): - fullname = f"{firstname} {lastname}" - slug=f"{firstname.lower()}-{lastname.lower()}" - coUniqueAttribs = {"first_name": firstname, "last_name": (lastname or ""), "slug": slug,} - otherAttribs = {"is_vfho": vfho, "fullname": fullname, "nickname": nickname} - person = Person.objects.create(**otherAttribs, **coUniqueAttribs) - - coUniqueAttribs = {"person": person, "expedition": cls.test_expo} - otherAttribs = {} - pe = PersonExpedition.objects.create(**otherAttribs, **coUniqueAttribs) - - return person - + def setUpTestData(cls): import troggle.settings as settings LOGBOOKS_PATH = settings.EXPOWEB / lbp.LOGBOOKS_DIR @@ -63,21 +75,23 @@ class ImportTest(TestCase): otherAttribs = {"name": f"CUCC expo-test {TEST_YEAR}"} cls.test_expo = Expedition.objects.create(**otherAttribs, **coUniqueAttribs) - fred = make_person("Fred", "Smartarse", nickname="freddy") - phil = make_person("Phil", "Tosser", nickname="tosspot") - dave = make_person("David", "Smartarse", "") - mike = make_person("Michael", "Wideboy", "WB", vfho=True) + fred = create_person("Fred", "Smartarse", nickname="freddy", exped=cls.test_expo) + phil = create_person("Phil", "Tosser", nickname="tosspot", exped=cls.test_expo) + dave = create_person("David", "Smartarse", "", exped=cls.test_expo) + mike = create_person("Michael", "Wideboy", "WB", vfho=True, exped=cls.test_expo) # NOT created Kurt, as the whole point is that he is a guest. def setUp(self): - from django.contrib.auth.models import User - - self.user = User.objects.get(username="expotest") # has password 'secretword' from fixture + create_user(name="expo") # needed for current_year() + self.user = create_user(name="expotest") self.client = Client() def tearDown(self): - pass + User.objects.all().delete() + Person.objects.all().delete() + PersonExpedition.objects.all().delete() + Expedition.objects.all().delete() def test_logbook_exists(self): self.assertTrue(self.test_logbook.is_file()) @@ -184,7 +198,7 @@ class ImportTest(TestCase): response = self.client.get(f"/aliases/{TEST_YEAR}") self.assertEqual(response.status_code, HTTPStatus.OK) content = response.content.decode() - # with open('_test_response.html', 'w') as f: + # with open('_test_responsealiases.html', 'w') as f: # f.write(content) ph = f"'fsmartarse'" phmatch = re.search(ph, content) diff --git a/core/utils.py b/core/utils.py index 77aba9d..eeb3c6a 100644 --- a/core/utils.py +++ b/core/utils.py @@ -124,7 +124,7 @@ def current_expo(): last_expo = expos[0].year if int(last_expo) < int(year): # coming year, after Dec.31st for y in range(int(last_expo)+1, int(year)+1): - print(f"--!{year}---") + #print(f"--!{year}---") make_new_expo(str(y)) make_new_expo_dir(str(y))