summaryrefslogtreecommitdiffstats
path: root/core/TESTS/test_logins.py
diff options
context:
space:
mode:
Diffstat (limited to 'core/TESTS/test_logins.py')
-rw-r--r--core/TESTS/test_logins.py449
1 files changed, 449 insertions, 0 deletions
diff --git a/core/TESTS/test_logins.py b/core/TESTS/test_logins.py
new file mode 100644
index 0000000..f50e292
--- /dev/null
+++ b/core/TESTS/test_logins.py
@@ -0,0 +1,449 @@
+"""
+Originally written for CUYC
+Philip Sargent (Feb.2021)
+
+Modified for Expo April 2021.
+"""
+
+import pathlib
+import re
+from http import HTTPStatus
+
+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
+
+
+class DataTests(TestCase):
+ """These check that the NULL and NON-UNIQUE constraints are working in the database"""
+
+ @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
+
+ def tearDown(self):
+ # self.member.delete() # must delete member before user
+ # self.user.delete() # horrible crash, why?
+ pass
+
+
+class FixturePageTests(TestCase):
+ # The fixtures have a password hash which is compatible with plain-text password 'secretword'
+ fixtures = ["auth_users"]
+
+ def setUp(self):
+ from django.contrib.auth.models import User
+
+ self.user = User.objects.get(username="expotest")
+
+ def tearDown(self):
+ pass
+
+ 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:
+ # f.write(content)
+ t = re.search(r"Troggle administration", content)
+ self.assertIsNone(t, "Logged in as '" + u.username + "' (not staff) but still managed to get the Admin page")
+
+
+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()
+
+ testyear = "2022"
+ wname = f"{testyear}:00"
+ self.testyear = testyear
+ w = Wallet()
+ w.pk = 9100
+ w.fpath = str(pathlib.Path(settings.SCANS_ROOT, wname))
+ w.walletname = wname
+ w.save()
+ self.wallet = w
+
+ e = Expedition()
+ e.year = testyear
+ e.save()
+ self.expedition = e
+
+ def test_file_permissions(self):
+ """Expect to be allowed to write to expofiles
+ Need to login first.
+ """
+ c = self.client
+ from django.contrib.auth.models import User
+
+ u = User.objects.get(username="expotest")
+ testyear = self.testyear
+
+ self.assertTrue(u.is_active, "User '" + u.username + "' is INACTIVE")
+ c.login(username=u.username, password="secretword")
+
+ for p in [settings.SCANS_ROOT,
+ settings.DRAWINGS_DATA / "walletjson",
+ settings.EXPOWEB / "documents",
+ settings.SURVEX_DATA / "docs"
+ ]:
+
+ _test_file_path = pathlib.Path(p, "_created_by_test_suite.txt")
+ self.assertEqual(_test_file_path.is_file(), False)
+
+ with open(_test_file_path, "w") as f:
+ f.write("test string: can we write to this directory?")
+ self.assertEqual(_test_file_path.is_file(), True)
+ _test_file_path.unlink()
+
+ def test_scan_upload(self):
+ """Expect scan upload to wallet to work on any file
+ Need to login first.
+
+ This upload form looks for the Cave and the Wallet, so the test fails if the database is not loaded with the cave
+ identified in the wallet
+ """
+ c = self.client
+ from django.contrib.auth.models import User
+
+ u = User.objects.get(username="expotest")
+ testyear = self.testyear
+
+ self.assertTrue(u.is_active, "User '" + u.username + "' is INACTIVE")
+ c.login(username=u.username, password="secretword")
+
+ with open("core/fixtures/test_upload_file.txt", "r") as testf:
+ response = self.client.post(
+ f"/walletedit/{testyear}:00", data={"name": "test_upload_file.txt", "uploadfiles": testf}
+ )
+ 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)
+ for ph in [
+ r"test_upload_",
+ rf"← {testyear}#00 →",
+ r"description written",
+ r"Plan not required",
+ r"edit settings or upload a file",
+ ]:
+ phmatch = re.search(ph, content)
+ self.assertIsNotNone(phmatch, "Failed to find expected text: '" + ph + "'")
+
+ # # Does not use the filename Django actually uses, assumes it is unchanged. Potential bug.
+ # remove_file = pathlib.Path(settings.SCANS_ROOT) / f'{testyear}' / f'{testyear}#00'/ 'test_upload_file.txt'
+ # remove_file.unlink()
+ # # Undo the auto create and commit of a new wallet
+ # cwd = settings.DRAWINGS_DATA
+ # sp = subprocess.run([settings.GIT, "reset", "--hard", "master^"], cwd=cwd, capture_output=True, text=True)
+ # print(f'git output: {cwd}:\n # {sp.stderr=}\n # {sp.stdout=} \n # return code: {str(sp.returncode)}')
+ # if sp.returncode != 0:
+ # print(f'git output: {cwd}:\n # {sp.stderr=}\n # {sp.stdout=} \n # return code: {str(sp.returncode)}')
+
+ 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
+ Deletes file afterwards
+ Need to login first.
+ """
+ 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")
+ c.login(username=u.username, password="secretword")
+
+ with open("core/fixtures/test_upload_file.txt", "r") as testf:
+ response = self.client.post(
+ "/photoupload/", data={"name": "test_upload_file.txt", "renameto": "", "uploadfiles": testf}
+ )
+ 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)
+ for ph in [
+ r"test_upload_",
+ r"Upload photos into /photos/" + str(settings.PHOTOS_YEAR),
+ r" you can create a new folder in your name",
+ r"Create new Photographer folder",
+ r"only photo image files are accepted",
+ ]:
+ phmatch = re.search(ph, content)
+ self.assertIsNotNone(phmatch, "Failed to find expected text: '" + ph + "'")
+
+ # Does not use the filename Django actually uses, assumes it is unchanged. Potential bug.
+ remove_file = pathlib.Path(settings.PHOTOS_ROOT, settings.PHOTOS_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
+ Deletes file afterwards
+ Need to login first.
+ """
+ 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")
+ c.login(username=u.username, password="secretword")
+
+ rename = "RENAMED-FILE.JPG"
+ with open("core/fixtures/test_upload_file.txt", "r") as testf:
+ response = self.client.post(
+ "/photoupload/", data={"name": "test_upload_file.txt", "renameto": rename, "uploadfiles": testf}
+ )
+ 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)
+ for ph in [rename]:
+ phmatch = re.search(ph, content)
+ self.assertIsNotNone(phmatch, "Failed to find expected text: '" + ph + "'")
+
+ # Does not use the filename Django actually uses, assumes it is unchanged. Potential bug.
+ remove_file = pathlib.Path(settings.PHOTOS_ROOT, settings.PHOTOS_YEAR) / rename
+ remove_file.unlink()
+
+ def test_photo_folder_create(self):
+ """Create folder for new user
+ Create in current default year. settings.PHOTOS_YEAR
+ Deletes folder afterwards
+ Need to login first.
+ """
+ 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")
+ c.login(username=u.username, password="secretword")
+
+ response = self.client.post("/photoupload/", data={"photographer": "GussieFinkNottle"})
+ 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)
+ for ph in [r"/GussieFinkNottle/", r"Create new Photographer folder"]:
+ phmatch = re.search(ph, content)
+ self.assertIsNotNone(phmatch, "Failed to find expected text: '" + ph + "'")
+
+ # Does not use the filename Django actually uses, assumes it is unchanged. Potential bug.
+ remove_dir = pathlib.Path(settings.PHOTOS_ROOT, settings.PHOTOS_YEAR) / "GussieFinkNottle"
+ 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 = User.objects.get(username="expotest")
+
+ self.assertTrue(u.is_active, "User '" + u.username + "' is INACTIVE")
+ c.login(username=u.username, password="secretword")
+
+ with open("core/fixtures/test_upload_file.pdf", "r") as testf:
+ response = self.client.post(
+ "/dwgupload/uploads", data={"name": "test_upload_file.txt", "uploadfiles": testf}
+ )
+ content = response.content.decode()
+ self.assertEqual(response.status_code, HTTPStatus.OK)
+ t = re.search("Files refused:", content)
+ self.assertIsNotNone(t, 'Logged in but failed to see "Files refused:"')
+
+ def test_dwg_upload_drawing(self):
+ """Expect no-suffix file to upload
+ Note that this skips the git commit process. That would need a new test.
+ Need to login first.
+ """
+ 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")
+ c.login(username=u.username, password="secretword")
+
+ with open("core/fixtures/test_upload_nosuffix", "r") as testf:
+ response = self.client.post(
+ "/dwguploadnogit/uploads", data={"name": "test_upload_nosuffix", "uploadfiles": testf}
+ )
+ content = response.content.decode()
+ # with open('_test_response.html', 'w') as f:
+ # f.write(content)
+ self.assertEqual(response.status_code, HTTPStatus.OK)
+ for ph in [
+ r"test_upload_nosuffix",
+ r"You cannot create folders here",
+ r"Creating a folder is done by a nerd",
+ ]:
+ phmatch = re.search(ph, content)
+ self.assertIsNotNone(
+ phmatch, "Expect no-suffix file to upload OK. Failed to find expected text: '" + ph + "'"
+ )
+
+ # 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.
+ remove_file = pathlib.Path(settings.DRAWINGS_DATA) / "uploads" / "test_upload_nosuffix"
+ remove_file.unlink()
+
+
+class ComplexLoginTests(TestCase):
+ """These test the login and capabilities of logged-in users, they do not use fixtures"""
+
+ 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
+
+ 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
+
+ # def test_login_redirect_for_non_logged_on_user(self): # need to fix this in real system
+ # c = self.client
+ # # Need to login first. Tests that we are redirected to login page if not logged in
+ # response = c.get('noinfo/cave-number-index')
+ # self.assertRedirects(response, "/login/?next=/committee/appointments/")
+
+ def test_ordinary_login(self):
+ c = self.client
+ u = self.user
+
+ 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("/accounts/login/") # defined by auth system
+ content = response.content.decode()
+ t = re.search(r"You are now logged in", content)
+ self.assertIsNotNone(t, "Logged in as '" + u.username + "' but failed to get 'Now you can' greeting")
+
+ def test_authentication_login(self):
+ c = self.client
+ u = self.user
+
+ 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 !
+ self.assertTrue(logged_in, "FAILED to login as '" + u.username + "'")
+
+ self.assertTrue(u.is_authenticated, "User '" + u.username + "' is NOT AUTHENTICATED after login")
+
+ # c.logout() # This next test always means user is still authenticated after logout. Surely not?
+ # self.assertFalse(u.is_authenticated, 'User \'' + u.username + '\' is STILL AUTHENTICATED after logout')
+
+ def test_admin_login(self):
+ c = self.client
+ u = self.user
+
+ 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:
+ # 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
+
+ logged_in = c.login(username=u.username, password="secretword") # fails if password=u.password !
+ self.assertTrue(logged_in, "FAILED to login as '" + u.username + "'")
+ response = c.get("/stats") # a page with the Troggle menus
+ content = response.content.decode()
+ t = re.search(r"User\:expotest", content)
+ self.assertIsNotNone(t, "Logged in as '" + u.username + "' but failed to get 'User:expotest' heading")
+
+ response = c.get("/noinfo/cave-number-index")
+ content = response.content.decode()
+ t = re.search(r"2001-07 Hoffnungschacht", content)
+ self.assertIsNotNone(t, "Logged in as '" + u.username + "' but failed to get /noinfo/ content")
+
+ def test_user_force(self):
+
+ c = self.client
+ u = self.user
+
+ try:
+ c.force_login(u)
+ except:
+ self.assertIsNotNone(
+ None,
+ "Unexpected exception trying to force_login as '"
+ + u.username
+ + "' but failed (Bad Django documentation?)",
+ )
+
+ response = c.get("/stats") # a page with the Troggle menus
+ content = response.content.decode()
+ t = re.search(r"Log out", content)
+ self.assertIsNotNone(t, "Forced logged in as '" + u.username + "' but failed to get Log out heading")
+
+ response = c.get("/accounts/login/")
+ content = response.content.decode()
+ t = re.search(r"You are now logged in", content)
+ self.assertIsNotNone(t, "Forced logged in as '" + u.username + "' but failed to get /accounts/profile/ content")