2
0
mirror of https://expo.survex.com/repositories/troggle/.git synced 2024-11-22 07:11:52 +00:00

fix side effects in tests: git and file upload

This commit is contained in:
Philip Sargent 2021-10-31 19:25:45 +02:00
parent 252fcc4716
commit 2869f228d4
5 changed files with 61 additions and 77 deletions

View File

@ -121,7 +121,8 @@ class SubprocessTest(TestCase):
pass pass
def test_installs(self): def test_installs(self):
''' Tests whether the external software is installed (but not whether it actually works) '''Expects external software installed: cavern, survexport, git
(but not whether it actually works)
''' '''
import troggle.settings as settings import troggle.settings as settings

View File

@ -7,10 +7,12 @@ Modified for Expo April 2021.
import unittest import unittest
import re import re
import pathlib
from http import HTTPStatus from http import HTTPStatus
from django.test import TestCase, SimpleTestCase, TransactionTestCase, Client from django.test import TestCase, SimpleTestCase, TransactionTestCase, Client
import troggle.settings as settings
class DataTests(TestCase ): 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 '''
@ -77,7 +79,8 @@ class PostTests(TestCase):
self.client = Client() self.client = Client()
def test_scan_upload(self): def test_scan_upload(self):
'''Test file upload. Need to login first. '''Expect scan upload to wallet to work on any file
Need to login first.
''' '''
c = self.client c = self.client
from django.contrib.auth.models import User from django.contrib.auth.models import User
@ -91,18 +94,22 @@ class PostTests(TestCase):
content = response.content.decode() content = response.content.decode()
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, HTTPStatus.OK) self.assertEqual(response.status_code, HTTPStatus.OK)
# with open('testresponse.html', 'w') as f: # with open('_test_response.html', 'w') as f:
# f.write(content) # f.write(content)
for ph in [ r'test_upload_', for ph in [ r'test_upload_',
r'← 2020#00 →', r'← 2020#00 →',
r'Upload more?']: r'Upload more?']:
phmatch = re.search(ph, content) phmatch = re.search(ph, content)
self.assertIsNotNone(phmatch, "Failed to find expected text: '" + ph +"'") 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.SURVEY_SCANS) / '2020' / '2020#00'/ 'test_upload_file.txt'
remove_file.unlink()
def test_dwg_upload(self):
'''Test file upload. Need to login first. def test_dwg_upload_txt(self):
First upload is refused as it is a TXT file '''Expect .txt file to be refused upload
Second upload is an image and suceeds. Need to login first.
''' '''
c = self.client c = self.client
from django.contrib.auth.models import User from django.contrib.auth.models import User
@ -118,17 +125,32 @@ class PostTests(TestCase):
t = re.search('Files refused:', content) t = re.search('Files refused:', content)
self.assertIsNotNone(t, 'Logged in but failed to see "Files refused:"' ) self.assertIsNotNone(t, 'Logged in but failed to see "Files refused:"' )
def test_dwg_upload_drawing(self):
'''Expect no-suffix file to 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')
logged_in = c.login(username=u.username, password='secretword')
with open('core/fixtures/test_upload_nosuffix','r') as testf: with open('core/fixtures/test_upload_nosuffix','r') as testf:
response = self.client.post('/dwgupload/uploads', data={'name': 'test_upload_nosuffix', 'uploadfiles': testf }) response = self.client.post('/dwguploadnogit/uploads', data={'name': 'test_upload_nosuffix', 'uploadfiles': testf })
content = response.content.decode() content = response.content.decode()
with open('testresponse.html', 'w') as f: # with open('_test_response.html', 'w') as f:
f.write(content) # f.write(content)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
for ph in [ r'Upload more', for ph in [ r'Upload more',
r' saved as ', r' saved as ',
r'Clicking on a filename only']: r'Clicking on a filename only']:
phmatch = re.search(ph, content) phmatch = re.search(ph, content)
self.assertIsNotNone(phmatch, "Failed to find expected text: '" + ph +"'") 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.DRAWINGS_DATA) / 'uploads' / 'test_upload_nosuffix'
remove_file.unlink()
class ComplexLoginTests(TestCase): class ComplexLoginTests(TestCase):

View File

