def test_delete_collections(self): """Test the "delete selected" checkboxes on the index page that can be used to delete multiple collections""" # first, add some sources num_sources = 2 for i in range(num_sources): self.source_app.get('/generate') self.source_app.post('/create') self.source_app.post('/submit', data=dict( msg="This is a test " + str(i) + ".", fh=(StringIO(''), ''), ), follow_redirects=True) common.logout(self.source_app) rv = self.journalist_app.get('/') # get all the checkbox values soup = BeautifulSoup(rv.data) checkbox_values = [ checkbox['value'] for checkbox in soup.select('input[name="cols_selected"]') ] rv = self.journalist_app.post('/col/process', data=dict(action='delete', cols_selected=checkbox_values), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertIn("%s collections deleted" % (num_sources, ), rv.data) # Make sure the collections are deleted from the filesystem self._wait_for(lambda: self.assertFalse( any([os.path.exists(store.path(sid)) for sid in checkbox_values])))
def test_delete_collections(self): """Test the "delete selected" checkboxes on the index page that can be used to delete multiple collections""" # first, add some sources num_sources = 2 for i in range(num_sources): self.source_app.get('/generate') self.source_app.post('/create') self.source_app.post('/submit', data=dict( msg="This is a test " + str(i) + ".", fh=(StringIO(''), ''), ), follow_redirects=True) common.logout(self.source_app) rv = self.journalist_app.get('/') # get all the checkbox values soup = BeautifulSoup(rv.data) checkbox_values = [checkbox['value'] for checkbox in soup.select('input[name="cols_selected"]')] rv = self.journalist_app.post('/col/process', data=dict( action='delete', cols_selected=checkbox_values ), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertIn("%s collections deleted" % (num_sources,), rv.data) # Make sure the collections are deleted from the filesystem self._wait_for( lambda: self.assertFalse(any([os.path.exists(store.path(sid)) for sid in checkbox_values])) )
def test_login_and_logout(self): rv = self.client.get('/login') self.assertEqual(rv.status_code, 200) self.assertIn("Login to check for responses", rv.data) codename = self._new_codename() with self.client as c: rv = c.post('/login', data=dict(codename=codename), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertIn("Submit documents and messages", rv.data) self.assertTrue(session['logged_in']) common.logout(c) with self.client as c: rv = self.client.post('/login', data=dict(codename='invalid'), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertIn('Sorry, that is not a recognized codename.', rv.data) self.assertNotIn('logged_in', session) with self.client as c: rv = c.post('/login', data=dict(codename=codename), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertTrue(session['logged_in']) rv = c.get('/logout', follow_redirects=True) self.assertTrue(not session) self.assertIn('Thank you for logging out!', rv.data)
def login_test(codename): rv = self.client.get("/login") self.assertEqual(rv.status_code, 200) self.assertIn("Login to check for responses", rv.data) with self.client as c: rv = c.post("/login", data=dict(codename=codename), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertIn("Submit documents and messages", rv.data) self.assertTrue(session["logged_in"]) common.logout(c)
def login_test(codename): rv = self.client.get('/login') self.assertEqual(rv.status_code, 200) self.assertIn("Login to check for responses", rv.data) with self.client as c: rv = c.post('/login', data=dict(codename=codename), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertIn("Submit documents and messages", rv.data) self.assertTrue(session['logged_in']) common.logout(c)
def main(): ENVIRONMENTS.extend(common.get('/environments').json()) test_table() prepare_users() with ProcessPoolExecutor( max_workers=os.cpu_count(), mp_context=mp.get_context('fork'), ) as executor: try: common.login() run_tests(executor) executor.shutdown(wait=True) finally: common.logout()
def test_login_and_logout(self): rv = self.client.get("/login") self.assertEqual(rv.status_code, 200) self.assertIn("Login to check for responses", rv.data) codename = self._new_codename() with self.client as c: rv = c.post("/login", data=dict(codename=codename), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertIn("Submit documents and messages", rv.data) self.assertTrue(session["logged_in"]) common.logout(c) with self.client as c: rv = self.client.post("/login", data=dict(codename="invalid"), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertIn("Sorry, that is not a recognized codename.", rv.data) self.assertNotIn("logged_in", session)
def test_submit_message(self): """When a source creates an account, test that a new entry appears in the journalist interface""" test_msg = "This is a test message." with self.source_app as source_app: rv = source_app.get('/generate') rv = source_app.post('/create', follow_redirects=True) codename = session['codename'] sid = g.sid # redirected to submission form rv = self.source_app.post('/submit', data=dict( msg=test_msg, fh=(StringIO(''), ''), ), follow_redirects=True) self.assertEqual(rv.status_code, 200) common.logout(source_app) # Request the Document Interface index rv = self.journalist_app.get('/') self.assertEqual(rv.status_code, 200) self.assertIn("Sources", rv.data) soup = BeautifulSoup(rv.data) # The source should have a "download unread" link that says "1 unread" col = soup.select('ul#cols > li')[0] unread_span = col.select('span.unread a')[0] self.assertIn("1 unread", unread_span.get_text()) col_url = soup.select('ul#cols > li a')[0]['href'] rv = self.journalist_app.get(col_url) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) submission_url = soup.select('ul#submissions li a')[0]['href'] self.assertIn("-msg", submission_url) span = soup.select('ul#submissions li span.info span')[0] self.assertRegexpMatches(span['title'], "\d+ bytes") rv = self.journalist_app.get(submission_url) self.assertEqual(rv.status_code, 200) decrypted_data = self.gpg.decrypt(rv.data) self.assertTrue(decrypted_data.ok) self.assertEqual(decrypted_data.data, test_msg) # delete submission rv = self.journalist_app.get(col_url) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) doc_name = soup.select( 'ul > li > input[name="doc_names_selected"]')[0]['value'] rv = self.journalist_app.post('/bulk', data=dict(action='confirm_delete', sid=sid, doc_names_selected=doc_name)) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) self.assertIn("The following file has been selected for", rv.data) # confirm delete submission doc_name = soup.select doc_name = soup.select( 'ul > li > input[name="doc_names_selected"]')[0]['value'] rv = self.journalist_app.post('/bulk', data=dict( action='delete', sid=sid, doc_names_selected=doc_name, ), follow_redirects=True) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) self.assertIn("Submission deleted.", rv.data) # confirm that submission deleted and absent in list of submissions rv = self.journalist_app.get(col_url) self.assertEqual(rv.status_code, 200) self.assertIn("No documents to display.", rv.data) # the file should be deleted from the filesystem # since file deletion is handled by a polling worker, this test needs # to wait for the worker to get the job and execute it self._wait_for(lambda: self.assertFalse( os.path.exists(store.path(sid, doc_name))))
def helper_test_reply(self, test_reply, expected_success=True): test_msg = "This is a test message." with self.source_app as source_app: rv = source_app.get('/generate') rv = source_app.post('/create', follow_redirects=True) codename = session['codename'] sid = g.sid # redirected to submission form rv = source_app.post('/submit', data=dict( msg=test_msg, fh=(StringIO(''), ''), ), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertFalse(g.source.flagged) common.logout(source_app) rv = self.journalist_app.get('/') self.assertEqual(rv.status_code, 200) self.assertIn("Sources", rv.data) soup = BeautifulSoup(rv.data) col_url = soup.select('ul#cols > li a')[0]['href'] rv = self.journalist_app.get(col_url) self.assertEqual(rv.status_code, 200) with self.source_app as source_app: rv = source_app.post('/login', data=dict(codename=codename), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertFalse(g.source.flagged) common.logout(source_app) with self.journalist_app as journalist_app: rv = journalist_app.post('/flag', data=dict(sid=sid)) self.assertEqual(rv.status_code, 200) with self.source_app as source_app: rv = source_app.post('/login', data=dict(codename=codename), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertTrue(g.source.flagged) source_app.get('/lookup') self.assertTrue(g.source.flagged) common.logout(source_app) # Block until the reply keypair has been generated, so we can test # sending a reply _block_on_reply_keypair_gen(codename) # Create 2 replies to test deleting on journalist and source interface for i in range(2): rv = self.journalist_app.post('/reply', data=dict(sid=sid, msg=test_reply), follow_redirects=True) self.assertEqual(rv.status_code, 200) if not expected_success: pass else: self.assertIn("Thanks! Your reply has been stored.", rv.data) with self.journalist_app as journalist_app: rv = journalist_app.get(col_url) self.assertIn("reply-", rv.data) soup = BeautifulSoup(rv.data) # Download the reply and verify that it can be decrypted with the # journalist's key as well as the source's reply key sid = soup.select('input[name="sid"]')[0]['value'] checkbox_values = [ soup.select('input[name="doc_names_selected"]')[1]['value'] ] rv = self.journalist_app.post('/bulk', data=dict( sid=sid, action='download', doc_names_selected=checkbox_values), follow_redirects=True) self.assertEqual(rv.status_code, 200) zf = zipfile.ZipFile(StringIO(rv.data), 'r') data = zf.read(zf.namelist()[0]) self._can_decrypt_with_key(data, config.JOURNALIST_KEY) self._can_decrypt_with_key(data, crypto_util.getkey(sid), codename) # Test deleting reply on the journalist interface last_reply_number = len( soup.select('input[name="doc_names_selected"]')) - 1 self.helper_filenames_delete(soup, last_reply_number) with self.source_app as source_app: rv = source_app.post('/login', data=dict(codename=codename), follow_redirects=True) self.assertEqual(rv.status_code, 200) rv = source_app.get('/lookup') self.assertEqual(rv.status_code, 200) if not expected_success: # there should be no reply self.assertNotIn("You have received a reply.", rv.data) else: self.assertIn( "You have received a reply. For your security, please delete all replies when you're done with them.", rv.data) self.assertIn(test_reply, rv.data) soup = BeautifulSoup(rv.data) msgid = soup.select( 'form.message > input[name="reply_filename"]')[0]['value'] rv = source_app.post('/delete', data=dict(sid=sid, reply_filename=msgid), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertIn("Reply deleted", rv.data) # Make sure the reply is deleted from the filesystem self._wait_for(lambda: self.assertFalse( os.path.exists(store.path(sid, msgid)))) common.logout(source_app)
def test_submit_message(self): """When a source creates an account, test that a new entry appears in the journalist interface""" test_msg = "This is a test message." with self.source_app as source_app: rv = source_app.get('/generate') rv = source_app.post('/create', follow_redirects=True) codename = session['codename'] sid = g.sid # redirected to submission form rv = self.source_app.post('/submit', data=dict( msg=test_msg, fh=(StringIO(''), ''), ), follow_redirects=True) self.assertEqual(rv.status_code, 200) common.logout(source_app) # Request the Document Interface index rv = self.journalist_app.get('/') self.assertEqual(rv.status_code, 200) self.assertIn("Sources", rv.data) soup = BeautifulSoup(rv.data) # The source should have a "download unread" link that says "1 unread" col = soup.select('ul#cols > li')[0] unread_span = col.select('span.unread a')[0] self.assertIn("1 unread", unread_span.get_text()) col_url = soup.select('ul#cols > li a')[0]['href'] rv = self.journalist_app.get(col_url) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) submission_url = soup.select('ul#submissions li a')[0]['href'] self.assertIn("-msg", submission_url) span = soup.select('ul#submissions li span.info span')[0] self.assertRegexpMatches(span['title'], "\d+ bytes") rv = self.journalist_app.get(submission_url) self.assertEqual(rv.status_code, 200) decrypted_data = self.gpg.decrypt(rv.data) self.assertTrue(decrypted_data.ok) self.assertEqual(decrypted_data.data, test_msg) # delete submission rv = self.journalist_app.get(col_url) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) doc_name = soup.select( 'ul > li > input[name="doc_names_selected"]')[0]['value'] rv = self.journalist_app.post('/bulk', data=dict( action='confirm_delete', sid=sid, doc_names_selected=doc_name )) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) self.assertIn("The following file has been selected for", rv.data) # confirm delete submission doc_name = soup.select doc_name = soup.select( 'ul > li > input[name="doc_names_selected"]')[0]['value'] rv = self.journalist_app.post('/bulk', data=dict( action='delete', sid=sid, doc_names_selected=doc_name, ), follow_redirects=True) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) self.assertIn("Submission deleted.", rv.data) # confirm that submission deleted and absent in list of submissions rv = self.journalist_app.get(col_url) self.assertEqual(rv.status_code, 200) self.assertIn("No documents to display.", rv.data) # the file should be deleted from the filesystem # since file deletion is handled by a polling worker, this test needs # to wait for the worker to get the job and execute it self._wait_for( lambda: self.assertFalse(os.path.exists(store.path(sid, doc_name))) )
client.channel.software.create(sessionKey, 'rhel-x86_64-server-6-epel', 'EPEL 6 x86_64', 'Extra Packages for Enterprise Linux 6 x86_64', 'channel-x86_64', 'rhel-x86_64-server-6', 'sha256') print '[OK]' print 'Step 2: Create repo repo-rhel-x86_64-server-6-epel . . .', client.channel.software.createRepo(sessionKey, 'repo-rhel-x86_64-server-6-epel', 'yum', 'http://mirrors.servercentral.net/fedora/epel/6/x86_64/') print '[OK]' print 'Step 3: Associate EPEL repo to EPEL channel . . .', client.channel.software.associateRepo(sessionKey, 'rhel-x86_64-server-6-epel', 'repo-rhel-x86_64-server-6-epel') print '[OK]' print 'Step 4: Initiating repo sync . . .', client.channel.software.syncRepo(sessionKey, 'rhel-x86_64-server-6-epel') print '[OK]' print 'Step 5: Logout . . .', common.logout(client, sessionKey) print '[OK]' print 'At this point, EPEL 6 will be syncing to your satellite. This may take some time. Grab a coffee.'
def test_user_registration(self): self.register_user() self.login_user() self.change_profile() logout(self) self.register_duplicate_mail()
def test_submit_file(self): """When a source creates an account, test that a new entry appears in the journalist interface""" test_file_contents = "This is a test file." test_filename = "test.txt" with self.source_app as source_app: rv = source_app.get('/generate') rv = source_app.post('/create', follow_redirects=True) codename = session['codename'] sid = g.sid # redirected to submission form rv = self.source_app.post('/submit', data=dict( msg="", fh=(StringIO(test_file_contents), test_filename), ), follow_redirects=True) self.assertEqual(rv.status_code, 200) common.logout(source_app) rv = self.journalist_app.get('/') self.assertEqual(rv.status_code, 200) self.assertIn("Sources", rv.data) soup = BeautifulSoup(rv.data) col_url = soup.select('ul#cols > li a')[0]['href'] rv = self.journalist_app.get(col_url) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) submission_url = soup.select('ul#submissions li a')[0]['href'] self.assertIn("-doc", submission_url) span = soup.select('ul#submissions li span.info span')[0] self.assertRegexpMatches(span['title'], "\d+ bytes") rv = self.journalist_app.get(submission_url) self.assertEqual(rv.status_code, 200) decrypted_data = self.gpg.decrypt(rv.data) self.assertTrue(decrypted_data.ok) sio = StringIO(decrypted_data.data) with gzip.GzipFile(mode='rb', fileobj=sio) as gzip_file: unzipped_decrypted_data = gzip_file.read() self.assertEqual(unzipped_decrypted_data, test_file_contents) # delete submission rv = self.journalist_app.get(col_url) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) doc_name = soup.select( 'ul > li > input[name="doc_names_selected"]')[0]['value'] rv = self.journalist_app.post('/bulk', data=dict( action='confirm_delete', sid=sid, doc_names_selected=doc_name )) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) self.assertIn("The following file has been selected for", rv.data) # confirm delete submission doc_name = soup.select doc_name = soup.select( 'ul > li > input[name="doc_names_selected"]')[0]['value'] rv = self.journalist_app.post('/bulk', data=dict( action='delete', sid=sid, doc_names_selected=doc_name, ), follow_redirects=True) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) self.assertIn("Submission deleted.", rv.data) # confirm that submission deleted and absent in list of submissions rv = self.journalist_app.get(col_url) self.assertEqual(rv.status_code, 200) self.assertIn("No documents to display.", rv.data) # the file should be deleted from the filesystem # since file deletion is handled by a polling worker, this test needs # to wait for the worker to get the job and execute it self._wait_for( lambda: self.assertFalse(os.path.exists(store.path(sid, doc_name))) )
def test_logout(self): print("Testing logout") auth = common.make_user(GATEWAY_URL, common.generate_user()) common.logout(GATEWAY_URL, auth)
(client, sessionKey) = common.login() print '[OK]' print 'Step 1: Create rhel-x86_64-server-6-epel as child of rhel-x86_64-server-6 . . .', client.channel.software.create(sessionKey, 'rhel-x86_64-server-6-epel', 'EPEL 6 x86_64', 'Extra Packages for Enterprise Linux 6 x86_64', 'channel-x86_64', 'rhel-x86_64-server-6', 'sha256') print '[OK]' print 'Step 2: Create repo repo-rhel-x86_64-server-6-epel . . .', client.channel.software.createRepo( sessionKey, 'repo-rhel-x86_64-server-6-epel', 'yum', 'http://mirrors.servercentral.net/fedora/epel/6/x86_64/') print '[OK]' print 'Step 3: Associate EPEL repo to EPEL channel . . .', client.channel.software.associateRepo(sessionKey, 'rhel-x86_64-server-6-epel', 'repo-rhel-x86_64-server-6-epel') print '[OK]' print 'Step 4: Initiating repo sync . . .', client.channel.software.syncRepo(sessionKey, 'rhel-x86_64-server-6-epel') print '[OK]' print 'Step 5: Logout . . .', common.logout(client, sessionKey) print '[OK]' print 'At this point, EPEL 6 will be syncing to your satellite. This may take some time. Grab a coffee.'
def helper_test_reply(self, test_reply, expected_success=True): test_msg = "This is a test message." with self.source_app as source_app: rv = source_app.get('/generate') rv = source_app.post('/create', follow_redirects=True) codename = session['codename'] sid = g.sid # redirected to submission form rv = source_app.post('/submit', data=dict( msg=test_msg, fh=(StringIO(''), ''), ), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertFalse(g.source.flagged) common.logout(source_app) rv = self.journalist_app.get('/') self.assertEqual(rv.status_code, 200) self.assertIn("Sources", rv.data) soup = BeautifulSoup(rv.data) col_url = soup.select('ul#cols > li a')[0]['href'] rv = self.journalist_app.get(col_url) self.assertEqual(rv.status_code, 200) with self.source_app as source_app: rv = source_app.post('/login', data=dict( codename=codename), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertFalse(g.source.flagged) common.logout(source_app) with self.journalist_app as journalist_app: rv = journalist_app.post('/flag', data=dict( sid=sid)) self.assertEqual(rv.status_code, 200) with self.source_app as source_app: rv = source_app.post('/login', data=dict( codename=codename), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertTrue(g.source.flagged) source_app.get('/lookup') self.assertTrue(g.source.flagged) common.logout(source_app) # Block until the reply keypair has been generated, so we can test # sending a reply _block_on_reply_keypair_gen(codename) # Create 2 replies to test deleting on journalist and source interface for i in range(2): rv = self.journalist_app.post('/reply', data=dict( sid=sid, msg=test_reply ), follow_redirects=True) self.assertEqual(rv.status_code, 200) if not expected_success: pass else: self.assertIn("Thanks! Your reply has been stored.", rv.data) with self.journalist_app as journalist_app: rv = journalist_app.get(col_url) self.assertIn("reply-", rv.data) soup = BeautifulSoup(rv.data) # Download the reply and verify that it can be decrypted with the # journalist's key as well as the source's reply key sid = soup.select('input[name="sid"]')[0]['value'] checkbox_values = [soup.select('input[name="doc_names_selected"]')[1]['value']] rv = self.journalist_app.post('/bulk', data=dict( sid=sid, action='download', doc_names_selected=checkbox_values ), follow_redirects=True) self.assertEqual(rv.status_code, 200) zf = zipfile.ZipFile(StringIO(rv.data), 'r') data = zf.read(zf.namelist()[0]) self._can_decrypt_with_key(data, config.JOURNALIST_KEY) self._can_decrypt_with_key(data, crypto_util.getkey(sid), codename) # Test deleting reply on the journalist interface last_reply_number = len(soup.select('input[name="doc_names_selected"]')) - 1 self.helper_filenames_delete(soup, last_reply_number) with self.source_app as source_app: rv = source_app.post('/login', data=dict(codename=codename), follow_redirects=True) self.assertEqual(rv.status_code, 200) rv = source_app.get('/lookup') self.assertEqual(rv.status_code, 200) if not expected_success: # there should be no reply self.assertNotIn("You have received a reply.", rv.data) else: self.assertIn( "You have received a reply. For your security, please delete all replies when you're done with them.", rv.data) self.assertIn(test_reply, rv.data) soup = BeautifulSoup(rv.data) msgid = soup.select('form.message > input[name="reply_filename"]')[0]['value'] rv = source_app.post('/delete', data=dict( sid=sid, reply_filename=msgid ), follow_redirects=True) self.assertEqual(rv.status_code, 200) self.assertIn("Reply deleted", rv.data) # Make sure the reply is deleted from the filesystem self._wait_for( lambda: self.assertFalse(os.path.exists(store.path(sid, msgid))) ) common.logout(source_app)
def test_submit_file(self): """When a source creates an account, test that a new entry appears in the journalist interface""" test_file_contents = "This is a test file." test_filename = "test.txt" with self.source_app as source_app: rv = source_app.get('/generate') rv = source_app.post('/create', follow_redirects=True) codename = session['codename'] sid = g.sid # redirected to submission form rv = self.source_app.post('/submit', data=dict( msg="", fh=(StringIO(test_file_contents), test_filename), ), follow_redirects=True) self.assertEqual(rv.status_code, 200) common.logout(source_app) rv = self.journalist_app.get('/') self.assertEqual(rv.status_code, 200) self.assertIn("Sources", rv.data) soup = BeautifulSoup(rv.data) col_url = soup.select('ul#cols > li a')[0]['href'] rv = self.journalist_app.get(col_url) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) submission_url = soup.select('ul#submissions li a')[0]['href'] self.assertIn("-doc", submission_url) span = soup.select('ul#submissions li span.info span')[0] self.assertRegexpMatches(span['title'], "\d+ bytes") rv = self.journalist_app.get(submission_url) self.assertEqual(rv.status_code, 200) decrypted_data = self.gpg.decrypt(rv.data) self.assertTrue(decrypted_data.ok) sio = StringIO(decrypted_data.data) with gzip.GzipFile(mode='rb', fileobj=sio) as gzip_file: unzipped_decrypted_data = gzip_file.read() self.assertEqual(unzipped_decrypted_data, test_file_contents) # delete submission rv = self.journalist_app.get(col_url) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) doc_name = soup.select( 'ul > li > input[name="doc_names_selected"]')[0]['value'] rv = self.journalist_app.post('/bulk', data=dict(action='confirm_delete', sid=sid, doc_names_selected=doc_name)) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) self.assertIn("The following file has been selected for", rv.data) # confirm delete submission doc_name = soup.select doc_name = soup.select( 'ul > li > input[name="doc_names_selected"]')[0]['value'] rv = self.journalist_app.post('/bulk', data=dict( action='delete', sid=sid, doc_names_selected=doc_name, ), follow_redirects=True) self.assertEqual(rv.status_code, 200) soup = BeautifulSoup(rv.data) self.assertIn("Submission deleted.", rv.data) # confirm that submission deleted and absent in list of submissions rv = self.journalist_app.get(col_url) self.assertEqual(rv.status_code, 200) self.assertIn("No documents to display.", rv.data) # the file should be deleted from the filesystem # since file deletion is handled by a polling worker, this test needs # to wait for the worker to get the job and execute it self._wait_for(lambda: self.assertFalse( os.path.exists(store.path(sid, doc_name))))