diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..49138a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Ignore the possible nginx directory that might be used to build in +nginx/** diff --git a/tests/tests.py b/tests/tests.py new file mode 100644 index 0000000..649b090 --- /dev/null +++ b/tests/tests.py @@ -0,0 +1,183 @@ +import unittest +import requests +import random +import string +import time + +class TestStringMethods(unittest.TestCase): + methods = ["PROPFIND", "OPTIONS", "LOCK", "UNLOCK", + "GET", "PUT", "DELETE", "MKCOL", "COPY", "MOVE"] + + def test_authorization_required(self): + # TODO the dav methods return forbidden instead of auth required + methods = ["PROPFIND", "OPTIONS", "LOCK", "UNLOCK"] + for method in methods: + r = requests.Session().request(method=method, + url='http://localhost:80/') + self.assertEqual(r.status_code, 401) + + def test_PROPFIND(self): + r = requests.Session().request(method="PROPFIND", + url='http://localhost:80/', + headers={'Depth': '0'}, + auth = ('user1', 'password1')) + self.assertEqual(r.status_code, 207) + #print(r.content.decode('utf-8')) + #self.assertTrue(r.content.decode('utf-8').startswith('''''')) + + def test_OPTIONS(self): + r = requests.Session().request(method="OPTIONS", + url='http://localhost:80/', + auth = ('user1', 'password1')) + self.assertEqual(r.status_code, 200) + self.assertEqual(r.headers["Allow"], + "GET,HEAD,PUT,DELETE,MKCOL,COPY,MOVE,PROPFIND,OPTIONS,LOCK,UNLOCK") + + def test_PUT_GET_DELETE(self): + filename = ''.join(random.choice(string.ascii_lowercase) for i in range(48)) + # Create a file + r = requests.Session().request(method="PUT", + url=f'http://localhost:80/{filename}', + auth = ('user1', 'password1'), + data="Hello, World!") + self.assertEqual(r.status_code, 201) + # Remaking the PUT request should return 204 no content + r = requests.Session().request(method="PUT", + url=f'http://localhost:80/{filename}', + auth = ('user1', 'password1'), + data="Hello, World!") + self.assertEqual(r.status_code, 204) + # Get it to make sure it's correct + r = requests.Session().request(method="GET", + url=f'http://localhost:80/{filename}', + auth = ('user1', 'password1')) + self.assertEqual(r.status_code, 200) + #self.assertEqual(r.headers['ETag'], '"66115221-d"') TODO the webdav etag seems to be timestamp based + self.assertEqual(r.content, b"Hello, World!") + # Delete the file + r = requests.Session().request(method="DELETE", + url=f'http://localhost:80/{filename}', + auth = ('user1', 'password1')) + self.assertEqual(r.status_code, 204) + + def test_MKCOL(self): + filename = ''.join(random.choice(string.ascii_lowercase) for i in range(48)) + # Ensure the directory doesn't exist + requests.Session().request(method="DELETE", + url=f'http://localhost:80/{filename}', + auth = ('user1', 'password1')) + # Test + r = requests.Session().request(method="MKCOL", + url=f'http://localhost:80/{filename}', + auth = ('user1', 'password1')) + self.assertEqual(r.status_code, 201) + # Cleanup the new directory + requests.Session().request(method="DELETE", + url=f'http://localhost:80/{filename}', + auth = ('user1', 'password1')) + r = requests.Session().request(method="PROPFIND", + url=f'http://localhost:80/{filename}/', + auth = ('user1', 'password1')) + self.assertEqual(r.status_code, 404) + + # Ensure the directory doesn't exist + requests.Session().request(method="DELETE", + url=f'http://localhost:80/{filename}', + auth = ('user1', 'password1')) + # Test + r = requests.Session().request(method="MKCOL", + url=f'http://localhost:80/{filename}/', + auth = ('user1', 'password1')) + + self.assertEqual(r.status_code, 201) + # Cleanup the new directory + requests.Session().request(method="DELETE", + url=f'http://localhost:80/{filename}', + auth = ('user1', 'password1')) + r = requests.Session().request(method="PROPFIND", + url=f'http://localhost:80/{filename}/', + auth = ('user1', 'password1')) + self.assertEqual(r.status_code, 404) + + def test_LOCK_UNLOCK(self): + # TODO something is going on with 201 and 200, locks with a trailing slash and locks withut + # TODO Lock-Token should be the same whether its with or without a trailing slash + # TODO locking a nonexistent top directory file is fine but a nonexisting directory or a file inside it returns 423 + # TODO odd replies with 200 + filename = ''.join(random.choice(string.ascii_lowercase) for i in range(48)) + # Create a file + r = requests.Session().request(method="PUT", + url=f'http://localhost:80/{filename}', + auth = ('user1', 'password1'), + data="Hello, World!") + self.assertEqual(r.status_code, 201) + # Lock it + r = requests.Session().request(method="LOCK", + url=f'http://localhost:80/{filename}', + auth = ('user1', 'password1')) + self.assertEqual(r.status_code, 200) + r = requests.Session().request(method="UNLOCK", + url=f'http://localhost:80/{filename}', + auth = ('user1', 'password1')) + self.assertEqual(r.status_code, 204) + # TODO the file that was created above should be deleted, need to find out why it fails + #r = requests.Session().request(method="DELETE", + # url=f'http://localhost:80/{filename}', + # auth = ('user1', 'password1')) + #self.assertEqual(r.status_code, 204) + + def test_COPY(self): + filename = ''.join(random.choice(string.ascii_lowercase) for i in range(48)) + # Ensure the directory doesn't exist + requests.Session().request(method="DELETE", + url=f'http://localhost:80/{filename}', + auth = ('user1', 'password1')) + # Make the directory to copy + r = requests.Session().request(method="MKCOL", + url=f'http://localhost:80/{filename}', + auth = ('user1', 'password1')) + self.assertEqual(r.status_code, 201) + # Copy the directory with various trailing slash configurations + for (i,j) in [('/','/'), ('/',''), ('','/'), ('','')]: + r = requests.Session().request(method="COPY", + url=f'http://localhost:80/{filename}'+i, + auth = ('user1', 'password1'), + headers={'Destination': '/{filename}cpy'+j}) + self.assertEqual(r.status_code, 201) + # Delete the directory copy for the next test + # TODO why does this fail?? + #r = requests.Session().request(method="DELETE", + # url=f'http://localhost:80/{filename}cpy', + # auth = ('user1', 'password1')) + #self.assertEqual(r.status_code, 204) + + def test_MOVE(self): + filename = ''.join(random.choice(string.ascii_lowercase) for i in range(48)) + # Copy the directory with various trailing slash configurations + for (i,j) in [('/','/'), ('/',''), ('','/'), ('','')]: + # Make the directory to move + r = requests.Session().request(method="MKCOL", + url='http://localhost:80/{filename}', + auth = ('user1', 'password1')) + self.assertEqual(r.status_code, 201) + r = requests.Session().request(method="MOVE", + url='http://localhost:80/{filename}'+i, + auth = ('user1', 'password1'), + headers={'Destination': '/{filename}mov'+j}) + self.assertEqual(r.status_code, 201) + # Delete the directory move for the next test + r = requests.Session().request(method="DELETE", + url='http://localhost:80/{filename}mov', + auth = ('user1', 'password1')) + self.assertEqual(r.status_code, 204) + # Ensure the directory doesn't exist + requests.Session().request(method="DELETE", + url='http://localhost:80/{filename}', + auth = ('user1', 'password1')) + + + + + +if __name__ == '__main__': + unittest.main()