@ -54,51 +54,5 @@ def dwgfilesingle(request, path):
return HttpResponse(content=open(tfile, errors='ignore'), content_type="text/xhtml") return HttpResponse(content=open(tfile, errors='ignore'), content_type="text/xhtml")
else: else:
return HttpResponse(content="Unable to understand the encoding for this file: not UTF-8 nor iso-8859-1, or some other read error happened.") return HttpResponse(content="Unable to understand the encoding for this file: not UTF-8 nor iso-8859-1, or some other read error happened.")
# def dwgfileupload(request, path):
# '''Use bits of this to REGISTEr a recently uploaded dwg file which used dwgupload
# '''
# try:
# dwgfile = DrawingFile.objects.get(dwgpath=urlunquote(path)) # need to check if inavlid query string and produce friendly error
# except:
# message = f'Drawing file error or not found \'{path}\' .'
# return render(request, 'errors/generic.html', {'message': message})
# tfile = Path(settings.DRAWINGS_DATA, dwgfile.dwgpath)
# project, user, password, tunnelversion = request.POST["tunnelproject"], request.POST["tunneluser"], request.POST["tunnelpassword"], request.POST["tunnelversion"]
# print(project, user, tunnelversion)
# if not (len(list(request.FILES.values())) == 1): # "only one file to upload"
# return HttpResponse(content="Error: more than one file selected for upload", content_type="text/plain")
# uploadedfile = list(request.FILES.values())[0]
# if uploadedfile.field_name != "sketch":
# return HttpResponse(content="Error: non-sketch file uploaded", content_type="text/plain")
# if uploadedfile.content_type != "text/plain":
# return HttpResponse(content="Error: non-plain content type", content_type="text/plain")
# # could use this to add new files
# if os.path.split(path)[1] != uploadedfile.name:
# return HttpResponse(content="Error: name disagrees", content_type="text/plain")
# orgsize = dwgfile.filesize # = os.stat(tfile)[stat.ST_SIZE]
# ttext = uploadedfile.read()
# # could check that the user and projects agree here
# fout = open(tfile, "w")
# fout.write(ttext)
# fout.close()
# # redo its settings of
# parsers.surveys.SetTunnelfileInfo(dwgfile) # commented out
# dwgfile.save()
# uploadedfile.close()
# message = "File size %d overwritten with size %d" % (orgsize, dwgfile.filesize)
# return HttpResponse(content=message, content_type="text/plain")

View File

@ -103,7 +103,7 @@ def scanupload(request, wallet=None):
{'form': form, 'wallet': wallet, **context, 'files': files, 'dirs': dirs, 'filesaved': filesaved, 'actual_saved': actual_saved}) {'form': form, 'wallet': wallet, **context, 'files': files, 'dirs': dirs, 'filesaved': filesaved, 'actual_saved': actual_saved})
@login_required_if_public @login_required_if_public
def dwgupload(request, folder=None): def dwgupload(request, folder=None, gitdisable='no'):
'''Upload DRAWING files (tunnel or therion) into the upload folder in :drawings: '''Upload DRAWING files (tunnel or therion) into the upload folder in :drawings:
This does NOT use a Django model linked to a Django form. Just a simple Django form. This does NOT use a Django model linked to a Django form. Just a simple Django form.
@ -115,14 +115,14 @@ def dwgupload(request, folder=None):
if name in [ '.gitignore', '.hgignore', ]: if name in [ '.gitignore', '.hgignore', ]:
return False return False
if Path(name).suffix.lower() in ['.xml', '.th', '.th2', '', '.svg', '.jpg', '.pdf', 'jpeg']: if Path(name).suffix.lower() in ['.xml', '.th', '.th2', '', '.svg', '.jpg', '.pdf', 'jpeg']:
return True return True # dangerous, we should check the actual file binary signature
return False return False
filesaved = False filesaved = False
actual_saved = [] actual_saved = []
refused = [] refused = []
doesnotexist = '' doesnotexist = ''
#print(f'! - FORM dwgupload - start "{folder}"') # print(f'! - FORM dwgupload - start "{folder}" - gitdisable "{gitdisable}"')
if folder is None: if folder is None:
folder = "" # improve this later folder = "" # improve this later
dirpath = Path(settings.DRAWINGS_DATA) dirpath = Path(settings.DRAWINGS_DATA)
@ -144,28 +144,31 @@ def dwgupload(request, folder=None):
actual_saved = [] actual_saved = []
refused = [] refused = []
git = settings.GIT if gitdisable != 'yes': # set in url 'dwguploadnogit/'
git = settings.GIT
else:
git = 'echo'
if multiple: if multiple:
for f in multiple: for f in multiple:
if dwgvalid(f.name): if dwgvalid(f.name):
saved_filename = fs.save(f.name, content=f) saved_filename = fs.save(f.name, content=f)
actual_saved.append(saved_filename) actual_saved.append(saved_filename)
subprocess.call([git, "add", saved_filename], cwd=dirpath) if gitdisable != 'yes':
# dwgfile = DrawingFile(dwgpath=f.name, dwgname=Path(f.name).stem, filesize=f.size) subprocess.call([git, "add", saved_filename], cwd=dirpath)
dwgfile, created = DrawingFile.objects.get_or_create(dwgpath=saved_filename, dwgname=Path(f.name).stem, filesize=f.size) dwgfile, created = DrawingFile.objects.get_or_create(dwgpath=saved_filename, dwgname=Path(f.name).stem, filesize=f.size)
# if not created:
# print(f'FAILED to create {saved_filename} in {dirpath}')
# else:
# print(f'{dwgfile}')
dwgfile.save() dwgfile.save()
else: else:
refused.append(f.name) refused.append(f.name)
# print(f'! - FORM dwgupload multiple {actual_saved}') if actual_saved: # maybe all were refused by the suffix test in dwgvalid()
filesaved = True filesaved = True
subprocess.call([git, "commit", "-m", 'dwgupload'], cwd=dirpath) if gitdisable != 'yes':
subprocess.call([git, "commit", "-m", 'dwgupload'], cwd=dirpath)
files = [] files = []
dirs = [] dirs = []
#print(f'! - FORM dwgupload - start {folder} \n"{dirpath}" \n"{dirpath.parent}" \n"{dirpath.exists()}"') # print(f'! - FORM dwgupload - start {folder} \n"{dirpath}" \n"{dirpath.parent}" \n"{dirpath.exists()}"')
try: try:
for f in dirpath.iterdir(): for f in dirpath.iterdir():
if f.is_dir(): if f.is_dir():

