class TestTUS(unittest.TestCase): layer = PLONE_RESTAPI_DX_FUNCTIONAL_TESTING def setUp(self): self.app = self.layer['app'] self.portal = self.layer['portal'] login(self.portal, SITE_OWNER_NAME) self.folder = api.content.create(container=self.portal, type='Folder', id='testfolder', title='Testfolder') self.upload_url = '{}/@tus-upload'.format(self.folder.absolute_url()) transaction.commit() self.api_session = RelativeSession(self.portal.absolute_url()) self.api_session.headers.update({'Accept': 'application/json'}) self.api_session.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) def get_tus_uid_from_url(self, url): uid = url.rsplit('/', 1)[-1] assert len(uid) == 32 return uid def get_tus_upload_instance(self, uid): return TUSUpload(uid) def test_tus_option_headers(self): response = self.api_session.options(self.upload_url) headers = response.headers self.assertEqual(response.status_code, 204) self.assertEqual(headers['Tus-Version'], '1.0.0') self.assertEqual(headers['Tus-Extension'], 'creation,expiration') self.assertEqual(headers['Tus-Resumable'], '1.0.0') def test_tus_post_without_version_header_returns_412(self): response = self.api_session.post(self.upload_url) self.assertEqual(412, response.status_code) def test_tus_post_with_wrong_version_header_returns_412(self): response = self.api_session.post(self.upload_url, headers={'Tus-Resumable': '0.2.2'}) self.assertEqual(412, response.status_code) def test_tus_post_initialization_requires_header_length(self): response = self.api_session.post(self.upload_url, headers={'Tus-Resumable': '1.0.0'}) self.assertEqual(response.json()['error']['type'], 'Bad Request') self.assertEqual(response.json()['error']['message'], 'Missing or invalid Upload-Length header') self.assertEqual(response.status_code, 400) def test_tus_post_initialization(self): response = self.api_session.post(self.upload_url, headers={ 'Tus-Resumable': '1.0.0', 'Upload-Length': str(UPLOAD_LENGTH), }) self.assertEqual(response.status_code, 201) location = response.headers['Location'] url_base, uid = location.rsplit('/', 1) self.assertEqual(url_base, self.upload_url) self.assertEqual(len(uid), 32) upload = TUSUpload(uid) stored_metadata = upload.metadata() self.assertEqual(stored_metadata, {u'length': 8, u'mode': u'create'}) upload.cleanup() def test_tus_post_initialization_with_metadata(self): metadata = 'filename {},content-type {}'.format( b64encode(UPLOAD_FILENAME), b64encode(UPLOAD_MIMETYPE)) response = self.api_session.post(self.upload_url, headers={ 'Tus-Resumable': '1.0.0', 'Upload-Length': str(UPLOAD_LENGTH), 'Upload-Metadata': metadata }) self.assertEqual(response.status_code, 201) uid = self.get_tus_uid_from_url(response.headers['Location']) upload = TUSUpload(uid) stored_metadata = upload.metadata() self.assertEqual( stored_metadata, { u'content-type': u'text/plain', u'filename': u'test.txt', u'length': 8, u'mode': u'create' }) upload.cleanup() def test_tus_post_replace(self): self.file = api.content.create(container=self.portal, type='File', id='testfile', title='Testfile') transaction.commit() response = self.api_session.post( '{}/@tus-replace'.format(self.file.absolute_url()), headers={ 'Tus-Resumable': '1.0.0', 'Upload-Length': str(UPLOAD_LENGTH), }) self.assertEqual(response.status_code, 201) location = response.headers['Location'] url_base, uid = location.rsplit('/', 1) upload = TUSUpload(uid) stored_metadata = upload.metadata() self.assertEqual(stored_metadata, {u'length': 8, u'mode': u'replace'}) upload.cleanup() def test_tus_head_on_not_existing_resource_returns_404(self): response = self.api_session.head(self.upload_url + '/myuid/123', headers={'Tus-Resumable': '1.0.0'}) self.assertEqual(404, response.status_code) response = self.api_session.head(self.upload_url + '/non-existing-uid', headers={'Tus-Resumable': '1.0.0'}) self.assertEqual(404, response.status_code) response = self.api_session.head(self.upload_url, headers={'Tus-Resumable': '1.0.0'}) self.assertEqual(404, response.status_code) def test_tus_head_with_unsupported_version_returns_412(self): tus = TUSUpload('myuid', {'length': 2048}) response = self.api_session.head(self.upload_url + '/myuid', headers={'Tus-Resumable': '0.2.2'}) self.assertEqual(412, response.status_code) tus.cleanup() def test_tus_head_response_includes_required_headers(self): tus = TUSUpload('myuid', {'length': 2048}) response = self.api_session.head(self.upload_url + '/myuid', headers={'Tus-Resumable': '1.0.0'}) self.assertIn('Upload-Length', response.headers) self.assertEqual('2048', response.headers['Upload-Length']) self.assertIn('Upload-Offset', response.headers) self.assertIn('Tus-Resumable', response.headers) self.assertIn('Cache-Control', response.headers) tus.cleanup() def test_head_in_create_mode_without_add_permission_raises_401(self): self.folder.manage_permission('Add portal content', [], 0) transaction.commit() tus = TUSUpload('myuid', {'mode': 'create', 'length': 12}) response = self.api_session.head(self.upload_url + '/myuid', headers={ 'Tus-Resumable': '1.0.0', 'Upload-Offset': '0' }) self.assertEqual(401, response.status_code) tus.cleanup() def test_head_in_replace_mode_without_modify_permission_raises_401(self): self.folder.manage_permission('Modify portal content', [], 0) transaction.commit() tus = TUSUpload('myuid', {'mode': 'replace', 'length': 12}) response = self.api_session.head(self.upload_url + '/myuid', headers={ 'Tus-Resumable': '1.0.0', 'Upload-Offset': '0' }) self.assertEqual(401, response.status_code) tus.cleanup() def test_tus_patch_on_not_existing_resource_returns_404(self): response = self.api_session.patch(self.upload_url + '/myuid/123', headers={'Tus-Resumable': '1.0.0'}) self.assertEqual(404, response.status_code) response = self.api_session.patch(self.upload_url + '/myuid', headers={'Tus-Resumable': '1.0.0'}) self.assertEqual(404, response.status_code) response = self.api_session.patch(self.upload_url, headers={'Tus-Resumable': '1.0.0'}) self.assertEqual(404, response.status_code) def test_tus_patch_with_unsupported_version_returns_412(self): tus = TUSUpload('myuid', {'length': 2048}) response = self.api_session.patch(self.upload_url + '/myuid', headers={'Tus-Resumable': '0.2.2'}) self.assertEqual(412, response.status_code) tus.cleanup() def test_tus_patch_with_unsupported_content_type_returns_400(self): tus = TUSUpload('myuid', {'length': 2048}) response = self.api_session.patch(self.upload_url + '/myuid', headers={ 'Tus-Resumable': '1.0.0', 'Content-Type': 'application/json' }) self.assertEqual(400, response.status_code) tus.cleanup() def test_tus_patch_with_invalid_offset_returns_400(self): tus = TUSUpload('myuid', {'length': 2048}) response = self.api_session.patch(self.upload_url + '/myuid', headers={ 'Tus-Resumable': '1.0.0', 'Content-Type': 'application/offset+octet-stream' }) self.assertEqual(400, response.status_code) tus.cleanup() def test_tus_patch_unfinished_upload_returns_expires_header(self): tus = TUSUpload('myuid', {'length': 2048}) response = self.api_session.patch( self.upload_url + '/myuid', headers={ 'Tus-Resumable': '1.0.0', 'Content-Type': 'application/offset+octet-stream', 'Upload-Offset': '0' }, data=StringIO('abcdefghijkl')) self.assertEqual(204, response.status_code) self.assertIn('Upload-Expires', response.headers) tus.cleanup() def test_tus_patch_non_primary_field(self): tus = TUSUpload( 'myuid', { '@type': 'DXTestDocument', 'length': 12, 'fieldname': 'test_namedblobfile_field' }) response = self.api_session.patch( self.upload_url + '/myuid', headers={ 'Tus-Resumable': '1.0.0', 'Content-Type': 'application/offset+octet-stream', 'Upload-Offset': '0' }, data=StringIO('abcdefghijkl')) self.assertEqual(204, response.status_code) transaction.commit() self.assertEqual(1, len(self.folder.objectIds())) id_ = self.folder.objectIds()[0] self.assertEqual('abcdefghijkl', self.folder[id_].test_namedblobfile_field.data) tus.cleanup() def test_patch_in_create_mode_without_add_permission_raises_401(self): self.folder.manage_permission('Add portal content', [], 0) transaction.commit() tus = TUSUpload('myuid', {'mode': 'create', 'length': 12}) response = self.api_session.patch( self.upload_url + '/myuid', headers={ 'Tus-Resumable': '1.0.0', 'Content-Type': 'application/offset+octet-stream', 'Upload-Offset': '0' }, data=StringIO('abcdefghijkl')) self.assertEqual(401, response.status_code) tus.cleanup() def test_patch_in_replace_mode_without_modify_permission_raises_401(self): self.folder.manage_permission('Modify portal content', [], 0) transaction.commit() tus = TUSUpload('myuid', {'mode': 'replace', 'length': 12}) response = self.api_session.patch( self.upload_url + '/myuid', headers={ 'Tus-Resumable': '1.0.0', 'Content-Type': 'application/offset+octet-stream', 'Upload-Offset': '0' }, data=StringIO('abcdefghijkl')) self.assertEqual(401, response.status_code) tus.cleanup() def test_tus_can_upload_pdf_file(self): # initialize the upload with POST pdf_file_path = os.path.join(os.path.dirname(__file__), UPLOAD_PDF_FILENAME) pdf_file_size = os.path.getsize(pdf_file_path) metadata = 'filename {},content-type {}'.format( b64encode(UPLOAD_PDF_FILENAME), b64encode(UPLOAD_PDF_MIMETYPE)) response = self.api_session.post(self.upload_url, headers={ 'Tus-Resumable': '1.0.0', 'Upload-Length': str(pdf_file_size), 'Upload-Metadata': metadata }) self.assertEqual(response.status_code, 201) location = response.headers['Location'] # upload the data with PATCH pdf_file = open(pdf_file_path, 'rb') response = self.api_session.patch( location, headers={ 'Content-Type': 'application/offset+octet-stream', 'Upload-Offset': '0', 'Tus-Resumable': '1.0.0' }, data=pdf_file) self.assertEqual(response.status_code, 204) transaction.commit() self.assertEqual([UPLOAD_PDF_FILENAME], self.folder.contentIds()) def test_tus_can_upload_text_file(self): # initialize the upload with POST metadata = 'filename {},content-type {}'.format( b64encode(UPLOAD_FILENAME), b64encode(UPLOAD_MIMETYPE)) response = self.api_session.post(self.upload_url, headers={ 'Tus-Resumable': '1.0.0', 'Upload-Length': str(UPLOAD_LENGTH), 'Upload-Metadata': metadata }) self.assertEqual(response.status_code, 201) location = response.headers['Location'] # upload the data with PATCH response = self.api_session.patch( location, headers={ 'Content-Type': 'application/offset+octet-stream', 'Upload-Offset': '0', 'Tus-Resumable': '1.0.0' }, data=StringIO(UPLOAD_DATA)) self.assertEqual(response.status_code, 204) def test_tus_can_replace_pdf_file(self): # Create a test file self.file = api.content.create(container=self.portal, type='File', id='testfile', title='Testfile') transaction.commit() # initialize the upload with POST pdf_file_path = os.path.join(os.path.dirname(__file__), UPLOAD_PDF_FILENAME) pdf_file_size = os.path.getsize(pdf_file_path) metadata = 'filename {},content-type {}'.format( b64encode(UPLOAD_PDF_FILENAME), b64encode(UPLOAD_PDF_MIMETYPE)) response = self.api_session.post( '{}/@tus-replace'.format(self.file.absolute_url()), headers={ 'Tus-Resumable': '1.0.0', 'Upload-Length': str(pdf_file_size), 'Upload-Metadata': metadata }) self.assertEqual(response.status_code, 201) location = response.headers['Location'] # upload the data with PATCH pdf_file = open(pdf_file_path, 'rb') response = self.api_session.patch( location, headers={ 'Content-Type': 'application/offset+octet-stream', 'Upload-Offset': '0', 'Tus-Resumable': '1.0.0' }, data=pdf_file) self.assertEqual(response.status_code, 204) transaction.commit() self.assertEqual(UPLOAD_PDF_FILENAME, self.file.file.filename) self.assertEqual(pdf_file_size, self.file.file.size) def tearDown(self): client_home = os.environ.get('CLIENT_HOME') tmp_dir = os.path.join(client_home, 'tus-uploads') if os.path.isdir(tmp_dir): shutil.rmtree(tmp_dir)
class TestTUS(unittest.TestCase): layer = PLONE_RESTAPI_DX_FUNCTIONAL_TESTING def setUp(self): self.app = self.layer["app"] self.portal = self.layer["portal"] login(self.portal, SITE_OWNER_NAME) self.folder = api.content.create(container=self.portal, type="Folder", id="testfolder", title="Testfolder") self.upload_url = f"{self.folder.absolute_url()}/@tus-upload" transaction.commit() self.api_session = RelativeSession(self.portal.absolute_url(), test=self) self.api_session.headers.update({"Accept": "application/json"}) self.api_session.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) def get_tus_uid_from_url(self, url): uid = url.rsplit("/", 1)[-1] assert len(uid) == 32 return uid def get_tus_upload_instance(self, uid): return TUSUpload(uid) def test_tus_option_headers(self): response = self.api_session.options(self.upload_url) headers = response.headers self.assertEqual(response.status_code, 204) self.assertEqual(headers["Tus-Version"], "1.0.0") self.assertEqual(headers["Tus-Extension"], "creation,expiration") self.assertEqual(headers["Tus-Resumable"], "1.0.0") def test_tus_post_without_version_header_returns_412(self): response = self.api_session.post(self.upload_url) self.assertEqual(412, response.status_code) def test_tus_post_with_wrong_version_header_returns_412(self): response = self.api_session.post(self.upload_url, headers={"Tus-Resumable": "0.2.2"}) self.assertEqual(412, response.status_code) def test_tus_post_initialization_requires_header_length(self): response = self.api_session.post(self.upload_url, headers={"Tus-Resumable": "1.0.0"}) self.assertEqual(response.json()["error"]["type"], "Bad Request") self.assertEqual( response.json()["error"]["message"], "Missing or invalid Upload-Length header", ) self.assertEqual(response.status_code, 400) def test_tus_post_initialization(self): response = self.api_session.post( self.upload_url, headers={ "Tus-Resumable": "1.0.0", "Upload-Length": str(UPLOAD_LENGTH) }, ) self.assertEqual(response.status_code, 201) location = response.headers["Location"] url_base, uid = location.rsplit("/", 1) self.assertEqual(url_base, self.upload_url) self.assertEqual(len(uid), 32) upload = TUSUpload(uid) stored_metadata = upload.metadata() self.assertEqual(stored_metadata, {"length": 8, "mode": "create"}) upload.cleanup() def test_tus_post_initialization_with_metadata(self): metadata = _prepare_metadata(UPLOAD_FILENAME, UPLOAD_MIMETYPE) response = self.api_session.post( self.upload_url, headers={ "Tus-Resumable": "1.0.0", "Upload-Length": str(UPLOAD_LENGTH), "Upload-Metadata": metadata, }, ) self.assertEqual(response.status_code, 201) uid = self.get_tus_uid_from_url(response.headers["Location"]) upload = TUSUpload(uid) stored_metadata = upload.metadata() self.assertEqual( stored_metadata, { "content-type": "text/plain", "filename": "test.txt", "length": 8, "mode": "create", }, ) upload.cleanup() def test_tus_post_replace(self): self.file = api.content.create(container=self.portal, type="File", id="testfile", title="Testfile") transaction.commit() response = self.api_session.post( f"{self.file.absolute_url()}/@tus-replace", headers={ "Tus-Resumable": "1.0.0", "Upload-Length": str(UPLOAD_LENGTH) }, ) self.assertEqual(response.status_code, 201) location = response.headers["Location"] url_base, uid = location.rsplit("/", 1) upload = TUSUpload(uid) stored_metadata = upload.metadata() self.assertEqual(stored_metadata, {"length": 8, "mode": "replace"}) upload.cleanup() def test_tus_head_on_not_existing_resource_returns_404(self): response = self.api_session.head(self.upload_url + "/myuid/123", headers={"Tus-Resumable": "1.0.0"}) self.assertEqual(404, response.status_code) response = self.api_session.head(self.upload_url + "/non-existing-uid", headers={"Tus-Resumable": "1.0.0"}) self.assertEqual(404, response.status_code) response = self.api_session.head(self.upload_url, headers={"Tus-Resumable": "1.0.0"}) self.assertEqual(404, response.status_code) def test_tus_head_with_unsupported_version_returns_412(self): tus = TUSUpload("myuid", {"length": 2048}) response = self.api_session.head(self.upload_url + "/myuid", headers={"Tus-Resumable": "0.2.2"}) self.assertEqual(412, response.status_code) tus.cleanup() def test_tus_head_response_includes_required_headers(self): tus = TUSUpload("myuid", {"length": 2048}) response = self.api_session.head(self.upload_url + "/myuid", headers={"Tus-Resumable": "1.0.0"}) self.assertIn("Upload-Length", response.headers) self.assertEqual("2048", response.headers["Upload-Length"]) self.assertIn("Upload-Offset", response.headers) self.assertIn("Tus-Resumable", response.headers) self.assertIn("Cache-Control", response.headers) tus.cleanup() def test_head_in_create_mode_without_add_permission_raises_401(self): self.folder.manage_permission("Add portal content", [], 0) transaction.commit() tus = TUSUpload("myuid", {"mode": "create", "length": 12}) response = self.api_session.head( self.upload_url + "/myuid", headers={ "Tus-Resumable": "1.0.0", "Upload-Offset": "0" }, ) self.assertEqual(401, response.status_code) tus.cleanup() def test_head_in_replace_mode_without_modify_permission_raises_401(self): self.folder.manage_permission("Modify portal content", [], 0) transaction.commit() tus = TUSUpload("myuid", {"mode": "replace", "length": 12}) response = self.api_session.head( self.upload_url + "/myuid", headers={ "Tus-Resumable": "1.0.0", "Upload-Offset": "0" }, ) self.assertEqual(401, response.status_code) tus.cleanup() def test_tus_patch_on_not_existing_resource_returns_404(self): response = self.api_session.patch(self.upload_url + "/myuid/123", headers={"Tus-Resumable": "1.0.0"}) self.assertEqual(404, response.status_code) response = self.api_session.patch(self.upload_url + "/myuid", headers={"Tus-Resumable": "1.0.0"}) self.assertEqual(404, response.status_code) response = self.api_session.patch(self.upload_url, headers={"Tus-Resumable": "1.0.0"}) self.assertEqual(404, response.status_code) def test_tus_patch_with_unsupported_version_returns_412(self): tus = TUSUpload("myuid", {"length": 2048}) response = self.api_session.patch(self.upload_url + "/myuid", headers={"Tus-Resumable": "0.2.2"}) self.assertEqual(412, response.status_code) tus.cleanup() def test_tus_patch_with_unsupported_content_type_returns_400(self): tus = TUSUpload("myuid", {"length": 2048}) response = self.api_session.patch( self.upload_url + "/myuid", headers={ "Tus-Resumable": "1.0.0", "Content-Type": "application/json" }, ) self.assertEqual(400, response.status_code) tus.cleanup() def test_tus_patch_with_invalid_offset_returns_400(self): tus = TUSUpload("myuid", {"length": 2048}) response = self.api_session.patch( self.upload_url + "/myuid", headers={ "Tus-Resumable": "1.0.0", "Content-Type": "application/offset+octet-stream", }, ) self.assertEqual(400, response.status_code) tus.cleanup() def test_tus_patch_unfinished_upload_returns_expires_header(self): tus = TUSUpload("myuid", {"length": 2048}) response = self.api_session.patch( self.upload_url + "/myuid", headers={ "Tus-Resumable": "1.0.0", "Content-Type": "application/offset+octet-stream", "Upload-Offset": "0", }, data=BytesIO(b"abcdefghijkl"), ) self.assertEqual(204, response.status_code) self.assertIn("Upload-Expires", response.headers) tus.cleanup() def test_tus_patch_non_primary_field(self): tus = TUSUpload( "myuid", { "@type": "DXTestDocument", "length": 12, "fieldname": "test_namedblobfile_field", }, ) response = self.api_session.patch( self.upload_url + "/myuid", headers={ "Tus-Resumable": "1.0.0", "Content-Type": "application/offset+octet-stream", "Upload-Offset": "0", }, data=BytesIO(b"abcdefghijkl"), ) self.assertEqual(204, response.status_code) transaction.commit() self.assertEqual(1, len(self.folder.objectIds())) id_ = self.folder.objectIds()[0] self.assertEqual(b"abcdefghijkl", self.folder[id_].test_namedblobfile_field.data) tus.cleanup() def test_patch_in_create_mode_without_add_permission_raises_401(self): self.folder.manage_permission("Add portal content", [], 0) transaction.commit() tus = TUSUpload("myuid", {"mode": "create", "length": 12}) response = self.api_session.patch( self.upload_url + "/myuid", headers={ "Tus-Resumable": "1.0.0", "Content-Type": "application/offset+octet-stream", "Upload-Offset": "0", }, data=BytesIO(b"abcdefghijkl"), ) self.assertEqual(401, response.status_code) tus.cleanup() def test_patch_in_replace_mode_without_modify_permission_raises_401(self): self.folder.manage_permission("Modify portal content", [], 0) transaction.commit() tus = TUSUpload("myuid", {"mode": "replace", "length": 12}) response = self.api_session.patch( self.upload_url + "/myuid", headers={ "Tus-Resumable": "1.0.0", "Content-Type": "application/offset+octet-stream", "Upload-Offset": "0", }, data=BytesIO(b"abcdefghijkl"), ) self.assertEqual(401, response.status_code) tus.cleanup() def test_tus_can_upload_pdf_file(self): # initialize the upload with POST pdf_file_path = os.path.join(os.path.dirname(__file__), UPLOAD_PDF_FILENAME) pdf_file_size = os.path.getsize(pdf_file_path) metadata = _prepare_metadata(UPLOAD_PDF_FILENAME, UPLOAD_PDF_MIMETYPE) response = self.api_session.post( self.upload_url, headers={ "Tus-Resumable": "1.0.0", "Upload-Length": str(pdf_file_size), "Upload-Metadata": metadata, }, ) self.assertEqual(response.status_code, 201) location = response.headers["Location"] # upload the data with PATCH with open(pdf_file_path, "rb") as pdf_file: response = self.api_session.patch( location, headers={ "Content-Type": "application/offset+octet-stream", "Upload-Offset": "0", "Tus-Resumable": "1.0.0", }, data=pdf_file, ) self.assertEqual(response.status_code, 204) transaction.commit() self.assertEqual([UPLOAD_PDF_FILENAME], self.folder.contentIds()) def test_tus_can_upload_text_file(self): # initialize the upload with POST metadata = _prepare_metadata(UPLOAD_FILENAME, UPLOAD_MIMETYPE) response = self.api_session.post( self.upload_url, headers={ "Tus-Resumable": "1.0.0", "Upload-Length": str(UPLOAD_LENGTH), "Upload-Metadata": metadata, }, ) self.assertEqual(response.status_code, 201) location = response.headers["Location"] # upload the data with PATCH response = self.api_session.patch( location, headers={ "Content-Type": "application/offset+octet-stream", "Upload-Offset": "0", "Tus-Resumable": "1.0.0", }, data=BytesIO(UPLOAD_DATA), ) self.assertEqual(response.status_code, 204) def test_tus_can_replace_pdf_file(self): # Create a test file self.file = api.content.create(container=self.portal, type="File", id="testfile", title="Testfile") transaction.commit() # initialize the upload with POST pdf_file_path = os.path.join(os.path.dirname(__file__), UPLOAD_PDF_FILENAME) pdf_file_size = os.path.getsize(pdf_file_path) metadata = _prepare_metadata(UPLOAD_PDF_FILENAME, UPLOAD_PDF_MIMETYPE) response = self.api_session.post( f"{self.file.absolute_url()}/@tus-replace", headers={ "Tus-Resumable": "1.0.0", "Upload-Length": str(pdf_file_size), "Upload-Metadata": metadata, }, ) self.assertEqual(response.status_code, 201) location = response.headers["Location"] # upload the data with PATCH with open(pdf_file_path, "rb") as pdf_file: response = self.api_session.patch( location, headers={ "Content-Type": "application/offset+octet-stream", "Upload-Offset": "0", "Tus-Resumable": "1.0.0", }, data=pdf_file, ) self.assertEqual(response.status_code, 204) transaction.commit() self.assertEqual(UPLOAD_PDF_FILENAME, self.file.file.filename) self.assertEqual(pdf_file_size, self.file.file.size) def test_create_with_tus_fires_proper_events(self): sm = getGlobalSiteManager() fired_events = [] def record_event(event): fired_events.append(event.__class__.__name__) sm.registerHandler(record_event, (IObjectCreatedEvent, )) sm.registerHandler(record_event, (IObjectWillBeAddedEvent, )) sm.registerHandler(record_event, (IObjectAddedEvent, )) sm.registerHandler(record_event, (IObjectModifiedEvent, )) # initialize the upload with POST pdf_file_path = os.path.join(os.path.dirname(__file__), UPLOAD_PDF_FILENAME) pdf_file_size = os.path.getsize(pdf_file_path) metadata = _prepare_metadata(UPLOAD_PDF_FILENAME, UPLOAD_PDF_MIMETYPE) response = self.api_session.post( self.upload_url, headers={ "Tus-Resumable": "1.0.0", "Upload-Length": str(pdf_file_size), "Upload-Metadata": metadata, }, ) self.assertEqual(response.status_code, 201) location = response.headers["Location"] # upload the data with PATCH with open(pdf_file_path, "rb") as pdf_file: response = self.api_session.patch( location, headers={ "Content-Type": "application/offset+octet-stream", "Upload-Offset": "0", "Tus-Resumable": "1.0.0", }, data=pdf_file, ) self.assertEqual(response.status_code, 204) self.assertEqual( fired_events, [ "ObjectCreatedEvent", "ObjectWillBeAddedEvent", "ObjectAddedEvent", "ContainerModifiedEvent", ], ) sm.unregisterHandler(record_event, (IObjectCreatedEvent, )) sm.unregisterHandler(record_event, (IObjectWillBeAddedEvent, )) sm.unregisterHandler(record_event, (IObjectAddedEvent, )) sm.unregisterHandler(record_event, (IObjectModifiedEvent, )) def test_replace_with_tus_fires_proper_events(self): # Create a test file self.file = api.content.create(container=self.portal, type="File", id="testfile", title="Testfile") transaction.commit() sm = getGlobalSiteManager() fired_events = [] def record_event(event): fired_events.append(event.__class__.__name__) sm.registerHandler(record_event, (IObjectCreatedEvent, )) sm.registerHandler(record_event, (IObjectWillBeAddedEvent, )) sm.registerHandler(record_event, (IObjectAddedEvent, )) sm.registerHandler(record_event, (IObjectModifiedEvent, )) # initialize the upload with POST pdf_file_path = os.path.join(os.path.dirname(__file__), UPLOAD_PDF_FILENAME) pdf_file_size = os.path.getsize(pdf_file_path) metadata = _prepare_metadata(UPLOAD_PDF_FILENAME, UPLOAD_PDF_MIMETYPE) response = self.api_session.post( f"{self.file.absolute_url()}/@tus-replace", headers={ "Tus-Resumable": "1.0.0", "Upload-Length": str(pdf_file_size), "Upload-Metadata": metadata, }, ) self.assertEqual(response.status_code, 201) location = response.headers["Location"] # upload the data with PATCH with open(pdf_file_path, "rb") as pdf_file: response = self.api_session.patch( location, headers={ "Content-Type": "application/offset+octet-stream", "Upload-Offset": "0", "Tus-Resumable": "1.0.0", }, data=pdf_file, ) self.assertEqual(response.status_code, 204) self.assertEqual(fired_events, ["ObjectModifiedEvent"]) sm.unregisterHandler(record_event, (IObjectCreatedEvent, )) sm.unregisterHandler(record_event, (IObjectWillBeAddedEvent, )) sm.unregisterHandler(record_event, (IObjectAddedEvent, )) sm.unregisterHandler(record_event, (IObjectModifiedEvent, )) def tearDown(self): self.api_session.close() client_home = os.environ.get("CLIENT_HOME") tmp_dir = os.path.join(client_home, "tus-uploads") if os.path.isdir(tmp_dir): shutil.rmtree(tmp_dir)