16
urls.py
View File

@ -39,7 +39,11 @@ which is vital to writing code for the webapp. So the URL dispatch is declarativ
The API urls return TSV or JSON and are new in July 2020. The API urls return TSV or JSON and are new in July 2020.
""" """
todo = '''Replace most re_path() with modern and simpler path(). Test VERY CAREFULLY for each chnage. It is fragile. todo = '''Replace most re_path() with modern and simpler path().
The admin and logout paths need to stay using re_path() as they
have to be locked to the start.
The final _edit and CATCHALL also have to use re_path().
Test VERY CAREFULLY for each change. It is fragile.
''' '''
# Many of these patterns do not work because troggle spent many years broken and we have # Many of these patterns do not work because troggle spent many years broken and we have
@ -80,9 +84,11 @@ trogglepatterns = [
re_path(r'^admin/', admin.site.urls), # includes admin login & logout urls re_path(r'^admin/', admin.site.urls), # includes admin login & logout urls
# Uploads - uploading a file # Uploads - uploading a file
path('scanupload/<wallet>', scanupload, name='scanupload'), # wallet=2020#01, not a path path('scanupload/<wallet>', scanupload, name='scanupload'), # wallet=2020#01, not a path
path('dwgupload/<path:folder>', dwgupload, name='dwgupload'), path('dwgupload/<path:folder>', dwgupload, name='dwgupload'),
path('dwgupload/', dwgupload, name='dwgupload'), path('dwgupload/', dwgupload, name='dwgupload'),
path('dwguploadnogit/', dwgupload, {'gitdisable': 'yes'}, name='dwguploadnogit'), # used in testing
path('dwguploadnogit/<path:folder>', dwgupload, {'gitdisable': 'yes'}, name='dwguploadnogit'), # used in testing
# setting LOGIN_URL = '/accounts/login/' is default # setting LOGIN_URL = '/accounts/login/' is default
# url ENDS WITH this string # url ENDS WITH this string
@ -160,8 +166,6 @@ trogglepatterns = [
path('dwgfiles', dwgallfiles, name="dwgallfiles"), path('dwgfiles', dwgallfiles, name="dwgallfiles"),
path('dwgfiles/', dwgallfiles, name="dwgallfiles"), path('dwgfiles/', dwgallfiles, name="dwgallfiles"),
path('dwgdataraw/<path:path>', dwgfilesingle, name="dwgfilesingle"), path('dwgdataraw/<path:path>', dwgfilesingle, name="dwgfilesingle"),
# path('dwgdataraw/<path:path>/upload', dwgfileupload, name="dwgfileupload"), # Not working
# QMs pages - must precede other /caves pages? # QMs pages - must precede other /caves pages?
re_path(r'^cave/qms/([^/]+)/?$', caves.caveQMs), # Broken- QMs have no proper link to cave id re_path(r'^cave/qms/([^/]+)/?$', caves.caveQMs), # Broken- QMs have no proper link to cave id